irm-kmi-ha/custom_components/irm_kmi/api.py
2023-12-26 18:04:57 +01:00

103 lines
3.1 KiB
Python

"""API Client for IRM KMI weather"""
from __future__ import annotations
import asyncio
import hashlib
import logging
import socket
from datetime import datetime
import aiohttp
import async_timeout
_LOGGER = logging.getLogger(__name__)
class IrmKmiApiError(Exception):
"""Exception to indicate a general API error."""
class IrmKmiApiCommunicationError(
IrmKmiApiError
):
"""Exception to indicate a communication error."""
class IrmKmiApiParametersError(
IrmKmiApiError
):
"""Exception to indicate a parameter error."""
def _api_key(method_name: str):
"""Get API key."""
return hashlib.md5(f"r9EnW374jkJ9acc;{method_name};{datetime.now().strftime('%d/%m/%Y')}".encode()).hexdigest()
class IrmKmiApiClient:
"""Sample API Client."""
COORD_DECIMALS = 6
def __init__(self, session: aiohttp.ClientSession) -> None:
"""Sample API Client."""
self._session = session
self._base_url = "https://app.meteo.be/services/appv4/"
async def get_forecasts_city(self, city_id: int) -> any:
"""Get forecasts for given city."""
return await self._api_wrapper(
params={"ins": city_id,
"s": "getForecasts"}
)
async def get_forecasts_coord(self, coord: dict) -> any:
"""Get forecasts for given city."""
assert 'lat' in coord
assert 'long' in coord
coord['lat'] = round(coord['lat'], self.COORD_DECIMALS)
coord['long'] = round(coord['long'], self.COORD_DECIMALS)
return await self._api_wrapper(
params={"s": "getForecasts"} | coord
)
async def _api_wrapper(
self,
params: dict,
path: str = "",
method: str = "get",
data: dict | None = None,
headers: dict | None = None
) -> any:
"""Get information from the API."""
if 's' not in params:
raise IrmKmiApiParametersError("No query provided as 's' argument for API")
else:
params['k'] = _api_key(params['s'])
try:
async with async_timeout.timeout(10):
_LOGGER.debug(f"Calling for {params}")
response = await self._session.request(
method=method,
url=f"{self._base_url}{path}",
headers=headers,
json=data,
params=params
)
_LOGGER.debug(f"API status code {response.status}")
response.raise_for_status()
return await response.json()
except asyncio.TimeoutError as exception:
raise IrmKmiApiCommunicationError(
"Timeout error fetching information",
) from exception
except (aiohttp.ClientError, socket.gaierror) as exception:
raise IrmKmiApiCommunicationError(
"Error fetching information",
) from exception
except Exception as exception: # pylint: disable=broad-except
raise IrmKmiApiError(
"Something really wrong happened!"
) from exception