-
-
Notifications
You must be signed in to change notification settings - Fork 36.4k
Actron air add sensor entity type #158154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
kclif9
wants to merge
20
commits into
home-assistant:dev
from
kclif9:Actron-Air-Add-Sensor-Entity-Type
Closed
Changes from all commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
95ad48e
Add switch entity platform
kclif9 fb71911
Merge branch 'dev' into Actron-Air-Add-Switch-Entity-Type
kclif9 5a5d3fb
fix copilot suggestions
kclif9 d4fcdbe
wip
kclif9 93f41d9
wip
kclif9 2f36d64
wip
kclif9 14f6803
fix state class
kclif9 7f098c3
mark completed items as done
kclif9 df741be
update units of measurement
kclif9 63ce89f
fix state classes
kclif9 df1cc6d
Merge branch 'dev' into Actron-Air-Add-Sensor-Entity-Type
kclif9 33d30c4
Refactor Actron Air integration: remove switch platform, add sensor e…
kclif9 8a1488c
update PR with recent changes to avoid merge conflicts
kclif9 bc06cd6
fix what will be merge conflicts when #158087 is merged
kclif9 1a95660
Merge branch 'dev' into Actron-Air-Add-Sensor-Entity-Type
kclif9 2b8c986
Refactor Actron Air sensor tests to validate peripheral sensor keys a…
kclif9 e460c6e
Update quality_scale.yaml to mark entity categories, device classes, …
kclif9 7415691
Update quality_scale.yaml to mark action-exceptions and reconfigurati…
kclif9 472832d
Refactor Actron Air integration:
kclif9 c80af6a
Merge branch 'dev' into Actron-Air-Add-Sensor-Entity-Type
kclif9 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| """Base entity classes for Actron Air integration.""" | ||
|
|
||
| from homeassistant.helpers.device_registry import DeviceInfo | ||
| from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||
|
|
||
| from .const import DOMAIN | ||
| from .coordinator import ActronAirSystemCoordinator | ||
|
|
||
|
|
||
| class ActronAirEntity(CoordinatorEntity[ActronAirSystemCoordinator]): | ||
| """Base class for Actron Air entities.""" | ||
|
|
||
| _attr_has_entity_name = True | ||
|
|
||
| def __init__(self, coordinator: ActronAirSystemCoordinator) -> None: | ||
| """Initialize the entity.""" | ||
| super().__init__(coordinator) | ||
| self._serial_number = coordinator.serial_number | ||
|
|
||
| self._attr_device_info: DeviceInfo = DeviceInfo( | ||
| identifiers={(DOMAIN, self._serial_number)}, | ||
| name=coordinator.data.ac_system.system_name, | ||
| manufacturer="Actron Air", | ||
| model_id=coordinator.data.ac_system.master_wc_model, | ||
| sw_version=coordinator.data.ac_system.master_wc_firmware_version, | ||
| serial_number=self._serial_number, | ||
| ) | ||
|
|
||
| @property | ||
| def available(self) -> bool: | ||
| """Return True if entity is available.""" | ||
| return not self.coordinator.is_device_stale() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,206 @@ | ||
| """Sensor platform for Actron Air integration.""" | ||
|
|
||
| from collections.abc import Callable | ||
| from dataclasses import dataclass | ||
|
|
||
| from actron_neo_api import ActronAirPeripheral, ActronAirStatus | ||
|
|
||
| from homeassistant.components.sensor import ( | ||
| SensorDeviceClass, | ||
| SensorEntity, | ||
| SensorEntityDescription, | ||
| SensorStateClass, | ||
| ) | ||
| from homeassistant.const import ( | ||
| PERCENTAGE, | ||
| REVOLUTIONS_PER_MINUTE, | ||
| EntityCategory, | ||
| UnitOfPower, | ||
| UnitOfTemperature, | ||
| ) | ||
| from homeassistant.core import HomeAssistant | ||
| from homeassistant.helpers.device_registry import DeviceInfo | ||
| from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback | ||
|
|
||
| from .const import DOMAIN | ||
| from .coordinator import ActronAirConfigEntry, ActronAirSystemCoordinator | ||
| from .entity import ActronAirEntity | ||
|
|
||
| PARALLEL_UPDATES = 0 | ||
|
|
||
|
|
||
| @dataclass(frozen=True, kw_only=True) | ||
| class ActronAirSensorEntityDescription(SensorEntityDescription): | ||
| """Describes Actron Air sensor entity.""" | ||
|
|
||
| value_fn: Callable[[ActronAirStatus], str | int | float | bool | None] | None = None | ||
|
|
||
|
|
||
| @dataclass(frozen=True, kw_only=True) | ||
| class ActronAirPeripheralSensorEntityDescription(SensorEntityDescription): | ||
| """Describes Actron Air peripheral sensor entity.""" | ||
|
|
||
| value_fn: Callable[[ActronAirPeripheral], str | int | float | None] | None = None | ||
|
|
||
|
|
||
| AC_SENSORS: tuple[ActronAirSensorEntityDescription, ...] = ( | ||
| ActronAirSensorEntityDescription( | ||
| key="compressor_chasing_temperature", | ||
| translation_key="compressor_chasing_temperature", | ||
| device_class=SensorDeviceClass.TEMPERATURE, | ||
| native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| entity_registry_enabled_default=False, | ||
| value_fn=lambda status: status.compressor_chasing_temperature, | ||
| ), | ||
| ActronAirSensorEntityDescription( | ||
| key="compressor_live_temperature", | ||
| translation_key="compressor_live_temperature", | ||
| device_class=SensorDeviceClass.TEMPERATURE, | ||
| native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| entity_registry_enabled_default=False, | ||
| value_fn=lambda status: status.compressor_live_temperature, | ||
| ), | ||
| ActronAirSensorEntityDescription( | ||
| key="compressor_speed", | ||
| translation_key="compressor_speed", | ||
| native_unit_of_measurement=REVOLUTIONS_PER_MINUTE, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| entity_registry_enabled_default=False, | ||
| value_fn=lambda status: status.compressor_speed, | ||
| ), | ||
| ActronAirSensorEntityDescription( | ||
| key="compressor_power", | ||
| translation_key="compressor_power", | ||
| device_class=SensorDeviceClass.POWER, | ||
| native_unit_of_measurement=UnitOfPower.WATT, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| entity_registry_enabled_default=False, | ||
| value_fn=lambda status: status.compressor_power, | ||
| ), | ||
| ActronAirSensorEntityDescription( | ||
| key="outdoor_temperature", | ||
| translation_key="outdoor_temperature", | ||
| device_class=SensorDeviceClass.TEMPERATURE, | ||
| native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| entity_registry_enabled_default=False, | ||
| value_fn=lambda status: status.outdoor_temperature, | ||
| ), | ||
| ) | ||
|
|
||
| PERIPHERAL_SENSORS: tuple[ActronAirPeripheralSensorEntityDescription, ...] = ( | ||
| ActronAirPeripheralSensorEntityDescription( | ||
| key="battery", | ||
| device_class=SensorDeviceClass.BATTERY, | ||
| native_unit_of_measurement=PERCENTAGE, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| value_fn=lambda peripheral: peripheral.battery_level, | ||
| ), | ||
| ActronAirPeripheralSensorEntityDescription( | ||
| key="humidity", | ||
| device_class=SensorDeviceClass.HUMIDITY, | ||
| native_unit_of_measurement=PERCENTAGE, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| value_fn=lambda peripheral: peripheral.humidity, | ||
| ), | ||
| ActronAirPeripheralSensorEntityDescription( | ||
| key="temperature", | ||
| device_class=SensorDeviceClass.TEMPERATURE, | ||
| native_unit_of_measurement=UnitOfTemperature.CELSIUS, | ||
| state_class=SensorStateClass.MEASUREMENT, | ||
| value_fn=lambda peripheral: peripheral.temperature, | ||
| ), | ||
| ) | ||
|
|
||
|
|
||
| async def async_setup_entry( | ||
| hass: HomeAssistant, | ||
| entry: ActronAirConfigEntry, | ||
| async_add_entities: AddConfigEntryEntitiesCallback, | ||
| ) -> None: | ||
| """Set up Actron Air sensor platform entities.""" | ||
| system_coordinators = entry.runtime_data.system_coordinators | ||
| entities: list[SensorEntity] = [] | ||
|
|
||
| for coordinator in system_coordinators.values(): | ||
| status = coordinator.data | ||
|
|
||
| # Add AC system sensors | ||
| entities.extend( | ||
| ActronAirSensor(coordinator, description) for description in AC_SENSORS | ||
| ) | ||
|
|
||
| # Add peripheral sensors | ||
| for peripheral in status.peripherals: | ||
| entities.extend( | ||
| ActronAirPeripheralSensorEntity(coordinator, peripheral, description) | ||
| for description in PERIPHERAL_SENSORS | ||
| ) | ||
|
|
||
| # Register all sensors | ||
| async_add_entities(entities) | ||
|
|
||
|
|
||
| class ActronAirSensor(ActronAirEntity, SensorEntity): | ||
| """Representation of an Actron Air sensor.""" | ||
|
|
||
| entity_description: ActronAirSensorEntityDescription | ||
| _attr_entity_category: EntityCategory | None = EntityCategory.DIAGNOSTIC | ||
|
|
||
| def __init__( | ||
| self, | ||
| coordinator: ActronAirSystemCoordinator, | ||
| description: ActronAirSensorEntityDescription, | ||
| ) -> None: | ||
| """Initialize the sensor.""" | ||
| super().__init__(coordinator) | ||
| self.entity_description = description | ||
| self._attr_unique_id = f"{self._serial_number}_{description.key}" | ||
|
|
||
| @property | ||
| def native_value(self) -> str | int | float | bool | None: | ||
| """Return the state of the sensor.""" | ||
| if self.entity_description.value_fn is None: | ||
| return None | ||
| return self.entity_description.value_fn(self.coordinator.data) | ||
|
|
||
|
|
||
| class ActronAirPeripheralSensorEntity(ActronAirEntity, SensorEntity): | ||
| """Representation of an Actron Air peripheral sensor.""" | ||
|
|
||
| entity_description: ActronAirPeripheralSensorEntityDescription | ||
| _attr_entity_category = None | ||
|
|
||
| def __init__( | ||
| self, | ||
| coordinator: ActronAirSystemCoordinator, | ||
| peripheral: ActronAirPeripheral, | ||
| description: ActronAirPeripheralSensorEntityDescription, | ||
| ) -> None: | ||
| """Initialize the sensor.""" | ||
| super().__init__(coordinator) | ||
|
|
||
| self._peripheral = peripheral | ||
| zone = peripheral.zones[0] | ||
| suggested_area = zone.title | ||
| zone_entity_id = f"{self._serial_number}_zone_{zone.zone_id}" | ||
|
|
||
| self.entity_description = description | ||
| self._attr_unique_id = f"{peripheral.serial_number}_{description.key}" | ||
| self._attr_device_info: DeviceInfo = DeviceInfo( | ||
| identifiers={(DOMAIN, peripheral.serial_number)}, | ||
| name=f"{peripheral.device_type} {peripheral.logical_address}", | ||
| model=peripheral.device_type, | ||
| suggested_area=suggested_area, | ||
| via_device=(DOMAIN, zone_entity_id), | ||
| serial_number=peripheral.serial_number, | ||
| ) | ||
|
|
||
| @property | ||
| def native_value(self) -> str | int | float | None: | ||
| """Return the state of the sensor.""" | ||
| if self.entity_description.value_fn is None: | ||
| return None | ||
| return self.entity_description.value_fn(self._peripheral) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.