Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

weatherkit: use stale data for up to an hour if updates fail #130398

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions homeassistant/components/weatherkit/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from datetime import timedelta
from datetime import datetime, timedelta

from apple_weatherkit import DataSetType
from apple_weatherkit.client import WeatherKitApiClient, WeatherKitApiClientError
Expand All @@ -20,12 +20,15 @@
DataSetType.HOURLY_FORECAST,
]

STALE_DATA_THRESHOLD = timedelta(hours=1)


class WeatherKitDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the API."""

config_entry: ConfigEntry
supported_data_sets: list[DataSetType] | None = None
last_updated_at: datetime | None = None

def __init__(
self,
Expand Down Expand Up @@ -62,10 +65,20 @@ async def _async_update_data(self):
if not self.supported_data_sets:
await self.update_supported_data_sets()

return await self.client.get_weather_data(
updated_data = await self.client.get_weather_data(
tjhorner marked this conversation as resolved.
Show resolved Hide resolved
self.config_entry.data[CONF_LATITUDE],
self.config_entry.data[CONF_LONGITUDE],
self.supported_data_sets,
)
except WeatherKitApiClientError as exception:
raise UpdateFailed(exception) from exception
if self.data is None or (
self.last_updated_at is not None
and datetime.now() - self.last_updated_at > STALE_DATA_THRESHOLD
):
raise UpdateFailed(exception) from exception

LOGGER.debug("Using stale data because update failed: %s", exception)
return self.data
else:
self.last_updated_at = datetime.now()
return updated_data
30 changes: 29 additions & 1 deletion tests/components/weatherkit/test_coordinator.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"""Test WeatherKit data coordinator."""

from datetime import timedelta
from datetime import datetime, timedelta
from unittest.mock import patch

from apple_weatherkit.client import WeatherKitApiClientError
from freezegun import freeze_time

from homeassistant.const import STATE_UNAVAILABLE
from homeassistant.core import HomeAssistant
Expand All @@ -18,6 +19,14 @@ async def test_failed_updates(hass: HomeAssistant) -> None:
"""Test that we properly handle failed updates."""
await init_integration(hass)

state = hass.states.get("weather.home")
assert state
assert state.state != STATE_UNAVAILABLE

initial_state = state.state

# Expect stale data to be used before one hour

with patch(
"homeassistant.components.weatherkit.WeatherKitApiClient.get_weather_data",
side_effect=WeatherKitApiClientError,
Expand All @@ -28,6 +37,25 @@ async def test_failed_updates(hass: HomeAssistant) -> None:
)
await hass.async_block_till_done()

state = hass.states.get("weather.home")
assert state
assert state.state == initial_state

# Expect state to be unavailable after one hour

with (
patch(
"homeassistant.components.weatherkit.WeatherKitApiClient.get_weather_data",
side_effect=WeatherKitApiClientError,
),
freeze_time(datetime.now() + timedelta(hours=1)),
):
async_fire_time_changed(
hass,
utcnow() + timedelta(hours=1),
)
await hass.async_block_till_done()

state = hass.states.get("weather.home")
assert state
assert state.state == STATE_UNAVAILABLE