Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Sensor platform for Sensibo integration."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Mapping
6 from dataclasses import dataclass
7 from datetime import datetime
8 from typing import TYPE_CHECKING, Any
9 
10 from pysensibo.model import MotionSensor, PureAQI, SensiboDevice
11 
13  SensorDeviceClass,
14  SensorEntity,
15  SensorEntityDescription,
16  SensorStateClass,
17 )
18 from homeassistant.const import (
19  CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
20  CONCENTRATION_PARTS_PER_BILLION,
21  CONCENTRATION_PARTS_PER_MILLION,
22  PERCENTAGE,
23  SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
24  EntityCategory,
25  UnitOfElectricPotential,
26  UnitOfTemperature,
27 )
28 from homeassistant.core import HomeAssistant
29 from homeassistant.helpers.entity_platform import AddEntitiesCallback
30 from homeassistant.helpers.typing import StateType
31 
32 from . import SensiboConfigEntry
33 from .coordinator import SensiboDataUpdateCoordinator
34 from .entity import SensiboDeviceBaseEntity, SensiboMotionBaseEntity
35 
36 PARALLEL_UPDATES = 0
37 
38 
39 @dataclass(frozen=True, kw_only=True)
41  """Describes Sensibo Motion sensor entity."""
42 
43  value_fn: Callable[[MotionSensor], StateType]
44 
45 
46 @dataclass(frozen=True, kw_only=True)
48  """Describes Sensibo Device sensor entity."""
49 
50  value_fn: Callable[[SensiboDevice], StateType | datetime]
51  extra_fn: Callable[[SensiboDevice], dict[str, str | bool | None] | None] | None
52 
53 
54 FILTER_LAST_RESET_DESCRIPTION = SensiboDeviceSensorEntityDescription(
55  key="filter_last_reset",
56  translation_key="filter_last_reset",
57  device_class=SensorDeviceClass.TIMESTAMP,
58  value_fn=lambda data: data.filter_last_reset,
59  extra_fn=None,
60 )
61 
62 MOTION_SENSOR_TYPES: tuple[SensiboMotionSensorEntityDescription, ...] = (
64  key="rssi",
65  translation_key="rssi",
66  device_class=SensorDeviceClass.SIGNAL_STRENGTH,
67  entity_category=EntityCategory.DIAGNOSTIC,
68  native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
69  state_class=SensorStateClass.MEASUREMENT,
70  value_fn=lambda data: data.rssi,
71  entity_registry_enabled_default=False,
72  ),
74  key="battery_voltage",
75  translation_key="battery_voltage",
76  device_class=SensorDeviceClass.VOLTAGE,
77  entity_category=EntityCategory.DIAGNOSTIC,
78  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
79  state_class=SensorStateClass.MEASUREMENT,
80  value_fn=lambda data: data.battery_voltage,
81  ),
83  key="humidity",
84  device_class=SensorDeviceClass.HUMIDITY,
85  native_unit_of_measurement=PERCENTAGE,
86  state_class=SensorStateClass.MEASUREMENT,
87  value_fn=lambda data: data.humidity,
88  ),
90  key="temperature",
91  device_class=SensorDeviceClass.TEMPERATURE,
92  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
93  state_class=SensorStateClass.MEASUREMENT,
94  value_fn=lambda data: data.temperature,
95  ),
96 )
97 PURE_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
99  key="pm25",
100  translation_key="pm25_pure",
101  device_class=SensorDeviceClass.ENUM,
102  value_fn=lambda data: data.pm25_pure.name.lower() if data.pm25_pure else None,
103  extra_fn=None,
104  options=[aqi.name.lower() for aqi in PureAQI],
105  ),
107  key="pure_sensitivity",
108  translation_key="sensitivity",
109  value_fn=lambda data: data.pure_sensitivity,
110  extra_fn=None,
111  ),
112  FILTER_LAST_RESET_DESCRIPTION,
113 )
114 
115 DEVICE_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
117  key="timer_time",
118  translation_key="timer_time",
119  device_class=SensorDeviceClass.TIMESTAMP,
120  value_fn=lambda data: data.timer_time,
121  extra_fn=lambda data: {"id": data.timer_id, "turn_on": data.timer_state_on},
122  ),
124  key="feels_like",
125  translation_key="feels_like",
126  device_class=SensorDeviceClass.TEMPERATURE,
127  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
128  state_class=SensorStateClass.MEASUREMENT,
129  value_fn=lambda data: data.feelslike,
130  extra_fn=None,
131  entity_registry_enabled_default=False,
132  ),
134  key="climate_react_low",
135  translation_key="climate_react_low",
136  device_class=SensorDeviceClass.TEMPERATURE,
137  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
138  state_class=SensorStateClass.MEASUREMENT,
139  value_fn=lambda data: data.smart_low_temp_threshold,
140  extra_fn=lambda data: data.smart_low_state,
141  entity_registry_enabled_default=False,
142  ),
144  key="climate_react_high",
145  translation_key="climate_react_high",
146  device_class=SensorDeviceClass.TEMPERATURE,
147  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
148  state_class=SensorStateClass.MEASUREMENT,
149  value_fn=lambda data: data.smart_high_temp_threshold,
150  extra_fn=lambda data: data.smart_high_state,
151  entity_registry_enabled_default=False,
152  ),
154  key="climate_react_type",
155  translation_key="smart_type",
156  value_fn=lambda data: data.smart_type,
157  extra_fn=None,
158  entity_registry_enabled_default=False,
159  ),
160  FILTER_LAST_RESET_DESCRIPTION,
161 )
162 
163 AIRQ_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
165  key="airq_tvoc",
166  translation_key="airq_tvoc",
167  native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
168  state_class=SensorStateClass.MEASUREMENT,
169  value_fn=lambda data: data.tvoc,
170  extra_fn=None,
171  ),
173  key="airq_co2",
174  translation_key="airq_co2",
175  device_class=SensorDeviceClass.CO2,
176  native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
177  state_class=SensorStateClass.MEASUREMENT,
178  value_fn=lambda data: data.co2,
179  extra_fn=None,
180  ),
181  *DEVICE_SENSOR_TYPES,
182 )
183 
184 ELEMENT_SENSOR_TYPES: tuple[SensiboDeviceSensorEntityDescription, ...] = (
186  key="pm25",
187  device_class=SensorDeviceClass.PM25,
188  native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
189  state_class=SensorStateClass.MEASUREMENT,
190  value_fn=lambda data: data.pm25,
191  extra_fn=None,
192  ),
194  key="tvoc",
195  translation_key="tvoc",
196  native_unit_of_measurement=CONCENTRATION_PARTS_PER_BILLION,
197  state_class=SensorStateClass.MEASUREMENT,
198  value_fn=lambda data: data.tvoc,
199  extra_fn=None,
200  ),
202  key="co2",
203  device_class=SensorDeviceClass.CO2,
204  native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
205  state_class=SensorStateClass.MEASUREMENT,
206  value_fn=lambda data: data.co2,
207  extra_fn=None,
208  ),
210  key="ethanol",
211  native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
212  state_class=SensorStateClass.MEASUREMENT,
213  translation_key="ethanol",
214  value_fn=lambda data: data.etoh,
215  extra_fn=None,
216  ),
218  key="iaq",
219  device_class=SensorDeviceClass.AQI,
220  state_class=SensorStateClass.MEASUREMENT,
221  value_fn=lambda data: data.iaq,
222  extra_fn=None,
223  ),
224 )
225 
226 DESCRIPTION_BY_MODELS = {
227  "pure": PURE_SENSOR_TYPES,
228  "airq": AIRQ_SENSOR_TYPES,
229  "elements": ELEMENT_SENSOR_TYPES,
230 }
231 
232 
234  hass: HomeAssistant,
235  entry: SensiboConfigEntry,
236  async_add_entities: AddEntitiesCallback,
237 ) -> None:
238  """Set up Sensibo sensor platform."""
239 
240  coordinator = entry.runtime_data
241 
242  entities: list[SensiboMotionSensor | SensiboDeviceSensor] = []
243 
244  for device_id, device_data in coordinator.data.parsed.items():
245  if device_data.motion_sensors:
246  entities.extend(
248  coordinator, device_id, sensor_id, sensor_data, description
249  )
250  for sensor_id, sensor_data in device_data.motion_sensors.items()
251  for description in MOTION_SENSOR_TYPES
252  )
253  entities.extend(
254  SensiboDeviceSensor(coordinator, device_id, description)
255  for device_id, device_data in coordinator.data.parsed.items()
256  for description in DESCRIPTION_BY_MODELS.get(
257  device_data.model, DEVICE_SENSOR_TYPES
258  )
259  )
260  async_add_entities(entities)
261 
262 
264  """Representation of a Sensibo Motion Sensor."""
265 
266  entity_description: SensiboMotionSensorEntityDescription
267 
268  def __init__(
269  self,
270  coordinator: SensiboDataUpdateCoordinator,
271  device_id: str,
272  sensor_id: str,
273  sensor_data: MotionSensor,
274  entity_description: SensiboMotionSensorEntityDescription,
275  ) -> None:
276  """Initiate Sensibo Motion Sensor."""
277  super().__init__(
278  coordinator,
279  device_id,
280  sensor_id,
281  sensor_data,
282  )
283  self.entity_descriptionentity_description = entity_description
284  self._attr_unique_id_attr_unique_id = f"{sensor_id}-{entity_description.key}"
285 
286  @property
287  def native_value(self) -> StateType:
288  """Return value of sensor."""
289  if TYPE_CHECKING:
290  assert self.sensor_datasensor_data
291  return self.entity_descriptionentity_description.value_fn(self.sensor_datasensor_data)
292 
293 
295  """Representation of a Sensibo Device Sensor."""
296 
297  entity_description: SensiboDeviceSensorEntityDescription
298 
299  def __init__(
300  self,
301  coordinator: SensiboDataUpdateCoordinator,
302  device_id: str,
303  entity_description: SensiboDeviceSensorEntityDescription,
304  ) -> None:
305  """Initiate Sensibo Device Sensor."""
306  super().__init__(
307  coordinator,
308  device_id,
309  )
310  self.entity_descriptionentity_description = entity_description
311  self._attr_unique_id_attr_unique_id = f"{device_id}-{entity_description.key}"
312 
313  @property
314  def native_value(self) -> StateType | datetime:
315  """Return value of sensor."""
316  return self.entity_descriptionentity_description.value_fn(self.device_datadevice_data)
317 
318  @property
319  def extra_state_attributes(self) -> Mapping[str, Any] | None:
320  """Return additional attributes."""
321  if self.entity_descriptionentity_description.extra_fn is not None:
322  return self.entity_descriptionentity_description.extra_fn(self.device_datadevice_data)
323  return None
None __init__(self, SensiboDataUpdateCoordinator coordinator, str device_id, SensiboDeviceSensorEntityDescription entity_description)
Definition: sensor.py:304
None __init__(self, SensiboDataUpdateCoordinator coordinator, str device_id, str sensor_id, MotionSensor sensor_data, SensiboMotionSensorEntityDescription entity_description)
Definition: sensor.py:275
None async_setup_entry(HomeAssistant hass, SensiboConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:237