Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for the Netatmo sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 import logging
8 from typing import Any, cast
9 
10 import pyatmo
11 from pyatmo.modules import PublicWeatherArea
12 
14  SensorDeviceClass,
15  SensorEntity,
16  SensorEntityDescription,
17  SensorStateClass,
18 )
19 from homeassistant.config_entries import ConfigEntry
20 from homeassistant.const import (
21  ATTR_LATITUDE,
22  ATTR_LONGITUDE,
23  CONCENTRATION_PARTS_PER_MILLION,
24  DEGREE,
25  PERCENTAGE,
26  EntityCategory,
27  UnitOfPower,
28  UnitOfPrecipitationDepth,
29  UnitOfPressure,
30  UnitOfSoundPressure,
31  UnitOfSpeed,
32  UnitOfTemperature,
33 )
34 from homeassistant.core import HomeAssistant, callback
35 from homeassistant.helpers import device_registry as dr
36 from homeassistant.helpers.device_registry import DeviceInfo
38  async_dispatcher_connect,
39  async_dispatcher_send,
40 )
41 from homeassistant.helpers.entity_platform import AddEntitiesCallback
42 from homeassistant.helpers.typing import StateType
43 
44 from .const import (
45  CONF_URL_ENERGY,
46  CONF_URL_PUBLIC_WEATHER,
47  CONF_WEATHER_AREAS,
48  DATA_HANDLER,
49  DOMAIN,
50  NETATMO_CREATE_BATTERY,
51  NETATMO_CREATE_ROOM_SENSOR,
52  NETATMO_CREATE_SENSOR,
53  NETATMO_CREATE_WEATHER_SENSOR,
54  SIGNAL_NAME,
55 )
56 from .data_handler import HOME, PUBLIC, NetatmoDataHandler, NetatmoDevice, NetatmoRoom
57 from .entity import (
58  NetatmoBaseEntity,
59  NetatmoModuleEntity,
60  NetatmoRoomEntity,
61  NetatmoWeatherModuleEntity,
62 )
63 from .helper import NetatmoArea
64 
65 _LOGGER = logging.getLogger(__name__)
66 
67 DIRECTION_OPTIONS = [
68  "n",
69  "ne",
70  "e",
71  "se",
72  "s",
73  "sw",
74  "w",
75  "nw",
76 ]
77 
78 
79 def process_health(health: StateType) -> str | None:
80  """Process health index and return string for display."""
81  if not isinstance(health, int):
82  return None
83  return {
84  0: "healthy",
85  1: "fine",
86  2: "fair",
87  3: "poor",
88  }.get(health, "unhealthy")
89 
90 
91 def process_rf(strength: StateType) -> str | None:
92  """Process wifi signal strength and return string for display."""
93  if not isinstance(strength, int):
94  return None
95  if strength >= 90:
96  return "Low"
97  if strength >= 76:
98  return "Medium"
99  if strength >= 60:
100  return "High"
101  return "Full"
102 
103 
104 def process_wifi(strength: StateType) -> str | None:
105  """Process wifi signal strength and return string for display."""
106  if not isinstance(strength, int):
107  return None
108  if strength >= 86:
109  return "Low"
110  if strength >= 71:
111  return "Medium"
112  if strength >= 56:
113  return "High"
114  return "Full"
115 
116 
117 @dataclass(frozen=True, kw_only=True)
119  """Describes Netatmo sensor entity."""
120 
121  netatmo_name: str
122  value_fn: Callable[[StateType], StateType] = lambda x: x
123 
124 
125 SENSOR_TYPES: tuple[NetatmoSensorEntityDescription, ...] = (
127  key="temperature",
128  netatmo_name="temperature",
129  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
130  state_class=SensorStateClass.MEASUREMENT,
131  device_class=SensorDeviceClass.TEMPERATURE,
132  suggested_display_precision=1,
133  ),
135  key="temp_trend",
136  netatmo_name="temp_trend",
137  entity_registry_enabled_default=False,
138  ),
140  key="co2",
141  netatmo_name="co2",
142  native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
143  state_class=SensorStateClass.MEASUREMENT,
144  device_class=SensorDeviceClass.CO2,
145  ),
147  key="pressure",
148  netatmo_name="pressure",
149  native_unit_of_measurement=UnitOfPressure.MBAR,
150  state_class=SensorStateClass.MEASUREMENT,
151  device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
152  suggested_display_precision=1,
153  ),
155  key="pressure_trend",
156  netatmo_name="pressure_trend",
157  entity_registry_enabled_default=False,
158  ),
160  key="noise",
161  netatmo_name="noise",
162  native_unit_of_measurement=UnitOfSoundPressure.DECIBEL,
163  device_class=SensorDeviceClass.SOUND_PRESSURE,
164  state_class=SensorStateClass.MEASUREMENT,
165  ),
167  key="humidity",
168  netatmo_name="humidity",
169  native_unit_of_measurement=PERCENTAGE,
170  state_class=SensorStateClass.MEASUREMENT,
171  device_class=SensorDeviceClass.HUMIDITY,
172  ),
174  key="rain",
175  netatmo_name="rain",
176  native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
177  device_class=SensorDeviceClass.PRECIPITATION,
178  state_class=SensorStateClass.MEASUREMENT,
179  ),
181  key="sum_rain_1",
182  netatmo_name="sum_rain_1",
183  entity_registry_enabled_default=False,
184  native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
185  device_class=SensorDeviceClass.PRECIPITATION,
186  state_class=SensorStateClass.TOTAL,
187  suggested_display_precision=1,
188  ),
190  key="sum_rain_24",
191  netatmo_name="sum_rain_24",
192  native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
193  device_class=SensorDeviceClass.PRECIPITATION,
194  state_class=SensorStateClass.TOTAL_INCREASING,
195  ),
197  key="battery_percent",
198  netatmo_name="battery",
199  entity_category=EntityCategory.DIAGNOSTIC,
200  native_unit_of_measurement=PERCENTAGE,
201  state_class=SensorStateClass.MEASUREMENT,
202  device_class=SensorDeviceClass.BATTERY,
203  ),
205  key="windangle",
206  netatmo_name="wind_direction",
207  device_class=SensorDeviceClass.ENUM,
208  options=DIRECTION_OPTIONS,
209  value_fn=lambda x: x.lower() if isinstance(x, str) else None,
210  ),
212  key="windangle_value",
213  netatmo_name="wind_angle",
214  entity_registry_enabled_default=False,
215  native_unit_of_measurement=DEGREE,
216  state_class=SensorStateClass.MEASUREMENT,
217  ),
219  key="windstrength",
220  netatmo_name="wind_strength",
221  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
222  device_class=SensorDeviceClass.WIND_SPEED,
223  state_class=SensorStateClass.MEASUREMENT,
224  ),
226  key="gustangle",
227  netatmo_name="gust_direction",
228  entity_registry_enabled_default=False,
229  device_class=SensorDeviceClass.ENUM,
230  options=DIRECTION_OPTIONS,
231  value_fn=lambda x: x.lower() if isinstance(x, str) else None,
232  ),
234  key="gustangle_value",
235  netatmo_name="gust_angle",
236  entity_registry_enabled_default=False,
237  native_unit_of_measurement=DEGREE,
238  state_class=SensorStateClass.MEASUREMENT,
239  ),
241  key="guststrength",
242  netatmo_name="gust_strength",
243  entity_registry_enabled_default=False,
244  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
245  device_class=SensorDeviceClass.WIND_SPEED,
246  state_class=SensorStateClass.MEASUREMENT,
247  ),
249  key="reachable",
250  netatmo_name="reachable",
251  entity_registry_enabled_default=False,
252  entity_category=EntityCategory.DIAGNOSTIC,
253  ),
255  key="rf_status",
256  netatmo_name="rf_strength",
257  entity_registry_enabled_default=False,
258  entity_category=EntityCategory.DIAGNOSTIC,
259  value_fn=process_rf,
260  ),
262  key="wifi_status",
263  netatmo_name="wifi_strength",
264  entity_registry_enabled_default=False,
265  entity_category=EntityCategory.DIAGNOSTIC,
266  value_fn=process_wifi,
267  ),
269  key="health_idx",
270  netatmo_name="health_idx",
271  device_class=SensorDeviceClass.ENUM,
272  options=["healthy", "fine", "fair", "poor", "unhealthy"],
273  value_fn=process_health,
274  ),
276  key="power",
277  netatmo_name="power",
278  native_unit_of_measurement=UnitOfPower.WATT,
279  state_class=SensorStateClass.MEASUREMENT,
280  device_class=SensorDeviceClass.POWER,
281  ),
282 )
283 SENSOR_TYPES_KEYS = [desc.key for desc in SENSOR_TYPES]
284 
285 
286 @dataclass(frozen=True, kw_only=True)
288  """Describes Netatmo sensor entity."""
289 
290  value_fn: Callable[[PublicWeatherArea], dict[str, Any]]
291 
292 
293 PUBLIC_WEATHER_STATION_TYPES: tuple[
294  NetatmoPublicWeatherSensorEntityDescription, ...
295 ] = (
297  key="temperature",
298  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
299  state_class=SensorStateClass.MEASUREMENT,
300  device_class=SensorDeviceClass.TEMPERATURE,
301  suggested_display_precision=1,
302  value_fn=lambda area: area.get_latest_temperatures(),
303  ),
305  key="pressure",
306  native_unit_of_measurement=UnitOfPressure.MBAR,
307  state_class=SensorStateClass.MEASUREMENT,
308  device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
309  suggested_display_precision=1,
310  value_fn=lambda area: area.get_latest_pressures(),
311  ),
313  key="humidity",
314  native_unit_of_measurement=PERCENTAGE,
315  state_class=SensorStateClass.MEASUREMENT,
316  device_class=SensorDeviceClass.HUMIDITY,
317  value_fn=lambda area: area.get_latest_humidities(),
318  ),
320  key="rain",
321  native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
322  device_class=SensorDeviceClass.PRECIPITATION,
323  state_class=SensorStateClass.MEASUREMENT,
324  value_fn=lambda area: area.get_latest_rain(),
325  ),
327  key="sum_rain_1",
328  translation_key="sum_rain_1",
329  entity_registry_enabled_default=False,
330  native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
331  device_class=SensorDeviceClass.PRECIPITATION,
332  state_class=SensorStateClass.TOTAL,
333  suggested_display_precision=1,
334  value_fn=lambda area: area.get_60_min_rain(),
335  ),
337  key="sum_rain_24",
338  translation_key="sum_rain_24",
339  native_unit_of_measurement=UnitOfPrecipitationDepth.MILLIMETERS,
340  device_class=SensorDeviceClass.PRECIPITATION,
341  state_class=SensorStateClass.TOTAL_INCREASING,
342  value_fn=lambda area: area.get_24_h_rain(),
343  ),
345  key="windangle_value",
346  entity_registry_enabled_default=False,
347  native_unit_of_measurement=DEGREE,
348  state_class=SensorStateClass.MEASUREMENT,
349  value_fn=lambda area: area.get_latest_wind_angles(),
350  ),
352  key="windstrength",
353  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
354  device_class=SensorDeviceClass.WIND_SPEED,
355  state_class=SensorStateClass.MEASUREMENT,
356  value_fn=lambda area: area.get_latest_wind_strengths(),
357  ),
359  key="gustangle_value",
360  translation_key="gust_angle",
361  entity_registry_enabled_default=False,
362  native_unit_of_measurement=DEGREE,
363  state_class=SensorStateClass.MEASUREMENT,
364  value_fn=lambda area: area.get_latest_gust_angles(),
365  ),
367  key="guststrength",
368  translation_key="gust_strength",
369  entity_registry_enabled_default=False,
370  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
371  device_class=SensorDeviceClass.WIND_SPEED,
372  state_class=SensorStateClass.MEASUREMENT,
373  value_fn=lambda area: area.get_latest_gust_strengths(),
374  ),
375 )
376 
377 BATTERY_SENSOR_DESCRIPTION = NetatmoSensorEntityDescription(
378  key="battery",
379  netatmo_name="battery",
380  entity_category=EntityCategory.DIAGNOSTIC,
381  native_unit_of_measurement=PERCENTAGE,
382  state_class=SensorStateClass.MEASUREMENT,
383  device_class=SensorDeviceClass.BATTERY,
384 )
385 
386 
388  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
389 ) -> None:
390  """Set up the Netatmo sensor platform."""
391 
392  @callback
393  def _create_battery_entity(netatmo_device: NetatmoDevice) -> None:
394  if not hasattr(netatmo_device.device, "battery"):
395  return
396  entity = NetatmoClimateBatterySensor(netatmo_device)
397  async_add_entities([entity])
398 
399  entry.async_on_unload(
400  async_dispatcher_connect(hass, NETATMO_CREATE_BATTERY, _create_battery_entity)
401  )
402 
403  @callback
404  def _create_weather_sensor_entity(netatmo_device: NetatmoDevice) -> None:
406  NetatmoWeatherSensor(netatmo_device, description)
407  for description in SENSOR_TYPES
408  if description.netatmo_name in netatmo_device.device.features
409  )
410 
411  entry.async_on_unload(
413  hass, NETATMO_CREATE_WEATHER_SENSOR, _create_weather_sensor_entity
414  )
415  )
416 
417  @callback
418  def _create_sensor_entity(netatmo_device: NetatmoDevice) -> None:
419  _LOGGER.debug(
420  "Adding %s sensor %s",
421  netatmo_device.device.device_category,
422  netatmo_device.device.name,
423  )
425  NetatmoSensor(netatmo_device, description)
426  for description in SENSOR_TYPES
427  if description.key in netatmo_device.device.features
428  )
429 
430  entry.async_on_unload(
431  async_dispatcher_connect(hass, NETATMO_CREATE_SENSOR, _create_sensor_entity)
432  )
433 
434  @callback
435  def _create_room_sensor_entity(netatmo_device: NetatmoRoom) -> None:
436  if not netatmo_device.room.climate_type:
437  msg = f"No climate type found for this room: {netatmo_device.room.name}"
438  _LOGGER.debug(msg)
439  return
441  NetatmoRoomSensor(netatmo_device, description)
442  for description in SENSOR_TYPES
443  if description.key in netatmo_device.room.features
444  )
445 
446  entry.async_on_unload(
448  hass, NETATMO_CREATE_ROOM_SENSOR, _create_room_sensor_entity
449  )
450  )
451 
452  device_registry = dr.async_get(hass)
453  data_handler = hass.data[DOMAIN][entry.entry_id][DATA_HANDLER]
454 
455  async def add_public_entities(update: bool = True) -> None:
456  """Retrieve Netatmo public weather entities."""
457  entities = {
458  device.name: device.id
459  for device in dr.async_entries_for_config_entry(
460  device_registry, entry.entry_id
461  )
462  if device.model == "Public Weather station"
463  }
464 
465  new_entities: list[NetatmoPublicSensor] = []
466  for area in [
467  NetatmoArea(**i) for i in entry.options.get(CONF_WEATHER_AREAS, {}).values()
468  ]:
469  signal_name = f"{PUBLIC}-{area.uuid}"
470 
471  if area.area_name in entities:
472  entities.pop(area.area_name)
473 
474  if update:
476  hass,
477  f"netatmo-config-{area.area_name}",
478  area,
479  )
480  continue
481 
482  await data_handler.subscribe(
483  PUBLIC,
484  signal_name,
485  None,
486  lat_ne=area.lat_ne,
487  lon_ne=area.lon_ne,
488  lat_sw=area.lat_sw,
489  lon_sw=area.lon_sw,
490  area_id=str(area.uuid),
491  )
492 
493  new_entities.extend(
494  NetatmoPublicSensor(data_handler, area, description)
495  for description in PUBLIC_WEATHER_STATION_TYPES
496  )
497 
498  for device_id in entities.values():
499  device_registry.async_remove_device(device_id)
500 
501  async_add_entities(new_entities)
502 
504  hass, f"signal-{DOMAIN}-public-update-{entry.entry_id}", add_public_entities
505  )
506 
507  await add_public_entities(False)
508 
509 
511  """Implementation of a Netatmo weather/home coach sensor."""
512 
513  entity_description: NetatmoSensorEntityDescription
514 
515  def __init__(
516  self,
517  netatmo_device: NetatmoDevice,
518  description: NetatmoSensorEntityDescription,
519  ) -> None:
520  """Initialize the sensor."""
521  super().__init__(netatmo_device)
522  self.entity_descriptionentity_description = description
523  self._attr_translation_key_attr_translation_key = description.netatmo_name
524  self._attr_unique_id_attr_unique_id = f"{self.device.entity_id}-{description.key}"
525 
526  @property
527  def available(self) -> bool:
528  """Return True if entity is available."""
529  return (
530  self.devicedevice.reachable
531  or getattr(self.devicedevice, self.entity_descriptionentity_description.netatmo_name) is not None
532  )
533 
534  @callback
535  def async_update_callback(self) -> None:
536  """Update the entity's state."""
537  value = cast(
538  StateType, getattr(self.devicedevice, self.entity_descriptionentity_description.netatmo_name)
539  )
540  if value is not None:
541  value = self.entity_descriptionentity_description.value_fn(value)
542  self._attr_native_value_attr_native_value = value
543  self.async_write_ha_stateasync_write_ha_state()
544 
545 
547  """Implementation of a Netatmo sensor."""
548 
549  entity_description: NetatmoSensorEntityDescription
550  device: pyatmo.modules.NRV
551  _attr_configuration_url = CONF_URL_ENERGY
552 
553  def __init__(self, netatmo_device: NetatmoDevice) -> None:
554  """Initialize the sensor."""
555  super().__init__(netatmo_device)
556  self.entity_descriptionentity_description = BATTERY_SENSOR_DESCRIPTION
557 
558  self._publishers.extend(
559  [
560  {
561  "name": HOME,
562  "home_id": netatmo_device.device.home.entity_id,
563  SIGNAL_NAME: netatmo_device.signal_name,
564  },
565  ]
566  )
567 
568  self._attr_unique_id_attr_unique_id = f"{netatmo_device.parent_id}-{self.device.entity_id}-{self.entity_description.key}"
570  identifiers={(DOMAIN, netatmo_device.parent_id)},
571  name=netatmo_device.device.name,
572  manufacturer=self.device_descriptiondevice_description[0],
573  model=self.device_descriptiondevice_description[1],
574  configuration_url=self._attr_configuration_url_attr_configuration_url,
575  )
576 
577  @callback
578  def async_update_callback(self) -> None:
579  """Update the entity's state."""
580  if not self.devicedevice.reachable:
581  if self.availableavailable:
582  self._attr_available_attr_available = False
583  return
584 
585  self._attr_available_attr_available = True
586  self._attr_native_value_attr_native_value = self.devicedevice.battery
587 
588 
590  """Implementation of a Netatmo sensor."""
591 
592  entity_description: NetatmoSensorEntityDescription
593  _attr_configuration_url = CONF_URL_ENERGY
594 
595  def __init__(
596  self,
597  netatmo_device: NetatmoDevice,
598  description: NetatmoSensorEntityDescription,
599  ) -> None:
600  """Initialize the sensor."""
601  super().__init__(netatmo_device)
602  self.entity_descriptionentity_description = description
603 
604  self._publishers.extend(
605  [
606  {
607  "name": HOME,
608  "home_id": self.homehome.entity_id,
609  SIGNAL_NAME: netatmo_device.signal_name,
610  },
611  ]
612  )
613 
614  self._attr_unique_id_attr_unique_id = (
615  f"{self.device.entity_id}-{self.device.entity_id}-{description.key}"
616  )
617 
618  @callback
619  def async_update_callback(self) -> None:
620  """Update the entity's state."""
621  if not self.devicedevice.reachable:
622  if self.availableavailable:
623  self._attr_available_attr_available = False
624  return
625 
626  if (state := getattr(self.devicedevice, self.entity_descriptionentity_description.key)) is None:
627  return
628 
629  self._attr_available_attr_available = True
630  self._attr_native_value_attr_native_value = state
631 
632  self.async_write_ha_stateasync_write_ha_state()
633 
634 
636  """Implementation of a Netatmo room sensor."""
637 
638  entity_description: NetatmoSensorEntityDescription
639 
640  def __init__(
641  self,
642  netatmo_room: NetatmoRoom,
643  description: NetatmoSensorEntityDescription,
644  ) -> None:
645  """Initialize the sensor."""
646  super().__init__(netatmo_room)
647  self.entity_descriptionentity_description = description
648 
649  self._publishers.extend(
650  [
651  {
652  "name": HOME,
653  "home_id": self.homehome.entity_id,
654  SIGNAL_NAME: netatmo_room.signal_name,
655  },
656  ]
657  )
658 
659  self._attr_unique_id_attr_unique_id = (
660  f"{self.device.entity_id}-{self.device.entity_id}-{description.key}"
661  )
662 
663  @callback
664  def async_update_callback(self) -> None:
665  """Update the entity's state."""
666  if (state := getattr(self.devicedevice, self.entity_descriptionentity_description.key)) is None:
667  return
668 
669  self._attr_native_value_attr_native_value = state
670 
671  self.async_write_ha_stateasync_write_ha_state()
672 
673 
675  """Represent a single sensor in a Netatmo."""
676 
677  entity_description: NetatmoPublicWeatherSensorEntityDescription
678 
679  def __init__(
680  self,
681  data_handler: NetatmoDataHandler,
682  area: NetatmoArea,
683  description: NetatmoPublicWeatherSensorEntityDescription,
684  ) -> None:
685  """Initialize the sensor."""
686  super().__init__(data_handler)
687  self.entity_descriptionentity_description = description
688 
689  self._signal_name_signal_name = f"{PUBLIC}-{area.uuid}"
690  self._publishers.append(
691  {
692  "name": PUBLIC,
693  "lat_ne": area.lat_ne,
694  "lon_ne": area.lon_ne,
695  "lat_sw": area.lat_sw,
696  "lon_sw": area.lon_sw,
697  "area_name": area.area_name,
698  SIGNAL_NAME: self._signal_name_signal_name,
699  }
700  )
701 
702  self._station_station = data_handler.account.public_weather_areas[str(area.uuid)]
703 
704  self.areaarea = area
705  self._mode_mode = area.mode
706  self._show_on_map_show_on_map = area.show_on_map
707  self._attr_unique_id_attr_unique_id = f"{area.area_name.replace(' ', '-')}-{description.key}"
708 
709  self._attr_extra_state_attributes_attr_extra_state_attributes.update(
710  {
711  ATTR_LATITUDE: (area.lat_ne + area.lat_sw) / 2,
712  ATTR_LONGITUDE: (area.lon_ne + area.lon_sw) / 2,
713  }
714  )
715  self._attr_device_info_attr_device_info = DeviceInfo(
716  identifiers={(DOMAIN, area.area_name)},
717  name=area.area_name,
718  model="Public Weather station",
719  manufacturer="Netatmo",
720  configuration_url=CONF_URL_PUBLIC_WEATHER,
721  )
722 
723  async def async_added_to_hass(self) -> None:
724  """Entity created."""
725  await super().async_added_to_hass()
726 
727  self.async_on_removeasync_on_remove(
729  self.hasshass,
730  f"netatmo-config-{self.area.area_name}",
731  self.async_config_update_callbackasync_config_update_callback,
732  )
733  )
734 
735  async def async_config_update_callback(self, area: NetatmoArea) -> None:
736  """Update the entity's config."""
737  if self.areaarea == area:
738  return
739 
740  await self.data_handlerdata_handler.unsubscribe(
741  self._signal_name_signal_name, self.async_update_callbackasync_update_callbackasync_update_callback
742  )
743 
744  self.areaarea = area
745  self._signal_name_signal_name = f"{PUBLIC}-{area.uuid}"
746  self._mode_mode = area.mode
747  self._show_on_map_show_on_map = area.show_on_map
748  await self.data_handlerdata_handler.subscribe(
749  PUBLIC,
750  self._signal_name_signal_name,
751  self.async_update_callbackasync_update_callbackasync_update_callback,
752  lat_ne=area.lat_ne,
753  lon_ne=area.lon_ne,
754  lat_sw=area.lat_sw,
755  lon_sw=area.lon_sw,
756  )
757 
758  @callback
759  def async_update_callback(self) -> None:
760  """Update the entity's state."""
761  data = self.entity_descriptionentity_description.value_fn(self._station_station)
762 
763  if not data:
764  if self.availableavailable:
765  _LOGGER.error(
766  "No station provides %s data in the area %s",
767  self.entity_descriptionentity_description.key,
768  self.areaarea.area_name,
769  )
770 
771  self._attr_available_attr_available = False
772  return
773 
774  if values := [x for x in data.values() if x is not None]:
775  if self._mode_mode == "avg":
776  self._attr_native_value_attr_native_value = round(sum(values) / len(values), 1)
777  elif self._mode_mode == "max":
778  self._attr_native_value_attr_native_value = max(values)
779  elif self._mode_mode == "min":
780  self._attr_native_value_attr_native_value = min(values)
781 
782  self._attr_available_attr_available = self.native_valuenative_value is not None
783  self.async_write_ha_stateasync_write_ha_state()
None __init__(self, NetatmoDevice netatmo_device)
Definition: sensor.py:553
None __init__(self, NetatmoDataHandler data_handler, NetatmoArea area, NetatmoPublicWeatherSensorEntityDescription description)
Definition: sensor.py:684
None async_config_update_callback(self, NetatmoArea area)
Definition: sensor.py:735
None __init__(self, NetatmoRoom netatmo_room, NetatmoSensorEntityDescription description)
Definition: sensor.py:644
None __init__(self, NetatmoDevice netatmo_device, NetatmoSensorEntityDescription description)
Definition: sensor.py:599
None __init__(self, NetatmoDevice netatmo_device, NetatmoSensorEntityDescription description)
Definition: sensor.py:519
StateType|date|datetime|Decimal native_value(self)
Definition: __init__.py:460
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
IssData update(pyiss.ISS iss)
Definition: __init__.py:33
Callable[[], None] subscribe(HomeAssistant hass, str topic, MessageCallbackType msg_callback, int qos=DEFAULT_QOS, str encoding="utf-8")
Definition: client.py:247
str|None process_health(StateType health)
Definition: sensor.py:79
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:389
str|None process_rf(StateType strength)
Definition: sensor.py:91
str|None process_wifi(StateType strength)
Definition: sensor.py:104
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
Definition: dispatcher.py:193