Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """The NWS coordinator."""
2 
3 from datetime import datetime
4 import logging
5 
6 from aiohttp import ClientResponseError
7 from pynws import NwsNoDataError, SimpleNWS, call_with_retry
8 
9 from homeassistant.core import HomeAssistant
10 from homeassistant.helpers import debounce
12  TimestampDataUpdateCoordinator,
13  UpdateFailed,
14 )
15 from homeassistant.util.dt import utcnow
16 
17 from .const import (
18  DEBOUNCE_TIME,
19  DEFAULT_SCAN_INTERVAL,
20  OBSERVATION_VALID_TIME,
21  RETRY_INTERVAL,
22  RETRY_STOP,
23  UPDATE_TIME_PERIOD,
24 )
25 
26 _LOGGER = logging.getLogger(__name__)
27 
28 
30  """Class to manage fetching NWS observation data."""
31 
32  def __init__(
33  self,
34  hass: HomeAssistant,
35  nws: SimpleNWS,
36  ) -> None:
37  """Initialize."""
38  self.nwsnws = nws
39  self.last_api_success_timelast_api_success_time: datetime | None = None
40  self.initializedinitialized: bool = False
41 
42  super().__init__(
43  hass,
44  _LOGGER,
45  name=f"NWS observation station {nws.station}",
46  update_interval=DEFAULT_SCAN_INTERVAL,
47  request_refresh_debouncer=debounce.Debouncer(
48  hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True
49  ),
50  )
51 
52  async def _async_update_data(self) -> None:
53  """Update data via library."""
54  if not self.initializedinitialized:
55  await self._async_first_update_data_async_first_update_data()
56  else:
57  await self._async_subsequent_update_data_async_subsequent_update_data()
58 
59  async def _async_first_update_data(self):
60  """Update data without retries first."""
61  try:
62  await self.nwsnws.update_observation(
63  raise_no_data=True,
64  start_time=utcnow() - UPDATE_TIME_PERIOD,
65  )
66  except (NwsNoDataError, ClientResponseError) as err:
67  raise UpdateFailed(err) from err
68  else:
69  self.last_api_success_timelast_api_success_time = utcnow()
70  finally:
71  self.initializedinitialized = True
72 
73  async def _async_subsequent_update_data(self) -> None:
74  """Update data with retries and caching data over multiple failed rounds."""
75  try:
76  await call_with_retry(
77  self.nwsnws.update_observation,
78  RETRY_INTERVAL,
79  RETRY_STOP,
80  retry_no_data=True,
81  start_time=utcnow() - UPDATE_TIME_PERIOD,
82  )
83  except (NwsNoDataError, ClientResponseError) as err:
84  if not self.last_api_success_timelast_api_success_time or (
85  utcnow() - self.last_api_success_timelast_api_success_time > OBSERVATION_VALID_TIME
86  ):
87  raise UpdateFailed(err) from err
88  _LOGGER.debug(
89  "NWS observation update failed, but data still valid. Last success: %s",
90  self.last_api_success_timelast_api_success_time,
91  )
92  else:
93  self.last_api_success_timelast_api_success_time = utcnow()