Skip to content

Commit

Permalink
Add rainfall sensor and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
jdejaegh committed Feb 22, 2025
1 parent 1844d02 commit be0a742
Show file tree
Hide file tree
Showing 15 changed files with 242 additions and 40 deletions.
2 changes: 1 addition & 1 deletion custom_components/irm_kmi/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,5 @@
'wind_speed': None,
'wind_gust_speed': None,
'wind_bearing': 'mdi:compass',
'uv_index': None,
'uv_index': 'mdi:sun-wireless',
'pressure': None}
4 changes: 3 additions & 1 deletion custom_components/irm_kmi/coordinator.py
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ def radar_list_to_forecast(data: dict | None) -> List[IrmKmiRadarForecast] | Non
if data is None:
return None
sequence = data.get("sequence", [])
unit = data.get("unit", {}).get("en", None)
ratios = [f['value'] / f['position'] for f in sequence if f['position'] > 0]

if len(ratios) > 0:
Expand All @@ -342,7 +343,8 @@ def radar_list_to_forecast(data: dict | None) -> List[IrmKmiRadarForecast] | Non
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
might_rain=f.get('positionHigher') > 0,
unit=unit
)
)
return forecast
Expand Down
1 change: 1 addition & 0 deletions custom_components/irm_kmi/radar_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class IrmKmiRadarForecast(Forecast):
rain_forecast_max: float
rain_forecast_min: float
might_rain: bool
unit: str | None


class AnimationFrameData(TypedDict, total=False):
Expand Down
58 changes: 56 additions & 2 deletions custom_components/irm_kmi/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
CURRENT_WEATHER_SENSOR_CLASS, CURRENT_WEATHER_SENSORS, CURRENT_WEATHER_SENSOR_ICON
from custom_components.irm_kmi.data import IrmKmiForecast
from custom_components.irm_kmi.pollen import PollenParser
from custom_components.irm_kmi.radar_data import IrmKmiRadarForecast

_LOGGER = logging.getLogger(__name__)

Expand All @@ -24,7 +25,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e
coordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities([IrmKmiPollen(coordinator, entry, pollen.lower()) for pollen in POLLEN_NAMES])
async_add_entities([IrmKmiCurrentWeather(coordinator, entry, name) for name in CURRENT_WEATHER_SENSORS])
async_add_entities([IrmKmiNextWarning(coordinator, entry),])
async_add_entities([IrmKmiNextWarning(coordinator, entry),
IrmKmiCurrentRainfall(coordinator, entry)])

