diff --git a/custom_components/irm_kmi/const.py b/custom_components/irm_kmi/const.py index c93d78c..235660d 100644 --- a/custom_components/irm_kmi/const.py +++ b/custom_components/irm_kmi/const.py @@ -1,6 +1,7 @@ """Constants for the IRM KMI integration.""" from typing import Final +from homeassistant.components.sensor import SensorDeviceClass from homeassistant.components.weather import (ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_CLOUDY, ATTR_CONDITION_FOG, @@ -11,7 +12,7 @@ from homeassistant.components.weather import (ATTR_CONDITION_CLEAR_NIGHT, ATTR_CONDITION_SNOWY, ATTR_CONDITION_SNOWY_RAINY, ATTR_CONDITION_SUNNY) -from homeassistant.const import Platform +from homeassistant.const import Platform, UnitOfPressure, UnitOfSpeed, UnitOfTemperature, DEGREE DOMAIN: Final = 'irm_kmi' PLATFORMS: Final = [Platform.WEATHER, Platform.CAMERA, Platform.BINARY_SENSOR, Platform.SENSOR] @@ -160,4 +161,29 @@ IRM_KMI_NAME: Final = { WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'] -USER_AGENT: Final = 'github.com/jdejaegh/irm-kmi-ha 0.2.29' \ No newline at end of file +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} diff --git a/custom_components/irm_kmi/coordinator.py b/custom_components/irm_kmi/coordinator.py index 5e4ac0e..125860c 100644 --- a/custom_components/irm_kmi/coordinator.py +++ b/custom_components/irm_kmi/coordinator.py @@ -327,6 +327,7 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator): 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: @@ -342,7 +343,8 @@ class IrmKmiCoordinator(TimestampDataUpdateCoordinator): 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 diff --git a/custom_components/irm_kmi/radar_data.py b/custom_components/irm_kmi/radar_data.py index dedcd9e..c6f7aad 100644 --- a/custom_components/irm_kmi/radar_data.py +++ b/custom_components/irm_kmi/radar_data.py @@ -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): diff --git a/custom_components/irm_kmi/sensor.py b/custom_components/irm_kmi/sensor.py index baeaca3..fcb11b8 100644 --- a/custom_components/irm_kmi/sensor.py +++ b/custom_components/irm_kmi/sensor.py @@ -11,9 +11,11 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from homeassistant.util import dt from custom_components.irm_kmi import DOMAIN, IrmKmiCoordinator -from custom_components.irm_kmi.const import POLLEN_NAMES, POLLEN_TO_ICON_MAP +from custom_components.irm_kmi.const import POLLEN_NAMES, POLLEN_TO_ICON_MAP, CURRENT_WEATHER_SENSOR_UNITS, \ + 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__) @@ -22,7 +24,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e """Set up the sensor platform""" coordinator = hass.data[DOMAIN][entry.entry_id] async_add_entities([IrmKmiPollen(coordinator, entry, pollen.lower()) for pollen in POLLEN_NAMES]) - async_add_entities([IrmKmiNextWarning(coordinator, entry),]) + async_add_entities([IrmKmiCurrentWeather(coordinator, entry, name) for name in CURRENT_WEATHER_SENSORS]) + 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']]) @@ -135,3 +139,91 @@ class IrmKmiNextSunMove(CoordinatorEntity, SensorEntity): if len(upcoming) > 0: return upcoming[0] 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) \ No newline at end of file diff --git a/custom_components/irm_kmi/translations/en.json b/custom_components/irm_kmi/translations/en.json index 0a5a529..3d160c1 100644 --- a/custom_components/irm_kmi/translations/en.json +++ b/custom_components/irm_kmi/translations/en.json @@ -182,6 +182,27 @@ "purple": "Purple", "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" } } }, diff --git a/custom_components/irm_kmi/translations/fr.json b/custom_components/irm_kmi/translations/fr.json index 00f5280..2e9c6f5 100644 --- a/custom_components/irm_kmi/translations/fr.json +++ b/custom_components/irm_kmi/translations/fr.json @@ -182,6 +182,27 @@ "purple": "Violet", "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" } } }, diff --git a/custom_components/irm_kmi/translations/nl.json b/custom_components/irm_kmi/translations/nl.json index 1545359..7a16fc7 100644 --- a/custom_components/irm_kmi/translations/nl.json +++ b/custom_components/irm_kmi/translations/nl.json @@ -182,6 +182,27 @@ "purple": "Paars", "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" } } }, diff --git a/custom_components/irm_kmi/translations/pt.json b/custom_components/irm_kmi/translations/pt.json index 99771d7..3a1629d 100644 --- a/custom_components/irm_kmi/translations/pt.json +++ b/custom_components/irm_kmi/translations/pt.json @@ -182,6 +182,27 @@ "purple": "Roxo", "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" } } }, diff --git a/tests/fixtures/be_forecast_warning.json b/tests/fixtures/be_forecast_warning.json index ac3412d..8e7e953 100644 --- a/tests/fixtures/be_forecast_warning.json +++ b/tests/fixtures/be_forecast_warning.json @@ -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 diff --git a/tests/fixtures/forecast_ams_no_ww.json b/tests/fixtures/forecast_ams_no_ww.json index fead883..82ef49b 100644 --- a/tests/fixtures/forecast_ams_no_ww.json +++ b/tests/fixtures/forecast_ams_no_ww.json @@ -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 diff --git a/tests/fixtures/forecast_nl.json b/tests/fixtures/forecast_nl.json index ef619d3..da1aef9 100644 --- a/tests/fixtures/forecast_nl.json +++ b/tests/fixtures/forecast_nl.json @@ -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": { @@ -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 diff --git a/tests/test_coordinator.py b/tests/test_coordinator.py index 124b21f..6768794 100644 --- a/tests/test_coordinator.py +++ b/tests/test_coordinator.py @@ -1,4 +1,3 @@ -import zoneinfo from datetime import datetime, timedelta from freezegun import freeze_time @@ -12,9 +11,8 @@ 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) -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 @@ -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 @@ -302,7 +300,8 @@ 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( @@ -310,7 +309,8 @@ def test_radar_forecast_rain_interval() -> None: 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 diff --git a/tests/test_current_weather_sensors.py b/tests/test_current_weather_sensors.py new file mode 100644 index 0000000..ef667ef --- /dev/null +++ b/tests/test_current_weather_sensors.py @@ -0,0 +1,159 @@ +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 diff --git a/tests/test_sensors.py b/tests/test_sensors.py index cadc2b7..e221897 100644 --- a/tests/test_sensors.py +++ b/tests/test_sensors.py @@ -7,8 +7,7 @@ from pytest_homeassistant_custom_component.common import MockConfigEntry from custom_components.irm_kmi import IrmKmiCoordinator from custom_components.irm_kmi.binary_sensor import IrmKmiWarning 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 diff --git a/tests/test_weather.py b/tests/test_weather.py index 0a24d54..6cebe02 100644 --- a/tests/test_weather.py +++ b/tests/test_weather.py @@ -5,7 +5,6 @@ from unittest.mock import AsyncMock from freezegun import freeze_time from homeassistant.components.weather import Forecast -from homeassistant.config_entries import ConfigEntryState from homeassistant.core import HomeAssistant from pytest_homeassistant_custom_component.common import MockConfigEntry @@ -30,7 +29,7 @@ async def test_weather_nl( coordinator = IrmKmiCoordinator(hass, mock_config_entry) await coordinator.async_refresh() - + print(coordinator.data) weather = IrmKmiWeather(coordinator, mock_config_entry) result = await weather.async_forecast_daily() @@ -118,27 +117,27 @@ async def test_radar_forecast_service( 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 result_service == expected[5:]