Improve iaqualink 429 handling (#170231)

This commit is contained in:
Florent Thoumie
2026-05-19 08:00:56 +00:00
committed by Franck Nijhof
parent 0830988687
commit b26c2f3854
2 changed files with 63 additions and 1 deletions
@@ -8,6 +8,7 @@ from typing import Any
import httpx
from iaqualink.exception import (
AqualinkServiceException,
AqualinkServiceThrottledException,
AqualinkServiceUnauthorizedException,
)
@@ -46,6 +47,12 @@ class AqualinkDataUpdateCoordinator(DataUpdateCoordinator[None]):
await self.system.update()
except AqualinkServiceUnauthorizedException as err:
raise ConfigEntryAuthFailed("Invalid credentials for iAquaLink") from err
except AqualinkServiceThrottledException:
_LOGGER.warning(
"Rate limited by iAquaLink system %s, will retry later",
self.system.serial,
)
return
except (AqualinkServiceException, httpx.HTTPError) as err:
raise UpdateFailed(
f"Unable to update iAquaLink system {self.system.serial}: {err}"
+56 -1
View File
@@ -6,6 +6,7 @@ from freezegun.api import FrozenDateTimeFactory
from iaqualink.client import AqualinkClient
from iaqualink.exception import (
AqualinkServiceException,
AqualinkServiceThrottledException,
AqualinkServiceUnauthorizedException,
)
from iaqualink.systems.iaqua.device import (
@@ -16,6 +17,7 @@ from iaqualink.systems.iaqua.device import (
IaquaThermostat,
)
from iaqualink.systems.iaqua.system import IaquaSystem
import pytest
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN
@@ -46,7 +48,9 @@ async def _advance_coordinator_time(
hass: HomeAssistant, freezer: FrozenDateTimeFactory
) -> None:
"""Advance time to trigger coordinator update interval."""
freezer.tick(delta=UPDATE_INTERVAL_BY_SYSTEM_TYPE["iaqua"])
update_interval = UPDATE_INTERVAL_BY_SYSTEM_TYPE["iaqua"]
freezer.tick(delta=update_interval)
async_fire_time_changed(hass, dt_util.utcnow())
await hass.async_block_till_done(wait_background_tasks=True)
@@ -104,6 +108,57 @@ async def test_system_refresh_failure_marks_entities_unavailable(
assert state.state == STATE_UNAVAILABLE
async def test_system_rate_limited_keeps_entities_available(
hass: HomeAssistant,
config_entry: MockConfigEntry,
client: AqualinkClient,
freezer: FrozenDateTimeFactory,
caplog: pytest.LogCaptureFixture,
) -> None:
"""Test a rate-limited update keeps entities at their last known state."""
config_entry.add_to_hass(hass)
system = get_aqualink_system(client, cls=IaquaSystem)
system.online = True
system.update = AsyncMock()
systems = {system.serial: system}
light = get_aqualink_device(
system, name="aux_1", cls=IaquaLightSwitch, data={"state": "1"}
)
devices = {light.name: light}
system.get_devices = AsyncMock(return_value=devices)
with (
patch(
"homeassistant.components.iaqualink.AqualinkClient.login",
return_value=None,
),
patch(
"homeassistant.components.iaqualink.AqualinkClient.get_systems",
return_value=systems,
),
):
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entity_ids = hass.states.async_entity_ids(LIGHT_DOMAIN)
assert len(entity_ids) == 1
entity_id = entity_ids[0]
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_ON
system.update = AsyncMock(side_effect=AqualinkServiceThrottledException)
await _advance_coordinator_time(hass, freezer)
state = hass.states.get(entity_id)
assert state is not None
assert state.state == STATE_ON
assert "Rate limited by iAquaLink" in caplog.text
async def test_light_service_calls_update_entity_state(
hass: HomeAssistant,
config_entry: MockConfigEntry,