diff --git a/homeassistant/components/nordpool/coordinator.py b/homeassistant/components/nordpool/coordinator.py index fa4e9ca2548..e6b36f7deee 100644 --- a/homeassistant/components/nordpool/coordinator.py +++ b/homeassistant/components/nordpool/coordinator.py @@ -2,6 +2,7 @@ from __future__ import annotations +import asyncio from collections.abc import Callable from datetime import datetime, timedelta from typing import TYPE_CHECKING @@ -69,23 +70,30 @@ class NordPoolDataUpdateCoordinator(DataUpdateCoordinator[DeliveryPeriodData]): self.unsub = async_track_point_in_utc_time( self.hass, self.fetch_data, self.get_next_interval(dt_util.utcnow()) ) + data = await self.api_call() + if data: + self.async_set_updated_data(data) + + async def api_call(self, retry: int = 3) -> DeliveryPeriodData | None: + """Make api call to retrieve data with retry if failure.""" + data = None try: data = await self.client.async_get_delivery_period( dt_util.now(), Currency(self.config_entry.data[CONF_CURRENCY]), self.config_entry.data[CONF_AREAS], ) - except NordPoolEmptyResponseError as error: - LOGGER.debug("Empty response error: %s", error) - self.async_set_update_error(error) - return - except NordPoolResponseError as error: - LOGGER.debug("Response error: %s", error) - self.async_set_update_error(error) - return - except NordPoolError as error: + except ( + NordPoolEmptyResponseError, + NordPoolResponseError, + NordPoolError, + ) as error: LOGGER.debug("Connection error: %s", error) + if retry > 0: + next_run = (4 - retry) * 15 + LOGGER.debug("Wait %d seconds for next try", next_run) + await asyncio.sleep(next_run) + return await self.api_call(retry - 1) self.async_set_update_error(error) - return - self.async_set_updated_data(data) + return data diff --git a/tests/components/nordpool/conftest.py b/tests/components/nordpool/conftest.py index d1c1972c568..9b7ab4b2afa 100644 --- a/tests/components/nordpool/conftest.py +++ b/tests/components/nordpool/conftest.py @@ -2,6 +2,7 @@ from __future__ import annotations +from collections.abc import AsyncGenerator from datetime import datetime import json from typing import Any @@ -23,6 +24,13 @@ from tests.common import MockConfigEntry, load_fixture from tests.test_util.aiohttp import AiohttpClientMocker +@pytest.fixture(autouse=True) +async def no_sleep() -> AsyncGenerator[None]: + """No sleeping.""" + with patch("homeassistant.components.nordpool.coordinator.asyncio.sleep"): + yield + + @pytest.fixture async def load_int( hass: HomeAssistant, get_data: DeliveryPeriodData diff --git a/tests/components/nordpool/test_coordinator.py b/tests/components/nordpool/test_coordinator.py index d2d912b1b99..68534237dee 100644 --- a/tests/components/nordpool/test_coordinator.py +++ b/tests/components/nordpool/test_coordinator.py @@ -58,7 +58,7 @@ async def test_coordinator( freezer.tick(timedelta(hours=1)) async_fire_time_changed(hass) await hass.async_block_till_done(wait_background_tasks=True) - mock_data.assert_called_once() + assert mock_data.call_count == 4 state = hass.states.get("sensor.nord_pool_se3_current_price") assert state.state == STATE_UNAVAILABLE mock_data.reset_mock() @@ -68,7 +68,7 @@ async def test_coordinator( freezer.tick(timedelta(hours=1)) async_fire_time_changed(hass) await hass.async_block_till_done(wait_background_tasks=True) - mock_data.assert_called_once() + assert mock_data.call_count == 4 state = hass.states.get("sensor.nord_pool_se3_current_price") assert state.state == STATE_UNAVAILABLE assert "Authentication error" in caplog.text @@ -79,7 +79,7 @@ async def test_coordinator( freezer.tick(timedelta(hours=1)) async_fire_time_changed(hass) await hass.async_block_till_done(wait_background_tasks=True) - mock_data.assert_called_once() + assert mock_data.call_count == 4 state = hass.states.get("sensor.nord_pool_se3_current_price") assert state.state == STATE_UNAVAILABLE assert "Empty response" in caplog.text @@ -90,7 +90,7 @@ async def test_coordinator( freezer.tick(timedelta(hours=1)) async_fire_time_changed(hass) await hass.async_block_till_done(wait_background_tasks=True) - mock_data.assert_called_once() + assert mock_data.call_count == 4 state = hass.states.get("sensor.nord_pool_se3_current_price") assert state.state == STATE_UNAVAILABLE assert "Response error" in caplog.text