From 286c91ebd41f47be5d10f5967e5c48edaa104148 Mon Sep 17 00:00:00 2001 From: Jules Dejaeghere Date: Sat, 10 May 2025 18:23:59 +0200 Subject: [PATCH] Move const + add docstring --- irm_kmi_api/api.py | 48 +++++++++++++++++----- irm_kmi_api/const.py | 75 ++++++++++++++++++++++++++++++++++ tests/conftest.py | 2 +- tests/const.py | 77 ----------------------------------- tests/test_current_weather.py | 2 +- tests/test_daily_forecast.py | 2 +- tests/test_hourly_forecast.py | 2 +- 7 files changed, 117 insertions(+), 91 deletions(-) delete mode 100644 tests/const.py diff --git a/irm_kmi_api/api.py b/irm_kmi_api/api.py index 426a7a9..433e13f 100644 --- a/irm_kmi_api/api.py +++ b/irm_kmi_api/api.py @@ -8,18 +8,30 @@ import time import urllib.parse from datetime import datetime, timedelta from statistics import mean -from typing import Dict, List +from typing import Dict, List, Tuple from zoneinfo import ZoneInfo import aiohttp -from .pollen import PollenName, PollenLevel +from .const import ( + IRM_KMI_TO_HA_CONDITION_MAP, + STYLE_TO_PARAM_MAP, + WEEKDAYS, + WWEVOL_TO_ENUM_MAP, +) from .const import MAP_WARNING_ID_TO_SLUG as SLUG_MAP -from .const import STYLE_TO_PARAM_MAP, WEEKDAYS, WWEVOL_TO_ENUM_MAP -from .data import (AnimationFrameData, CurrentWeatherData, ExtendedForecast, - Forecast, RadarAnimationData, RadarForecast, RadarStyle, - WarningData, WarningType) -from .pollen import PollenParser +from .data import ( + AnimationFrameData, + CurrentWeatherData, + ExtendedForecast, + Forecast, + RadarAnimationData, + RadarForecast, + RadarStyle, + WarningData, + WarningType, +) +from .pollen import PollenLevel, PollenName, PollenParser _LOGGER = logging.getLogger(__name__) @@ -37,10 +49,16 @@ class IrmKmiApiClient: COORD_DECIMALS = 6 _cache_max_age = 60 * 60 * 2 # Remove items from the cache if they have not been hit since 2 hours _cache = {} + _base_url = "https://app.meteo.be/services/appv4/" def __init__(self, session: aiohttp.ClientSession, user_agent: str) -> None: + """ + Create a new instance of the API client + + :param session: aiohttp.ClientSession to use for the request + :param user_agent: string that will indentify your application in the User-Agent header of the HTTP requests + """ self._session = session - self._base_url = "https://app.meteo.be/services/appv4/" self._user_agent = user_agent async def get_forecasts_coord(self, coord: Dict[str, float | int]) -> dict: @@ -163,10 +181,20 @@ class IrmKmiApiClient: class IrmKmiApiClientHa(IrmKmiApiClient): """API client for IRM KMI weather data with additional methods to integrate easily with Home Assistant""" - def __init__(self, session: aiohttp.ClientSession, user_agent: str, cdt_map: dict) -> None: + def __init__(self, session: aiohttp.ClientSession, user_agent: str, cdt_map: Dict[Tuple[int, str], str] | None = None) -> None: + """ + Create a new instance of the API client. This client has more methods to integrate easily with Home Assistant + + :param session: aiohttp.ClientSession to use for the request + :param user_agent: string that will indentify your application in the User-Agent header of the HTTP requests + :param cdt_map: mapping of weather conditions returned by the API and string that should be used when calling the + methods. See the wiki for more information on what conditions are possible: + https://github.com/jdejaegh/irm-kmi-api/wiki/API-documentation#obs-key (Table with icons matching). + Example: cdt_map = { (0, 'd'): 'sunny', (0, 'n'): 'clear_night' } + """ super().__init__(session, user_agent) self._api_data = dict() - self._cdt_map = cdt_map + self._cdt_map = cdt_map if cdt_map is not None else IRM_KMI_TO_HA_CONDITION_MAP async def refresh_forecasts_coord(self, coord: Dict[str, float | int]) -> None: """ diff --git a/irm_kmi_api/const.py b/irm_kmi_api/const.py index 1a0fbd2..4f4790b 100644 --- a/irm_kmi_api/const.py +++ b/irm_kmi_api/const.py @@ -39,3 +39,78 @@ WWEVOL_TO_ENUM_MAP: Final = { 0: ConditionEvol.ONE_WAY, 1: ConditionEvol.TWO_WAYS } + +ATTR_CONDITION_CLEAR_NIGHT = "clear-night" +ATTR_CONDITION_CLOUDY = "cloudy" +ATTR_CONDITION_EXCEPTIONAL = "exceptional" +ATTR_CONDITION_FOG = "fog" +ATTR_CONDITION_HAIL = "hail" +ATTR_CONDITION_LIGHTNING = "lightning" +ATTR_CONDITION_LIGHTNING_RAINY = "lightning-rainy" +ATTR_CONDITION_PARTLYCLOUDY = "partlycloudy" +ATTR_CONDITION_POURING = "pouring" +ATTR_CONDITION_RAINY = "rainy" +ATTR_CONDITION_SNOWY = "snowy" +ATTR_CONDITION_SNOWY_RAINY = "snowy-rainy" +ATTR_CONDITION_SUNNY = "sunny" +ATTR_CONDITION_WINDY = "windy" +ATTR_CONDITION_WINDY_VARIANT = "windy-variant" + +IRM_KMI_TO_HA_CONDITION_MAP: Final = { + (0, 'd'): ATTR_CONDITION_SUNNY, + (0, 'n'): ATTR_CONDITION_CLEAR_NIGHT, + (1, 'd'): ATTR_CONDITION_SUNNY, + (1, 'n'): ATTR_CONDITION_CLEAR_NIGHT, + (2, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, + (2, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, + (3, 'd'): ATTR_CONDITION_PARTLYCLOUDY, + (3, 'n'): ATTR_CONDITION_PARTLYCLOUDY, + (4, 'd'): ATTR_CONDITION_POURING, + (4, 'n'): ATTR_CONDITION_POURING, + (5, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, + (5, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, + (6, 'd'): ATTR_CONDITION_POURING, + (6, 'n'): ATTR_CONDITION_POURING, + (7, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, + (7, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, + (8, 'd'): ATTR_CONDITION_SNOWY_RAINY, + (8, 'n'): ATTR_CONDITION_SNOWY_RAINY, + (9, 'd'): ATTR_CONDITION_SNOWY_RAINY, + (9, 'n'): ATTR_CONDITION_SNOWY_RAINY, + (10, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, + (10, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, + (11, 'd'): ATTR_CONDITION_SNOWY, + (11, 'n'): ATTR_CONDITION_SNOWY, + (12, 'd'): ATTR_CONDITION_SNOWY, + (12, 'n'): ATTR_CONDITION_SNOWY, + (13, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, + (13, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, + (14, 'd'): ATTR_CONDITION_CLOUDY, + (14, 'n'): ATTR_CONDITION_CLOUDY, + (15, 'd'): ATTR_CONDITION_CLOUDY, + (15, 'n'): ATTR_CONDITION_CLOUDY, + (16, 'd'): ATTR_CONDITION_POURING, + (16, 'n'): ATTR_CONDITION_POURING, + (17, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, + (17, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, + (18, 'd'): ATTR_CONDITION_RAINY, + (18, 'n'): ATTR_CONDITION_RAINY, + (19, 'd'): ATTR_CONDITION_POURING, + (19, 'n'): ATTR_CONDITION_POURING, + (20, 'd'): ATTR_CONDITION_SNOWY_RAINY, + (20, 'n'): ATTR_CONDITION_SNOWY_RAINY, + (21, 'd'): ATTR_CONDITION_RAINY, + (21, 'n'): ATTR_CONDITION_RAINY, + (22, 'd'): ATTR_CONDITION_SNOWY, + (22, 'n'): ATTR_CONDITION_SNOWY, + (23, 'd'): ATTR_CONDITION_SNOWY, + (23, 'n'): ATTR_CONDITION_SNOWY, + (24, 'd'): ATTR_CONDITION_FOG, + (24, 'n'): ATTR_CONDITION_FOG, + (25, 'd'): ATTR_CONDITION_FOG, + (25, 'n'): ATTR_CONDITION_FOG, + (26, 'd'): ATTR_CONDITION_FOG, + (26, 'n'): ATTR_CONDITION_FOG, + (27, 'd'): ATTR_CONDITION_FOG, + (27, 'n'): ATTR_CONDITION_FOG +} diff --git a/tests/conftest.py b/tests/conftest.py index 5d4d5c7..ee69c08 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -5,7 +5,7 @@ import json from unittest.mock import MagicMock from irm_kmi_api import IrmKmiApiClientHa -from tests.const import IRM_KMI_TO_HA_CONDITION_MAP +from irm_kmi_api.const import IRM_KMI_TO_HA_CONDITION_MAP def load_fixture(fixture): diff --git a/tests/const.py b/tests/const.py deleted file mode 100644 index 20910ef..0000000 --- a/tests/const.py +++ /dev/null @@ -1,77 +0,0 @@ -from typing import Final - -ATTR_CONDITION_CLASS = "condition_class" -ATTR_CONDITION_CLEAR_NIGHT = "clear-night" -ATTR_CONDITION_CLOUDY = "cloudy" -ATTR_CONDITION_EXCEPTIONAL = "exceptional" -ATTR_CONDITION_FOG = "fog" -ATTR_CONDITION_HAIL = "hail" -ATTR_CONDITION_LIGHTNING = "lightning" -ATTR_CONDITION_LIGHTNING_RAINY = "lightning-rainy" -ATTR_CONDITION_PARTLYCLOUDY = "partlycloudy" -ATTR_CONDITION_POURING = "pouring" -ATTR_CONDITION_RAINY = "rainy" -ATTR_CONDITION_SNOWY = "snowy" -ATTR_CONDITION_SNOWY_RAINY = "snowy-rainy" -ATTR_CONDITION_SUNNY = "sunny" -ATTR_CONDITION_WINDY = "windy" -ATTR_CONDITION_WINDY_VARIANT = "windy-variant" - -IRM_KMI_TO_HA_CONDITION_MAP: Final = { - (0, 'd'): ATTR_CONDITION_SUNNY, - (0, 'n'): ATTR_CONDITION_CLEAR_NIGHT, - (1, 'd'): ATTR_CONDITION_SUNNY, - (1, 'n'): ATTR_CONDITION_CLEAR_NIGHT, - (2, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, - (2, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, - (3, 'd'): ATTR_CONDITION_PARTLYCLOUDY, - (3, 'n'): ATTR_CONDITION_PARTLYCLOUDY, - (4, 'd'): ATTR_CONDITION_POURING, - (4, 'n'): ATTR_CONDITION_POURING, - (5, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, - (5, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, - (6, 'd'): ATTR_CONDITION_POURING, - (6, 'n'): ATTR_CONDITION_POURING, - (7, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, - (7, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, - (8, 'd'): ATTR_CONDITION_SNOWY_RAINY, - (8, 'n'): ATTR_CONDITION_SNOWY_RAINY, - (9, 'd'): ATTR_CONDITION_SNOWY_RAINY, - (9, 'n'): ATTR_CONDITION_SNOWY_RAINY, - (10, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, - (10, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, - (11, 'd'): ATTR_CONDITION_SNOWY, - (11, 'n'): ATTR_CONDITION_SNOWY, - (12, 'd'): ATTR_CONDITION_SNOWY, - (12, 'n'): ATTR_CONDITION_SNOWY, - (13, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, - (13, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, - (14, 'd'): ATTR_CONDITION_CLOUDY, - (14, 'n'): ATTR_CONDITION_CLOUDY, - (15, 'd'): ATTR_CONDITION_CLOUDY, - (15, 'n'): ATTR_CONDITION_CLOUDY, - (16, 'd'): ATTR_CONDITION_POURING, - (16, 'n'): ATTR_CONDITION_POURING, - (17, 'd'): ATTR_CONDITION_LIGHTNING_RAINY, - (17, 'n'): ATTR_CONDITION_LIGHTNING_RAINY, - (18, 'd'): ATTR_CONDITION_RAINY, - (18, 'n'): ATTR_CONDITION_RAINY, - (19, 'd'): ATTR_CONDITION_POURING, - (19, 'n'): ATTR_CONDITION_POURING, - (20, 'd'): ATTR_CONDITION_SNOWY_RAINY, - (20, 'n'): ATTR_CONDITION_SNOWY_RAINY, - (21, 'd'): ATTR_CONDITION_RAINY, - (21, 'n'): ATTR_CONDITION_RAINY, - (22, 'd'): ATTR_CONDITION_SNOWY, - (22, 'n'): ATTR_CONDITION_SNOWY, - (23, 'd'): ATTR_CONDITION_SNOWY, - (23, 'n'): ATTR_CONDITION_SNOWY, - (24, 'd'): ATTR_CONDITION_FOG, - (24, 'n'): ATTR_CONDITION_FOG, - (25, 'd'): ATTR_CONDITION_FOG, - (25, 'n'): ATTR_CONDITION_FOG, - (26, 'd'): ATTR_CONDITION_FOG, - (26, 'n'): ATTR_CONDITION_FOG, - (27, 'd'): ATTR_CONDITION_FOG, - (27, 'n'): ATTR_CONDITION_FOG -} diff --git a/tests/test_current_weather.py b/tests/test_current_weather.py index bf07dc6..5fe7c41 100644 --- a/tests/test_current_weather.py +++ b/tests/test_current_weather.py @@ -6,7 +6,7 @@ from freezegun import freeze_time from irm_kmi_api import CurrentWeatherData from tests.conftest import get_api_data, get_api_with_data -from tests.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_PARTLYCLOUDY +from irm_kmi_api.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_PARTLYCLOUDY @freeze_time(datetime.fromisoformat('2023-12-26T17:30:00+00:00')) diff --git a/tests/test_daily_forecast.py b/tests/test_daily_forecast.py index 5d58560..da96a39 100644 --- a/tests/test_daily_forecast.py +++ b/tests/test_daily_forecast.py @@ -5,7 +5,7 @@ from freezegun import freeze_time from irm_kmi_api import ConditionEvol, ExtendedForecast from tests.conftest import get_api_with_data -from tests.const import ATTR_CONDITION_PARTLYCLOUDY +from irm_kmi_api.const import ATTR_CONDITION_PARTLYCLOUDY @freeze_time(datetime.fromisoformat('2023-12-26T18:30:00+01:00')) diff --git a/tests/test_hourly_forecast.py b/tests/test_hourly_forecast.py index 9ca0de1..929a631 100644 --- a/tests/test_hourly_forecast.py +++ b/tests/test_hourly_forecast.py @@ -5,7 +5,7 @@ from freezegun import freeze_time from irm_kmi_api import Forecast from tests.conftest import get_api_with_data -from tests.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_RAINY +from irm_kmi_api.const import ATTR_CONDITION_CLOUDY, ATTR_CONDITION_RAINY @freeze_time(datetime.fromisoformat('2023-12-26T18:30:00+01:00'))