Merge pull request #42 from jdejaegh/37-confidence-intervals-get_forecasts_radar

Add  confidence intervals for irm_kmi.get_forecasts_radar
This commit is contained in:
Jules 2024-06-01 20:50:43 +02:00 committed by GitHub
commit 89b08dca0f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 1630 additions and 28 deletions

View file

@ -2,6 +2,7 @@
import asyncio
import logging
from datetime import datetime, timedelta
from statistics import mean
from typing import Any, List, Tuple
import async_timeout
@ -23,7 +24,8 @@ 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 OPTION_STYLE_SATELLITE, OUT_OF_BENELUX, STYLE_TO_PARAM_MAP
from .data import (AnimationFrameData, CurrentWeatherData, IrmKmiForecast,
ProcessedCoordinatorData, RadarAnimationData, WarningData)
IrmKmiRadarForecast, ProcessedCoordinatorData,
RadarAnimationData, WarningData)
from .pollen import PollenParser
from .rain_graph import RainGraph
from .utils import disable_from_config, get_config_value, preferred_language
@ -140,6 +142,7 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
return radar_animation
async def _async_pollen_data(self, api_data: dict) -> dict:
"""Get SVG pollen info from the API, return the pollen data dict"""
_LOGGER.debug("Getting pollen data from API")
svg_url = None
for module in api_data.get('module', []):
@ -322,16 +325,27 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
return forecasts
@staticmethod
def radar_list_to_forecast(data: dict | None) -> List[Forecast] | None:
def radar_list_to_forecast(data: dict | None) -> List[IrmKmiRadarForecast] | None:
"""Create a list of short term forecasts for rain based on the data provided by the rain radar"""
if data is 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()
for f in data.get("sequence", []):
for f in sequence:
forecast.append(
Forecast(
IrmKmiRadarForecast(
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

View file

@ -12,6 +12,13 @@ class IrmKmiForecast(Forecast):
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 to hold the currently observable weather at a given location"""
condition: str | None

View file

@ -69,6 +69,7 @@ class RainGraph:
self._dwg_still: Drawing = Drawing()
async def build(self) -> Self:
"""Build the rain graph by calling all the method in the right order. Returns self when done"""
await self.draw_svg_frame()
self.draw_hour_bars()
self.draw_chances_path()

File diff suppressed because it is too large Load diff

View file

@ -10,6 +10,7 @@ from pytest_homeassistant_custom_component.common import MockConfigEntry
from custom_components.irm_kmi.const import CONF_LANGUAGE_OVERRIDE
from custom_components.irm_kmi.coordinator import IrmKmiCoordinator
from custom_components.irm_kmi.data import (CurrentWeatherData, IrmKmiForecast,
IrmKmiRadarForecast,
ProcessedCoordinatorData,
RadarAnimationData)
from custom_components.irm_kmi.pollen import PollenParser
@ -238,17 +239,52 @@ def test_radar_forecast() -> None:
result = IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation'))
expected = [
Forecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1),
Forecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01),
Forecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12),
Forecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2),
Forecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2),
Forecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0)
IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
rain_forecast_max=0, rain_forecast_min=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
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,8 @@ from homeassistant.core import HomeAssistant
from pytest_homeassistant_custom_component.common import MockConfigEntry
from custom_components.irm_kmi import IrmKmiCoordinator, IrmKmiWeather
from custom_components.irm_kmi.data import ProcessedCoordinatorData
from custom_components.irm_kmi.data import (IrmKmiRadarForecast,
ProcessedCoordinatorData)
from tests.conftest import get_api_data
@ -115,17 +116,28 @@ async def test_radar_forecast_service(
result_service: List[Forecast] = weather.get_forecasts_radar_service(False)
expected = [
Forecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1),
Forecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01),
Forecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12),
Forecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2),
Forecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2),
Forecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0),
Forecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0)
IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
rain_forecast_max=0, rain_forecast_min=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:]