From a952e3566fc23b1136ea6e883e6710437f613c2e Mon Sep 17 00:00:00 2001 From: Jules Dejaeghere Date: Sat, 1 Jun 2024 20:35:28 +0200 Subject: [PATCH 1/3] Implement confidence intervals for irm_kmi.get_forecasts_radar --- custom_components/irm_kmi/coordinator.py | 21 +- custom_components/irm_kmi/data.py | 7 + .../fixtures/forecast_with_rain_on_radar.json | 1532 +++++++++++++++++ tests/test_coordinator.py | 59 +- tests/test_weather.py | 35 +- 5 files changed, 1625 insertions(+), 29 deletions(-) create mode 100644 tests/fixtures/forecast_with_rain_on_radar.json diff --git a/custom_components/irm_kmi/coordinator.py b/custom_components/irm_kmi/coordinator.py index a4031b4..1f7fcfa 100644 --- a/custom_components/irm_kmi/coordinator.py +++ b/custom_components/irm_kmi/coordinator.py @@ -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,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 OPTION_STYLE_SATELLITE, OUT_OF_BENELUX, STYLE_TO_PARAM_MAP from .data import (AnimationFrameData, CurrentWeatherData, IrmKmiForecast, - ProcessedCoordinatorData, RadarAnimationData, WarningData) + ProcessedCoordinatorData, RadarAnimationData, WarningData, IrmKmiRadarForecast) from .pollen import PollenParser from .rain_graph import RainGraph from .utils import disable_from_config, get_config_value, preferred_language @@ -322,16 +323,26 @@ 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: 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 diff --git a/custom_components/irm_kmi/data.py b/custom_components/irm_kmi/data.py index 7108bd5..510d2f1 100644 --- a/custom_components/irm_kmi/data.py +++ b/custom_components/irm_kmi/data.py @@ -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 diff --git a/tests/fixtures/forecast_with_rain_on_radar.json b/tests/fixtures/forecast_with_rain_on_radar.json new file mode 100644 index 0000000..5d2aa49 --- /dev/null +++ b/tests/fixtures/forecast_with_rain_on_radar.json @@ -0,0 +1,1532 @@ +{ + "cityName": "L\u00ebtzebuerg", + "country": "LU", + "obs": { + "temp": 13, + "timestamp": "2024-05-30T17:40:00+02:00", + "ww": 19, + "dayNight": "d" + }, + "for": { + "daily": [ + { + "dayName": { + "fr": "Jeudi", + "nl": "Donderdag", + "en": "Thursday", + "de": "Donnerstag" + }, + "period": "0", + "day_night": "1", + "dayNight": "d", + "text": { + "nl": "Variablement nuageux avec des averses de pluie jusqu'en d\u00e9but de nuit. Un orage isol\u00e9 ne peut pas \u00eatre exclu. Apr\u00e8s minuit le temps reste sec mais de la brume peut se former localement.", + "fr": "Variablement nuageux avec des averses de pluie jusqu'en d\u00e9but de nuit. Un orage isol\u00e9 ne peut pas \u00eatre exclu. Apr\u00e8s minuit le temps reste sec mais de la brume peut se former localement.", + "de": "Bei wechselnder Bew\u00f6lkung sind bis zum Einbruch der Nacht Regenschauer zu erwarten. Dabei kann ein kurzes Gewitter nicht ausgeschlossen werden. Ab Mitternacht bleibt es trocken aber stellenweise kann sich Dunst bilden." + }, + "dawnRiseSeconds": "17518", + "dawnSetSeconds": "80902", + "tempMin": 9, + "tempMax": 19, + "ww1": 3, + "ww2": 6, + "wwevol": 0, + "ff1": 1, + "ff2": null, + "ffevol": null, + "dd": 90, + "ddText": { + "fr": "O", + "nl": "W", + "en": "W", + "de": "W" + }, + "wind": { + "speed": 5, + "peakSpeed": null, + "dir": 90, + "dirText": { + "fr": "O", + "nl": "W", + "en": "W", + "de": "W" + } + }, + "precipChance": 0, + "precipQuantity": null + }, + { + "dayName": { + "fr": "Cette nuit", + "nl": "Vannacht", + "en": "Tonight", + "de": "heute abend" + }, + "period": "0", + "day_night": "0", + "dayNight": "n", + "text": { + "nl": "Variablement nuageux avec des averses de pluie jusqu'en d\u00e9but de nuit. Un orage isol\u00e9 ne peut pas \u00eatre exclu. Apr\u00e8s minuit le temps reste sec mais de la brume peut se former localement.", + "fr": "Variablement nuageux avec des averses de pluie jusqu'en d\u00e9but de nuit. Un orage isol\u00e9 ne peut pas \u00eatre exclu. Apr\u00e8s minuit le temps reste sec mais de la brume peut se former localement.", + "de": "Bei wechselnder Bew\u00f6lkung sind bis zum Einbruch der Nacht Regenschauer zu erwarten. Dabei kann ein kurzes Gewitter nicht ausgeschlossen werden. Ab Mitternacht bleibt es trocken aber stellenweise kann sich Dunst bilden." + }, + "dawnRiseSeconds": "17518", + "dawnSetSeconds": "80902", + "tempMin": 13, + "tempMax": 15, + "ww1": 6, + "ww2": null, + "wwevol": null, + "ff1": 1, + "ff2": null, + "ffevol": null, + "dd": 135, + "ddText": { + "fr": "NO", + "nl": "NW", + "en": "NW", + "de": "NW" + }, + "wind": { + "speed": 5, + "peakSpeed": null, + "dir": 135, + "dirText": { + "fr": "NO", + "nl": "NW", + "en": "NW", + "de": "NW" + } + }, + "precipChance": 50, + "precipQuantity": null + }, + { + "dayName": { + "fr": "Vendredi", + "nl": "Vrijdag", + "en": "Friday", + "de": "Freitag" + }, + "period": "0", + "day_night": "1", + "dayNight": "d", + "text": { + "nl": "Toujours instable avec quelques averses de pluie.", + "fr": "Toujours instable avec quelques averses de pluie.", + "de": "Es bleibt unbest\u00e4ndig mit einigen Regenschauern." + }, + "dawnRiseSeconds": "17461", + "dawnSetSeconds": "80976", + "tempMin": 8, + "tempMax": 18, + "ww1": 6, + "ww2": null, + "wwevol": null, + "ff1": 2, + "ff2": null, + "ffevol": null, + "dd": 90, + "ddText": { + "fr": "O", + "nl": "W", + "en": "W", + "de": "W" + }, + "wind": { + "speed": 10, + "peakSpeed": null, + "dir": 90, + "dirText": { + "fr": "O", + "nl": "W", + "en": "W", + "de": "W" + } + }, + "precipChance": 100, + "precipQuantity": null + }, + { + "dayName": { + "fr": "Samedi", + "nl": "Zaterdag", + "en": "Saturday", + "de": "Samstag" + }, + "period": "0", + "day_night": "1", + "dayNight": "d", + "text": { + "nl": "Nuit: Pluie faible\nMatin: Faible averse de pluie\nApr\u00e8s-midi: Pluie faible\nSoir\u00e9e: Pluie faible", + "fr": "Nuit: Pluie faible\nMatin: Faible averse de pluie\nApr\u00e8s-midi: Pluie faible\nSoir\u00e9e: Pluie faible", + "de": "Nachts: Leichter Regen\nMorgens: Leichter Regenschauer\nNachmittags: Leichter Regen\nAbends: Leichter Regen" + }, + "dawnRiseSeconds": "17407", + "dawnSetSeconds": "81048", + "tempMin": 8, + "tempMax": 18, + "ww1": 6, + "ww2": null, + "wwevol": null, + "ff1": 2, + "ff2": null, + "ffevol": null, + "dd": 180, + "ddText": { + "fr": "N", + "nl": "N", + "en": "N", + "de": "N" + }, + "wind": { + "speed": 10, + "peakSpeed": null, + "dir": 180, + "dirText": { + "fr": "N", + "nl": "N", + "en": "N", + "de": "N" + } + }, + "precipChance": 90, + "precipQuantity": null + }, + { + "dayName": { + "fr": "Dimanche", + "nl": "Zondag", + "en": "Sunday", + "de": "Sonntag" + }, + "period": "0", + "day_night": "1", + "dayNight": "d", + "text": { + "nl": "Nuit: Faible averse de pluie\nMatin: Nuageux\nApr\u00e8s-midi: Nuageux\nSoir\u00e9e: Peu nuageux", + "fr": "Nuit: Faible averse de pluie\nMatin: Nuageux\nApr\u00e8s-midi: Nuageux\nSoir\u00e9e: Peu nuageux", + "de": "Nachts: Leichter Regenschauer\nMorgens: Wolkig\nNachmittags: Wolkig\nAbends: Leicht bew\u00f6lkt" + }, + "dawnRiseSeconds": "17356", + "dawnSetSeconds": "81118", + "tempMin": 9, + "tempMax": 20, + "ww1": 3, + "ww2": null, + "wwevol": null, + "ff1": 2, + "ff2": null, + "ffevol": null, + "dd": 180, + "ddText": { + "fr": "N", + "nl": "N", + "en": "N", + "de": "N" + }, + "wind": { + "speed": 10, + "peakSpeed": null, + "dir": 180, + "dirText": { + "fr": "N", + "nl": "N", + "en": "N", + "de": "N" + } + }, + "precipChance": 0, + "precipQuantity": null + }, + { + "dayName": { + "fr": "Lundi", + "nl": "Maandag", + "en": "Monday", + "de": "Montag" + }, + "period": "0", + "day_night": "1", + "dayNight": "d", + "text": { + "nl": "Nuit: Peu nuageux\nMatin: Peu nuageux\nApr\u00e8s-midi: Nuageux\nSoir\u00e9e: Peu nuageux", + "fr": "Nuit: Peu nuageux\nMatin: Peu nuageux\nApr\u00e8s-midi: Nuageux\nSoir\u00e9e: Peu nuageux", + "de": "Nachts: Leicht bew\u00f6lkt\nMorgens: Leicht bew\u00f6lkt\nNachmittags: Wolkig\nAbends: Leicht bew\u00f6lkt" + }, + "dawnRiseSeconds": "17308", + "dawnSetSeconds": "81185", + "tempMin": 8, + "tempMax": 20, + "ww1": 3, + "ww2": null, + "wwevol": null, + "ff1": 2, + "ff2": null, + "ffevol": null, + "dd": 180, + "ddText": { + "fr": "N", + "nl": "N", + "en": "N", + "de": "N" + }, + "wind": { + "speed": 10, + "peakSpeed": null, + "dir": 180, + "dirText": { + "fr": "N", + "nl": "N", + "en": "N", + "de": "N" + } + }, + "precipChance": 0, + "precipQuantity": null + }, + { + "dayName": { + "fr": "Mardi", + "nl": "Dinsdag", + "en": "Tuesday", + "de": "Dienstag" + }, + "period": "0", + "day_night": "1", + "dayNight": "d", + "text": { + "nl": "Nuit: Peu nuageux\nMatin: Peu nuageux\nApr\u00e8s-midi: Peu nuageux\nSoir\u00e9e: Ciel d\u00e9gag\u00e9", + "fr": "Nuit: Peu nuageux\nMatin: Peu nuageux\nApr\u00e8s-midi: Peu nuageux\nSoir\u00e9e: Ciel d\u00e9gag\u00e9", + "de": "Nachts: Leicht bew\u00f6lkt\nMorgens: Leicht bew\u00f6lkt\nNachmittags: Leicht bew\u00f6lkt\nAbends: Wolkenlos" + }, + "dawnRiseSeconds": "17264", + "dawnSetSeconds": "81249", + "tempMin": 9, + "tempMax": 23, + "ww1": 1, + "ww2": null, + "wwevol": null, + "ff1": 2, + "ff2": null, + "ffevol": null, + "dd": 135, + "ddText": { + "fr": "NO", + "nl": "NW", + "en": "NW", + "de": "NW" + }, + "wind": { + "speed": 10, + "peakSpeed": null, + "dir": 135, + "dirText": { + "fr": "NO", + "nl": "NW", + "en": "NW", + "de": "NW" + } + }, + "precipChance": 0, + "precipQuantity": null + } + ], + "showWarningTab": false, + "graph": { + "svg": [ + { + "url": { + "nl": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tx&l=nl&k=d6cc54e35a6962b66e5499c7ac9049e9", + "fr": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tx&l=fr&k=d6cc54e35a6962b66e5499c7ac9049e9", + "en": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tx&l=en&k=d6cc54e35a6962b66e5499c7ac9049e9", + "de": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tx&l=de&k=d6cc54e35a6962b66e5499c7ac9049e9" + }, + "ratio": 1.3638709677419354 + }, + { + "url": { + "nl": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tn&l=nl&k=d6cc54e35a6962b66e5499c7ac9049e9", + "fr": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tn&l=fr&k=d6cc54e35a6962b66e5499c7ac9049e9", + "en": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tn&l=en&k=d6cc54e35a6962b66e5499c7ac9049e9", + "de": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=tn&l=de&k=d6cc54e35a6962b66e5499c7ac9049e9" + }, + "ratio": 1.3638709677419354 + }, + { + "url": { + "nl": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=rr&l=nl&k=d6cc54e35a6962b66e5499c7ac9049e9", + "fr": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=rr&l=fr&k=d6cc54e35a6962b66e5499c7ac9049e9", + "en": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=rr&l=en&k=d6cc54e35a6962b66e5499c7ac9049e9", + "de": "https:\/\/app.meteo.be\/services\/appv4\/?s=getSvg&ins=100062&e=rr&l=de&k=d6cc54e35a6962b66e5499c7ac9049e9" + }, + "ratio": 1.3638709677419354 + } + ] + }, + "hourly": [ + { + "hour": "17", + "temp": 13, + "ww": "19", + "precipChance": "90", + "precipQuantity": 2.06, + "pressure": 1006, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 113, + "windDirectionText": { + "nl": "WNW", + "fr": "ONO", + "en": "WNW", + "de": "WNW" + }, + "dayNight": "d" + }, + { + "hour": "18", + "temp": 12, + "ww": "19", + "precipChance": "90", + "precipQuantity": 5.26, + "pressure": 1006, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 158, + "windDirectionText": { + "nl": "NNW", + "fr": "NNO", + "en": "NNW", + "de": "NNW" + }, + "dayNight": "d" + }, + { + "hour": "19", + "temp": 12, + "ww": "19", + "precipChance": "80", + "precipQuantity": 4.64, + "pressure": 1007, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 158, + "windDirectionText": { + "nl": "NNW", + "fr": "NNO", + "en": "NNW", + "de": "NNW" + }, + "dayNight": "d" + }, + { + "hour": "20", + "temp": 12, + "ww": "14", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1007, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 158, + "windDirectionText": { + "nl": "NNW", + "fr": "NNO", + "en": "NNW", + "de": "NNW" + }, + "dayNight": "d" + }, + { + "hour": "21", + "temp": 11, + "ww": "6", + "precipChance": "70", + "precipQuantity": 0.14, + "pressure": 1008, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "22", + "temp": 12, + "ww": "18", + "precipChance": "70", + "precipQuantity": 0.14, + "pressure": 1008, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "23", + "temp": 12, + "ww": "19", + "precipChance": "30", + "precipQuantity": 2.89, + "pressure": 1009, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "00", + "temp": 11, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0.03, + "pressure": 1009, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n", + "dateShow": "31\/05", + "dateShowLocalized": { + "nl": "Vri.", + "fr": "Ven.", + "en": "Fri.", + "de": "Fre." + } + }, + { + "hour": "01", + "temp": 11, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0.03, + "pressure": 1009, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "02", + "temp": 10, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1010, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "03", + "temp": 10, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1010, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "04", + "temp": 10, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1010, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "05", + "temp": 10, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0.03, + "pressure": 1010, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "06", + "temp": 10, + "ww": "14", + "precipChance": "0", + "precipQuantity": 0.03, + "pressure": 1010, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "07", + "temp": 11, + "ww": "15", + "precipChance": "30", + "precipQuantity": 0.03, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "08", + "temp": 11, + "ww": "18", + "precipChance": "70", + "precipQuantity": 0.12, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "09", + "temp": 12, + "ww": "18", + "precipChance": "90", + "precipQuantity": 0.12, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "10", + "temp": 13, + "ww": "6", + "precipChance": "90", + "precipQuantity": 0.12, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "11", + "temp": 14, + "ww": "6", + "precipChance": "90", + "precipQuantity": 0.12000000000000001, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "12", + "temp": 15, + "ww": "6", + "precipChance": "90", + "precipQuantity": 0.12000000000000001, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "13", + "temp": 16, + "ww": "4", + "precipChance": "90", + "precipQuantity": 0.12000000000000001, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "14", + "temp": 16, + "ww": "4", + "precipChance": "90", + "precipQuantity": 0.16, + "pressure": 1011, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "15", + "temp": 16, + "ww": "4", + "precipChance": "90", + "precipQuantity": 0.16, + "pressure": 1012, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "16", + "temp": 16, + "ww": "4", + "precipChance": "70", + "precipQuantity": 0.16, + "pressure": 1012, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "17", + "temp": 16, + "ww": "3", + "precipChance": "40", + "precipQuantity": 0.07, + "pressure": 1012, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "18", + "temp": 16, + "ww": "3", + "precipChance": "20", + "precipQuantity": 0.07, + "pressure": 1012, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "19", + "temp": 16, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0.07, + "pressure": 1012, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "20", + "temp": 15, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1012, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 158, + "windDirectionText": { + "nl": "NNW", + "fr": "NNO", + "en": "NNW", + "de": "NNW" + }, + "dayNight": "d" + }, + { + "hour": "21", + "temp": 14, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1013, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "22", + "temp": 13, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1013, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "23", + "temp": 12, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1014, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "00", + "temp": 11, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1014, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n", + "dateShow": "01\/06", + "dateShowLocalized": { + "nl": "Zat.", + "fr": "Sam.", + "en": "Sat.", + "de": "Sam." + } + }, + { + "hour": "01", + "temp": 11, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1014, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "02", + "temp": 10, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1014, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "03", + "temp": 10, + "ww": "3", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1014, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "04", + "temp": 10, + "ww": "15", + "precipChance": "0", + "precipQuantity": 0, + "pressure": 1014, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "05", + "temp": 10, + "ww": "15", + "precipChance": "0", + "precipQuantity": 0.01, + "pressure": 1015, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "n" + }, + { + "hour": "06", + "temp": 10, + "ww": "15", + "precipChance": "0", + "precipQuantity": 0.01, + "pressure": 1015, + "windSpeedKm": 10, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "07", + "temp": 11, + "ww": "15", + "precipChance": "0", + "precipQuantity": 0.01, + "pressure": 1015, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "08", + "temp": 11, + "ww": "15", + "precipChance": "0", + "precipQuantity": 0.05, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "09", + "temp": 12, + "ww": "15", + "precipChance": "20", + "precipQuantity": 0.05, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "10", + "temp": 13, + "ww": "15", + "precipChance": "40", + "precipQuantity": 0.05, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "11", + "temp": 14, + "ww": "18", + "precipChance": "60", + "precipQuantity": 0.12, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "12", + "temp": 14, + "ww": "18", + "precipChance": "80", + "precipQuantity": 0.12, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "13", + "temp": 15, + "ww": "18", + "precipChance": "90", + "precipQuantity": 0.12, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "14", + "temp": 16, + "ww": "18", + "precipChance": "90", + "precipQuantity": 0.12000000000000001, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "15", + "temp": 16, + "ww": "18", + "precipChance": "70", + "precipQuantity": 0.12000000000000001, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "16", + "temp": 16, + "ww": "18", + "precipChance": "50", + "precipQuantity": 0.12000000000000001, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + }, + { + "hour": "17", + "temp": 17, + "ww": "14", + "precipChance": "30", + "precipQuantity": 0.03, + "pressure": 1016, + "windSpeedKm": 15, + "windPeakSpeedKm": null, + "windDirection": 135, + "windDirectionText": { + "nl": "NW", + "fr": "NO", + "en": "NW", + "de": "NW" + }, + "dayNight": "d" + } + ], + "warning": [] + }, + "module": [], + "animation": { + "localisationLayer": "https:\/\/app.meteo.be\/services\/appv4\/?s=getLocalizationLayer&ins=100062&f=2&k=e71f91c418ae2c46035e3dc9bee0d0ad", + "localisationLayerRatioX": 0.8805, + "localisationLayerRatioY": 0.7997, + "speed": 0.3, + "type": "10min", + "unit": { + "fr": "mm\/10min", + "nl": "mm\/10min", + "en": "mm\/10min", + "de": "mm\/10min" + }, + "country": "LU", + "sequence": [ + { + "time": "2024-05-30T16:00:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301410&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0, + "position": 0, + "positionLower": 0, + "positionHigher": 0 + }, + { + "time": "2024-05-30T16:10:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301420&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.07, + "position": 0.042, + "positionLower": 0.042, + "positionHigher": 0.042 + }, + { + "time": "2024-05-30T16:20:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301430&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.08, + "position": 0.048, + "positionLower": 0.048, + "positionHigher": 0.048 + }, + { + "time": "2024-05-30T16:30:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301440&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.13, + "position": 0.078, + "positionLower": 0.078, + "positionHigher": 0.078 + }, + { + "time": "2024-05-30T16:40:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301450&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.22, + "position": 0.132, + "positionLower": 0.132, + "positionHigher": 0.132 + }, + { + "time": "2024-05-30T16:50:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301500&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.32, + "position": 0.192, + "positionLower": 0.192, + "positionHigher": 0.192 + }, + { + "time": "2024-05-30T17:00:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301510&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.21, + "position": 0.126, + "positionLower": 0.126, + "positionHigher": 0.126 + }, + { + "time": "2024-05-30T17:10:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301520&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.23, + "position": 0.138, + "positionLower": 0.138, + "positionHigher": 0.138 + }, + { + "time": "2024-05-30T17:20:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301530&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.24, + "position": 0.144, + "positionLower": 0.144, + "positionHigher": 0.144 + }, + { + "time": "2024-05-30T17:30:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301540&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.27, + "position": 0.162, + "positionLower": 0.144, + "positionHigher": 0.192 + }, + { + "time": "2024-05-30T17:40:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301550&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.33, + "position": 0.198, + "positionLower": 0.18, + "positionHigher": 0.311 + }, + { + "time": "2024-05-30T17:50:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301600&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.66, + "position": 0.395, + "positionLower": 0.21, + "positionHigher": 0.653 + }, + { + "time": "2024-05-30T18:00:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301610&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.89, + "position": 0.533, + "positionLower": 0.299, + "positionHigher": 0.671 + }, + { + "time": "2024-05-30T18:10:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301620&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.83, + "position": 0.497, + "positionLower": 0.383, + "positionHigher": 0.653 + }, + { + "time": "2024-05-30T18:20:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301630&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.81, + "position": 0.485, + "positionLower": 0.293, + "positionHigher": 0.617 + }, + { + "time": "2024-05-30T18:30:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301640&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.65, + "position": 0.389, + "positionLower": 0.18, + "positionHigher": 0.599 + }, + { + "time": "2024-05-30T18:40:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301650&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.51, + "position": 0.305, + "positionLower": 0.114, + "positionHigher": 0.563 + }, + { + "time": "2024-05-30T18:50:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301700&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.38, + "position": 0.228, + "positionLower": 0.066, + "positionHigher": 0.503 + }, + { + "time": "2024-05-30T19:00:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301710&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.27, + "position": 0.162, + "positionLower": 0.042, + "positionHigher": 0.437 + }, + { + "time": "2024-05-30T19:10:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301720&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.17, + "position": 0.102, + "positionLower": 0.018, + "positionHigher": 0.407 + }, + { + "time": "2024-05-30T19:20:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301730&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.12, + "position": 0.072, + "positionLower": 0, + "positionHigher": 0.323 + }, + { + "time": "2024-05-30T19:30:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301740&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.07, + "position": 0.042, + "positionLower": 0, + "positionHigher": 0.275 + }, + { + "time": "2024-05-30T19:40:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301750&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.04, + "position": 0.024, + "positionLower": 0, + "positionHigher": 0.198 + }, + { + "time": "2024-05-30T19:50:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301800&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.02, + "position": 0.012, + "positionLower": 0, + "positionHigher": 0.156 + }, + { + "time": "2024-05-30T20:00:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301810&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0.02, + "position": 0.012, + "positionLower": 0, + "positionHigher": 0.114 + }, + { + "time": "2024-05-30T20:10:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301820&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0, + "position": 0, + "positionLower": 0, + "positionHigher": 0.084 + }, + { + "time": "2024-05-30T20:20:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301830&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0, + "position": 0, + "positionLower": 0, + "positionHigher": 0.066 + }, + { + "time": "2024-05-30T20:30:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301840&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0, + "position": 0, + "positionLower": 0, + "positionHigher": 0.042 + }, + { + "time": "2024-05-30T20:40:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301850&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0, + "position": 0, + "positionLower": 0, + "positionHigher": 0.03 + }, + { + "time": "2024-05-30T20:50:00+02:00", + "uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202405301900&f=2&k=086a1eee85904109dccc5e6bf0ea1e61&d=202405301530", + "value": 0, + "position": 0, + "positionLower": 0, + "positionHigher": 0.024 + } + ], + "threshold": [], + "sequenceHint": { + "nl": "Regen gedurende 2u.30", + "fr": "Pluie pendant 2h30", + "en": "Rain for 2:30", + "de": "Regen w\u00e4hrend 2:30" + } + }, + "todayObsCount": 925 +} \ No newline at end of file diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index a41948a..c82cd32 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -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.data import (CurrentWeatherData, IrmKmiForecast, ProcessedCoordinatorData, - RadarAnimationData) + RadarAnimationData, IrmKmiRadarForecast) from custom_components.irm_kmi.pollen import PollenParser 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')) 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 diff --git a/tests/test_weather.py b/tests/test_weather.py index 174313f..b4f293e 100644 --- a/tests/test_weather.py +++ b/tests/test_weather.py @@ -9,7 +9,7 @@ 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 ProcessedCoordinatorData, IrmKmiRadarForecast 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) 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:] From c647e83c4cc771d816a962834a2b81f0361fb4f1 Mon Sep 17 00:00:00 2001 From: Jules Dejaeghere Date: Sat, 1 Jun 2024 20:39:37 +0200 Subject: [PATCH 2/3] Add docstring --- custom_components/irm_kmi/coordinator.py | 2 ++ custom_components/irm_kmi/rain_graph.py | 1 + 2 files changed, 3 insertions(+) diff --git a/custom_components/irm_kmi/coordinator.py b/custom_components/irm_kmi/coordinator.py index 1f7fcfa..a99f97b 100644 --- a/custom_components/irm_kmi/coordinator.py +++ b/custom_components/irm_kmi/coordinator.py @@ -141,6 +141,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', []): @@ -324,6 +325,7 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator): @staticmethod 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", []) diff --git a/custom_components/irm_kmi/rain_graph.py b/custom_components/irm_kmi/rain_graph.py index 2ead986..c6ff21d 100644 --- a/custom_components/irm_kmi/rain_graph.py +++ b/custom_components/irm_kmi/rain_graph.py @@ -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() From 98079d904d5689483362bcc27e062c8753263986 Mon Sep 17 00:00:00 2001 From: Jules Dejaeghere Date: Sat, 1 Jun 2024 20:41:23 +0200 Subject: [PATCH 3/3] Linter changes --- custom_components/irm_kmi/coordinator.py | 3 ++- tests/test_coordinator.py | 3 ++- tests/test_weather.py | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/custom_components/irm_kmi/coordinator.py b/custom_components/irm_kmi/coordinator.py index a99f97b..6854a14 100644 --- a/custom_components/irm_kmi/coordinator.py +++ b/custom_components/irm_kmi/coordinator.py @@ -24,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) + IrmKmiRadarForecast, ProcessedCoordinatorData, + RadarAnimationData, WarningData) from .pollen import PollenParser from .rain_graph import RainGraph from .utils import disable_from_config, get_config_value, preferred_language diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index c82cd32..df0f746 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -10,8 +10,9 @@ 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, IrmKmiRadarForecast) + RadarAnimationData) from custom_components.irm_kmi.pollen import PollenParser from tests.conftest import get_api_data diff --git a/tests/test_weather.py b/tests/test_weather.py index b4f293e..705efee 100644 --- a/tests/test_weather.py +++ b/tests/test_weather.py @@ -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, IrmKmiRadarForecast +from custom_components.irm_kmi.data import (IrmKmiRadarForecast, + ProcessedCoordinatorData) from tests.conftest import get_api_data