Avoid a naive datetime.now() in buienradar (#178368)

This commit is contained in:
soldier2008
2026-08-19 13:56:37 +02:00
committed by GitHub
parent 465624ef51
commit c3510f000c
3 changed files with 106 additions and 3 deletions
@@ -14,6 +14,9 @@ CONF_TIMEFRAME = "timeframe"
SUPPORTED_COUNTRY_CODES = ["NL", "BE"]
DEFAULT_COUNTRY = "NL"
SERVICE_TIME_ZONE = "Europe/Amsterdam"
"""Time zone of the buienradar.nl service, which updates around local midnight."""
SCHEDULE_OK = 10
"""Schedule next call after (minutes)."""
SCHEDULE_NOK = 2
+8 -3
View File
@@ -1,6 +1,6 @@
"""Shared utilities for different supported platforms."""
from datetime import datetime, timedelta
from datetime import timedelta
from http import HTTPStatus
import logging
from typing import Any
@@ -34,7 +34,7 @@ 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
from .const import DEFAULT_TIMEOUT, SCHEDULE_NOK, SCHEDULE_OK
from .const import DEFAULT_TIMEOUT, SCHEDULE_NOK, SCHEDULE_OK, SERVICE_TIME_ZONE
__all__ = ["BrData"]
_LOGGER = logging.getLogger(__name__)
@@ -158,7 +158,12 @@ class BrData:
_LOGGER.debug("Buienradar parsed data: %s", result)
if result.get(SUCCESS) is not True:
if int(datetime.now().strftime("%H")) > 0: # pylint: disable=home-assistant-enforce-naive-now
# buienradar.nl updates its forecast for the next day between 00:00
# and 01:00 CE(S)T and often serves nothing during that hour, so the
# warning is only meaningful outside it. The hour that decides this
# is the one at the service, not in the user's configured time zone.
service_tz = await dt_util.async_get_time_zone(SERVICE_TIME_ZONE)
if service_tz is None or dt_util.utcnow().astimezone(service_tz).hour > 0:
_LOGGER.warning(
"Unable to parse data from Buienradar. (Msg: %s)",
result.get(MESSAGE),
+95
View File
@@ -0,0 +1,95 @@
"""Tests for the Buienradar utilities."""
import datetime
from http import HTTPStatus
from unittest.mock import patch
from buienradar.constants import MESSAGE, SUCCESS
from freezegun.api import FrozenDateTimeFactory
import pytest
from homeassistant.components.buienradar.const import DOMAIN
from homeassistant.const import CONF_LATITUDE, CONF_LONGITUDE
from homeassistant.core import HomeAssistant
from homeassistant.util import dt as dt_util
from tests.common import MockConfigEntry, async_fire_time_changed
from tests.test_util.aiohttp import AiohttpClientMocker
TEST_LATITUDE = 51.5
TEST_LONGITUDE = 5.5
TEST_CFG_DATA = {CONF_LATITUDE: TEST_LATITUDE, CONF_LONGITUDE: TEST_LONGITUDE}
WARNING = "Unable to parse data from Buienradar"
@pytest.mark.parametrize(
("update_at", "expect_warning"),
[
("2026-01-14T23:00:00+00:00", False),
("2026-01-14T23:59:59+00:00", False),
("2026-01-15T00:00:00+00:00", True),
("2026-07-14T22:30:00+00:00", False),
("2026-01-15T06:30:00+00:00", True),
],
ids=[
"cet_0000_start_of_quiet_hour",
"cet_0059_end_of_quiet_hour",
"cet_0100_just_after",
"cest_0030_quiet_hour_in_dst",
"cet_0730_quiet_only_where_user_lives",
],
)
async def test_unparsable_data_is_quiet_during_the_midnight_hour(
hass: HomeAssistant,
aioclient_mock: AiohttpClientMocker,
freezer: FrozenDateTimeFactory,
caplog: pytest.LogCaptureFixture,
update_at: str,
expect_warning: bool,
) -> None:
"""Test the parse failure warning is suppressed in the midnight hour.
buienradar.nl serves no data while it updates its forecast between 00:00 and
01:00 CE(S)T, so the warning is only interesting outside that hour. The hour
that decides this belongs to the service, so the configured time zone here is
deliberately somewhere else: America/Regina is UTC-6 with no DST, which puts
every case below in a different hour locally than in Amsterdam.
The times are UTC. The first three pin the edges of the quiet hour in CET,
the fourth repeats it in CEST so the offset is not assumed, and the last one
is the quiet hour in America/Regina rather than in Amsterdam, so it must
still warn.
"""
await hass.config.async_set_time_zone("America/Regina")
aioclient_mock.get(
"https://data.buienradar.nl/2.0/feed/json", status=HTTPStatus.OK, text="{}"
)
aioclient_mock.get(
f"https://gps.buienradar.nl/getrr.php?lat={TEST_LATITUDE}&lon={TEST_LONGITUDE}",
status=HTTPStatus.OK,
text="",
)
update = dt_util.parse_datetime(update_at)
assert update is not None
# A failed update reschedules itself two minutes later, which is the update
# the assertion below is about.
freezer.move_to(update - datetime.timedelta(minutes=2))
entry = MockConfigEntry(domain=DOMAIN, unique_id="TEST_ID", data=TEST_CFG_DATA)
entry.add_to_hass(hass)
with patch(
"homeassistant.components.buienradar.util.parse_data",
return_value={SUCCESS: False, MESSAGE: "no data"},
):
await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()
caplog.clear()
freezer.move_to(update)
async_fire_time_changed(hass, dt_util.utcnow())
await hass.async_block_till_done()
assert (WARNING in caplog.text) is expect_warning