Skip to content

Commit 5d46630

Browse files
Try different operator ids to get results for more stations
1 parent 7f2c0d6 commit 5d46630

4 files changed

Lines changed: 91 additions & 18 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "pychargecloud"
3-
version = "0.0.5"
3+
version = "0.1.0"
44
dependencies = [
55
"aiohttp",
66
"yarl",

src/chargecloudapi/api.py

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,86 @@
1-
import aiohttp.client_exceptions
1+
import datetime
2+
23
import pydantic
34
from aiohttp import ClientSession, ClientResponse
45
from yarl import URL
56
from .models import *
67
import logging
78

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+
]
914

1015

1116
class Api:
1217
"""Class to make authenticated requests."""
1318

14-
def __init__(self, websession: ClientSession, base_url: str | None = None):
19+
def __init__(self, websession: ClientSession):
1520
"""Initialize the auth."""
1621
self.websession = websession
17-
self.base_url = URL(base_url or DEFAULT_URL)
1822
self.logger = logging.getLogger("chargecloudapi")
1923

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+
2284
response.raise_for_status()
2385
json = await response.json()
2486
self.logger.debug(f"got json {json}")

src/chargecloudapi/models.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ class Coordinates(BaseModel):
1515
class Connector(BaseModel):
1616
id: int
1717
status: Status
18-
standard: Literal["IEC_62196_T2", "IEC_62196_T2_COMBO", "DOMESTIC_F", "CHADEMO", "TESLA"]
18+
standard: Literal[
19+
"IEC_62196_T2", "IEC_62196_T2_COMBO", "DOMESTIC_F", "CHADEMO", "TESLA"
20+
]
1921
format: Literal["CABLE", "SOCKET"]
2022
power_type: Literal["AC_1_PHASE", "AC_3_PHASE", "DC"]
2123
ampere: float
@@ -79,3 +81,14 @@ class Response(BaseModel):
7981
status_code: str
8082
status_message: str
8183
timestamp: DateTimeISO8601
84+
85+
86+
class OperatorID(BaseModel):
87+
name: str
88+
op_id: str
89+
90+
91+
class SmartCallData(BaseModel):
92+
evse_id: str
93+
last_call: DateTimeISO8601
94+
operator_id: OperatorID | None

src/main.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import sys
22

33
import chargecloudapi
4+
from chargecloudapi.api import operatorIDs
45
import aiohttp
56
import asyncio
67
import logging
78

89

910
async def main():
10-
operator_IDs = {
11-
"maingau": "606a0da0dfdd338ee4134605653d4fd8",
12-
"SW Kiel": "6336fe713f2eb7fa04b97ff6651b76f8",
13-
"Rheinenergie": "c4ce9bb82a86766833df8a4818fa1b5c",
14-
}
1511
evse_ids = [
1612
"DE*REK*E100241*002",
1713
"DE*REK*E100196*001",
@@ -21,18 +17,20 @@ async def main():
2117
"DE*UFC*E210004",
2218
"DE*ION*E207101",
2319
"DE*EDR*E11000150*2",
20+
"DESWME052601",
21+
"DE*SWM*E052601",
22+
"DE*TNK*E00136*02",
2423
]
2524
results: dict[str, dict[str, list[chargecloudapi.Location]]] = {
2625
evse_id: {} for evse_id in evse_ids
2726
}
28-
for operator_name, operator_id in operator_IDs.items():
27+
for operator_id in operatorIDs:
2928
async with aiohttp.ClientSession() as session:
30-
base_url = f"https://app.chargecloud.de/emobility:ocpi/{operator_id}/app/2.0/locations"
31-
api = chargecloudapi.Api(session, base_url=base_url)
29+
api = chargecloudapi.Api(session)
3230

3331
for evse_id in evse_ids:
34-
locations = await api.location_by_evse_id(evse_id)
35-
results[evse_id][operator_name] = locations
32+
locations = await api.location_by_evse_id(evse_id, operator_id)
33+
results[evse_id][operator_id.name] = locations
3634

3735
for evse_id, res in results.items():
3836
print(f"evse_id {evse_id}:")

0 commit comments

Comments
 (0)