"""Implementation of a RymPro inteface.""" import aiohttp import asyncio from datetime import datetime from typing import Any, Optional from .const import Endpoint class RymPro: """A connection to RYM Pro.""" def __init__(self, session: Optional[aiohttp.ClientSession] = None) -> None: """Initialize the object.""" self._created_session = False self._session = session self._access_token: Optional[str] = None async def close(self) -> None: """Close the connection.""" if self._created_session and self._session is not None: await self._session.close() self._session = None self._created_session = False def set_token(self, token: str) -> None: """Use a pre-existing token instead of logging in.""" self._init_session() self._access_token = token async def login(self, email: str, password: str, device_id: str) -> str: """Login to RYM Pro and return a token.""" self._init_session() headers = {"Content-Type": "application/json"} body = {"email": email, "pw": password, "deviceId": device_id} assert self._session try: async with self._session.post( Endpoint.LOGIN.value, headers=headers, json=body ) as response: json = await response.json() token = json.get("token") error_code = json.get("code") error = json.get("error") if error_code == 5060: raise UnauthorizedError(error) elif token is None or error_code: raise CannotConnectError(f"code: {error_code}, error: {error}") else: self._access_token = token return token except aiohttp.client_exceptions.ClientConnectorError as e: raise CannotConnectError from e async def account_info(self) -> dict[str, Any]: """Get the account information.""" return await self._get(Endpoint.ACCOUNT_INFO) async def last_read(self) -> dict[int, dict[str, Any]]: """Get the latest meter reads.""" raw: list[dict[str, Any]] = await self._get(Endpoint.LAST_READ) return { meter["meterCount"]: meter for meter in raw } async def consumption_forecast(self, meter_id: int) -> float: """Get the consumption forecast for this month.""" return (await self._get(Endpoint.CONSUMPTION_FORECAST, meter_id=meter_id))["estimatedConsumption"] async def daily_consumption(self, meter_id: int) -> float: """Get the consumption for today.""" today = datetime.now().strftime("%Y-%m-%d") result = await self._get(Endpoint.DAILY_CONSUMPTION, meter_id=meter_id, start_date=today, end_date=today) return result[0]["cons"] async def monthly_consumption(self, meter_id: int) -> float: """Get the consumption this month.""" today = datetime.now().strftime("%Y-%m-%d") result = await self._get(Endpoint.MONTHLY_CONSUMPTION, meter_id=meter_id, start_date=today, end_date=today) return result[0]["cons"] async def _get(self, endpoint: Endpoint, **kwargs: Any) -> Any: if not self._access_token: raise OperationError("Please login") headers = {"Content-Type": "application/json", "x-access-token": self._access_token} assert self._session try: async with self._session.get(endpoint.value.format(**kwargs), headers=headers) as response: if response.status == 200: return await response.json() elif response.status == 401: raise UnauthorizedError(response) else: raise OperationError(response) except (asyncio.TimeoutError, aiohttp.ClientError) as error: raise OperationError() from error def _init_session(self) -> None: if self._session == None: self._session = aiohttp.ClientSession() self._created_session = True # async def _post(self, endpoint, json_payload=None): # if not self._access_token: # raise OperationError("Please login") # headers = {"Content-Type": "application/json", "x-access-token": self._access_token} # try: # async with self._session.post(endpoint.value, headers=headers, json=json_payload) as response: # if response.status == 200: # return await response.json() # else: # raise OperationError(response) # except (asyncio.TimeoutError, aiohttp.ClientError) as error: # raise OperationError() from error class CannotConnectError(Exception): """Exception to indicate an error in connection.""" class UnauthorizedError(Exception): """Exception to indicate an error in authorization.""" class OperationError(Exception): """Exception to indicate an error in operation."""