94 lines
2.9 KiB
Python
94 lines
2.9 KiB
Python
"""The NWS coordinator."""
|
|
|
|
from datetime import datetime
|
|
import logging
|
|
|
|
from aiohttp import ClientResponseError
|
|
from pynws import NwsNoDataError, SimpleNWS, call_with_retry
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.helpers import debounce
|
|
from homeassistant.helpers.update_coordinator import (
|
|
TimestampDataUpdateCoordinator,
|
|
UpdateFailed,
|
|
)
|
|
from homeassistant.util.dt import utcnow
|
|
|
|
from .const import (
|
|
DEBOUNCE_TIME,
|
|
DEFAULT_SCAN_INTERVAL,
|
|
OBSERVATION_VALID_TIME,
|
|
RETRY_INTERVAL,
|
|
RETRY_STOP,
|
|
UPDATE_TIME_PERIOD,
|
|
)
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
class NWSObservationDataUpdateCoordinator(TimestampDataUpdateCoordinator[None]):
|
|
"""Class to manage fetching NWS observation data."""
|
|
|
|
def __init__(
|
|
self,
|
|
hass: HomeAssistant,
|
|
nws: SimpleNWS,
|
|
) -> None:
|
|
"""Initialize."""
|
|
self.nws = nws
|
|
self.last_api_success_time: datetime | None = None
|
|
self.initialized: bool = False
|
|
|
|
super().__init__(
|
|
hass,
|
|
_LOGGER,
|
|
name=f"NWS observation station {nws.station}",
|
|
update_interval=DEFAULT_SCAN_INTERVAL,
|
|
request_refresh_debouncer=debounce.Debouncer(
|
|
hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True
|
|
),
|
|
)
|
|
|
|
async def _async_update_data(self) -> None:
|
|
"""Update data via library."""
|
|
if not self.initialized:
|
|
await self._async_first_update_data()
|
|
else:
|
|
await self._async_subsequent_update_data()
|
|
|
|
async def _async_first_update_data(self):
|
|
"""Update data without retries first."""
|
|
try:
|
|
await self.nws.update_observation(
|
|
raise_no_data=True,
|
|
start_time=utcnow() - UPDATE_TIME_PERIOD,
|
|
)
|
|
except (NwsNoDataError, ClientResponseError) as err:
|
|
raise UpdateFailed(err) from err
|
|
else:
|
|
self.last_api_success_time = utcnow()
|
|
finally:
|
|
self.initialized = True
|
|
|
|
async def _async_subsequent_update_data(self) -> None:
|
|
"""Update data with retries and caching data over multiple failed rounds."""
|
|
try:
|
|
await call_with_retry(
|
|
self.nws.update_observation,
|
|
RETRY_INTERVAL,
|
|
RETRY_STOP,
|
|
retry_no_data=True,
|
|
start_time=utcnow() - UPDATE_TIME_PERIOD,
|
|
)
|
|
except (NwsNoDataError, ClientResponseError) as err:
|
|
if not self.last_api_success_time or (
|
|
utcnow() - self.last_api_success_time > OBSERVATION_VALID_TIME
|
|
):
|
|
raise UpdateFailed(err) from err
|
|
_LOGGER.debug(
|
|
"NWS observation update failed, but data still valid. Last success: %s",
|
|
self.last_api_success_time,
|
|
)
|
|
else:
|
|
self.last_api_success_time = utcnow()
|