Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for Rflink sensors."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from rflink.parser import PACKET_FIELDS, UNITS
8 import voluptuous as vol
9 
11  PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
12  SensorDeviceClass,
13  SensorEntity,
14  SensorEntityDescription,
15  SensorStateClass,
16 )
17 from homeassistant.const import (
18  CONCENTRATION_PARTS_PER_MILLION,
19  CONF_DEVICES,
20  CONF_NAME,
21  CONF_SENSOR_TYPE,
22  CONF_UNIT_OF_MEASUREMENT,
23  DEGREE,
24  LIGHT_LUX,
25  PERCENTAGE,
26  UV_INDEX,
27  UnitOfElectricCurrent,
28  UnitOfElectricPotential,
29  UnitOfLength,
30  UnitOfPower,
31  UnitOfPrecipitationDepth,
32  UnitOfPressure,
33  UnitOfSpeed,
34  UnitOfTemperature,
35  UnitOfVolumetricFlux,
36 )
37 from homeassistant.core import HomeAssistant
39 from homeassistant.helpers.dispatcher import async_dispatcher_connect
40 from homeassistant.helpers.entity_platform import AddEntitiesCallback
41 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
42 
43 from .const import (
44  CONF_ALIASES,
45  CONF_AUTOMATIC_ADD,
46  DATA_DEVICE_REGISTER,
47  DATA_ENTITY_LOOKUP,
48  EVENT_KEY_ID,
49  EVENT_KEY_SENSOR,
50  EVENT_KEY_UNIT,
51  SIGNAL_AVAILABILITY,
52  SIGNAL_HANDLE_EVENT,
53  TMP_ENTITY,
54 )
55 from .entity import RflinkDevice
56 
57 SENSOR_TYPES = (
58  # check new descriptors against PACKET_FIELDS & UNITS from rflink.parser
60  key="average_windspeed",
61  name="Average windspeed",
62  device_class=SensorDeviceClass.WIND_SPEED,
63  state_class=SensorStateClass.MEASUREMENT,
64  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
65  ),
67  key="barometric_pressure",
68  name="Barometric pressure",
69  device_class=SensorDeviceClass.PRESSURE,
70  state_class=SensorStateClass.MEASUREMENT,
71  native_unit_of_measurement=UnitOfPressure.HPA,
72  ),
74  # Rflink devices reports ok/low so device class can’t be used
75  # It should be migrated to a binary sensor
76  key="battery",
77  name="Battery",
78  icon="mdi:battery",
79  ),
81  key="co2_air_quality",
82  name="CO2 air quality",
83  device_class=SensorDeviceClass.CO2,
84  state_class=SensorStateClass.MEASUREMENT,
85  native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
86  ),
88  key="command",
89  name="Command",
90  icon="mdi:text",
91  ),
93  key="current_phase_1",
94  name="Current phase 1",
95  device_class=SensorDeviceClass.CURRENT,
96  state_class=SensorStateClass.MEASUREMENT,
97  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
98  ),
100  key="current_phase_2",
101  name="Current phase 2",
102  device_class=SensorDeviceClass.CURRENT,
103  state_class=SensorStateClass.MEASUREMENT,
104  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
105  ),
107  key="current_phase_3",
108  name="Current phase 3",
109  device_class=SensorDeviceClass.CURRENT,
110  state_class=SensorStateClass.MEASUREMENT,
111  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
112  ),
114  key="distance",
115  name="Distance",
116  device_class=SensorDeviceClass.DISTANCE,
117  state_class=SensorStateClass.MEASUREMENT,
118  native_unit_of_measurement=UnitOfLength.MILLIMETERS,
119  ),
121  key="doorbell_melody",
122  name="Doorbell melody",
123  icon="mdi:bell",
124  ),
126  key="firmware",
127  name="Firmware",
128  icon="mdi:information-outline",
129  ),
131  key="hardware",
132  name="Hardware",
133  icon="mdi:chip",
134  ),
136  key="humidity",
137  name="Humidity",
138  device_class=SensorDeviceClass.HUMIDITY,
139  state_class=SensorStateClass.MEASUREMENT,
140  native_unit_of_measurement=PERCENTAGE,
141  ),
143  key="humidity_status",
144  name="Humidity status",
145  icon="mdi:water-percent",
146  ),
148  key="kilowatt",
149  name="Kilowatt",
150  device_class=SensorDeviceClass.POWER,
151  state_class=SensorStateClass.MEASUREMENT,
152  native_unit_of_measurement=UnitOfPower.KILO_WATT,
153  ),
155  key="light_intensity",
156  name="Light intensity",
157  device_class=SensorDeviceClass.ILLUMINANCE,
158  state_class=SensorStateClass.MEASUREMENT,
159  native_unit_of_measurement=LIGHT_LUX,
160  ),
162  key="meter_value",
163  name="Meter value",
164  icon="mdi:counter",
165  ),
167  key="noise_level",
168  name="Noise level",
169  icon="mdi:bell-alert",
170  ),
172  key="rain_rate",
173  name="Rain rate",
174  device_class=SensorDeviceClass.PRECIPITATION_INTENSITY,
175  state_class=SensorStateClass.MEASUREMENT,
176  native_unit_of_measurement=UnitOfVolumetricFlux.MILLIMETERS_PER_HOUR,
177  ),
179  key="revision",
180  name="Revision",
181  icon="mdi:information",
182  ),
184  key="temperature",
185  name="Temperature",
186  device_class=SensorDeviceClass.TEMPERATURE,
187  state_class=SensorStateClass.MEASUREMENT,
188  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
189  ),
191  key="total_rain",
192  name="Total rain",
193  device_class=SensorDeviceClass.PRECIPITATION,
194  state_class=SensorStateClass.TOTAL_INCREASING,
195  native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
196  ),
198  key="uv_intensity",
199  name="UV intensity",
200  icon="mdi:sunglasses",
201  state_class=SensorStateClass.MEASUREMENT,
202  native_unit_of_measurement=UV_INDEX,
203  ),
205  key="version",
206  name="Version",
207  icon="mdi:information",
208  ),
210  key="voltage",
211  name="Voltage",
212  device_class=SensorDeviceClass.VOLTAGE,
213  state_class=SensorStateClass.MEASUREMENT,
214  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
215  ),
217  key="watt",
218  name="Watt",
219  device_class=SensorDeviceClass.POWER,
220  state_class=SensorStateClass.MEASUREMENT,
221  native_unit_of_measurement=UnitOfPower.WATT,
222  ),
224  key="weather_forecast",
225  name="Weather forecast",
226  icon="mdi:weather-cloudy-clock",
227  ),
229  key="windchill",
230  name="Wind chill",
231  device_class=SensorDeviceClass.TEMPERATURE,
232  state_class=SensorStateClass.MEASUREMENT,
233  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
234  ),
236  key="winddirection",
237  name="Wind direction",
238  icon="mdi:compass",
239  state_class=SensorStateClass.MEASUREMENT,
240  native_unit_of_measurement=DEGREE,
241  ),
243  key="windgusts",
244  name="Wind gusts",
245  device_class=SensorDeviceClass.WIND_SPEED,
246  state_class=SensorStateClass.MEASUREMENT,
247  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
248  ),
250  key="windspeed",
251  name="Wind speed",
252  device_class=SensorDeviceClass.WIND_SPEED,
253  state_class=SensorStateClass.MEASUREMENT,
254  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
255  ),
257  key="windtemp",
258  name="Wind temperature",
259  device_class=SensorDeviceClass.TEMPERATURE,
260  state_class=SensorStateClass.MEASUREMENT,
261  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
262  ),
263 )
264 
265 SENSOR_TYPES_DICT = {desc.key: desc for desc in SENSOR_TYPES}
266 
267 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
268  {
269  vol.Optional(CONF_AUTOMATIC_ADD, default=True): cv.boolean,
270  vol.Optional(CONF_DEVICES, default={}): {
271  cv.string: vol.Schema(
272  {
273  vol.Optional(CONF_NAME): cv.string,
274  vol.Required(CONF_SENSOR_TYPE): cv.string,
275  vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
276  vol.Optional(CONF_ALIASES, default=[]): vol.All(
277  cv.ensure_list, [cv.string]
278  ),
279  }
280  )
281  },
282  },
283  extra=vol.ALLOW_EXTRA,
284 )
285 
286 
288  """Get unit for sensor type.
289 
290  Async friendly.
291  """
292  field_abbrev = {v: k for k, v in PACKET_FIELDS.items()}
293 
294  return UNITS.get(field_abbrev.get(sensor_type))
295 
296 
297 def devices_from_config(domain_config):
298  """Parse configuration and add Rflink sensor devices."""
299  devices = []
300  for device_id, config in domain_config[CONF_DEVICES].items():
301  device = RflinkSensor(device_id, **config)
302  devices.append(device)
303 
304  return devices
305 
306 
308  hass: HomeAssistant,
309  config: ConfigType,
310  async_add_entities: AddEntitiesCallback,
311  discovery_info: DiscoveryInfoType | None = None,
312 ) -> None:
313  """Set up the Rflink platform."""
315 
316  async def add_new_device(event):
317  """Check if device is known, otherwise create device entity."""
318  device_id = event[EVENT_KEY_ID]
319 
320  device = RflinkSensor(
321  device_id,
322  event[EVENT_KEY_SENSOR],
323  event[EVENT_KEY_UNIT],
324  initial_event=event,
325  )
326  # Add device entity
327  async_add_entities([device])
328 
329  if config[CONF_AUTOMATIC_ADD]:
330  hass.data[DATA_DEVICE_REGISTER][EVENT_KEY_SENSOR] = add_new_device
331 
332 
334  """Representation of a Rflink sensor."""
335 
336  def __init__(
337  self,
338  device_id: str,
339  sensor_type: str,
340  unit_of_measurement: str | None = None,
341  initial_event=None,
342  **kwargs: Any,
343  ) -> None:
344  """Handle sensor specific args and super init."""
345  self._sensor_type_sensor_type = sensor_type
346  self._unit_of_measurement_unit_of_measurement = unit_of_measurement
347  if sensor_type in SENSOR_TYPES_DICT:
348  self.entity_descriptionentity_description = SENSOR_TYPES_DICT[sensor_type]
349  elif not unit_of_measurement:
350  self._unit_of_measurement_unit_of_measurement = lookup_unit_for_sensor_type(sensor_type)
351 
352  super().__init__(device_id, initial_event=initial_event, **kwargs)
353 
354  def _handle_event(self, event):
355  """Domain specific event handler."""
356  self._state_state = event["value"]
357 
358  # pylint: disable-next=hass-missing-super-call
359  async def async_added_to_hass(self) -> None:
360  """Register update callback."""
361  # Remove temporary bogus entity_id if added
362  tmp_entity = TMP_ENTITY.format(self._device_id_device_id)
363  if (
364  tmp_entity
365  in self.hasshass.data[DATA_ENTITY_LOOKUP][EVENT_KEY_SENSOR][self._device_id_device_id]
366  ):
367  self.hasshass.data[DATA_ENTITY_LOOKUP][EVENT_KEY_SENSOR][
368  self._device_id_device_id
369  ].remove(tmp_entity)
370 
371  # Register id and aliases
372  self.hasshass.data[DATA_ENTITY_LOOKUP][EVENT_KEY_SENSOR][self._device_id_device_id].append(
373  self.entity_identity_id
374  )
375  if self._aliases_aliases:
376  for _id in self._aliases_aliases:
377  self.hasshass.data[DATA_ENTITY_LOOKUP][EVENT_KEY_SENSOR][_id].append(
378  self.entity_identity_id
379  )
380  self.async_on_removeasync_on_remove(
382  self.hasshass, SIGNAL_AVAILABILITY, self._availability_callback_availability_callback
383  )
384  )
385  self.async_on_removeasync_on_remove(
387  self.hasshass,
388  SIGNAL_HANDLE_EVENT.format(self.entity_identity_id),
389  self.handle_event_callbackhandle_event_callback,
390  )
391  )
392 
393  # Process the initial event now that the entity is created
394  if self._initial_event_initial_event:
395  self.handle_event_callbackhandle_event_callback(self._initial_event_initial_event)
396 
397  @property
399  """Return measurement unit."""
400  if self._unit_of_measurement_unit_of_measurement:
401  return self._unit_of_measurement_unit_of_measurement
402  if hasattr(self, "entity_description"):
403  return self.entity_descriptionentity_description.native_unit_of_measurement
404  return None
405 
406  @property
407  def native_value(self):
408  """Return value."""
409  return self._state_state
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
bool remove(self, _T matcher)
Definition: match.py:214
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103