Implement confidence intervals for irm_kmi.get_forecasts_radar

This commit is contained in:
Jules 2024-06-01 20:35:28 +02:00
parent 0812ef5eef
commit a952e3566f
Signed by: jdejaegh
GPG key ID: 99D6D184CA66933A
5 changed files with 1625 additions and 29 deletions

View file

@ -2,6 +2,7 @@
import asyncio import asyncio
import logging import logging
from datetime import datetime, timedelta from datetime import datetime, timedelta
from statistics import mean
from typing import Any, List, Tuple from typing import Any, List, Tuple
import async_timeout import async_timeout
@ -23,7 +24,7 @@ from .const import IRM_KMI_TO_HA_CONDITION_MAP as CDT_MAP
from .const import MAP_WARNING_ID_TO_SLUG as SLUG_MAP from .const import MAP_WARNING_ID_TO_SLUG as SLUG_MAP
from .const import OPTION_STYLE_SATELLITE, OUT_OF_BENELUX, STYLE_TO_PARAM_MAP from .const import OPTION_STYLE_SATELLITE, OUT_OF_BENELUX, STYLE_TO_PARAM_MAP
from .data import (AnimationFrameData, CurrentWeatherData, IrmKmiForecast, from .data import (AnimationFrameData, CurrentWeatherData, IrmKmiForecast,
ProcessedCoordinatorData, RadarAnimationData, WarningData) ProcessedCoordinatorData, RadarAnimationData, WarningData, IrmKmiRadarForecast)
from .pollen import PollenParser from .pollen import PollenParser
from .rain_graph import RainGraph from .rain_graph import RainGraph
from .utils import disable_from_config, get_config_value, preferred_language from .utils import disable_from_config, get_config_value, preferred_language
@ -322,16 +323,26 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
return forecasts return forecasts
@staticmethod @staticmethod
def radar_list_to_forecast(data: dict | None) -> List[Forecast] | None: def radar_list_to_forecast(data: dict | None) -> List[IrmKmiRadarForecast] | None:
if data is None: if data is None:
return None return None
sequence = data.get("sequence", [])
ratios = [f['value'] / f['position'] for f in sequence if f['position'] > 0]
if len(ratios) > 0:
ratio = mean(ratios)
else:
ratio = 0
forecast = list() forecast = list()
for f in data.get("sequence", []): for f in sequence:
forecast.append( forecast.append(
Forecast( IrmKmiRadarForecast(
datetime=f.get("time"), datetime=f.get("time"),
native_precipitation=f.get('value') native_precipitation=f.get('value'),
rain_forecast_max=round(f.get('positionHigher')*ratio, 2),
rain_forecast_min=round(f.get('positionLower')*ratio, 2),
might_rain=f.get('positionHigher') > 0
) )
) )
return forecast return forecast

View file

@ -12,6 +12,13 @@ class IrmKmiForecast(Forecast):
text: str | None text: str | None
class IrmKmiRadarForecast(Forecast):
"""Forecast class to handle rain forecast from the IRM KMI rain radar"""
rain_forecast_max: float
rain_forecast_min: float
might_rain: bool
class CurrentWeatherData(TypedDict, total=False): class CurrentWeatherData(TypedDict, total=False):
"""Class to hold the currently observable weather at a given location""" """Class to hold the currently observable weather at a given location"""
condition: str | None condition: str | None

File diff suppressed because it is too large Load diff

View file

@ -11,7 +11,7 @@ from custom_components.irm_kmi.const import CONF_LANGUAGE_OVERRIDE
from custom_components.irm_kmi.coordinator import IrmKmiCoordinator from custom_components.irm_kmi.coordinator import IrmKmiCoordinator
from custom_components.irm_kmi.data import (CurrentWeatherData, IrmKmiForecast, from custom_components.irm_kmi.data import (CurrentWeatherData, IrmKmiForecast,
ProcessedCoordinatorData, ProcessedCoordinatorData,
RadarAnimationData) RadarAnimationData, IrmKmiRadarForecast)
from custom_components.irm_kmi.pollen import PollenParser from custom_components.irm_kmi.pollen import PollenParser
from tests.conftest import get_api_data from tests.conftest import get_api_data
@ -238,17 +238,52 @@ def test_radar_forecast() -> None:
result = IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation')) result = IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation'))
expected = [ expected = [
Forecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0), IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0), IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1), IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12), IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2), IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
Forecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0) IrmKmiRadarForecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0)
] ]
assert expected == result assert expected == result
def test_radar_forecast_rain_interval() -> None:
api_data = get_api_data('forecast_with_rain_on_radar.json')
result = IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation'))
_12 = IrmKmiRadarForecast(
datetime='2024-05-30T18:00:00+02:00',
native_precipitation=0.89,
might_rain=True,
rain_forecast_max=1.12,
rain_forecast_min=0.50
)
_13 = IrmKmiRadarForecast(
datetime="2024-05-30T18:10:00+02:00",
native_precipitation=0.83,
might_rain=True,
rain_forecast_max=1.09,
rain_forecast_min=0.64
)
assert result[12] == _12
assert result[13] == _13

View file

@ -9,7 +9,7 @@ from homeassistant.core import HomeAssistant
from pytest_homeassistant_custom_component.common import MockConfigEntry from pytest_homeassistant_custom_component.common import MockConfigEntry
from custom_components.irm_kmi import IrmKmiCoordinator, IrmKmiWeather from custom_components.irm_kmi import IrmKmiCoordinator, IrmKmiWeather
from custom_components.irm_kmi.data import ProcessedCoordinatorData from custom_components.irm_kmi.data import ProcessedCoordinatorData, IrmKmiRadarForecast
from tests.conftest import get_api_data from tests.conftest import get_api_data
@ -115,17 +115,28 @@ async def test_radar_forecast_service(
result_service: List[Forecast] = weather.get_forecasts_radar_service(False) result_service: List[Forecast] = weather.get_forecasts_radar_service(False)
expected = [ expected = [
Forecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0), IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0), IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1), IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12), IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
Forecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2), IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
Forecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0), rain_forecast_max=0, rain_forecast_min=0),
Forecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0) IrmKmiRadarForecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0)
] ]
assert result_service == expected[5:] assert result_service == expected[5:]