import json from datetime import datetime from typing import List from freezegun import freeze_time from homeassistant.components.weather import Forecast from homeassistant.core import HomeAssistant from irm_kmi_api.data import IrmKmiRadarForecast from pytest_homeassistant_custom_component.common import (MockConfigEntry, load_fixture) from custom_components.irm_kmi import IrmKmiCoordinator, IrmKmiWeather from custom_components.irm_kmi.data import ProcessedCoordinatorData from tests.conftest import get_api_with_data @freeze_time(datetime.fromisoformat("2023-12-28T15:30:00+01:00")) async def test_weather_nl( hass: HomeAssistant, mock_config_entry: MockConfigEntry ) -> None: coordinator = IrmKmiCoordinator(hass, mock_config_entry) forecast = json.loads(load_fixture("forecast_nl.json")) coordinator._api._api_data = forecast coordinator.data = await coordinator.process_api_data() weather = IrmKmiWeather(coordinator, mock_config_entry) result = await weather.async_forecast_daily() assert isinstance(result, list) assert len(result) == 7 # When getting daily forecast, the min temperature of the current day # should be the min temperature of the coming night assert result[0]['native_templow'] == 9 @freeze_time(datetime.fromisoformat("2024-01-21T14:15:00+01:00")) async def test_weather_higher_temp_at_night( hass: HomeAssistant, mock_config_entry: MockConfigEntry ) -> None: # Test case for https://github.com/jdejaegh/irm-kmi-ha/issues/8 coordinator = IrmKmiCoordinator(hass, mock_config_entry) forecast = json.loads(load_fixture("high_low_temp.json")) coordinator._api._api_data = forecast coordinator.data = await coordinator.process_api_data() weather = IrmKmiWeather(coordinator, mock_config_entry) result: List[Forecast] = await weather.async_forecast_daily() for f in result: if f['native_temperature'] is not None and f['native_templow'] is not None: assert f['native_temperature'] >= f['native_templow'] result: List[Forecast] = await weather.async_forecast_twice_daily() for f in result: if f['native_temperature'] is not None and f['native_templow'] is not None: assert f['native_temperature'] >= f['native_templow'] @freeze_time(datetime.fromisoformat("2023-12-26T18:30:00+01:00")) async def test_forecast_attribute_same_as_service_call( hass: HomeAssistant, mock_config_entry_with_deprecated: MockConfigEntry ) -> None: coordinator = IrmKmiCoordinator(hass, mock_config_entry_with_deprecated) forecast = json.loads(load_fixture("forecast.json")) coordinator._api._api_data = forecast coordinator.data = await coordinator.process_api_data() weather = IrmKmiWeather(coordinator, mock_config_entry_with_deprecated) result_service: List[Forecast] = await weather.async_forecast_twice_daily() result_forecast: List[Forecast] = weather.extra_state_attributes['forecast'] assert result_service == result_forecast @freeze_time(datetime.fromisoformat("2023-12-26T17:58:03+01:00")) async def test_radar_forecast_service( hass: HomeAssistant, mock_config_entry: MockConfigEntry ): hass.config.time_zone = 'Europe/Brussels' coordinator = IrmKmiCoordinator(hass, mock_config_entry) coordinator._api = get_api_with_data("forecast.json") coordinator.data = ProcessedCoordinatorData( radar_forecast=coordinator._api.get_radar_forecast() ) weather = IrmKmiWeather(coordinator, mock_config_entry) result_service: List[Forecast] = weather.get_forecasts_radar_service(False) expected = [ IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'), IrmKmiRadarForecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0, might_rain=False, rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min') ] assert result_service == expected[5:] result_service: List[Forecast] = weather.get_forecasts_radar_service(True) assert result_service == expected def is_serializable(x): try: json.dumps(x) return True except (TypeError, OverflowError): return False def all_serializable(elements: list[Forecast]): for element in elements: for v in element.values(): assert is_serializable(v) async def test_forecast_types_are_serializable( hass: HomeAssistant, mock_config_entry: MockConfigEntry ) -> None: coordinator = IrmKmiCoordinator(hass, mock_config_entry) forecast = json.loads(load_fixture("forecast.json")) coordinator._api._api_data = forecast coordinator.data = await coordinator.process_api_data() weather = IrmKmiWeather(coordinator, mock_config_entry) result = await weather.async_forecast_daily() all_serializable(result) result = await weather.async_forecast_twice_daily() all_serializable(result) result = await weather.async_forecast_hourly() all_serializable(result) result = weather.get_forecasts_radar_service(True) all_serializable(result)