Skip to content
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

Provide metadata for the calculation of extra_state_attributes #56

Merged
merged 2 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion tests/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ async def async_test_temperature(
zha_gateway: Gateway, cluster: Cluster, entity: PlatformEntity
) -> None:
"""Test temperature sensor."""
assert entity.extra_state_attribute_names is None
await send_attributes_report(zha_gateway, cluster, {1: 1, 0: 2900, 2: 100})
assert_state(entity, 29.0, "°C")

Expand Down Expand Up @@ -117,6 +118,11 @@ async def async_test_metering(
zha_gateway: Gateway, cluster: Cluster, entity: PlatformEntity
) -> None:
"""Test Smart Energy metering sensor."""
assert entity.extra_state_attribute_names == {
"status",
"device_type",
"zcl_unit_of_measurement",
}
await send_attributes_report(
zha_gateway, cluster, {1025: 1, 1024: 12345, 1026: 100}
)
Expand Down Expand Up @@ -166,7 +172,11 @@ async def async_test_smart_energy_summation_delivered(
zha_gateway: Gateway, cluster, entity
):
"""Test SmartEnergy Summation delivered sensor."""

assert entity.extra_state_attribute_names == {
"status",
"device_type",
"zcl_unit_of_measurement",
}
await send_attributes_report(
zha_gateway, cluster, {1025: 1, "current_summ_delivered": 12321, 1026: 100}
)
Expand Down Expand Up @@ -316,6 +326,12 @@ async def async_test_powerconfiguration(
zha_gateway: Gateway, cluster: Cluster, entity: PlatformEntity
) -> None:
"""Test powerconfiguration/battery sensor."""
assert entity.extra_state_attribute_names == {
"battery_voltage",
"battery_quantity",
"battery_size",
"battery_voltage",
}
await send_attributes_report(zha_gateway, cluster, {33: 98})
assert_state(entity, 49, "%")
assert entity.state["battery_voltage"] == 2.9
Expand Down
11 changes: 11 additions & 0 deletions zha/application/platforms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,17 @@ def state(self) -> dict[str, Any]:
"class_name": self.__class__.__name__,
}

@cached_property
def extra_state_attribute_names(self) -> set[str] | None:
"""Return entity specific state attribute names.

Implemented by platform classes. Convention for attribute names
is lowercase snake_case.
"""
if hasattr(self, "_attr_extra_state_attribute_names"):
return self._attr_extra_state_attribute_names
return None

async def on_remove(self) -> None:
"""Cancel tasks and timers this entity owns."""
for handle in self._tracked_handles:
Expand Down
10 changes: 10 additions & 0 deletions zha/application/platforms/climate/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ class Thermostat(PlatformEntity):
_attr_temperature_unit = UnitOfTemperature.CELSIUS
_attr_translation_key: str = "thermostat"
_enable_turn_on_off_backwards_compatibility = False
_attr_extra_state_attribute_names: set[str] = {
ATTR_SYS_MODE,
ATTR_OCCUPANCY,
ATTR_OCCP_COOL_SETPT,
ATTR_OCCP_HEAT_SETPT,
ATTR_PI_HEATING_DEMAND,
ATTR_PI_COOLING_DEMAND,
ATTR_UNOCCP_COOL_SETPT,
ATTR_UNOCCP_HEAT_SETPT,
}

def __init__(
self,
Expand Down
4 changes: 4 additions & 0 deletions zha/application/platforms/light/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ class BaseLight(BaseEntity, ABC):
PLATFORM = Platform.LIGHT
_FORCE_ON = False
_DEFAULT_MIN_TRANSITION_TIME: float = 0
_attr_extra_state_attribute_names: set[str] = {
"off_with_transition",
"off_brightness",
}

def __init__(self, *args, **kwargs):
"""Initialize the light."""
Expand Down
31 changes: 30 additions & 1 deletion zha/application/platforms/sensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,11 @@ def handle_cluster_handler_attribute_updated(
event: ClusterAttributeUpdatedEvent, # pylint: disable=unused-argument
) -> None:
"""Handle attribute updates from the cluster handler."""
if event.attribute_name == self._attribute_name:
if event.attribute_name == self._attribute_name or (
hasattr(self, "_attr_extra_state_attribute_names")
and event.attribute_name
in getattr(self, "_attr_extra_state_attribute_names")
):
self.maybe_emit_state_changed_event()

def formatter(self, value: int | enum.IntEnum) -> int | float | str | None:
Expand Down Expand Up @@ -489,6 +493,11 @@ class Battery(Sensor):
_attr_state_class: SensorStateClass = SensorStateClass.MEASUREMENT
_attr_entity_category = EntityCategory.DIAGNOSTIC
_attr_native_unit_of_measurement = PERCENTAGE
_attr_extra_state_attribute_names: set[str] = {
"battery_size",
"battery_quantity",
"battery_voltage",
}

@classmethod
def create_platform_entity(
Expand Down Expand Up @@ -549,6 +558,21 @@ class ElectricalMeasurement(PollableSensor):
_attr_native_unit_of_measurement: str = UnitOfPower.WATT
_div_mul_prefix: str | None = "ac_power"

def __init__(
self,
unique_id: str,
cluster_handlers: list[ClusterHandler],
endpoint: Endpoint,
device: Device,
**kwargs: Any,
) -> None:
"""Init this sensor."""
super().__init__(unique_id, cluster_handlers, endpoint, device, **kwargs)
self._attr_extra_state_attribute_names: set[str] = {
"measurement_type",
f"{self._attribute_name}_max",
}

@property
def state(self) -> dict[str, Any]:
"""Return the state for this sensor."""
Expand Down Expand Up @@ -734,6 +758,11 @@ class SmartEnergyMetering(PollableSensor):
_use_custom_polling: bool = False
_attribute_name = "instantaneous_demand"
_attr_translation_key: str = "instantaneous_demand"
_attr_extra_state_attribute_names: set[str] = {
"device_type",
"status",
"zcl_unit_of_measurement",
}

_ENTITY_DESCRIPTION_MAP = {
0x00: SmartEnergyMeteringEntityDescription(
Expand Down
Loading