diff --git a/homeassistant/components/buienradar/const.py b/homeassistant/components/buienradar/const.py index 8111f63c923..718812c5c73 100644 --- a/homeassistant/components/buienradar/const.py +++ b/homeassistant/components/buienradar/const.py @@ -14,10 +14,10 @@ CONF_TIMEFRAME = "timeframe" SUPPORTED_COUNTRY_CODES = ["NL", "BE"] DEFAULT_COUNTRY = "NL" -"""Schedule next call after (minutes).""" SCHEDULE_OK = 10 -"""When an error occurred, new call after (minutes).""" +"""Schedule next call after (minutes).""" SCHEDULE_NOK = 2 +"""When an error occurred, new call after (minutes).""" STATE_CONDITIONS = ["clear", "cloudy", "fog", "rainy", "snowy", "lightning"] diff --git a/homeassistant/components/buienradar/sensor.py b/homeassistant/components/buienradar/sensor.py index 00740eb4801..fe3ce3164fe 100644 --- a/homeassistant/components/buienradar/sensor.py +++ b/homeassistant/components/buienradar/sensor.py @@ -714,17 +714,18 @@ async def async_setup_entry( timeframe, ) + # create weather entities: entities = [ BrSensor(config.get(CONF_NAME, "Buienradar"), coordinates, description) for description in SENSOR_TYPES ] - async_add_entities(entities) - + # create weather data: data = BrData(hass, coordinates, timeframe, entities) - # schedule the first update in 1 minute from now: - await data.schedule_update(1) hass.data[DOMAIN][entry.entry_id][Platform.SENSOR] = data + await data.async_update() + + async_add_entities(entities) class BrSensor(SensorEntity): @@ -755,7 +756,7 @@ class BrSensor(SensorEntity): @callback def data_updated(self, data: BrData): """Update data.""" - if self.hass and self._load_data(data.data): + if self._load_data(data.data) and self.hass: self.async_write_ha_state() @callback diff --git a/homeassistant/components/buienradar/util.py b/homeassistant/components/buienradar/util.py index 9d0c2a575c9..3c50b3097cb 100644 --- a/homeassistant/components/buienradar/util.py +++ b/homeassistant/components/buienradar/util.py @@ -27,7 +27,7 @@ from buienradar.constants import ( from buienradar.urls import JSON_FEED_URL, json_precipitation_forecast_url from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE -from homeassistant.core import CALLBACK_TYPE +from homeassistant.core import CALLBACK_TYPE, callback from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.util import dt as dt_util @@ -77,7 +77,8 @@ class BrData: for dev in self.devices: dev.data_updated(self) - async def schedule_update(self, minute=1): + @callback + def async_schedule_update(self, minute=1): """Schedule an update after minute minutes.""" _LOGGER.debug("Scheduling next update in %s minutes", minute) nxt = dt_util.utcnow() + timedelta(minutes=minute) @@ -110,7 +111,7 @@ class BrData: if resp is not None: await resp.release() - async def async_update(self, *_): + async def _async_update(self): """Update the data from buienradar.""" content = await self.get_data(JSON_FEED_URL) @@ -123,9 +124,7 @@ class BrData: content.get(MESSAGE), content.get(STATUS_CODE), ) - # schedule new call - await self.schedule_update(SCHEDULE_NOK) - return + return None self.load_error_count = 0 # rounding coordinates prevents unnecessary redirects/calls @@ -143,9 +142,7 @@ class BrData: raincontent.get(MESSAGE), raincontent.get(STATUS_CODE), ) - # schedule new call - await self.schedule_update(SCHEDULE_NOK) - return + return None self.rain_error_count = 0 result = parse_data( @@ -164,12 +161,21 @@ class BrData: "Unable to parse data from Buienradar. (Msg: %s)", result.get(MESSAGE), ) - await self.schedule_update(SCHEDULE_NOK) + return None + + return result[DATA] + + async def async_update(self, *_): + """Update the data from buienradar and schedule the next update.""" + data = await self._async_update() + + if data is None: + self.async_schedule_update(SCHEDULE_NOK) return - self.data = result.get(DATA) + self.data = data await self.update_devices() - await self.schedule_update(SCHEDULE_OK) + self.async_schedule_update(SCHEDULE_OK) @property def attribution(self): diff --git a/homeassistant/components/buienradar/weather.py b/homeassistant/components/buienradar/weather.py index cdb8adf1dac..66c3b23ec8b 100644 --- a/homeassistant/components/buienradar/weather.py +++ b/homeassistant/components/buienradar/weather.py @@ -82,6 +82,11 @@ CONDITION_CLASSES = { ATTR_CONDITION_WINDY_VARIANT: (), ATTR_CONDITION_EXCEPTIONAL: (), } +CONDITION_MAP = { + cond_code: cond_ha + for cond_ha, cond_codes in CONDITION_CLASSES.items() + for cond_code in cond_codes +} async def async_setup_entry( @@ -106,20 +111,10 @@ async def async_setup_entry( # create weather data: data = BrData(hass, coordinates, DEFAULT_TIMEFRAME, entities) hass.data[DOMAIN][entry.entry_id][Platform.WEATHER] = data - - # create condition helper - if DATA_CONDITION not in hass.data[DOMAIN]: - cond_keys = [str(chr(x)) for x in range(97, 123)] - hass.data[DOMAIN][DATA_CONDITION] = dict.fromkeys(cond_keys) - for cond, condlst in CONDITION_CLASSES.items(): - for condi in condlst: - hass.data[DOMAIN][DATA_CONDITION][condi] = cond + await data.async_update() async_add_entities(entities) - # schedule the first update in 1 minute from now: - await data.schedule_update(1) - class BrWeather(WeatherEntity): """Representation of a weather condition.""" @@ -143,9 +138,6 @@ class BrWeather(WeatherEntity): @callback def data_updated(self, data: BrData) -> None: """Update data.""" - if not self.hass: - return - self._attr_attribution = data.attribution self._attr_condition = self._calc_condition(data) self._attr_forecast = self._calc_forecast(data) @@ -158,22 +150,20 @@ class BrWeather(WeatherEntity): self._attr_native_visibility = data.visibility self._attr_native_wind_speed = data.wind_speed self._attr_wind_bearing = data.wind_bearing + + if not self.hass: + return self.async_write_ha_state() def _calc_condition(self, data: BrData): """Return the current condition.""" - if ( - data.condition - and (ccode := data.condition.get(CONDCODE)) - and (conditions := self.hass.data[DOMAIN].get(DATA_CONDITION)) - ): - return conditions.get(ccode) + if data.condition and (ccode := data.condition.get(CONDCODE)): + return CONDITION_MAP.get(ccode) return None def _calc_forecast(self, data: BrData): """Return the forecast array.""" fcdata_out = [] - cond = self.hass.data[DOMAIN][DATA_CONDITION] if not data.forecast: return None @@ -181,10 +171,10 @@ class BrWeather(WeatherEntity): for data_in in data.forecast: # remap keys from external library to # keys understood by the weather component: - condcode = data_in.get(CONDITION, []).get(CONDCODE) + condcode = data_in.get(CONDITION, {}).get(CONDCODE) data_out = { ATTR_FORECAST_TIME: data_in.get(DATETIME).isoformat(), - ATTR_FORECAST_CONDITION: cond[condcode], + ATTR_FORECAST_CONDITION: CONDITION_MAP.get(condcode), ATTR_FORECAST_NATIVE_TEMP_LOW: data_in.get(MIN_TEMP), ATTR_FORECAST_NATIVE_TEMP: data_in.get(MAX_TEMP), ATTR_FORECAST_NATIVE_PRECIPITATION: data_in.get(RAIN), diff --git a/tests/components/buienradar/test_sensor.py b/tests/components/buienradar/test_sensor.py index 725b03a6cc5..fb83d7a13db 100644 --- a/tests/components/buienradar/test_sensor.py +++ b/tests/components/buienradar/test_sensor.py @@ -1,4 +1,6 @@ """The tests for the Buienradar sensor platform.""" +from http import HTTPStatus + from homeassistant.components.buienradar.const import DOMAIN from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE from homeassistant.core import HomeAssistant @@ -18,6 +20,9 @@ async def test_smoke_test_setup_component( aioclient_mock: AiohttpClientMocker, hass: HomeAssistant ) -> None: """Smoke test for successfully set-up with default config.""" + aioclient_mock.get( + "https://data.buienradar.nl/2.0/feed/json", status=HTTPStatus.NOT_FOUND + ) mock_entry = MockConfigEntry(domain=DOMAIN, unique_id="TEST_ID", data=TEST_CFG_DATA) mock_entry.add_to_hass(hass) diff --git a/tests/components/buienradar/test_weather.py b/tests/components/buienradar/test_weather.py index c8b0d459b78..d4c4af5f62a 100644 --- a/tests/components/buienradar/test_weather.py +++ b/tests/components/buienradar/test_weather.py @@ -1,4 +1,6 @@ """The tests for the buienradar weather component.""" +from http import HTTPStatus + from homeassistant.components.buienradar.const import DOMAIN from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE from homeassistant.core import HomeAssistant @@ -13,6 +15,9 @@ async def test_smoke_test_setup_component( aioclient_mock: AiohttpClientMocker, hass: HomeAssistant ) -> None: """Smoke test for successfully set-up with default config.""" + aioclient_mock.get( + "https://data.buienradar.nl/2.0/feed/json", status=HTTPStatus.NOT_FOUND + ) mock_entry = MockConfigEntry(domain=DOMAIN, unique_id="TEST_ID", data=TEST_CFG_DATA) mock_entry.add_to_hass(hass)