if coordinator.data.get('country') != 'NL':
async_add_entities([IrmKmiNextSunMove(coordinator, entry, move) for move in ['sunset', 'sunrise']])
Expand Down Expand Up @@ -152,7 +154,7 @@ def __init__(self,
super().__init__(coordinator)
SensorEntity.__init__(self)
self._attr_unique_id = f"{entry.entry_id}-current-{sensor_name}"
self.entity_id = sensor.ENTITY_ID_FORMAT.format(f"{str(entry.title).lower()}_next_{sensor_name}")
self.entity_id = sensor.ENTITY_ID_FORMAT.format(f"{str(entry.title).lower()}_current_{sensor_name}")
self._attr_device_info = coordinator.shared_device_info
self._attr_translation_key = f"current_{sensor_name}"
self._sensor_name: str = sensor_name
Expand All @@ -173,3 +175,55 @@ def device_class(self) -> SensorDeviceClass | None:
@property
def icon(self) -> str | None:
return CURRENT_WEATHER_SENSOR_ICON[self._sensor_name]


class IrmKmiCurrentRainfall(CoordinatorEntity, SensorEntity):
"""Representation of a current rainfall sensor"""

_attr_has_entity_name = True
_attr_attribution = "Weather data from the Royal Meteorological Institute of Belgium meteo.be"

def __init__(self,
coordinator: IrmKmiCoordinator,
entry: ConfigEntry) -> None:
super().__init__(coordinator)
SensorEntity.__init__(self)
self._attr_unique_id = f"{entry.entry_id}-current-rainfall"
self.entity_id = sensor.ENTITY_ID_FORMAT.format(f"{str(entry.title).lower()}_current_rainfall")
self._attr_device_info = coordinator.shared_device_info
self._attr_translation_key = "current_rainfall"
self._attr_icon = 'mdi:weather-pouring'

def _current_forecast(self) -> IrmKmiRadarForecast | None:
now = dt.now()
forecasts = self.coordinator.data.get('radar_forecast', None)

if forecasts is None:
return None

prev = forecasts[0]
for f in forecasts:
if datetime.fromisoformat(f.get('datetime')) > now:
return prev
prev = f

return forecasts[-1]

@property
def native_value(self) -> float | None:
"""Return the current value of the sensor"""
current = self._current_forecast()

if current is None:
return None

return current.get('native_precipitation', None)

@property
def native_unit_of_measurement(self) -> str | None:
current = self._current_forecast()

if current is None:
return None

return current.get('unit', None)
3 changes: 3 additions & 0 deletions custom_components/irm_kmi/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
},
"current_pressure": {
"name": "Atmospheric pressure"
},
"current_rainfall": {
"name": "Rainfall"
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions custom_components/irm_kmi/translations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
},
"current_pressure": {
"name": "Pression atmosphérique"
},
"current_rainfall": {
"name": "Precipitation"
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions custom_components/irm_kmi/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
},
"current_pressure": {
"name": "Luchtdruk"
},
"current_rainfall": {
"name": "Neerslag"
}
}
},
Expand Down
3 changes: 3 additions & 0 deletions custom_components/irm_kmi/translations/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@
},
"current_pressure": {
"name": "Pressão atmosférica"
},
"current_rainfall": {
"name": "Precipitação"
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/be_forecast_warning.json
Original file line number Diff line number Diff line change
Expand Up @@ -1474,7 +1474,7 @@
{
"time": "2024-01-12T10:10:00+01:00",
"uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202401120920&f=2&k=2160a92594985471351907ee5cc75d1f&d=202401120900",
"value": 0,
"value": 0.42,
"position": 0,
"positionLower": 0,
"positionHigher": 0
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/forecast_ams_no_ww.json
Original file line number Diff line number Diff line change
Expand Up @@ -1642,7 +1642,7 @@
{
"time": "2024-06-09T13:40:00+00:00",
"uri": "https:\/\/cdn.knmi.nl\/knmi\/map\/page\/weer\/actueel-weer\/neerslagradar\/weerapp\/RAD_NL25_PCP_CM_202406091340_640.png",
"value": 0,
"value": 0.1341,
"position": 0,
"positionLower": 0,
"positionHigher": 0
Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/forecast_nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"municipality_code": "0995",
"temp": 11,
"windSpeedKm": 40,
"timestamp": "2023-12-28T14:20:00+00:00",
"timestamp": "2023-12-28T14:30:00+00:00",
"windDirection": 45,
"municipality": "Lelystad",
"windDirectionText": {
Expand Down Expand Up @@ -1337,7 +1337,7 @@
{
"time": "2023-12-28T14:25:00+00:00",
"uri": "https:\/\/cdn.knmi.nl\/knmi\/map\/page\/weer\/actueel-weer\/neerslagradar\/weerapp\/RAD_NL25_PCP_CM_202312281425_640.png",
"value": 0,
"value": 0.15,
"position": 0,
"positionLower": 0,
"positionHigher": 0
Expand Down
32 changes: 16 additions & 16 deletions tests/test_coordinator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import zoneinfo
from datetime import datetime, timedelta

from freezegun import freeze_time
Expand All @@ -12,9 +11,8 @@
from custom_components.irm_kmi.coordinator import IrmKmiCoordinator
from custom_components.irm_kmi.data import (CurrentWeatherData, IrmKmiForecast,
ProcessedCoordinatorData)
from custom_components.irm_kmi.radar_data import IrmKmiRadarForecast, RadarAnimationData
from custom_components.irm_kmi.pollen import PollenParser
from custom_components.irm_kmi.rain_graph import RainGraph
from custom_components.irm_kmi.radar_data import IrmKmiRadarForecast
from tests.conftest import get_api_data


Expand Down Expand Up @@ -267,27 +265,27 @@ def test_radar_forecast() -> None:

expected = [
IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
rain_forecast_max=0, rain_forecast_min=0),
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),
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),
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),
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),
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),
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),
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),
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),
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),
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)
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min')
]

assert expected == result
Expand All @@ -302,15 +300,17 @@ def test_radar_forecast_rain_interval() -> None:
native_precipitation=0.89,
might_rain=True,
rain_forecast_max=1.12,
rain_forecast_min=0.50
rain_forecast_min=0.50,
unit='mm/10min'
)

_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
rain_forecast_min=0.64,
unit='mm/10min'
)

assert result[12] == _12
Expand Down
Loading

0 comments on commit be0a742

Please sign in to comment.