Home Assistant Unofficial Reference 2024.12.1
weather.py
Go to the documentation of this file.
1 """Demo platform that offers fake meteorological data."""
2 
3 from __future__ import annotations
4 
5 from datetime import datetime, timedelta
6 
8  ATTR_CONDITION_CLOUDY,
9  ATTR_CONDITION_EXCEPTIONAL,
10  ATTR_CONDITION_FOG,
11  ATTR_CONDITION_HAIL,
12  ATTR_CONDITION_LIGHTNING,
13  ATTR_CONDITION_LIGHTNING_RAINY,
14  ATTR_CONDITION_PARTLYCLOUDY,
15  ATTR_CONDITION_POURING,
16  ATTR_CONDITION_RAINY,
17  ATTR_CONDITION_SNOWY,
18  ATTR_CONDITION_SNOWY_RAINY,
19  ATTR_CONDITION_SUNNY,
20  ATTR_CONDITION_WINDY,
21  ATTR_CONDITION_WINDY_VARIANT,
22  Forecast,
23  WeatherEntity,
24  WeatherEntityFeature,
25 )
26 from homeassistant.config_entries import ConfigEntry
27 from homeassistant.const import UnitOfPressure, UnitOfSpeed, UnitOfTemperature
28 from homeassistant.core import HomeAssistant
29 from homeassistant.helpers.entity_platform import AddEntitiesCallback
30 from homeassistant.helpers.event import async_track_time_interval
31 import homeassistant.util.dt as dt_util
32 
33 CONDITION_CLASSES: dict[str, list[str]] = {
34  ATTR_CONDITION_CLOUDY: [],
35  ATTR_CONDITION_FOG: [],
36  ATTR_CONDITION_HAIL: [],
37  ATTR_CONDITION_LIGHTNING: [],
38  ATTR_CONDITION_LIGHTNING_RAINY: [],
39  ATTR_CONDITION_PARTLYCLOUDY: [],
40  ATTR_CONDITION_POURING: [],
41  ATTR_CONDITION_RAINY: ["shower rain"],
42  ATTR_CONDITION_SNOWY: [],
43  ATTR_CONDITION_SNOWY_RAINY: [],
44  ATTR_CONDITION_SUNNY: ["sunshine"],
45  ATTR_CONDITION_WINDY: [],
46  ATTR_CONDITION_WINDY_VARIANT: [],
47  ATTR_CONDITION_EXCEPTIONAL: [],
48 }
49 CONDITION_MAP = {
50  cond_code: cond_ha
51  for cond_ha, cond_codes in CONDITION_CLASSES.items()
52  for cond_code in cond_codes
53 }
54 
55 WEATHER_UPDATE_INTERVAL = timedelta(minutes=30)
56 
57 
59  hass: HomeAssistant,
60  config_entry: ConfigEntry,
61  async_add_entities: AddEntitiesCallback,
62 ) -> None:
63  """Set up the Demo config entry."""
65  [
67  "South",
68  "Sunshine",
69  21.6414,
70  92,
71  1099,
72  0.5,
73  UnitOfTemperature.CELSIUS,
74  UnitOfPressure.HPA,
75  UnitOfSpeed.METERS_PER_SECOND,
76  [
77  [ATTR_CONDITION_RAINY, 1, 22, 15, 60],
78  [ATTR_CONDITION_RAINY, 5, 19, 8, 30],
79  [ATTR_CONDITION_CLOUDY, 0, 15, 9, 10],
80  [ATTR_CONDITION_SUNNY, 0, 12, 6, 0],
81  [ATTR_CONDITION_PARTLYCLOUDY, 2, 14, 7, 20],
82  [ATTR_CONDITION_RAINY, 15, 18, 7, 0],
83  [ATTR_CONDITION_FOG, 0.2, 21, 12, 100],
84  ],
85  None,
86  None,
87  ),
89  "North",
90  "Shower rain",
91  -12,
92  54,
93  987,
94  4.8,
95  UnitOfTemperature.FAHRENHEIT,
96  UnitOfPressure.INHG,
97  UnitOfSpeed.MILES_PER_HOUR,
98  [
99  [ATTR_CONDITION_SNOWY, 2, -10, -15, 60],
100  [ATTR_CONDITION_PARTLYCLOUDY, 1, -13, -14, 25],
101  [ATTR_CONDITION_SUNNY, 0, -18, -22, 70],
102  [ATTR_CONDITION_SUNNY, 0.1, -23, -23, 90],
103  [ATTR_CONDITION_SNOWY, 4, -19, -20, 40],
104  [ATTR_CONDITION_SUNNY, 0.3, -14, -19, 0],
105  [ATTR_CONDITION_SUNNY, 0, -9, -12, 0],
106  ],
107  [
108  [ATTR_CONDITION_SUNNY, 2, -10, -15, 60],
109  [ATTR_CONDITION_SUNNY, 1, -13, -14, 25],
110  [ATTR_CONDITION_SUNNY, 0, -18, -22, 70],
111  [ATTR_CONDITION_SUNNY, 0.1, -23, -23, 90],
112  [ATTR_CONDITION_SUNNY, 4, -19, -20, 40],
113  [ATTR_CONDITION_SUNNY, 0.3, -14, -19, 0],
114  [ATTR_CONDITION_SUNNY, 0, -9, -12, 0],
115  ],
116  [
117  [ATTR_CONDITION_SNOWY, 2, -10, -15, 60, True],
118  [ATTR_CONDITION_PARTLYCLOUDY, 1, -13, -14, 25, False],
119  [ATTR_CONDITION_SUNNY, 0, -18, -22, 70, True],
120  [ATTR_CONDITION_SUNNY, 0.1, -23, -23, 90, False],
121  [ATTR_CONDITION_SNOWY, 4, -19, -20, 40, True],
122  [ATTR_CONDITION_SUNNY, 0.3, -14, -19, 0, False],
123  [ATTR_CONDITION_SUNNY, 0, -9, -12, 0, True],
124  ],
125  ),
126  ]
127  )
128 
129 
131  """Representation of a weather condition."""
132 
133  _attr_attribution = "Powered by Home Assistant"
134  _attr_should_poll = False
135 
136  def __init__(
137  self,
138  name: str,
139  condition: str,
140  temperature: float,
141  humidity: float,
142  pressure: float,
143  wind_speed: float,
144  temperature_unit: str,
145  pressure_unit: str,
146  wind_speed_unit: str,
147  forecast_daily: list[list] | None,
148  forecast_hourly: list[list] | None,
149  forecast_twice_daily: list[list] | None,
150  ) -> None:
151  """Initialize the Demo weather."""
152  self._attr_name_attr_name = f"Demo Weather {name}"
153  self._attr_unique_id_attr_unique_id = f"demo-weather-{name.lower()}"
154  self._condition_condition = condition
155  self._native_temperature_native_temperature = temperature
156  self._native_temperature_unit_native_temperature_unit = temperature_unit
157  self._humidity_humidity = humidity
158  self._native_pressure_native_pressure = pressure
159  self._native_pressure_unit_native_pressure_unit = pressure_unit
160  self._native_wind_speed_native_wind_speed = wind_speed
161  self._native_wind_speed_unit_native_wind_speed_unit = wind_speed_unit
162  self._forecast_daily_forecast_daily = forecast_daily
163  self._forecast_hourly_forecast_hourly = forecast_hourly
164  self._forecast_twice_daily_forecast_twice_daily = forecast_twice_daily
165  self._attr_supported_features_attr_supported_features = 0
166  if self._forecast_daily_forecast_daily:
167  self._attr_supported_features_attr_supported_features |= WeatherEntityFeature.FORECAST_DAILY
168  if self._forecast_hourly_forecast_hourly:
169  self._attr_supported_features_attr_supported_features |= WeatherEntityFeature.FORECAST_HOURLY
170  if self._forecast_twice_daily_forecast_twice_daily:
171  self._attr_supported_features_attr_supported_features |= WeatherEntityFeature.FORECAST_TWICE_DAILY
172 
173  async def async_added_to_hass(self) -> None:
174  """Set up a timer updating the forecasts."""
175 
176  async def update_forecasts(_: datetime) -> None:
177  if self._forecast_daily_forecast_daily:
178  self._forecast_daily_forecast_daily = (
179  self._forecast_daily_forecast_daily[1:] + self._forecast_daily_forecast_daily[:1]
180  )
181  if self._forecast_hourly_forecast_hourly:
182  self._forecast_hourly_forecast_hourly = (
183  self._forecast_hourly_forecast_hourly[1:] + self._forecast_hourly_forecast_hourly[:1]
184  )
185  if self._forecast_twice_daily_forecast_twice_daily:
186  self._forecast_twice_daily_forecast_twice_daily = (
187  self._forecast_twice_daily_forecast_twice_daily[1:] + self._forecast_twice_daily_forecast_twice_daily[:1]
188  )
189  await self.async_update_listenersasync_update_listeners(None)
190 
191  self.async_on_removeasync_on_remove(
193  self.hasshass, update_forecasts, WEATHER_UPDATE_INTERVAL
194  )
195  )
196 
197  @property
198  def native_temperature(self) -> float:
199  """Return the temperature."""
200  return self._native_temperature_native_temperature
201 
202  @property
203  def native_temperature_unit(self) -> str:
204  """Return the unit of measurement."""
205  return self._native_temperature_unit_native_temperature_unit
206 
207  @property
208  def humidity(self) -> float:
209  """Return the humidity."""
210  return self._humidity_humidity
211 
212  @property
213  def native_wind_speed(self) -> float:
214  """Return the wind speed."""
215  return self._native_wind_speed_native_wind_speed
216 
217  @property
218  def native_wind_speed_unit(self) -> str:
219  """Return the wind speed."""
220  return self._native_wind_speed_unit_native_wind_speed_unit
221 
222  @property
223  def native_pressure(self) -> float:
224  """Return the pressure."""
225  return self._native_pressure_native_pressure
226 
227  @property
228  def native_pressure_unit(self) -> str:
229  """Return the pressure."""
230  return self._native_pressure_unit_native_pressure_unit
231 
232  @property
233  def condition(self) -> str:
234  """Return the weather condition."""
235  return CONDITION_MAP[self._condition_condition.lower()]
236 
237  async def async_forecast_daily(self) -> list[Forecast]:
238  """Return the daily forecast."""
239  reftime = dt_util.now().replace(hour=16, minute=00)
240 
241  forecast_data = []
242  assert self._forecast_daily_forecast_daily is not None
243  for entry in self._forecast_daily_forecast_daily:
244  data_dict = Forecast(
245  datetime=reftime.isoformat(),
246  condition=entry[0],
247  precipitation=entry[1],
248  temperature=entry[2],
249  templow=entry[3],
250  precipitation_probability=entry[4],
251  )
252  reftime = reftime + timedelta(hours=24)
253  forecast_data.append(data_dict)
254 
255  return forecast_data
256 
257  async def async_forecast_hourly(self) -> list[Forecast]:
258  """Return the hourly forecast."""
259  reftime = dt_util.now().replace(hour=16, minute=00)
260 
261  forecast_data = []
262  assert self._forecast_hourly_forecast_hourly is not None
263  for entry in self._forecast_hourly_forecast_hourly:
264  data_dict = Forecast(
265  datetime=reftime.isoformat(),
266  condition=entry[0],
267  precipitation=entry[1],
268  temperature=entry[2],
269  templow=entry[3],
270  precipitation_probability=entry[4],
271  )
272  reftime = reftime + timedelta(hours=1)
273  forecast_data.append(data_dict)
274 
275  return forecast_data
276 
277  async def async_forecast_twice_daily(self) -> list[Forecast]:
278  """Return the twice daily forecast."""
279  reftime = dt_util.now().replace(hour=11, minute=00)
280 
281  forecast_data = []
282  assert self._forecast_twice_daily_forecast_twice_daily is not None
283  for entry in self._forecast_twice_daily_forecast_twice_daily:
284  data_dict = Forecast(
285  datetime=reftime.isoformat(),
286  condition=entry[0],
287  precipitation=entry[1],
288  temperature=entry[2],
289  templow=entry[3],
290  precipitation_probability=entry[4],
291  is_daytime=entry[5],
292  )
293  reftime = reftime + timedelta(hours=12)
294  forecast_data.append(data_dict)
295 
296  return forecast_data
None __init__(self, str name, str condition, float temperature, float humidity, float pressure, float wind_speed, str temperature_unit, str pressure_unit, str wind_speed_unit, list[list]|None forecast_daily, list[list]|None forecast_hourly, list[list]|None forecast_twice_daily)
Definition: weather.py:150
None async_update_listeners(self, Iterable[Literal["daily", "hourly", "twice_daily"]]|None forecast_types)
Definition: __init__.py:961
None async_on_remove(self, CALLBACK_TYPE func)
Definition: entity.py:1331
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: weather.py:62
CALLBACK_TYPE async_track_time_interval(HomeAssistant hass, Callable[[datetime], Coroutine[Any, Any, None]|None] action, timedelta interval, *str|None name=None, bool|None cancel_on_shutdown=None)
Definition: event.py:1679