diff --git a/homeassistant/components/tankerkoenig/coordinator.py b/homeassistant/components/tankerkoenig/coordinator.py index f1f200a59642..c28ebf4aab2c 100644 --- a/homeassistant/components/tankerkoenig/coordinator.py +++ b/homeassistant/components/tankerkoenig/coordinator.py @@ -12,6 +12,7 @@ TankerkoenigConnectionError, TankerkoenigError, TankerkoenigInvalidKeyError, + TankerkoenigRateLimitError, ) from homeassistant.config_entries import ConfigEntry @@ -19,7 +20,7 @@ from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed from .const import CONF_FUEL_TYPES, CONF_STATIONS @@ -78,13 +79,22 @@ async def _async_update_data(self) -> dict[str, PriceInfo]: station_ids = list(self.stations) prices = {} - # The API seems to only return at most 10 results, so split the list in chunks of 10 # and merge it together. for index in range(ceil(len(station_ids) / 10)): - data = await self._tankerkoenig.prices( - station_ids[index * 10 : (index + 1) * 10] - ) + try: + data = await self._tankerkoenig.prices( + station_ids[index * 10 : (index + 1) * 10] + ) + except TankerkoenigInvalidKeyError as err: + raise ConfigEntryAuthFailed(err) from err + except (TankerkoenigError, TankerkoenigConnectionError) as err: + if isinstance(err, TankerkoenigRateLimitError): + _LOGGER.warning( + "API rate limit reached, consider to increase polling interval" + ) + raise UpdateFailed(err) from err + prices.update(data) return prices diff --git a/homeassistant/components/tankerkoenig/manifest.json b/homeassistant/components/tankerkoenig/manifest.json index adea5b964902..cac849b7bb56 100644 --- a/homeassistant/components/tankerkoenig/manifest.json +++ b/homeassistant/components/tankerkoenig/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/tankerkoenig", "iot_class": "cloud_polling", "loggers": ["aiotankerkoenig"], - "requirements": ["aiotankerkoenig==0.3.0"] + "requirements": ["aiotankerkoenig==0.4.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 707cc3c3f4ff..4163c4dc8575 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -383,7 +383,7 @@ aioswitcher==3.4.1 aiosyncthing==0.5.1 # homeassistant.components.tankerkoenig -aiotankerkoenig==0.3.0 +aiotankerkoenig==0.4.0 # homeassistant.components.tractive aiotractive==0.5.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 20ec493b543a..4ca8ecd1ad48 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -356,7 +356,7 @@ aioswitcher==3.4.1 aiosyncthing==0.5.1 # homeassistant.components.tankerkoenig -aiotankerkoenig==0.3.0 +aiotankerkoenig==0.4.0 # homeassistant.components.tractive aiotractive==0.5.6 diff --git a/tests/components/tankerkoenig/test_coordinator.py b/tests/components/tankerkoenig/test_coordinator.py new file mode 100644 index 000000000000..650fa5a18ace --- /dev/null +++ b/tests/components/tankerkoenig/test_coordinator.py @@ -0,0 +1,51 @@ +"""Tests for the Tankerkoening integration.""" +from __future__ import annotations + +from datetime import timedelta +from unittest.mock import AsyncMock + +from aiotankerkoenig.exceptions import TankerkoenigRateLimitError +import pytest + +from homeassistant.components.tankerkoenig.const import DEFAULT_SCAN_INTERVAL +from homeassistant.config_entries import ConfigEntryState +from homeassistant.const import STATE_UNAVAILABLE +from homeassistant.core import HomeAssistant +import homeassistant.util.dt as dt_util + +from tests.common import MockConfigEntry, async_fire_time_changed + + +@pytest.mark.usefixtures("setup_integration") +async def test_rate_limit( + hass: HomeAssistant, + config_entry: MockConfigEntry, + tankerkoenig: AsyncMock, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test detection of API rate limit.""" + assert config_entry.state == ConfigEntryState.LOADED + state = hass.states.get("binary_sensor.station_somewhere_street_1_status") + assert state + assert state.state == "on" + + tankerkoenig.prices.side_effect = TankerkoenigRateLimitError + async_fire_time_changed( + hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_SCAN_INTERVAL) + ) + await hass.async_block_till_done() + assert ( + "API rate limit reached, consider to increase polling interval" in caplog.text + ) + state = hass.states.get("binary_sensor.station_somewhere_street_1_status") + assert state + assert state.state == STATE_UNAVAILABLE + + tankerkoenig.prices.side_effect = None + async_fire_time_changed( + hass, dt_util.utcnow() + timedelta(minutes=DEFAULT_SCAN_INTERVAL * 2) + ) + await hass.async_block_till_done() + state = hass.states.get("binary_sensor.station_somewhere_street_1_status") + assert state + assert state.state == "on"