mirror of
https://github.com/jdejaegh/irm-kmi-ha.git
synced 2025-06-27 19:49:26 +02:00
Compare commits
No commits in common. "fee2a10f5eb44af56f3d47c9fe24489e2969acf7" and "fbab30e33fafc305f64069da2d74ef87a8d3c2dd" have entirely different histories.
fee2a10f5e
...
fbab30e33f
17 changed files with 42 additions and 404 deletions
|
@ -1,7 +1,6 @@
|
||||||
"""Constants for the IRM KMI integration."""
|
"""Constants for the IRM KMI integration."""
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
from homeassistant.components.sensor import SensorDeviceClass
|
|
||||||
from homeassistant.components.weather import (ATTR_CONDITION_CLEAR_NIGHT,
|
from homeassistant.components.weather import (ATTR_CONDITION_CLEAR_NIGHT,
|
||||||
ATTR_CONDITION_CLOUDY,
|
ATTR_CONDITION_CLOUDY,
|
||||||
ATTR_CONDITION_FOG,
|
ATTR_CONDITION_FOG,
|
||||||
|
@ -12,7 +11,7 @@ from homeassistant.components.weather import (ATTR_CONDITION_CLEAR_NIGHT,
|
||||||
ATTR_CONDITION_SNOWY,
|
ATTR_CONDITION_SNOWY,
|
||||||
ATTR_CONDITION_SNOWY_RAINY,
|
ATTR_CONDITION_SNOWY_RAINY,
|
||||||
ATTR_CONDITION_SUNNY)
|
ATTR_CONDITION_SUNNY)
|
||||||
from homeassistant.const import Platform, UnitOfPressure, UnitOfSpeed, UnitOfTemperature, DEGREE
|
from homeassistant.const import Platform
|
||||||
|
|
||||||
DOMAIN: Final = 'irm_kmi'
|
DOMAIN: Final = 'irm_kmi'
|
||||||
PLATFORMS: Final = [Platform.WEATHER, Platform.CAMERA, Platform.BINARY_SENSOR, Platform.SENSOR]
|
PLATFORMS: Final = [Platform.WEATHER, Platform.CAMERA, Platform.BINARY_SENSOR, Platform.SENSOR]
|
||||||
|
@ -161,29 +160,4 @@ IRM_KMI_NAME: Final = {
|
||||||
|
|
||||||
WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
|
WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
|
||||||
|
|
||||||
USER_AGENT: Final = 'github.com/jdejaegh/irm-kmi-ha 0.2.30'
|
USER_AGENT: Final = 'github.com/jdejaegh/irm-kmi-ha 0.2.29'
|
||||||
|
|
||||||
CURRENT_WEATHER_SENSORS: Final = {'temperature', 'wind_speed', 'wind_gust_speed', 'wind_bearing', 'uv_index',
|
|
||||||
'pressure'}
|
|
||||||
|
|
||||||
CURRENT_WEATHER_SENSOR_UNITS: Final = {'temperature': UnitOfTemperature.CELSIUS,
|
|
||||||
'wind_speed': UnitOfSpeed.KILOMETERS_PER_HOUR,
|
|
||||||
'wind_gust_speed': UnitOfSpeed.KILOMETERS_PER_HOUR,
|
|
||||||
'wind_bearing': DEGREE,
|
|
||||||
'uv_index': None,
|
|
||||||
'pressure': UnitOfPressure.HPA}
|
|
||||||
|
|
||||||
CURRENT_WEATHER_SENSOR_CLASS: Final = {'temperature': SensorDeviceClass.TEMPERATURE,
|
|
||||||
'wind_speed': SensorDeviceClass.WIND_SPEED,
|
|
||||||
'wind_gust_speed': SensorDeviceClass.WIND_SPEED,
|
|
||||||
'wind_bearing': None,
|
|
||||||
'uv_index': None,
|
|
||||||
'pressure': SensorDeviceClass.ATMOSPHERIC_PRESSURE}
|
|
||||||
|
|
||||||
# Leave None when we want the default icon to be shown
|
|
||||||
CURRENT_WEATHER_SENSOR_ICON: Final = {'temperature': None,
|
|
||||||
'wind_speed': None,
|
|
||||||
'wind_gust_speed': None,
|
|
||||||
'wind_bearing': 'mdi:compass',
|
|
||||||
'uv_index': 'mdi:sun-wireless',
|
|
||||||
'pressure': None}
|
|
|
@ -327,7 +327,6 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
|
||||||
if data is None:
|
if data is None:
|
||||||
return None
|
return None
|
||||||
sequence = data.get("sequence", [])
|
sequence = data.get("sequence", [])
|
||||||
unit = data.get("unit", {}).get("en", None)
|
|
||||||
ratios = [f['value'] / f['position'] for f in sequence if f['position'] > 0]
|
ratios = [f['value'] / f['position'] for f in sequence if f['position'] > 0]
|
||||||
|
|
||||||
if len(ratios) > 0:
|
if len(ratios) > 0:
|
||||||
|
@ -343,8 +342,7 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator):
|
||||||
native_precipitation=f.get('value'),
|
native_precipitation=f.get('value'),
|
||||||
rain_forecast_max=round(f.get('positionHigher') * ratio, 2),
|
rain_forecast_max=round(f.get('positionHigher') * ratio, 2),
|
||||||
rain_forecast_min=round(f.get('positionLower') * 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
|
return forecast
|
||||||
|
|
|
@ -12,5 +12,5 @@
|
||||||
"svgwrite==1.4.3",
|
"svgwrite==1.4.3",
|
||||||
"aiofile==3.9.0"
|
"aiofile==3.9.0"
|
||||||
],
|
],
|
||||||
"version": "0.2.30"
|
"version": "0.2.29"
|
||||||
}
|
}
|
|
@ -11,7 +11,6 @@ class IrmKmiRadarForecast(Forecast):
|
||||||
rain_forecast_max: float
|
rain_forecast_max: float
|
||||||
rain_forecast_min: float
|
rain_forecast_min: float
|
||||||
might_rain: bool
|
might_rain: bool
|
||||||
unit: str | None
|
|
||||||
|
|
||||||
|
|
||||||
class AnimationFrameData(TypedDict, total=False):
|
class AnimationFrameData(TypedDict, total=False):
|
||||||
|
|
|
@ -11,11 +11,9 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
from homeassistant.util import dt
|
from homeassistant.util import dt
|
||||||
|
|
||||||
from custom_components.irm_kmi import DOMAIN, IrmKmiCoordinator
|
from custom_components.irm_kmi import DOMAIN, IrmKmiCoordinator
|
||||||
from custom_components.irm_kmi.const import POLLEN_NAMES, POLLEN_TO_ICON_MAP, CURRENT_WEATHER_SENSOR_UNITS, \
|
from custom_components.irm_kmi.const import POLLEN_NAMES, POLLEN_TO_ICON_MAP
|
||||||
CURRENT_WEATHER_SENSOR_CLASS, CURRENT_WEATHER_SENSORS, CURRENT_WEATHER_SENSOR_ICON
|
|
||||||
from custom_components.irm_kmi.data import IrmKmiForecast
|
from custom_components.irm_kmi.data import IrmKmiForecast
|
||||||
from custom_components.irm_kmi.pollen import PollenParser
|
from custom_components.irm_kmi.pollen import PollenParser
|
||||||
from custom_components.irm_kmi.radar_data import IrmKmiRadarForecast
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -24,9 +22,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e
|
||||||
"""Set up the sensor platform"""
|
"""Set up the sensor platform"""
|
||||||
coordinator = hass.data[DOMAIN][entry.entry_id]
|
coordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
async_add_entities([IrmKmiPollen(coordinator, entry, pollen.lower()) for pollen in POLLEN_NAMES])
|
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':
|
if coordinator.data.get('country') != 'NL':
|
||||||
async_add_entities([IrmKmiNextSunMove(coordinator, entry, move) for move in ['sunset', 'sunrise']])
|
async_add_entities([IrmKmiNextSunMove(coordinator, entry, move) for move in ['sunset', 'sunrise']])
|
||||||
|
@ -139,91 +135,3 @@ class IrmKmiNextSunMove(CoordinatorEntity, SensorEntity):
|
||||||
if len(upcoming) > 0:
|
if len(upcoming) > 0:
|
||||||
return upcoming[0]
|
return upcoming[0]
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class IrmKmiCurrentWeather(CoordinatorEntity, SensorEntity):
|
|
||||||
"""Representation of a current weather 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,
|
|
||||||
sensor_name: str) -> None:
|
|
||||||
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()}_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
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self) -> float | None:
|
|
||||||
"""Return the current value of the sensor"""
|
|
||||||
return self.coordinator.data.get('current_weather', {}).get(self._sensor_name, None)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_unit_of_measurement(self) -> str | None:
|
|
||||||
return CURRENT_WEATHER_SENSOR_UNITS[self._sensor_name]
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_class(self) -> SensorDeviceClass | None:
|
|
||||||
return CURRENT_WEATHER_SENSOR_CLASS[self._sensor_name]
|
|
||||||
|
|
||||||
@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)
|
|
|
@ -182,27 +182,6 @@
|
||||||
"purple": "Purple",
|
"purple": "Purple",
|
||||||
"none": "None"
|
"none": "None"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"current_temperature": {
|
|
||||||
"name": "Temperature"
|
|
||||||
},
|
|
||||||
"current_wind_speed": {
|
|
||||||
"name": "Wind speed"
|
|
||||||
},
|
|
||||||
"current_wind_gust_speed": {
|
|
||||||
"name": "Wind gust speed"
|
|
||||||
},
|
|
||||||
"current_wind_bearing": {
|
|
||||||
"name": "Wind bearing"
|
|
||||||
},
|
|
||||||
"current_uv_index": {
|
|
||||||
"name": "UV index"
|
|
||||||
},
|
|
||||||
"current_pressure": {
|
|
||||||
"name": "Atmospheric pressure"
|
|
||||||
},
|
|
||||||
"current_rainfall": {
|
|
||||||
"name": "Rainfall"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -182,27 +182,6 @@
|
||||||
"purple": "Violet",
|
"purple": "Violet",
|
||||||
"none": "Aucun"
|
"none": "Aucun"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"current_temperature": {
|
|
||||||
"name": "Température"
|
|
||||||
},
|
|
||||||
"current_wind_speed": {
|
|
||||||
"name": "Vitesse du vent"
|
|
||||||
},
|
|
||||||
"current_wind_gust_speed": {
|
|
||||||
"name": "Vitesse des rafales de vent"
|
|
||||||
},
|
|
||||||
"current_wind_bearing": {
|
|
||||||
"name": "Direction du vent"
|
|
||||||
},
|
|
||||||
"current_uv_index": {
|
|
||||||
"name": "Index UV"
|
|
||||||
},
|
|
||||||
"current_pressure": {
|
|
||||||
"name": "Pression atmosphérique"
|
|
||||||
},
|
|
||||||
"current_rainfall": {
|
|
||||||
"name": "Precipitation"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -182,27 +182,6 @@
|
||||||
"purple": "Paars",
|
"purple": "Paars",
|
||||||
"none": "Geen"
|
"none": "Geen"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"current_temperature": {
|
|
||||||
"name": "Temperatuur"
|
|
||||||
},
|
|
||||||
"current_wind_speed": {
|
|
||||||
"name": "Windsnelheid"
|
|
||||||
},
|
|
||||||
"current_wind_gust_speed": {
|
|
||||||
"name": "Snelheid windvlaag"
|
|
||||||
},
|
|
||||||
"current_wind_bearing": {
|
|
||||||
"name": "Windrichting"
|
|
||||||
},
|
|
||||||
"current_uv_index": {
|
|
||||||
"name": "UV-index"
|
|
||||||
},
|
|
||||||
"current_pressure": {
|
|
||||||
"name": "Luchtdruk"
|
|
||||||
},
|
|
||||||
"current_rainfall": {
|
|
||||||
"name": "Neerslag"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -182,27 +182,6 @@
|
||||||
"purple": "Roxo",
|
"purple": "Roxo",
|
||||||
"none": "Nenhum"
|
"none": "Nenhum"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"current_temperature": {
|
|
||||||
"name": "Temperatura"
|
|
||||||
},
|
|
||||||
"current_wind_speed": {
|
|
||||||
"name": "Velocidade do vento"
|
|
||||||
},
|
|
||||||
"current_wind_gust_speed": {
|
|
||||||
"name": "Velocidade da rajada de vento"
|
|
||||||
},
|
|
||||||
"current_wind_bearing": {
|
|
||||||
"name": "Direção do vento"
|
|
||||||
},
|
|
||||||
"current_uv_index": {
|
|
||||||
"name": "Índice UV"
|
|
||||||
},
|
|
||||||
"current_pressure": {
|
|
||||||
"name": "Pressão atmosférica"
|
|
||||||
},
|
|
||||||
"current_rainfall": {
|
|
||||||
"name": "Precipitação"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[tool.bumpver]
|
[tool.bumpver]
|
||||||
current_version = "0.2.30"
|
current_version = "0.2.29"
|
||||||
version_pattern = "MAJOR.MINOR.PATCH"
|
version_pattern = "MAJOR.MINOR.PATCH"
|
||||||
commit_message = "bump version {old_version} -> {new_version}"
|
commit_message = "bump version {old_version} -> {new_version}"
|
||||||
tag_message = "{new_version}"
|
tag_message = "{new_version}"
|
||||||
|
|
2
tests/fixtures/be_forecast_warning.json
vendored
2
tests/fixtures/be_forecast_warning.json
vendored
|
@ -1474,7 +1474,7 @@
|
||||||
{
|
{
|
||||||
"time": "2024-01-12T10:10:00+01:00",
|
"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",
|
"uri": "https:\/\/app.meteo.be\/services\/appv4\/?s=getIncaImage&i=202401120920&f=2&k=2160a92594985471351907ee5cc75d1f&d=202401120900",
|
||||||
"value": 0.42,
|
"value": 0,
|
||||||
"position": 0,
|
"position": 0,
|
||||||
"positionLower": 0,
|
"positionLower": 0,
|
||||||
"positionHigher": 0
|
"positionHigher": 0
|
||||||
|
|
2
tests/fixtures/forecast_ams_no_ww.json
vendored
2
tests/fixtures/forecast_ams_no_ww.json
vendored
|
@ -1642,7 +1642,7 @@
|
||||||
{
|
{
|
||||||
"time": "2024-06-09T13:40:00+00:00",
|
"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",
|
"uri": "https:\/\/cdn.knmi.nl\/knmi\/map\/page\/weer\/actueel-weer\/neerslagradar\/weerapp\/RAD_NL25_PCP_CM_202406091340_640.png",
|
||||||
"value": 0.1341,
|
"value": 0,
|
||||||
"position": 0,
|
"position": 0,
|
||||||
"positionLower": 0,
|
"positionLower": 0,
|
||||||
"positionHigher": 0
|
"positionHigher": 0
|
||||||
|
|
4
tests/fixtures/forecast_nl.json
vendored
4
tests/fixtures/forecast_nl.json
vendored
|
@ -6,7 +6,7 @@
|
||||||
"municipality_code": "0995",
|
"municipality_code": "0995",
|
||||||
"temp": 11,
|
"temp": 11,
|
||||||
"windSpeedKm": 40,
|
"windSpeedKm": 40,
|
||||||
"timestamp": "2023-12-28T14:30:00+00:00",
|
"timestamp": "2023-12-28T14:20:00+00:00",
|
||||||
"windDirection": 45,
|
"windDirection": 45,
|
||||||
"municipality": "Lelystad",
|
"municipality": "Lelystad",
|
||||||
"windDirectionText": {
|
"windDirectionText": {
|
||||||
|
@ -1337,7 +1337,7 @@
|
||||||
{
|
{
|
||||||
"time": "2023-12-28T14:25:00+00:00",
|
"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",
|
"uri": "https:\/\/cdn.knmi.nl\/knmi\/map\/page\/weer\/actueel-weer\/neerslagradar\/weerapp\/RAD_NL25_PCP_CM_202312281425_640.png",
|
||||||
"value": 0.15,
|
"value": 0,
|
||||||
"position": 0,
|
"position": 0,
|
||||||
"positionLower": 0,
|
"positionLower": 0,
|
||||||
"positionHigher": 0
|
"positionHigher": 0
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import zoneinfo
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
@ -11,8 +12,9 @@ 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)
|
||||||
|
from custom_components.irm_kmi.radar_data import IrmKmiRadarForecast, RadarAnimationData
|
||||||
from custom_components.irm_kmi.pollen import PollenParser
|
from custom_components.irm_kmi.pollen import PollenParser
|
||||||
from custom_components.irm_kmi.radar_data import IrmKmiRadarForecast
|
from custom_components.irm_kmi.rain_graph import RainGraph
|
||||||
from tests.conftest import get_api_data
|
from tests.conftest import get_api_data
|
||||||
|
|
||||||
|
|
||||||
|
@ -265,27 +267,27 @@ def test_radar_forecast() -> None:
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min')
|
rain_forecast_max=0, rain_forecast_min=0)
|
||||||
]
|
]
|
||||||
|
|
||||||
assert expected == result
|
assert expected == result
|
||||||
|
@ -300,8 +302,7 @@ def test_radar_forecast_rain_interval() -> None:
|
||||||
native_precipitation=0.89,
|
native_precipitation=0.89,
|
||||||
might_rain=True,
|
might_rain=True,
|
||||||
rain_forecast_max=1.12,
|
rain_forecast_max=1.12,
|
||||||
rain_forecast_min=0.50,
|
rain_forecast_min=0.50
|
||||||
unit='mm/10min'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
_13 = IrmKmiRadarForecast(
|
_13 = IrmKmiRadarForecast(
|
||||||
|
@ -309,8 +310,7 @@ def test_radar_forecast_rain_interval() -> None:
|
||||||
native_precipitation=0.83,
|
native_precipitation=0.83,
|
||||||
might_rain=True,
|
might_rain=True,
|
||||||
rain_forecast_max=1.09,
|
rain_forecast_max=1.09,
|
||||||
rain_forecast_min=0.64,
|
rain_forecast_min=0.64
|
||||||
unit='mm/10min'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result[12] == _12
|
assert result[12] == _12
|
||||||
|
|
|
@ -1,159 +0,0 @@
|
||||||
import inspect
|
|
||||||
from datetime import datetime, timedelta
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
from freezegun import freeze_time
|
|
||||||
from homeassistant.core import HomeAssistant
|
|
||||||
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
|
||||||
|
|
||||||
from custom_components.irm_kmi import IrmKmiCoordinator
|
|
||||||
from custom_components.irm_kmi.const import CURRENT_WEATHER_SENSORS, CURRENT_WEATHER_SENSOR_UNITS, \
|
|
||||||
CURRENT_WEATHER_SENSOR_CLASS
|
|
||||||
from custom_components.irm_kmi.data import CurrentWeatherData, ProcessedCoordinatorData
|
|
||||||
from custom_components.irm_kmi.sensor import IrmKmiCurrentWeather, IrmKmiCurrentRainfall
|
|
||||||
from tests.conftest import get_api_data
|
|
||||||
|
|
||||||
|
|
||||||
def test_sensors_in_current_weather_data():
|
|
||||||
weather_data_keys = inspect.get_annotations(CurrentWeatherData).keys()
|
|
||||||
|
|
||||||
for sensor in CURRENT_WEATHER_SENSORS:
|
|
||||||
assert sensor in weather_data_keys
|
|
||||||
|
|
||||||
def test_sensors_have_unit():
|
|
||||||
weather_sensor_units_keys = CURRENT_WEATHER_SENSOR_UNITS.keys()
|
|
||||||
|
|
||||||
for sensor in CURRENT_WEATHER_SENSORS:
|
|
||||||
assert sensor in weather_sensor_units_keys
|
|
||||||
|
|
||||||
def test_sensors_have_class():
|
|
||||||
weather_sensor_class_keys = CURRENT_WEATHER_SENSOR_CLASS.keys()
|
|
||||||
|
|
||||||
for sensor in CURRENT_WEATHER_SENSORS:
|
|
||||||
assert sensor in weather_sensor_class_keys
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("sensor,expected,filename",
|
|
||||||
[
|
|
||||||
('temperature', -2, 'be_forecast_warning.json'),
|
|
||||||
('temperature', 7, 'forecast.json'),
|
|
||||||
('temperature', 15, 'forecast_ams_no_ww.json'),
|
|
||||||
('temperature', 9, 'forecast_out_of_benelux.json'),
|
|
||||||
('temperature', 13, 'forecast_with_rain_on_radar.json'),
|
|
||||||
('temperature', 4, 'high_low_temp.json'),
|
|
||||||
('temperature', 14, 'midnight-bug-31-05-2024T00-13.json'),
|
|
||||||
('temperature', 13, 'no-midnight-bug-31-05-2024T01-55.json'),
|
|
||||||
|
|
||||||
('wind_speed', 10, 'be_forecast_warning.json'),
|
|
||||||
('wind_speed', 5, 'forecast.json'),
|
|
||||||
('wind_speed', 26, 'forecast_ams_no_ww.json'),
|
|
||||||
('wind_speed', 25, 'forecast_out_of_benelux.json'),
|
|
||||||
('wind_speed', 15, 'forecast_with_rain_on_radar.json'),
|
|
||||||
('wind_speed', 30, 'high_low_temp.json'),
|
|
||||||
('wind_speed', 10, 'midnight-bug-31-05-2024T00-13.json'),
|
|
||||||
('wind_speed', 15, 'no-midnight-bug-31-05-2024T01-55.json'),
|
|
||||||
|
|
||||||
('wind_gust_speed', None, 'be_forecast_warning.json'),
|
|
||||||
('wind_gust_speed', None, 'forecast.json'),
|
|
||||||
('wind_gust_speed', None, 'forecast_ams_no_ww.json'),
|
|
||||||
('wind_gust_speed', None, 'forecast_out_of_benelux.json'),
|
|
||||||
('wind_gust_speed', None, 'forecast_with_rain_on_radar.json'),
|
|
||||||
('wind_gust_speed', 50, 'high_low_temp.json'),
|
|
||||||
('wind_gust_speed', None, 'midnight-bug-31-05-2024T00-13.json'),
|
|
||||||
('wind_gust_speed', None, 'no-midnight-bug-31-05-2024T01-55.json'),
|
|
||||||
|
|
||||||
('wind_bearing', 23, 'be_forecast_warning.json'),
|
|
||||||
('wind_bearing', 248, 'forecast.json'),
|
|
||||||
('wind_bearing', 270, 'forecast_ams_no_ww.json'),
|
|
||||||
('wind_bearing', 180, 'forecast_out_of_benelux.json'),
|
|
||||||
('wind_bearing', 293, 'forecast_with_rain_on_radar.json'),
|
|
||||||
('wind_bearing', 180, 'high_low_temp.json'),
|
|
||||||
('wind_bearing', 293, 'midnight-bug-31-05-2024T00-13.json'),
|
|
||||||
('wind_bearing', 270, 'no-midnight-bug-31-05-2024T01-55.json'),
|
|
||||||
|
|
||||||
('uv_index', 0.7, 'be_forecast_warning.json'),
|
|
||||||
('uv_index', 0.7, 'forecast.json'),
|
|
||||||
('uv_index', 6, 'forecast_ams_no_ww.json'),
|
|
||||||
('uv_index', 0.6, 'forecast_out_of_benelux.json'),
|
|
||||||
('uv_index', None, 'forecast_with_rain_on_radar.json'),
|
|
||||||
('uv_index', 0.7, 'high_low_temp.json'),
|
|
||||||
('uv_index', 5.6, 'midnight-bug-31-05-2024T00-13.json'),
|
|
||||||
('uv_index', 5.6, 'no-midnight-bug-31-05-2024T01-55.json'),
|
|
||||||
|
|
||||||
('pressure', 1034, 'be_forecast_warning.json'),
|
|
||||||
('pressure', 1020, 'forecast.json'),
|
|
||||||
('pressure', 1010, 'forecast_ams_no_ww.json'),
|
|
||||||
('pressure', 1013, 'forecast_out_of_benelux.json'),
|
|
||||||
('pressure', 1006, 'forecast_with_rain_on_radar.json'),
|
|
||||||
('pressure', 1022, 'high_low_temp.json'),
|
|
||||||
('pressure', 1010, 'midnight-bug-31-05-2024T00-13.json'),
|
|
||||||
('pressure', 1010, 'no-midnight-bug-31-05-2024T01-55.json'),
|
|
||||||
|
|
||||||
('rainfall', 0.42, 'be_forecast_warning.json'),
|
|
||||||
('rainfall', 0.15, 'forecast_nl.json'),
|
|
||||||
('rainfall', 0, 'forecast.json'),
|
|
||||||
('rainfall', 0.1341, 'forecast_ams_no_ww.json'),
|
|
||||||
('rainfall', 0, 'forecast_out_of_benelux.json'),
|
|
||||||
('rainfall', 0.33, 'forecast_with_rain_on_radar.json'),
|
|
||||||
('rainfall', 0, 'high_low_temp.json'),
|
|
||||||
('rainfall', 0, 'midnight-bug-31-05-2024T00-13.json'),
|
|
||||||
('rainfall', 0, 'no-midnight-bug-31-05-2024T01-55.json'),
|
|
||||||
])
|
|
||||||
async def test_current_weather_sensors(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
mock_config_entry: MockConfigEntry,
|
|
||||||
sensor,
|
|
||||||
expected,
|
|
||||||
filename
|
|
||||||
) -> None:
|
|
||||||
hass.config.time_zone = 'Europe/Brussels'
|
|
||||||
|
|
||||||
api_data = get_api_data(filename)
|
|
||||||
time = api_data.get('obs').get('timestamp')
|
|
||||||
|
|
||||||
@freeze_time(datetime.fromisoformat(time) + timedelta(seconds=45, minutes=1))
|
|
||||||
async def run(mock_config_entry_, sensor_, expected_):
|
|
||||||
coordinator = IrmKmiCoordinator(hass, mock_config_entry_)
|
|
||||||
coordinator.data = ProcessedCoordinatorData(
|
|
||||||
current_weather=await IrmKmiCoordinator.current_weather_from_data(api_data),
|
|
||||||
hourly_forecast=await IrmKmiCoordinator.hourly_list_to_forecast(api_data.get('for', {}).get('hourly')),
|
|
||||||
radar_forecast=IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation', {})),
|
|
||||||
country=api_data.get('country')
|
|
||||||
)
|
|
||||||
|
|
||||||
if sensor_ == 'rainfall':
|
|
||||||
s = IrmKmiCurrentRainfall(coordinator, mock_config_entry_)
|
|
||||||
else:
|
|
||||||
s = IrmKmiCurrentWeather(coordinator, mock_config_entry_, sensor_)
|
|
||||||
|
|
||||||
assert s.native_value == expected_
|
|
||||||
|
|
||||||
await run(mock_config_entry, sensor, expected)
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("expected,filename",
|
|
||||||
[
|
|
||||||
('mm/h', 'forecast_ams_no_ww.json'),
|
|
||||||
('mm/10min', 'forecast_out_of_benelux.json'),
|
|
||||||
('mm/10min', 'forecast_with_rain_on_radar.json'),
|
|
||||||
])
|
|
||||||
async def test_current_rainfall_unit(
|
|
||||||
hass: HomeAssistant,
|
|
||||||
mock_config_entry: MockConfigEntry,
|
|
||||||
expected,
|
|
||||||
filename
|
|
||||||
) -> None:
|
|
||||||
hass.config.time_zone = 'Europe/Brussels'
|
|
||||||
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
|
|
||||||
api_data = get_api_data(filename)
|
|
||||||
|
|
||||||
coordinator.data = ProcessedCoordinatorData(
|
|
||||||
current_weather=await IrmKmiCoordinator.current_weather_from_data(api_data),
|
|
||||||
hourly_forecast=await IrmKmiCoordinator.hourly_list_to_forecast(api_data.get('for', {}).get('hourly')),
|
|
||||||
radar_forecast=IrmKmiCoordinator.radar_list_to_forecast(api_data.get('animation', {})),
|
|
||||||
country=api_data.get('country')
|
|
||||||
)
|
|
||||||
|
|
||||||
s = IrmKmiCurrentRainfall(coordinator, mock_config_entry)
|
|
||||||
|
|
||||||
assert s.native_unit_of_measurement == expected
|
|
|
@ -7,7 +7,8 @@ from pytest_homeassistant_custom_component.common import MockConfigEntry
|
||||||
from custom_components.irm_kmi import IrmKmiCoordinator
|
from custom_components.irm_kmi import IrmKmiCoordinator
|
||||||
from custom_components.irm_kmi.binary_sensor import IrmKmiWarning
|
from custom_components.irm_kmi.binary_sensor import IrmKmiWarning
|
||||||
from custom_components.irm_kmi.const import CONF_LANGUAGE_OVERRIDE
|
from custom_components.irm_kmi.const import CONF_LANGUAGE_OVERRIDE
|
||||||
from custom_components.irm_kmi.sensor import IrmKmiNextSunMove, IrmKmiNextWarning
|
from custom_components.irm_kmi.sensor import (IrmKmiNextSunMove,
|
||||||
|
IrmKmiNextWarning)
|
||||||
from tests.conftest import get_api_data
|
from tests.conftest import get_api_data
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ from unittest.mock import AsyncMock
|
||||||
|
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
from homeassistant.components.weather import Forecast
|
from homeassistant.components.weather import Forecast
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ async def test_weather_nl(
|
||||||
|
|
||||||
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
|
coordinator = IrmKmiCoordinator(hass, mock_config_entry)
|
||||||
await coordinator.async_refresh()
|
await coordinator.async_refresh()
|
||||||
print(coordinator.data)
|
|
||||||
weather = IrmKmiWeather(coordinator, mock_config_entry)
|
weather = IrmKmiWeather(coordinator, mock_config_entry)
|
||||||
result = await weather.async_forecast_daily()
|
result = await weather.async_forecast_daily()
|
||||||
|
|
||||||
|
@ -117,27 +118,27 @@ async def test_radar_forecast_service(
|
||||||
|
|
||||||
expected = [
|
expected = [
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:00:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:10:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:20:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:30:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:40:00+01:00", native_precipitation=0.1, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T17:50:00+01:00", native_precipitation=0.01, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:00:00+01:00", native_precipitation=0.12, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:10:00+01:00", native_precipitation=1.2, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:20:00+01:00", native_precipitation=2, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:30:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min'),
|
rain_forecast_max=0, rain_forecast_min=0),
|
||||||
IrmKmiRadarForecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0, might_rain=False,
|
IrmKmiRadarForecast(datetime="2023-12-26T18:40:00+01:00", native_precipitation=0, might_rain=False,
|
||||||
rain_forecast_max=0, rain_forecast_min=0, unit='mm/10min')
|
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