Skip to content

Commit

Permalink
Detect reached API rate limit in Tankerkoenig (home-assistant#110432)
Browse files Browse the repository at this point in the history
  • Loading branch information
mib1185 authored and astrandb committed Feb 13, 2024
1 parent c50c378 commit f672fec
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 8 deletions.
20 changes: 15 additions & 5 deletions homeassistant/components/tankerkoenig/coordinator.py
Expand Up @@ -12,14 +12,15 @@
TankerkoenigConnectionError,
TankerkoenigError,
TankerkoenigInvalidKeyError,
TankerkoenigRateLimitError,
)

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, CONF_SHOW_ON_MAP
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

Expand Down Expand Up @@ -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
2 changes: 1 addition & 1 deletion homeassistant/components/tankerkoenig/manifest.json
Expand Up @@ -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"]
}
2 changes: 1 addition & 1 deletion requirements_all.txt
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Expand Up @@ -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
Expand Down
51 changes: 51 additions & 0 deletions 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"

0 comments on commit f672fec

Please sign in to comment.