|
1 | | -import aiohttp.client_exceptions |
| 1 | +import datetime |
| 2 | + |
2 | 3 | import pydantic |
3 | 4 | from aiohttp import ClientSession, ClientResponse |
4 | 5 | from yarl import URL |
5 | 6 | from .models import * |
6 | 7 | import logging |
7 | 8 |
|
8 | | -DEFAULT_URL = "https://app.chargecloud.de/emobility:ocpi/606a0da0dfdd338ee4134605653d4fd8/app/2.0/locations" |
| 9 | +operatorIDs = [ |
| 10 | + OperatorID(name="maingau", op_id="606a0da0dfdd338ee4134605653d4fd8"), |
| 11 | + OperatorID(name="SW Kiel", op_id="6336fe713f2eb7fa04b97ff6651b76f8"), |
| 12 | + OperatorID(name="Rheinenergie", op_id="c4ce9bb82a86766833df8a4818fa1b5c"), |
| 13 | +] |
9 | 14 |
|
10 | 15 |
|
11 | 16 | class Api: |
12 | 17 | """Class to make authenticated requests.""" |
13 | 18 |
|
14 | | - def __init__(self, websession: ClientSession, base_url: str | None = None): |
| 19 | + def __init__(self, websession: ClientSession): |
15 | 20 | """Initialize the auth.""" |
16 | 21 | self.websession = websession |
17 | | - self.base_url = URL(base_url or DEFAULT_URL) |
18 | 22 | self.logger = logging.getLogger("chargecloudapi") |
19 | 23 |
|
20 | | - async def location_by_evse_id(self, evse_id: str, **kwargs) -> list[Location]: |
21 | | - response = await self.request("GET", self.base_url % {"evse": evse_id}) |
| 24 | + async def perform_smart_api_call( |
| 25 | + self, evse_id: str, call_data: SmartCallData | None |
| 26 | + ) -> tuple[Location | None, SmartCallData]: |
| 27 | + """ |
| 28 | + Perform API request with automatic operatorId choice. |
| 29 | +
|
| 30 | + When calling for a specific evse for the first time, set call_data = None. |
| 31 | + This function will automatically try some operatorIDs and find the best one. |
| 32 | + It will then return a SmartCallData along with the result. |
| 33 | +
|
| 34 | + If you want to repeat the API request, specify the SmartCallData object for improved efficiency. |
| 35 | + """ |
| 36 | + |
| 37 | + if call_data is None: |
| 38 | + call_data = SmartCallData( |
| 39 | + evse_id=evse_id, |
| 40 | + last_call=datetime.datetime.now().isoformat(), |
| 41 | + operator_id=None, |
| 42 | + ) |
| 43 | + if call_data.evse_id != evse_id: |
| 44 | + raise ValueError("call_data does not fit to evse_id") |
| 45 | + |
| 46 | + ret = None |
| 47 | + if call_data.operator_id is not None: |
| 48 | + ret = await self.location_by_evse_id(evse_id, call_data.operator_id) |
| 49 | + if len(ret) == 0: |
| 50 | + self.logger.warning(f"empty resp from {call_data.operator_id.name}") |
| 51 | + call_data.operator_id = None |
| 52 | + |
| 53 | + if call_data.operator_id is None: |
| 54 | + self.logger.debug(f"trying all operators") |
| 55 | + for opid in operatorIDs: |
| 56 | + ret = await self.location_by_evse_id(evse_id=evse_id, operator_id=opid) |
| 57 | + if len(ret) != 0: |
| 58 | + call_data.operator_id = opid |
| 59 | + self.logger.info(f"found operator {opid.name}") |
| 60 | + break |
| 61 | + if ret is None: |
| 62 | + return None, call_data |
| 63 | + else: |
| 64 | + return ret[0], call_data |
| 65 | + |
| 66 | + async def location_by_evse_id( |
| 67 | + self, evse_id: str, operator_id: str | OperatorID, **kwargs |
| 68 | + ) -> list[Location]: |
| 69 | + """ |
| 70 | + Perform API request. |
| 71 | + Usually yields just one Location object. |
| 72 | +
|
| 73 | + for the operator id, see chargecloudapi.api.operatorIDs for examples |
| 74 | + """ |
| 75 | + if isinstance(operator_id, OperatorID): |
| 76 | + operator_id = operator_id.op_id |
| 77 | + elif not operator_id: |
| 78 | + raise ValueError("no operator_id given") |
| 79 | + url_template = "https://app.chargecloud.de/emobility:ocpi/{}/app/2.0/locations" |
| 80 | + |
| 81 | + url_obj = URL(url_template.format(operator_id)) |
| 82 | + response = await self.request("GET", url_obj % {"evse": evse_id}) |
| 83 | + |
22 | 84 | response.raise_for_status() |
23 | 85 | json = await response.json() |
24 | 86 | self.logger.debug(f"got json {json}") |
|
0 commit comments