Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for UK Met Office weather service."""
2 
3 from __future__ import annotations
4 
5 from typing import Any
6 
7 from datapoint.Element import Element
8 
10  SensorDeviceClass,
11  SensorEntity,
12  SensorEntityDescription,
13 )
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import (
16  PERCENTAGE,
17  UV_INDEX,
18  UnitOfLength,
19  UnitOfSpeed,
20  UnitOfTemperature,
21 )
22 from homeassistant.core import HomeAssistant
23 from homeassistant.helpers.entity_platform import AddEntitiesCallback
24 from homeassistant.helpers.typing import StateType
26  CoordinatorEntity,
27  DataUpdateCoordinator,
28 )
29 
30 from . import get_device_info
31 from .const import (
32  ATTRIBUTION,
33  CONDITION_MAP,
34  DOMAIN,
35  METOFFICE_COORDINATES,
36  METOFFICE_DAILY_COORDINATOR,
37  METOFFICE_HOURLY_COORDINATOR,
38  METOFFICE_NAME,
39  MODE_DAILY,
40  VISIBILITY_CLASSES,
41  VISIBILITY_DISTANCE_CLASSES,
42 )
43 from .data import MetOfficeData
44 
45 ATTR_LAST_UPDATE = "last_update"
46 ATTR_SENSOR_ID = "sensor_id"
47 ATTR_SITE_ID = "site_id"
48 ATTR_SITE_NAME = "site_name"
49 
50 
51 SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
53  key="name",
54  name="Station name",
55  icon="mdi:label-outline",
56  entity_registry_enabled_default=False,
57  ),
59  key="weather",
60  name="Weather",
61  icon="mdi:weather-sunny", # but will adapt to current conditions
62  entity_registry_enabled_default=True,
63  ),
65  key="temperature",
66  name="Temperature",
67  device_class=SensorDeviceClass.TEMPERATURE,
68  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
69  icon=None,
70  entity_registry_enabled_default=True,
71  ),
73  key="feels_like_temperature",
74  name="Feels like temperature",
75  device_class=SensorDeviceClass.TEMPERATURE,
76  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
77  icon=None,
78  entity_registry_enabled_default=False,
79  ),
81  key="wind_speed",
82  name="Wind speed",
83  native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR,
84  # Hint mph because that's the preferred unit for wind speeds in UK
85  # This can be removed if we add a mixed metric/imperial unit system for UK users
86  suggested_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR,
87  device_class=SensorDeviceClass.WIND_SPEED,
88  entity_registry_enabled_default=True,
89  ),
91  key="wind_direction",
92  name="Wind direction",
93  icon="mdi:compass-outline",
94  entity_registry_enabled_default=False,
95  ),
97  key="wind_gust",
98  name="Wind gust",
99  native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR,
100  # Hint mph because that's the preferred unit for wind speeds in UK
101  # This can be removed if we add a mixed metric/imperial unit system for UK users
102  suggested_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR,
103  device_class=SensorDeviceClass.WIND_SPEED,
104  entity_registry_enabled_default=False,
105  ),
107  key="visibility",
108  name="Visibility",
109  icon="mdi:eye",
110  entity_registry_enabled_default=False,
111  ),
113  key="visibility_distance",
114  name="Visibility distance",
115  native_unit_of_measurement=UnitOfLength.KILOMETERS,
116  icon="mdi:eye",
117  entity_registry_enabled_default=False,
118  ),
120  key="uv",
121  name="UV index",
122  native_unit_of_measurement=UV_INDEX,
123  icon="mdi:weather-sunny-alert",
124  entity_registry_enabled_default=True,
125  ),
127  key="precipitation",
128  name="Probability of precipitation",
129  native_unit_of_measurement=PERCENTAGE,
130  icon="mdi:weather-rainy",
131  entity_registry_enabled_default=True,
132  ),
134  key="humidity",
135  name="Humidity",
136  device_class=SensorDeviceClass.HUMIDITY,
137  native_unit_of_measurement=PERCENTAGE,
138  icon=None,
139  entity_registry_enabled_default=False,
140  ),
141 )
142 
143 
145  hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
146 ) -> None:
147  """Set up the Met Office weather sensor platform."""
148  hass_data = hass.data[DOMAIN][entry.entry_id]
149 
151  [
153  hass_data[METOFFICE_HOURLY_COORDINATOR],
154  hass_data,
155  True,
156  description,
157  )
158  for description in SENSOR_TYPES
159  ]
160  + [
162  hass_data[METOFFICE_DAILY_COORDINATOR],
163  hass_data,
164  False,
165  description,
166  )
167  for description in SENSOR_TYPES
168  ],
169  False,
170  )
171 
172 
174  CoordinatorEntity[DataUpdateCoordinator[MetOfficeData]], SensorEntity
175 ):
176  """Implementation of a Met Office current weather condition sensor."""
177 
178  _attr_attribution = ATTRIBUTION
179  _attr_has_entity_name = True
180 
181  def __init__(
182  self,
183  coordinator: DataUpdateCoordinator[MetOfficeData],
184  hass_data: dict[str, Any],
185  use_3hourly: bool,
186  description: SensorEntityDescription,
187  ) -> None:
188  """Initialize the sensor."""
189  super().__init__(coordinator)
190 
191  self.entity_descriptionentity_description = description
192  mode_label = "3-hourly" if use_3hourly else "daily"
193 
194  self._attr_device_info_attr_device_info = get_device_info(
195  coordinates=hass_data[METOFFICE_COORDINATES], name=hass_data[METOFFICE_NAME]
196  )
197  self._attr_name_attr_name = f"{description.name} {mode_label}"
198  self._attr_unique_id_attr_unique_id = f"{description.key}_{hass_data[METOFFICE_COORDINATES]}"
199  if not use_3hourly:
200  self._attr_unique_id_attr_unique_id = f"{self._attr_unique_id}_{MODE_DAILY}"
201  self._attr_entity_registry_enabled_default_attr_entity_registry_enabled_default = (
202  self.entity_descriptionentity_description.entity_registry_enabled_default and use_3hourly
203  )
204 
205  @property
206  def native_value(self) -> StateType:
207  """Return the state of the sensor."""
208  value = None
209 
210  if self.entity_descriptionentity_description.key == "visibility_distance" and hasattr(
211  self.coordinator.data.now, "visibility"
212  ):
213  value = VISIBILITY_DISTANCE_CLASSES.get(
214  self.coordinator.data.now.visibility.value
215  )
216 
217  if self.entity_descriptionentity_description.key == "visibility" and hasattr(
218  self.coordinator.data.now, "visibility"
219  ):
220  value = VISIBILITY_CLASSES.get(self.coordinator.data.now.visibility.value)
221 
222  elif self.entity_descriptionentity_description.key == "weather" and hasattr(
223  self.coordinator.data.now, self.entity_descriptionentity_description.key
224  ):
225  value = CONDITION_MAP.get(self.coordinator.data.now.weather.value)
226 
227  elif hasattr(self.coordinator.data.now, self.entity_descriptionentity_description.key):
228  value = getattr(self.coordinator.data.now, self.entity_descriptionentity_description.key)
229 
230  if isinstance(value, Element):
231  value = value.value
232 
233  return value
234 
235  @property
236  def icon(self) -> str | None:
237  """Return the icon for the entity card."""
238  value = self.entity_descriptionentity_description.icon
239  if self.entity_descriptionentity_description.key == "weather":
240  value = self.statestatestate
241  if value is None:
242  value = "sunny"
243  elif value == "partlycloudy":
244  value = "partly-cloudy"
245  value = f"mdi:weather-{value}"
246 
247  return value
248 
249  @property
250  def extra_state_attributes(self) -> dict[str, Any]:
251  """Return the state attributes of the device."""
252  return {
253  ATTR_LAST_UPDATE: self.coordinator.data.now.date,
254  ATTR_SENSOR_ID: self.entity_descriptionentity_description.key,
255  ATTR_SITE_ID: self.coordinator.data.site.location_id,
256  ATTR_SITE_NAME: self.coordinator.data.site.name,
257  }
None __init__(self, DataUpdateCoordinator[MetOfficeData] coordinator, dict[str, Any] hass_data, bool use_3hourly, SensorEntityDescription description)
Definition: sensor.py:187
None async_setup_entry(HomeAssistant hass, ConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:146
DeviceInfo get_device_info(str coordinates, str name)
Definition: __init__.py:156