Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Sensors for National Weather Service (NWS)."""
2 
3 from __future__ import annotations
4 
5 from dataclasses import dataclass
6 from datetime import datetime
7 from types import MappingProxyType
8 from typing import Any
9 
11  SensorDeviceClass,
12  SensorEntity,
13  SensorEntityDescription,
14  SensorStateClass,
15 )
16 from homeassistant.const import (
17  CONF_LATITUDE,
18  CONF_LONGITUDE,
19  DEGREE,
20  PERCENTAGE,
21  UnitOfLength,
22  UnitOfPressure,
23  UnitOfSpeed,
24  UnitOfTemperature,
25 )
26 from homeassistant.core import HomeAssistant
27 from homeassistant.helpers.entity_platform import AddEntitiesCallback
29  CoordinatorEntity,
30  TimestampDataUpdateCoordinator,
31 )
32 from homeassistant.util.dt import parse_datetime
34  DistanceConverter,
35  PressureConverter,
36  SpeedConverter,
37 )
38 from homeassistant.util.unit_system import US_CUSTOMARY_SYSTEM
39 
40 from . import NWSConfigEntry, NWSData, base_unique_id, device_info
41 from .const import ATTRIBUTION, CONF_STATION
42 
43 PARALLEL_UPDATES = 0
44 
45 
46 @dataclass(frozen=True)
48  """Class describing NWSSensor entities."""
49 
50  unit_convert: str | None = None
51 
52 
53 SENSOR_TYPES: tuple[NWSSensorEntityDescription, ...] = (
55  key="dewpoint",
56  name="Dew Point",
57  device_class=SensorDeviceClass.TEMPERATURE,
58  state_class=SensorStateClass.MEASUREMENT,
59  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
60  unit_convert=UnitOfTemperature.CELSIUS,
61  ),
63  key="temperature",
64  name="Temperature",
65  device_class=SensorDeviceClass.TEMPERATURE,
66  state_class=SensorStateClass.MEASUREMENT,
67  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
68  unit_convert=UnitOfTemperature.CELSIUS,
69  ),
71  key="windChill",
72  name="Wind Chill",
73  device_class=SensorDeviceClass.TEMPERATURE,
74  state_class=SensorStateClass.MEASUREMENT,
75  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
76  unit_convert=UnitOfTemperature.CELSIUS,
77  ),
79  key="heatIndex",
80  name="Heat Index",
81  device_class=SensorDeviceClass.TEMPERATURE,
82  state_class=SensorStateClass.MEASUREMENT,
83  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
84  unit_convert=UnitOfTemperature.CELSIUS,
85  ),
87  key="relativeHumidity",
88  name="Relative Humidity",
89  device_class=SensorDeviceClass.HUMIDITY,
90  state_class=SensorStateClass.MEASUREMENT,
91  native_unit_of_measurement=PERCENTAGE,
92  unit_convert=PERCENTAGE,
93  ),
95  key="windSpeed",
96  name="Wind Speed",
97  device_class=SensorDeviceClass.WIND_SPEED,
98  state_class=SensorStateClass.MEASUREMENT,
99  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
100  unit_convert=UnitOfSpeed.MILES_PER_HOUR,
101  ),
103  key="windGust",
104  name="Wind Gust",
105  device_class=SensorDeviceClass.WIND_SPEED,
106  state_class=SensorStateClass.MEASUREMENT,
107  native_unit_of_measurement=UnitOfSpeed.KILOMETERS_PER_HOUR,
108  unit_convert=UnitOfSpeed.MILES_PER_HOUR,
109  ),
110  # statistics currently doesn't handle circular statistics
112  key="windDirection",
113  name="Wind Direction",
114  icon="mdi:compass-rose",
115  native_unit_of_measurement=DEGREE,
116  unit_convert=DEGREE,
117  ),
119  key="barometricPressure",
120  name="Barometric Pressure",
121  device_class=SensorDeviceClass.PRESSURE,
122  state_class=SensorStateClass.MEASUREMENT,
123  native_unit_of_measurement=UnitOfPressure.PA,
124  unit_convert=UnitOfPressure.INHG,
125  ),
127  key="seaLevelPressure",
128  name="Sea Level Pressure",
129  device_class=SensorDeviceClass.PRESSURE,
130  state_class=SensorStateClass.MEASUREMENT,
131  native_unit_of_measurement=UnitOfPressure.PA,
132  unit_convert=UnitOfPressure.INHG,
133  ),
135  key="visibility",
136  name="Visibility",
137  icon="mdi:eye",
138  state_class=SensorStateClass.MEASUREMENT,
139  native_unit_of_measurement=UnitOfLength.METERS,
140  unit_convert=UnitOfLength.MILES,
141  ),
143  key="timestamp",
144  name="Latest Observation Time",
145  device_class=SensorDeviceClass.TIMESTAMP,
146  ),
147 )
148 
149 
151  hass: HomeAssistant, entry: NWSConfigEntry, async_add_entities: AddEntitiesCallback
152 ) -> None:
153  """Set up the NWS weather platform."""
154  nws_data = entry.runtime_data
155  station = entry.data[CONF_STATION]
156 
158  NWSSensor(
159  hass=hass,
160  entry_data=entry.data,
161  nws_data=nws_data,
162  description=description,
163  station=station,
164  )
165  for description in SENSOR_TYPES
166  )
167 
168 
169 class NWSSensor(CoordinatorEntity[TimestampDataUpdateCoordinator[None]], SensorEntity):
170  """An NWS Sensor Entity."""
171 
172  entity_description: NWSSensorEntityDescription
173  _attr_attribution = ATTRIBUTION
174  _attr_entity_registry_enabled_default = False
175 
176  def __init__(
177  self,
178  hass: HomeAssistant,
179  entry_data: MappingProxyType[str, Any],
180  nws_data: NWSData,
181  description: NWSSensorEntityDescription,
182  station: str,
183  ) -> None:
184  """Initialise the platform with a data instance."""
185  super().__init__(nws_data.coordinator_observation)
186  self._nws_nws = nws_data.api
187  latitude = entry_data[CONF_LATITUDE]
188  longitude = entry_data[CONF_LONGITUDE]
189  self.entity_descriptionentity_description = description
190 
191  self._attr_name_attr_name = f"{station} {description.name}"
192  if hass.config.units is US_CUSTOMARY_SYSTEM:
193  self._attr_native_unit_of_measurement_attr_native_unit_of_measurement = description.unit_convert
194  self._attr_device_info_attr_device_info = device_info(latitude, longitude)
195  self._attr_unique_id_attr_unique_id = (
196  f"{base_unique_id(latitude, longitude)}_{description.key}"
197  )
198 
199  @property
200  def native_value(self) -> float | datetime | None:
201  """Return the state."""
202  if (
203  not (observation := self._nws_nws.observation)
204  or (value := observation.get(self.entity_descriptionentity_description.key)) is None
205  ):
206  return None
207 
208  # Set alias to unit property -> prevent unnecessary hasattr calls
209  unit_of_measurement = self.native_unit_of_measurementnative_unit_of_measurement
210  if unit_of_measurement == UnitOfSpeed.MILES_PER_HOUR:
211  return round(
212  SpeedConverter.convert(
213  value, UnitOfSpeed.KILOMETERS_PER_HOUR, UnitOfSpeed.MILES_PER_HOUR
214  )
215  )
216  if unit_of_measurement == UnitOfLength.MILES:
217  return round(
218  DistanceConverter.convert(
219  value, UnitOfLength.METERS, UnitOfLength.MILES
220  )
221  )
222  if unit_of_measurement == UnitOfPressure.INHG:
223  return round(
224  PressureConverter.convert(
225  value, UnitOfPressure.PA, UnitOfPressure.INHG
226  ),
227  2,
228  )
229  if unit_of_measurement == UnitOfTemperature.CELSIUS:
230  return round(value, 1)
231  if unit_of_measurement == PERCENTAGE:
232  return round(value)
233  if self.device_classdevice_classdevice_classdevice_class == SensorDeviceClass.TIMESTAMP:
234  return parse_datetime(value)
235  return value
float|datetime|None native_value(self)
Definition: sensor.py:200
None __init__(self, HomeAssistant hass, MappingProxyType[str, Any] entry_data, NWSData nws_data, NWSSensorEntityDescription description, str station)
Definition: sensor.py:183
SensorDeviceClass|None device_class(self)
Definition: __init__.py:313
DeviceInfo|None device_info(self)
Definition: entity.py:798
datetime|None parse_datetime(str|None value)
Definition: sensor.py:138
None async_setup_entry(HomeAssistant hass, NWSConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:152