mirror of
https://github.com/jdejaegh/irm-kmi-ha.git
synced 2025-06-27 03:35:56 +02:00
Implement confidence intervals for irm_kmi.get_forecasts_radar
This commit is contained in:
parent
0812ef5eef
commit
a952e3566f
5 changed files with 1625 additions and 29 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
1532
tests/fixtures/forecast_with_rain_on_radar.json
vendored
Normal file
1532
tests/fixtures/forecast_with_rain_on_radar.json
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||||
|
|
|
@ -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:]
|
||||||
|
|
Loading…
Add table
Reference in a new issue