From a280c616fab30a8c80b2d791306c8b1f14e38e20 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Tue, 25 Jun 2024 09:17:37 +0200 Subject: [PATCH 1/4] split models and add abstract methods to base class --- chargeamps/base.py | 185 ++++++++++++++++++----------------------- chargeamps/external.py | 4 +- chargeamps/models.py | 98 ++++++++++++++++++++++ 3 files changed, 183 insertions(+), 104 deletions(-) create mode 100644 chargeamps/models.py diff --git a/chargeamps/base.py b/chargeamps/base.py index e1c8795..3c2db19 100644 --- a/chargeamps/base.py +++ b/chargeamps/base.py @@ -1,104 +1,85 @@ -"""Base class and data classes for ChargeAmps API""" +"""Base class for ChargeAmps API""" -from abc import ABCMeta -from dataclasses import dataclass +from abc import ABCMeta, abstractmethod from datetime import datetime -from typing import List, Optional - -from dataclasses_json import LetterCase, dataclass_json - -from .utils import datetime_field - - -class ChargeAmpsClient(metaclass=ABCMeta): # noqa - pass - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=True) -class ChargePointConnector: - charge_point_id: str - connector_id: int - type: str - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=True) -class ChargePoint: - id: str - name: str - password: str - type: str - is_loadbalanced: bool - firmware_version: str - hardware_version: str - connectors: List[ChargePointConnector] - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=True) -class ChargePointMeasurement: - phase: str - current: float - voltage: float - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=True) -class ChargePointConnectorStatus: - charge_point_id: str - connector_id: int - total_consumption_kwh: float - status: str - measurements: Optional[List[ChargePointMeasurement]] - start_time: Optional[datetime] = datetime_field() - end_time: Optional[datetime] = datetime_field() - session_id: Optional[str] = None - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=True) -class ChargePointStatus: - id: str - status: str - connector_statuses: List[ChargePointConnectorStatus] - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=False) -class ChargePointSettings: - id: str - dimmer: str - down_light: bool - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=False) -class ChargePointConnectorSettings: - charge_point_id: str - connector_id: int - mode: str - rfid_lock: bool - cable_lock: bool - max_current: Optional[float] = None - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=True) -class ChargingSession: - id: str - charge_point_id: str - connector_id: int - session_type: str - total_consumption_kwh: float - start_time: Optional[datetime] = datetime_field() - end_time: Optional[datetime] = datetime_field() - - -@dataclass_json(letter_case=LetterCase.CAMEL) -@dataclass(frozen=True) -class StartAuth: - rfid_length: int - rfid_format: str - rfid: str - external_transaction_id: str +from typing import Optional + +from .models import ( + ChargePoint, + ChargePointConnectorSettings, + ChargePointSettings, + ChargePointStatus, + ChargingSession, + StartAuth, +) + + +class ChargeAmpsClient(metaclass=ABCMeta): + @abstractmethod + async def shutdown(self): + pass + + @abstractmethod + async def get_chargepoints(self) -> list[ChargePoint]: + """Get all owned chargepoints""" + pass + + @abstractmethod + async def get_all_chargingsessions( + self, + charge_point_id: str, + start_time: Optional[datetime] = None, + end_time: Optional[datetime] = None, + ) -> list[ChargingSession]: + """Get all charging sessions""" + pass + + @abstractmethod + async def get_chargingsession( + self, charge_point_id: str, session: int + ) -> ChargingSession: + """Get charging session""" + pass + + @abstractmethod + async def get_chargepoint_status(self, charge_point_id: str) -> ChargePointStatus: + """Get charge point status""" + pass + + @abstractmethod + async def get_chargepoint_settings( + self, charge_point_id: str + ) -> ChargePointSettings: + """Get chargepoint settings""" + pass + + @abstractmethod + async def set_chargepoint_settings(self, settings: ChargePointSettings) -> None: + """Set chargepoint settings""" + pass + + @abstractmethod + async def get_chargepoint_connector_settings( + self, charge_point_id: str, connector_id: int + ) -> ChargePointConnectorSettings: + """Get all owned chargepoints""" + pass + + @abstractmethod + async def set_chargepoint_connector_settings( + self, settings: ChargePointConnectorSettings + ) -> None: + """Get all owned chargepoints""" + pass + + @abstractmethod + async def remote_start( + self, charge_point_id: str, connector_id: int, start_auth: StartAuth + ) -> None: + """Remote start chargepoint""" + pass + + @abstractmethod + async def remote_stop(self, charge_point_id: str, connector_id: int) -> None: + """Remote stop chargepoint""" + pass diff --git a/chargeamps/external.py b/chargeamps/external.py index 376a892..f3213d7 100644 --- a/chargeamps/external.py +++ b/chargeamps/external.py @@ -9,8 +9,8 @@ import jwt from aiohttp import ClientResponse, ClientSession -from .base import ( - ChargeAmpsClient, +from .base import ChargeAmpsClient +from .models import ( ChargePoint, ChargePointConnectorSettings, ChargePointSettings, diff --git a/chargeamps/models.py b/chargeamps/models.py new file mode 100644 index 0000000..69b79b4 --- /dev/null +++ b/chargeamps/models.py @@ -0,0 +1,98 @@ +"""Data classes for ChargeAmps API""" + +from dataclasses import dataclass +from datetime import datetime + +from dataclasses_json import LetterCase, dataclass_json + +from .utils import datetime_field + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=True) +class ChargePointConnector: + charge_point_id: str + connector_id: int + type: str + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=True) +class ChargePoint: + id: str + name: str + password: str + type: str + is_loadbalanced: bool + firmware_version: str + hardware_version: str + connectors: list[ChargePointConnector] + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=True) +class ChargePointMeasurement: + phase: str + current: float + voltage: float + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=True) +class ChargePointConnectorStatus: + charge_point_id: str + connector_id: int + total_consumption_kwh: float + status: str + measurements: list[ChargePointMeasurement] | None + start_time: datetime | None = datetime_field() + end_time: datetime | None = datetime_field() + session_id: str | None = None + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=True) +class ChargePointStatus: + id: str + status: str + connector_statuses: list[ChargePointConnectorStatus] + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=False) +class ChargePointSettings: + id: str + dimmer: str + down_light: bool + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=False) +class ChargePointConnectorSettings: + charge_point_id: str + connector_id: int + mode: str + rfid_lock: bool + cable_lock: bool + max_current: float | None = None + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=True) +class ChargingSession: + id: str + charge_point_id: str + connector_id: int + session_type: str + total_consumption_kwh: float + start_time: datetime | None = datetime_field() + end_time: datetime | None = datetime_field() + + +@dataclass_json(letter_case=LetterCase.CAMEL) +@dataclass(frozen=True) +class StartAuth: + rfid_length: int + rfid_format: str + rfid: str + external_transaction_id: str From 5112a124e2121399570c0b5516d307790b3cd130 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Tue, 25 Jun 2024 09:27:51 +0200 Subject: [PATCH 2/4] use Optional for now --- chargeamps/models.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/chargeamps/models.py b/chargeamps/models.py index 69b79b4..7744912 100644 --- a/chargeamps/models.py +++ b/chargeamps/models.py @@ -1,7 +1,8 @@ -"""Data classes for ChargeAmps API""" +"""Base class and data classes for ChargeAmps API""" from dataclasses import dataclass from datetime import datetime +from typing import Optional from dataclasses_json import LetterCase, dataclass_json @@ -44,10 +45,10 @@ class ChargePointConnectorStatus: connector_id: int total_consumption_kwh: float status: str - measurements: list[ChargePointMeasurement] | None - start_time: datetime | None = datetime_field() - end_time: datetime | None = datetime_field() - session_id: str | None = None + measurements: Optional[list[ChargePointMeasurement]] + start_time: Optional[datetime] = datetime_field() + end_time: Optional[datetime] = datetime_field() + session_id: Optional[str] = None @dataclass_json(letter_case=LetterCase.CAMEL) @@ -74,7 +75,7 @@ class ChargePointConnectorSettings: mode: str rfid_lock: bool cable_lock: bool - max_current: float | None = None + max_current: Optional[float] = None @dataclass_json(letter_case=LetterCase.CAMEL) @@ -85,8 +86,8 @@ class ChargingSession: connector_id: int session_type: str total_consumption_kwh: float - start_time: datetime | None = datetime_field() - end_time: datetime | None = datetime_field() + start_time: Optional[datetime] = datetime_field() + end_time: Optional[datetime] = datetime_field() @dataclass_json(letter_case=LetterCase.CAMEL) From cb28dcdb556f79808d07b724aea7c019f71251e5 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Tue, 25 Jun 2024 09:53:42 +0200 Subject: [PATCH 3/4] remove methods only applicable to external API --- chargeamps/base.py | 33 --------------------------------- 1 file changed, 33 deletions(-) diff --git a/chargeamps/base.py b/chargeamps/base.py index 3c2db19..4f461d1 100644 --- a/chargeamps/base.py +++ b/chargeamps/base.py @@ -1,16 +1,12 @@ """Base class for ChargeAmps API""" from abc import ABCMeta, abstractmethod -from datetime import datetime -from typing import Optional from .models import ( ChargePoint, ChargePointConnectorSettings, ChargePointSettings, ChargePointStatus, - ChargingSession, - StartAuth, ) @@ -24,23 +20,6 @@ async def get_chargepoints(self) -> list[ChargePoint]: """Get all owned chargepoints""" pass - @abstractmethod - async def get_all_chargingsessions( - self, - charge_point_id: str, - start_time: Optional[datetime] = None, - end_time: Optional[datetime] = None, - ) -> list[ChargingSession]: - """Get all charging sessions""" - pass - - @abstractmethod - async def get_chargingsession( - self, charge_point_id: str, session: int - ) -> ChargingSession: - """Get charging session""" - pass - @abstractmethod async def get_chargepoint_status(self, charge_point_id: str) -> ChargePointStatus: """Get charge point status""" @@ -71,15 +50,3 @@ async def set_chargepoint_connector_settings( ) -> None: """Get all owned chargepoints""" pass - - @abstractmethod - async def remote_start( - self, charge_point_id: str, connector_id: int, start_auth: StartAuth - ) -> None: - """Remote start chargepoint""" - pass - - @abstractmethod - async def remote_stop(self, charge_point_id: str, connector_id: int) -> None: - """Remote stop chargepoint""" - pass From 08386c836ee17e4ebae207cb27045e6999e1d250 Mon Sep 17 00:00:00 2001 From: Jakob Schlyter Date: Wed, 26 Jun 2024 09:09:20 +0200 Subject: [PATCH 4/4] use asyncio.run --- chargeamps/cli.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/chargeamps/cli.py b/chargeamps/cli.py index 7433ebe..f74ccd7 100644 --- a/chargeamps/cli.py +++ b/chargeamps/cli.py @@ -324,11 +324,7 @@ async def main_loop() -> None: def main() -> None: - loop = asyncio.get_event_loop() - try: - loop.run_until_complete(main_loop()) - finally: - loop.close() + asyncio.run(main_loop()) if __name__ == "__main__":