1 """Support for IKEA Tradfri sensors."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
7 from typing
import Any, cast
9 from pytradfri.command
import Command
10 from pytradfri.device
import Device
15 SensorEntityDescription,
20 CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
37 from .coordinator
import TradfriDeviceDataUpdateCoordinator
38 from .entity
import TradfriBaseEntity
41 @dataclass(frozen=True, kw_only=True)
43 """Class describing Tradfri sensor entities."""
45 value: Callable[[Device], Any |
None]
49 """Fetch the air quality value."""
50 assert device.air_purifier_control
is not None
52 device.air_purifier_control.air_purifiers[0].air_quality == 65535
56 return cast(int, device.air_purifier_control.air_purifiers[0].air_quality)
60 """Fetch the filter's remaining lifetime (in hours)."""
61 assert device.air_purifier_control
is not None
64 int, device.air_purifier_control.air_purifiers[0].filter_lifetime_remaining
70 SENSOR_DESCRIPTIONS_BATTERY: tuple[TradfriSensorEntityDescription, ...] = (
73 device_class=SensorDeviceClass.BATTERY,
74 state_class=SensorStateClass.MEASUREMENT,
75 native_unit_of_measurement=PERCENTAGE,
76 value=
lambda device: cast(int, device.device_info.battery_level),
81 SENSOR_DESCRIPTIONS_FAN: tuple[TradfriSensorEntityDescription, ...] = (
84 translation_key=
"aqi",
85 state_class=SensorStateClass.MEASUREMENT,
86 native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
87 value=_get_air_quality,
90 key=
"filter_life_remaining",
91 translation_key=
"filter_life_remaining",
92 state_class=SensorStateClass.MEASUREMENT,
93 native_unit_of_measurement=UnitOfTime.HOURS,
94 value=_get_filter_time_left,
101 """Migrate unique IDs to the new format."""
102 ent_reg = er.async_get(hass)
104 entity_id = ent_reg.async_get_entity_id(Platform.SENSOR, DOMAIN, old_unique_id)
106 if entity_id
is None:
109 new_unique_id = f
"{old_unique_id}-{key}"
112 ent_reg.async_update_entity(entity_id, new_unique_id=new_unique_id)
115 "Skip migration of id [%s] to [%s] because it already exists",
122 "Migrating unique_id from [%s] to [%s]",
130 config_entry: ConfigEntry,
131 async_add_entities: AddEntitiesCallback,
133 """Set up a Tradfri config entry."""
134 gateway_id = config_entry.data[CONF_GATEWAY_ID]
135 coordinator_data = hass.data[DOMAIN][config_entry.entry_id][COORDINATOR]
136 api = coordinator_data[KEY_API]
138 entities: list[TradfriSensor] = []
140 for device_coordinator
in coordinator_data[COORDINATOR_LIST]:
142 not device_coordinator.device.has_light_control
143 and not device_coordinator.device.has_socket_control
144 and not device_coordinator.device.has_signal_repeater_control
145 and not device_coordinator.device.has_air_purifier_control
147 descriptions = SENSOR_DESCRIPTIONS_BATTERY
148 elif device_coordinator.device.has_air_purifier_control:
149 descriptions = SENSOR_DESCRIPTIONS_FAN
153 for description
in descriptions:
157 old_unique_id=f
"{gateway_id}-{device_coordinator.device.id}",
166 description=description,
174 """The platform class required by Home Assistant."""
176 entity_description: TradfriSensorEntityDescription
180 device_coordinator: TradfriDeviceDataUpdateCoordinator,
181 api: Callable[[Command | list[Command]], Any],
183 description: TradfriSensorEntityDescription,
185 """Initialize a Tradfri sensor."""
187 device_coordinator=device_coordinator,
189 gateway_id=gateway_id,
199 """Refresh the device."""
None __init__(self, TradfriDeviceDataUpdateCoordinator device_coordinator, Callable[[Command|list[Command]], Any] api, str gateway_id, TradfriSensorEntityDescription description)
None _migrate_old_unique_ids(HomeAssistant hass, str old_unique_id, str key)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
int _get_filter_time_left(Device device)
int|None _get_air_quality(Device device)