mirror of
https://github.com/home-assistant/core.git
synced 2025-07-19 11:17:21 +00:00
Improve Deconz sensors (#65259)
This commit is contained in:
parent
334a8ab13f
commit
1bc936ca8d
@ -3,10 +3,10 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from collections.abc import Callable, ValuesView
|
from collections.abc import Callable, ValuesView
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from pydeconz.sensor import (
|
from pydeconz.sensor import (
|
||||||
AirQuality,
|
AirQuality,
|
||||||
Battery,
|
|
||||||
Consumption,
|
Consumption,
|
||||||
Daylight,
|
Daylight,
|
||||||
DeconzSensor as PydeconzSensor,
|
DeconzSensor as PydeconzSensor,
|
||||||
@ -17,7 +17,6 @@ from pydeconz.sensor import (
|
|||||||
Pressure,
|
Pressure,
|
||||||
Switch,
|
Switch,
|
||||||
Temperature,
|
Temperature,
|
||||||
Thermostat,
|
|
||||||
Time,
|
Time,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,22 +47,21 @@ from homeassistant.helpers.dispatcher import (
|
|||||||
from homeassistant.helpers.entity import EntityCategory
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
from homeassistant.helpers.typing import StateType
|
from homeassistant.helpers.typing import StateType
|
||||||
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from .const import ATTR_DARK, ATTR_ON
|
from .const import ATTR_DARK, ATTR_ON
|
||||||
from .deconz_device import DeconzDevice
|
from .deconz_device import DeconzDevice
|
||||||
from .gateway import DeconzGateway, get_gateway_from_config_entry
|
from .gateway import DeconzGateway, get_gateway_from_config_entry
|
||||||
|
|
||||||
DECONZ_SENSORS = (
|
PROVIDES_EXTRA_ATTRIBUTES = (
|
||||||
AirQuality,
|
"battery",
|
||||||
Consumption,
|
"consumption",
|
||||||
Daylight,
|
"status",
|
||||||
GenericStatus,
|
"humidity",
|
||||||
Humidity,
|
"light_level",
|
||||||
LightLevel,
|
"power",
|
||||||
Power,
|
"pressure",
|
||||||
Pressure,
|
"temperature",
|
||||||
Temperature,
|
|
||||||
Time,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ATTR_CURRENT = "current"
|
ATTR_CURRENT = "current"
|
||||||
@ -76,9 +74,7 @@ ATTR_EVENT_ID = "event_id"
|
|||||||
class DeconzSensorDescriptionMixin:
|
class DeconzSensorDescriptionMixin:
|
||||||
"""Required values when describing secondary sensor attributes."""
|
"""Required values when describing secondary sensor attributes."""
|
||||||
|
|
||||||
suffix: str
|
|
||||||
update_key: str
|
update_key: str
|
||||||
required_attr: str
|
|
||||||
value_fn: Callable[[PydeconzSensor], float | int | None]
|
value_fn: Callable[[PydeconzSensor], float | int | None]
|
||||||
|
|
||||||
|
|
||||||
@ -89,78 +85,133 @@ class DeconzSensorDescription(
|
|||||||
):
|
):
|
||||||
"""Class describing deCONZ binary sensor entities."""
|
"""Class describing deCONZ binary sensor entities."""
|
||||||
|
|
||||||
|
suffix: str = ""
|
||||||
|
|
||||||
|
|
||||||
ENTITY_DESCRIPTIONS = {
|
ENTITY_DESCRIPTIONS = {
|
||||||
Battery: SensorEntityDescription(
|
AirQuality: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="air_quality",
|
||||||
|
value_fn=lambda device: device.air_quality, # type: ignore[no-any-return]
|
||||||
|
update_key="airquality",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
),
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="air_quality_ppb",
|
||||||
|
value_fn=lambda device: device.air_quality_ppb, # type: ignore[no-any-return]
|
||||||
|
suffix="PPB",
|
||||||
|
update_key="airqualityppb",
|
||||||
|
device_class=SensorDeviceClass.AQI,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
Consumption: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="consumption",
|
||||||
|
value_fn=lambda device: device.scaled_consumption, # type: ignore[no-any-return]
|
||||||
|
update_key="consumption",
|
||||||
|
device_class=SensorDeviceClass.ENERGY,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
native_unit_of_measurement=ENERGY_KILO_WATT_HOUR,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Daylight: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="status",
|
||||||
|
value_fn=lambda device: device.status, # type: ignore[no-any-return]
|
||||||
|
update_key="status",
|
||||||
|
icon="mdi:white-balance-sunny",
|
||||||
|
entity_registry_enabled_default=False,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
GenericStatus: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="status",
|
||||||
|
value_fn=lambda device: device.status, # type: ignore[no-any-return]
|
||||||
|
update_key="status",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Humidity: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="humidity",
|
||||||
|
value_fn=lambda device: device.scaled_humidity, # type: ignore[no-any-return]
|
||||||
|
update_key="humidity",
|
||||||
|
device_class=SensorDeviceClass.HUMIDITY,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
LightLevel: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="light_level",
|
||||||
|
value_fn=lambda device: device.scaled_light_level, # type: ignore[no-any-return]
|
||||||
|
update_key="lightlevel",
|
||||||
|
device_class=SensorDeviceClass.ILLUMINANCE,
|
||||||
|
native_unit_of_measurement=LIGHT_LUX,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Power: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="power",
|
||||||
|
value_fn=lambda device: device.power, # type: ignore[no-any-return]
|
||||||
|
update_key="power",
|
||||||
|
device_class=SensorDeviceClass.POWER,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=POWER_WATT,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Pressure: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="pressure",
|
||||||
|
value_fn=lambda device: device.pressure, # type: ignore[no-any-return]
|
||||||
|
update_key="pressure",
|
||||||
|
device_class=SensorDeviceClass.PRESSURE,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=PRESSURE_HPA,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Temperature: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="temperature",
|
||||||
|
value_fn=lambda device: device.temperature, # type: ignore[no-any-return]
|
||||||
|
update_key="temperature",
|
||||||
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
native_unit_of_measurement=TEMP_CELSIUS,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
Time: [
|
||||||
|
DeconzSensorDescription(
|
||||||
|
key="last_set",
|
||||||
|
value_fn=lambda device: device.last_set, # type: ignore[no-any-return]
|
||||||
|
update_key="lastset",
|
||||||
|
device_class=SensorDeviceClass.TIMESTAMP,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
SENSOR_DESCRIPTIONS = [
|
||||||
|
DeconzSensorDescription(
|
||||||
key="battery",
|
key="battery",
|
||||||
|
value_fn=lambda device: device.battery, # type: ignore[no-any-return]
|
||||||
|
suffix="Battery",
|
||||||
|
update_key="battery",
|
||||||
device_class=SensorDeviceClass.BATTERY,
|
device_class=SensorDeviceClass.BATTERY,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
),
|
),
|
||||||
Consumption: SensorEntityDescription(
|
|
||||||
key="consumption",
|
|
||||||
device_class=SensorDeviceClass.ENERGY,
|
|
||||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
|
||||||
native_unit_of_measurement=ENERGY_KILO_WATT_HOUR,
|
|
||||||
),
|
|
||||||
Daylight: SensorEntityDescription(
|
|
||||||
key="daylight",
|
|
||||||
icon="mdi:white-balance-sunny",
|
|
||||||
entity_registry_enabled_default=False,
|
|
||||||
),
|
|
||||||
Humidity: SensorEntityDescription(
|
|
||||||
key="humidity",
|
|
||||||
device_class=SensorDeviceClass.HUMIDITY,
|
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
|
||||||
),
|
|
||||||
LightLevel: SensorEntityDescription(
|
|
||||||
key="lightlevel",
|
|
||||||
device_class=SensorDeviceClass.ILLUMINANCE,
|
|
||||||
native_unit_of_measurement=LIGHT_LUX,
|
|
||||||
),
|
|
||||||
Power: SensorEntityDescription(
|
|
||||||
key="power",
|
|
||||||
device_class=SensorDeviceClass.POWER,
|
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
|
||||||
native_unit_of_measurement=POWER_WATT,
|
|
||||||
),
|
|
||||||
Pressure: SensorEntityDescription(
|
|
||||||
key="pressure",
|
|
||||||
device_class=SensorDeviceClass.PRESSURE,
|
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
|
||||||
native_unit_of_measurement=PRESSURE_HPA,
|
|
||||||
),
|
|
||||||
Temperature: SensorEntityDescription(
|
|
||||||
key="temperature",
|
|
||||||
device_class=SensorDeviceClass.TEMPERATURE,
|
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
|
||||||
native_unit_of_measurement=TEMP_CELSIUS,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
SENSOR_DESCRIPTIONS = [
|
|
||||||
DeconzSensorDescription(
|
DeconzSensorDescription(
|
||||||
key="temperature",
|
key="secondary_temperature",
|
||||||
required_attr="secondary_temperature",
|
value_fn=lambda device: device.secondary_temperature, # type: ignore[no-any-return]
|
||||||
value_fn=lambda device: device.secondary_temperature,
|
|
||||||
suffix="Temperature",
|
suffix="Temperature",
|
||||||
update_key="temperature",
|
update_key="temperature",
|
||||||
device_class=SensorDeviceClass.TEMPERATURE,
|
device_class=SensorDeviceClass.TEMPERATURE,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
native_unit_of_measurement=TEMP_CELSIUS,
|
native_unit_of_measurement=TEMP_CELSIUS,
|
||||||
),
|
),
|
||||||
DeconzSensorDescription(
|
|
||||||
key="air_quality_ppb",
|
|
||||||
required_attr="air_quality_ppb",
|
|
||||||
value_fn=lambda device: device.air_quality_ppb,
|
|
||||||
suffix="PPB",
|
|
||||||
update_key="airqualityppb",
|
|
||||||
device_class=SensorDeviceClass.AQI,
|
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
|
||||||
native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -185,42 +236,33 @@ async def async_setup_entry(
|
|||||||
Create DeconzBattery if sensor has a battery attribute.
|
Create DeconzBattery if sensor has a battery attribute.
|
||||||
Create DeconzSensor if not a battery, switch or thermostat and not a binary sensor.
|
Create DeconzSensor if not a battery, switch or thermostat and not a binary sensor.
|
||||||
"""
|
"""
|
||||||
entities: list[DeconzBattery | DeconzSensor | DeconzPropertySensor] = []
|
entities: list[DeconzSensor] = []
|
||||||
|
|
||||||
for sensor in sensors:
|
for sensor in sensors:
|
||||||
|
|
||||||
if not gateway.option_allow_clip_sensor and sensor.type.startswith("CLIP"):
|
if not gateway.option_allow_clip_sensor and sensor.type.startswith("CLIP"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if sensor.battery is not None:
|
if sensor.battery is None:
|
||||||
battery_handler.remove_tracker(sensor)
|
|
||||||
|
|
||||||
known_batteries = set(gateway.entities[DOMAIN])
|
|
||||||
new_battery = DeconzBattery(sensor, gateway)
|
|
||||||
if new_battery.unique_id not in known_batteries:
|
|
||||||
entities.append(new_battery)
|
|
||||||
|
|
||||||
else:
|
|
||||||
battery_handler.create_tracker(sensor)
|
battery_handler.create_tracker(sensor)
|
||||||
|
|
||||||
if (
|
known_entities = set(gateway.entities[DOMAIN])
|
||||||
isinstance(sensor, DECONZ_SENSORS)
|
for description in (
|
||||||
and not isinstance(sensor, Thermostat)
|
ENTITY_DESCRIPTIONS.get(type(sensor), []) + SENSOR_DESCRIPTIONS
|
||||||
and sensor.unique_id not in gateway.entities[DOMAIN]
|
|
||||||
):
|
):
|
||||||
entities.append(DeconzSensor(sensor, gateway))
|
|
||||||
|
|
||||||
known_sensor_entities = set(gateway.entities[DOMAIN])
|
if (
|
||||||
for sensor_description in SENSOR_DESCRIPTIONS:
|
not hasattr(sensor, description.key)
|
||||||
|
or description.value_fn(sensor) is None
|
||||||
if not hasattr(
|
):
|
||||||
sensor, sensor_description.required_attr
|
|
||||||
) or not sensor_description.value_fn(sensor):
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
new_sensor = DeconzPropertySensor(sensor, gateway, sensor_description)
|
new_entity = DeconzSensor(sensor, gateway, description)
|
||||||
if new_sensor.unique_id not in known_sensor_entities:
|
if new_entity.unique_id not in known_entities:
|
||||||
entities.append(new_sensor)
|
entities.append(new_entity)
|
||||||
|
|
||||||
|
if description.key == "battery":
|
||||||
|
battery_handler.remove_tracker(sensor)
|
||||||
|
|
||||||
if entities:
|
if entities:
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
@ -243,30 +285,66 @@ class DeconzSensor(DeconzDevice, SensorEntity):
|
|||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
_device: PydeconzSensor
|
_device: PydeconzSensor
|
||||||
|
entity_description: DeconzSensorDescription
|
||||||
|
|
||||||
def __init__(self, device: PydeconzSensor, gateway: DeconzGateway) -> None:
|
def __init__(
|
||||||
"""Initialize deCONZ binary sensor."""
|
self,
|
||||||
|
device: PydeconzSensor,
|
||||||
|
gateway: DeconzGateway,
|
||||||
|
description: DeconzSensorDescription,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize deCONZ sensor."""
|
||||||
|
self.entity_description = description
|
||||||
super().__init__(device, gateway)
|
super().__init__(device, gateway)
|
||||||
|
|
||||||
if entity_description := ENTITY_DESCRIPTIONS.get(type(device)):
|
if description.suffix:
|
||||||
self.entity_description = entity_description
|
self._attr_name = f"{device.name} {description.suffix}"
|
||||||
|
|
||||||
|
self._update_keys = {description.update_key, "reachable"}
|
||||||
|
if self.entity_description.key in PROVIDES_EXTRA_ATTRIBUTES:
|
||||||
|
self._update_keys.update({"on", "state"})
|
||||||
|
|
||||||
|
@property
|
||||||
|
def unique_id(self) -> str:
|
||||||
|
"""Return a unique identifier for this device."""
|
||||||
|
if (
|
||||||
|
self.entity_description.key == "battery"
|
||||||
|
and self._device.manufacturer == "Danfoss"
|
||||||
|
and self._device.model_id
|
||||||
|
in [
|
||||||
|
"0x8030",
|
||||||
|
"0x8031",
|
||||||
|
"0x8034",
|
||||||
|
"0x8035",
|
||||||
|
]
|
||||||
|
):
|
||||||
|
return f"{super().unique_id}-battery"
|
||||||
|
if self.entity_description.suffix:
|
||||||
|
return f"{self.serial}-{self.entity_description.suffix.lower()}"
|
||||||
|
return super().unique_id
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_callback(self) -> None:
|
def async_update_callback(self) -> None:
|
||||||
"""Update the sensor's state."""
|
"""Update the sensor's state."""
|
||||||
keys = {"on", "reachable", "state"}
|
if self._device.changed_keys.intersection(self._update_keys):
|
||||||
if self._device.changed_keys.intersection(keys):
|
|
||||||
super().async_update_callback()
|
super().async_update_callback()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def native_value(self) -> StateType:
|
def native_value(self) -> StateType | datetime:
|
||||||
"""Return the state of the sensor."""
|
"""Return the state of the sensor."""
|
||||||
return self._device.state # type: ignore[no-any-return]
|
if self.entity_description.device_class is SensorDeviceClass.TIMESTAMP:
|
||||||
|
return dt_util.parse_datetime(
|
||||||
|
self.entity_description.value_fn(self._device)
|
||||||
|
)
|
||||||
|
return self.entity_description.value_fn(self._device)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> dict[str, bool | float | int | None]:
|
def extra_state_attributes(self) -> dict[str, bool | float | int | None]:
|
||||||
"""Return the state attributes of the sensor."""
|
"""Return the state attributes of the sensor."""
|
||||||
attr = {}
|
attr: dict[str, bool | float | int | None] = {}
|
||||||
|
|
||||||
|
if self.entity_description.key not in PROVIDES_EXTRA_ATTRIBUTES:
|
||||||
|
return attr
|
||||||
|
|
||||||
if self._device.on is not None:
|
if self._device.on is not None:
|
||||||
attr[ATTR_ON] = self._device.on
|
attr[ATTR_ON] = self._device.on
|
||||||
@ -292,93 +370,7 @@ class DeconzSensor(DeconzDevice, SensorEntity):
|
|||||||
attr[ATTR_CURRENT] = self._device.current
|
attr[ATTR_CURRENT] = self._device.current
|
||||||
attr[ATTR_VOLTAGE] = self._device.voltage
|
attr[ATTR_VOLTAGE] = self._device.voltage
|
||||||
|
|
||||||
return attr
|
elif isinstance(self._device, Switch):
|
||||||
|
|
||||||
|
|
||||||
class DeconzPropertySensor(DeconzDevice, SensorEntity):
|
|
||||||
"""Representation of a deCONZ secondary attribute sensor."""
|
|
||||||
|
|
||||||
TYPE = DOMAIN
|
|
||||||
_device: PydeconzSensor
|
|
||||||
entity_description: DeconzSensorDescription
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
device: PydeconzSensor,
|
|
||||||
gateway: DeconzGateway,
|
|
||||||
description: DeconzSensorDescription,
|
|
||||||
) -> None:
|
|
||||||
"""Initialize deCONZ sensor."""
|
|
||||||
self.entity_description = description
|
|
||||||
super().__init__(device, gateway)
|
|
||||||
|
|
||||||
self._attr_name = f"{self._device.name} {description.suffix}"
|
|
||||||
self._update_keys = {description.update_key, "reachable"}
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self) -> str:
|
|
||||||
"""Return a unique identifier for this device."""
|
|
||||||
return f"{self.serial}-{self.entity_description.suffix.lower()}"
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_update_callback(self) -> None:
|
|
||||||
"""Update the sensor's state."""
|
|
||||||
if self._device.changed_keys.intersection(self._update_keys):
|
|
||||||
super().async_update_callback()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self) -> StateType:
|
|
||||||
"""Return the state of the sensor."""
|
|
||||||
return self.entity_description.value_fn(self._device)
|
|
||||||
|
|
||||||
|
|
||||||
class DeconzBattery(DeconzDevice, SensorEntity):
|
|
||||||
"""Battery class for when a device is only represented as an event."""
|
|
||||||
|
|
||||||
TYPE = DOMAIN
|
|
||||||
_device: PydeconzSensor
|
|
||||||
|
|
||||||
def __init__(self, device: PydeconzSensor, gateway: DeconzGateway) -> None:
|
|
||||||
"""Initialize deCONZ battery level sensor."""
|
|
||||||
super().__init__(device, gateway)
|
|
||||||
|
|
||||||
self.entity_description = ENTITY_DESCRIPTIONS[Battery]
|
|
||||||
self._attr_name = f"{self._device.name} Battery Level"
|
|
||||||
|
|
||||||
@callback
|
|
||||||
def async_update_callback(self) -> None:
|
|
||||||
"""Update the battery's state, if needed."""
|
|
||||||
keys = {"battery", "reachable"}
|
|
||||||
if self._device.changed_keys.intersection(keys):
|
|
||||||
super().async_update_callback()
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self) -> str:
|
|
||||||
"""Return a unique identifier for this device.
|
|
||||||
|
|
||||||
Normally there should only be one battery sensor per device from deCONZ.
|
|
||||||
With specific Danfoss devices each endpoint can report its own battery state.
|
|
||||||
"""
|
|
||||||
if self._device.manufacturer == "Danfoss" and self._device.model_id in [
|
|
||||||
"0x8030",
|
|
||||||
"0x8031",
|
|
||||||
"0x8034",
|
|
||||||
"0x8035",
|
|
||||||
]:
|
|
||||||
return f"{super().unique_id}-battery"
|
|
||||||
return f"{self.serial}-battery"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self) -> StateType:
|
|
||||||
"""Return the state of the battery."""
|
|
||||||
return self._device.battery # type: ignore[no-any-return]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def extra_state_attributes(self) -> dict[str, str]:
|
|
||||||
"""Return the state attributes of the battery."""
|
|
||||||
attr = {}
|
|
||||||
|
|
||||||
if isinstance(self._device, Switch):
|
|
||||||
for event in self.gateway.events:
|
for event in self.gateway.events:
|
||||||
if self._device == event.device:
|
if self._device == event.device:
|
||||||
attr[ATTR_EVENT_ID] = event.event_id
|
attr[ATTR_EVENT_ID] = event.event_id
|
||||||
|
@ -111,7 +111,7 @@ async def test_simple_climate_device(hass, aioclient_mock, mock_deconz_websocket
|
|||||||
assert climate_thermostat.attributes["current_temperature"] == 21.0
|
assert climate_thermostat.attributes["current_temperature"] == 21.0
|
||||||
assert climate_thermostat.attributes["temperature"] == 21.0
|
assert climate_thermostat.attributes["temperature"] == 21.0
|
||||||
assert climate_thermostat.attributes["locked"] is True
|
assert climate_thermostat.attributes["locked"] is True
|
||||||
assert hass.states.get("sensor.thermostat_battery_level").state == "59"
|
assert hass.states.get("sensor.thermostat_battery").state == "59"
|
||||||
|
|
||||||
# Event signals thermostat configured off
|
# Event signals thermostat configured off
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ async def test_climate_device_without_cooling_support(
|
|||||||
assert climate_thermostat.attributes["current_temperature"] == 22.6
|
assert climate_thermostat.attributes["current_temperature"] == 22.6
|
||||||
assert climate_thermostat.attributes["temperature"] == 22.0
|
assert climate_thermostat.attributes["temperature"] == 22.0
|
||||||
assert hass.states.get("sensor.thermostat") is None
|
assert hass.states.get("sensor.thermostat") is None
|
||||||
assert hass.states.get("sensor.thermostat_battery_level").state == "100"
|
assert hass.states.get("sensor.thermostat_battery").state == "100"
|
||||||
assert hass.states.get("climate.presence_sensor") is None
|
assert hass.states.get("climate.presence_sensor") is None
|
||||||
assert hass.states.get("climate.clip_thermostat") is None
|
assert hass.states.get("climate.clip_thermostat") is None
|
||||||
|
|
||||||
@ -385,7 +385,7 @@ async def test_climate_device_with_cooling_support(
|
|||||||
]
|
]
|
||||||
assert climate_thermostat.attributes["current_temperature"] == 23.2
|
assert climate_thermostat.attributes["current_temperature"] == 23.2
|
||||||
assert climate_thermostat.attributes["temperature"] == 22.2
|
assert climate_thermostat.attributes["temperature"] == 22.2
|
||||||
assert hass.states.get("sensor.zen_01_battery_level").state == "25"
|
assert hass.states.get("sensor.zen_01_battery").state == "25"
|
||||||
|
|
||||||
# Event signals thermostat state cool
|
# Event signals thermostat state cool
|
||||||
|
|
||||||
@ -787,4 +787,4 @@ async def test_add_new_climate_device(hass, aioclient_mock, mock_deconz_websocke
|
|||||||
|
|
||||||
assert len(hass.states.async_all()) == 2
|
assert len(hass.states.async_all()) == 2
|
||||||
assert hass.states.get("climate.thermostat").state == HVAC_MODE_AUTO
|
assert hass.states.get("climate.thermostat").state == HVAC_MODE_AUTO
|
||||||
assert hass.states.get("sensor.thermostat_battery_level").state == "100"
|
assert hass.states.get("sensor.thermostat_battery").state == "100"
|
||||||
|
@ -80,9 +80,9 @@ async def test_deconz_events(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
assert (
|
assert (
|
||||||
len(async_entries_for_config_entry(device_registry, config_entry.entry_id)) == 7
|
len(async_entries_for_config_entry(device_registry, config_entry.entry_id)) == 7
|
||||||
)
|
)
|
||||||
assert hass.states.get("sensor.switch_2_battery_level").state == "100"
|
assert hass.states.get("sensor.switch_2_battery").state == "100"
|
||||||
assert hass.states.get("sensor.switch_3_battery_level").state == "100"
|
assert hass.states.get("sensor.switch_3_battery").state == "100"
|
||||||
assert hass.states.get("sensor.switch_4_battery_level").state == "100"
|
assert hass.states.get("sensor.switch_4_battery").state == "100"
|
||||||
|
|
||||||
captured_events = async_capture_events(hass, CONF_DECONZ_EVENT)
|
captured_events = async_capture_events(hass, CONF_DECONZ_EVENT)
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ async def test_get_triggers(hass, aioclient_mock):
|
|||||||
{
|
{
|
||||||
CONF_DEVICE_ID: device.id,
|
CONF_DEVICE_ID: device.id,
|
||||||
CONF_DOMAIN: SENSOR_DOMAIN,
|
CONF_DOMAIN: SENSOR_DOMAIN,
|
||||||
ATTR_ENTITY_ID: "sensor.tradfri_on_off_switch_battery_level",
|
ATTR_ENTITY_ID: "sensor.tradfri_on_off_switch_battery",
|
||||||
CONF_PLATFORM: "device",
|
CONF_PLATFORM: "device",
|
||||||
CONF_TYPE: ATTR_BATTERY_LEVEL,
|
CONF_TYPE: ATTR_BATTERY_LEVEL,
|
||||||
},
|
},
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user