Skip to content

Commit cd28cef

Browse files
drc38lbbrhzn
andauthored
Update to ocpp 2.0.0 to fix blocking (#1423)
* test pre-release candidate * bump to rc3 * Try async validation false * Tidy up * Revert "Tidy up" This reverts commit 3c5c4bd. * Add note * Update ocpp to 2.0.0rc3 * Ocpp 2.0.0 * Ocpp 2.0.0 * Update v201 Type Enums * fix datatype import * fix enums in test * fix datatypes and @action * fix find replace errors * fix token_type * other fixes --------- Co-authored-by: lbbrhzn <[email protected]>
1 parent 22d09ea commit cd28cef

File tree

4 files changed

+237
-219
lines changed

4 files changed

+237
-219
lines changed

custom_components/ocpp/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"iot_class": "local_push",
1414
"issue_tracker": "https://github.com/lbbrhzn/ocpp/issues",
1515
"requirements": [
16-
"ocpp==1.0.0",
16+
"ocpp>=2.0.0",
1717
"websockets>=14.1"
1818
],
1919
"version": "0.6.3"

custom_components/ocpp/ocppv201.py

Lines changed: 79 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,23 +17,24 @@
1717
from ocpp.v201 import call, call_result
1818
from ocpp.v16.enums import ChargePointStatus as ChargePointStatusv16
1919
from ocpp.v201.enums import (
20-
ConnectorStatusType,
21-
GetVariableStatusType,
22-
IdTokenType,
23-
MeasurandType,
24-
OperationalStatusType,
25-
ResetType,
26-
ResetStatusType,
27-
SetVariableStatusType,
28-
AuthorizationStatusType,
29-
TransactionEventType,
30-
ReadingContextType,
31-
RequestStartStopStatusType,
32-
ChargingStateType,
33-
ChargingProfilePurposeType,
34-
ChargingRateUnitType,
35-
ChargingProfileKindType,
36-
ChargingProfileStatus,
20+
Action,
21+
ConnectorStatusEnumType,
22+
GetVariableStatusEnumType,
23+
IdTokenEnumType,
24+
MeasurandEnumType,
25+
OperationalStatusEnumType,
26+
ResetEnumType,
27+
ResetStatusEnumType,
28+
SetVariableStatusEnumType,
29+
AuthorizationStatusEnumType,
30+
TransactionEventEnumType,
31+
ReadingContextEnumType,
32+
RequestStartStopStatusEnumType,
33+
ChargingStateEnumType,
34+
ChargingProfilePurposeEnumType,
35+
ChargingRateUnitEnumType,
36+
ChargingProfileKindEnumType,
37+
ChargingProfileStatusEnumType,
3738
)
3839

3940
from .chargepoint import (
@@ -71,15 +72,15 @@ class InventoryReport:
7172
smart_charging_available: bool = False
7273
reservation_available: bool = False
7374
local_auth_available: bool = False
74-
tx_updated_measurands: list[MeasurandType] = []
75+
tx_updated_measurands: list[MeasurandEnumType] = []
7576

7677

7778
class ChargePoint(cp):
7879
"""Server side representation of a charger."""
7980

8081
_inventory: InventoryReport | None = None
8182
_wait_inventory: asyncio.Event | None = None
82-
_connector_status: list[list[ConnectorStatusType | None]] = []
83+
_connector_status: list[list[ConnectorStatusEnumType | None]] = []
8384
_tx_start_time: datetime | None = None
8485

8586
def __init__(
@@ -254,7 +255,7 @@ async def clear_profile(self):
254255
req: call.ClearChargingProfile = call.ClearChargingProfile(
255256
None,
256257
{
257-
"charging_profile_Purpose": ChargingProfilePurposeType.charging_station_max_profile.value
258+
"charging_profile_Purpose": ChargingProfilePurposeEnumType.charging_station_max_profile.value
258259
},
259260
)
260261
await self.call(req)
@@ -275,10 +276,10 @@ async def set_charge_rate(
275276
schedule: dict = {"id": 1}
276277
if limit_amps < 32:
277278
period["limit"] = limit_amps
278-
schedule["charging_rate_unit"] = ChargingRateUnitType.amps.value
279+
schedule["charging_rate_unit"] = ChargingRateUnitEnumType.amps.value
279280
elif limit_watts < 22000:
280281
period["limit"] = limit_watts
281-
schedule["charging_rate_unit"] = ChargingRateUnitType.watts.value
282+
schedule["charging_rate_unit"] = ChargingRateUnitEnumType.watts.value
282283
else:
283284
await self.clear_profile()
284285
return
@@ -289,14 +290,14 @@ async def set_charge_rate(
289290
{
290291
"id": 1,
291292
"stack_level": 0,
292-
"charging_profile_purpose": ChargingProfilePurposeType.charging_station_max_profile,
293-
"charging_profile_kind": ChargingProfileKindType.relative.value,
293+
"charging_profile_purpose": ChargingProfilePurposeEnumType.charging_station_max_profile,
294+
"charging_profile_kind": ChargingProfileKindEnumType.relative.value,
294295
"charging_schedule": [schedule],
295296
},
296297
)
297298

298299
resp: call_result.SetChargingProfile = await self.call(req)
299-
if resp.status != ChargingProfileStatus.accepted:
300+
if resp.status != ChargingProfileStatusEnumType.accepted:
300301
raise HomeAssistantError(
301302
translation_domain=DOMAIN,
302303
translation_key="set_variables_error",
@@ -308,9 +309,9 @@ async def set_charge_rate(
308309
async def set_availability(self, state: bool = True):
309310
"""Change availability."""
310311
req: call.ChangeAvailability = call.ChangeAvailability(
311-
OperationalStatusType.operative.value
312+
OperationalStatusEnumType.operative.value
312313
if state
313-
else OperationalStatusType.inoperative.value
314+
else OperationalStatusEnumType.inoperative.value
314315
)
315316
await self.call(req)
316317

@@ -319,26 +320,26 @@ async def start_transaction(self) -> bool:
319320
req: call.RequestStartTransaction = call.RequestStartTransaction(
320321
id_token={
321322
"id_token": self._remote_id_tag,
322-
"type": IdTokenType.central.value,
323+
"type": IdTokenEnumType.central.value,
323324
},
324325
remote_start_id=1,
325326
)
326327
resp: call_result.RequestStartTransaction = await self.call(req)
327-
return resp.status == RequestStartStopStatusType.accepted.value
328+
return resp.status == RequestStartStopStatusEnumType.accepted.value
328329

329330
async def stop_transaction(self) -> bool:
330331
"""Request remote stop of current transaction."""
331332
req: call.RequestStopTransaction = call.RequestStopTransaction(
332333
transaction_id=self._metrics[csess.transaction_id.value].value
333334
)
334335
resp: call_result.RequestStopTransaction = await self.call(req)
335-
return resp.status == RequestStartStopStatusType.accepted.value
336+
return resp.status == RequestStartStopStatusEnumType.accepted.value
336337

337338
async def reset(self, typ: str = ""):
338339
"""Hard reset charger unless soft reset requested."""
339-
req: call.Reset = call.Reset(ResetType.immediate)
340+
req: call.Reset = call.Reset(ResetEnumType.immediate)
340341
resp = await self.call(req)
341-
if resp.status != ResetStatusType.accepted.value:
342+
if resp.status != ResetStatusEnumType.accepted.value:
342343
status_suffix: str = f": {resp.status_info}" if resp.status_info else ""
343344
raise HomeAssistantError(
344345
translation_domain=DOMAIN,
@@ -382,7 +383,7 @@ async def get_configuration(self, key: str = "") -> str | None:
382383
translation_placeholders={"message": str(e)},
383384
)
384385
result: dict = resp.get_variable_result[0]
385-
if result["attribute_status"] != GetVariableStatusType.accepted:
386+
if result["attribute_status"] != GetVariableStatusEnumType.accepted:
386387
raise HomeAssistantError(
387388
translation_domain=DOMAIN,
388389
translation_key="get_variables_error",
@@ -405,9 +406,9 @@ async def configure(self, key: str, value: str) -> SetVariableResult:
405406
translation_placeholders={"message": str(e)},
406407
)
407408
result: dict = resp.set_variable_result[0]
408-
if result["attribute_status"] == SetVariableStatusType.accepted:
409+
if result["attribute_status"] == SetVariableStatusEnumType.accepted:
409410
return SetVariableResult.accepted
410-
elif result["attribute_status"] == SetVariableStatusType.reboot_required:
411+
elif result["attribute_status"] == SetVariableStatusEnumType.reboot_required:
411412
return SetVariableResult.reboot_required
412413
else:
413414
raise HomeAssistantError(
@@ -416,7 +417,7 @@ async def configure(self, key: str, value: str) -> SetVariableResult:
416417
translation_placeholders={"message": str(result)},
417418
)
418419

419-
@on("BootNotification")
420+
@on(Action.boot_notification)
420421
def on_boot_notification(self, charging_station, reason, **kwargs):
421422
"""Perform OCPP callback."""
422423
resp = call_result.BootNotification(
@@ -432,7 +433,7 @@ def on_boot_notification(self, charging_station, reason, **kwargs):
432433
self._register_boot_notification()
433434
return resp
434435

435-
@on("Heartbeat")
436+
@on(Action.heartbeat)
436437
def on_heartbeat(self, **kwargs):
437438
"""Perform OCPP callback."""
438439
return call_result.Heartbeat(current_time=datetime.now(tz=UTC).isoformat())
@@ -448,7 +449,7 @@ def _report_evse_status(self, evse_id: int, evse_status_v16: ChargePointStatusv1
448449
)
449450
self.hass.async_create_task(self.update(self.central.cpid))
450451

451-
@on("StatusNotification")
452+
@on(Action.status_notification)
452453
def on_status_notification(
453454
self, timestamp: str, connector_status: str, evse_id: int, connector_id: int
454455
):
@@ -460,25 +461,25 @@ def on_status_notification(
460461
connector_id - len(self._connector_status[evse_id - 1])
461462
)
462463

463-
evse: list[ConnectorStatusType] = self._connector_status[evse_id - 1]
464-
evse[connector_id - 1] = ConnectorStatusType(connector_status)
465-
evse_status: ConnectorStatusType | None = None
464+
evse: list[ConnectorStatusEnumType] = self._connector_status[evse_id - 1]
465+
evse[connector_id - 1] = ConnectorStatusEnumType(connector_status)
466+
evse_status: ConnectorStatusEnumType | None = None
466467
for status in evse:
467468
if status is None:
468469
evse_status = status
469470
break
470471
else:
471472
evse_status = status
472-
if status != ConnectorStatusType.available:
473+
if status != ConnectorStatusEnumType.available:
473474
break
474475
evse_status_v16: ChargePointStatusv16 | None
475476
if evse_status is None:
476477
evse_status_v16 = None
477-
elif evse_status == ConnectorStatusType.available:
478+
elif evse_status == ConnectorStatusEnumType.available:
478479
evse_status_v16 = ChargePointStatusv16.available
479-
elif evse_status == ConnectorStatusType.faulted:
480+
elif evse_status == ConnectorStatusEnumType.faulted:
480481
evse_status_v16 = ChargePointStatusv16.faulted
481-
elif evse_status == ConnectorStatusType.unavailable:
482+
elif evse_status == ConnectorStatusEnumType.unavailable:
482483
evse_status_v16 = ChargePointStatusv16.unavailable
483484
else:
484485
evse_status_v16 = ChargePointStatusv16.preparing
@@ -488,15 +489,15 @@ def on_status_notification(
488489

489490
return call_result.StatusNotification()
490491

491-
@on("FirmwareStatusNotification")
492-
@on("MeterValues")
493-
@on("LogStatusNotification")
494-
@on("NotifyEvent")
492+
@on(Action.firmware_status_notification)
493+
@on(Action.meter_values)
494+
@on(Action.log_status_notification)
495+
@on(Action.notify_event)
495496
def ack(self, **kwargs):
496497
"""Perform OCPP callback."""
497498
return call_result.StatusNotification()
498499

499-
@on("NotifyReport")
500+
@on(Action.notify_report)
500501
def on_report(self, request_id: int, generated_at: str, seq_no: int, **kwargs):
501502
"""Perform OCPP callback."""
502503
if self._wait_inventory is None:
@@ -559,23 +560,23 @@ def on_report(self, request_id: int, generated_at: str, seq_no: int, **kwargs):
559560
characteristics: dict = report_data["variable_characteristics"]
560561
values: str = characteristics.get("values_list", "")
561562
self._inventory.tx_updated_measurands = [
562-
MeasurandType(s) for s in values.split(",")
563+
MeasurandEnumType(s) for s in values.split(",")
563564
]
564565

565566
if not kwargs.get("tbc", False):
566567
self._wait_inventory.set()
567568
return call_result.NotifyReport()
568569

569-
@on("Authorize")
570+
@on(Action.authorize)
570571
def on_authorize(self, id_token: dict, **kwargs):
571572
"""Perform OCPP callback."""
572-
status: str = AuthorizationStatusType.unknown.value
573+
status: str = AuthorizationStatusEnumType.unknown.value
573574
token_type: str = id_token["type"]
574575
token: str = id_token["id_token"]
575576
if (
576-
(token_type == IdTokenType.iso14443)
577-
or (token_type == IdTokenType.iso15693)
578-
or (token_type == IdTokenType.central)
577+
(token_type == IdTokenEnumType.iso14443)
578+
or (token_type == IdTokenEnumType.iso15693)
579+
or (token_type == IdTokenEnumType.central)
579580
):
580581
status = self.get_authorization_status(token)
581582
return call_result.Authorize(id_token_info={"status": status})
@@ -586,7 +587,7 @@ def _set_meter_values(self, tx_event_type: str, meter_values: list[dict]):
586587
measurands: list[MeasurandValue] = []
587588
for sampled_value in meter_value["sampled_value"]:
588589
measurand: str = sampled_value.get(
589-
"measurand", MeasurandType.energy_active_import_register.value
590+
"measurand", MeasurandEnumType.energy_active_import_register.value
590591
)
591592
value: float = sampled_value["value"]
592593
context: str = sampled_value.get("context", None)
@@ -602,11 +603,11 @@ def _set_meter_values(self, tx_event_type: str, meter_values: list[dict]):
602603
)
603604
converted_values.append(measurands)
604605

605-
if (tx_event_type == TransactionEventType.started.value) or (
606-
(tx_event_type == TransactionEventType.updated.value)
606+
if (tx_event_type == TransactionEventEnumType.started.value) or (
607+
(tx_event_type == TransactionEventEnumType.updated.value)
607608
and (self._metrics[csess.meter_start].value is None)
608609
):
609-
energy_measurand = MeasurandType.energy_active_import_register.value
610+
energy_measurand = MeasurandEnumType.energy_active_import_register.value
610611
for meter_value in converted_values:
611612
for measurand_item in meter_value:
612613
if measurand_item.measurand == energy_measurand:
@@ -617,9 +618,9 @@ def _set_meter_values(self, tx_event_type: str, meter_values: list[dict]):
617618

618619
self.process_measurands(converted_values, True)
619620

620-
if tx_event_type == TransactionEventType.ended.value:
621+
if tx_event_type == TransactionEventEnumType.ended.value:
621622
measurands_in_tx: set[str] = set()
622-
tx_end_context = ReadingContextType.transaction_end.value
623+
tx_end_context = ReadingContextEnumType.transaction_end.value
623624
for meter_value in converted_values:
624625
for measurand_item in meter_value:
625626
if measurand_item.context == tx_end_context:
@@ -633,9 +634,15 @@ def _set_meter_values(self, tx_event_type: str, meter_values: list[dict]):
633634
):
634635
self._metrics[measurand].value = 0
635636

636-
@on("TransactionEvent")
637+
@on(Action.transaction_event)
637638
def on_transaction_event(
638-
self, event_type, timestamp, trigger_reason, seq_no, transaction_info, **kwargs
639+
self,
640+
event_type,
641+
timestamp,
642+
trigger_reason,
643+
seq_no,
644+
transaction_info,
645+
**kwargs,
639646
):
640647
"""Perform OCPP callback."""
641648
offline: bool = kwargs.get("offline", False)
@@ -647,27 +654,27 @@ def on_transaction_event(
647654
state = transaction_info["charging_state"]
648655
evse_id: int = kwargs["evse"]["id"] if "evse" in kwargs else 1
649656
evse_status_v16: ChargePointStatusv16 | None = None
650-
if state == ChargingStateType.idle:
657+
if state == ChargingStateEnumType.idle:
651658
evse_status_v16 = ChargePointStatusv16.available
652-
elif state == ChargingStateType.ev_connected:
659+
elif state == ChargingStateEnumType.ev_connected:
653660
evse_status_v16 = ChargePointStatusv16.preparing
654-
elif state == ChargingStateType.suspended_evse:
661+
elif state == ChargingStateEnumType.suspended_evse:
655662
evse_status_v16 = ChargePointStatusv16.suspended_evse
656-
elif state == ChargingStateType.suspended_ev:
663+
elif state == ChargingStateEnumType.suspended_ev:
657664
evse_status_v16 = ChargePointStatusv16.suspended_ev
658-
elif state == ChargingStateType.charging:
665+
elif state == ChargingStateEnumType.charging:
659666
evse_status_v16 = ChargePointStatusv16.charging
660667
if evse_status_v16:
661668
self._report_evse_status(evse_id, evse_status_v16)
662669

663670
response = call_result.TransactionEvent()
664671
id_token = kwargs.get("id_token")
665672
if id_token:
666-
response.id_token_info = {"status": AuthorizationStatusType.accepted}
673+
response.id_token_info = {"status": AuthorizationStatusEnumType.accepted}
667674
id_tag_string: str = id_token["type"] + ":" + id_token["id_token"]
668675
self._metrics[cstat.id_tag.value].value = id_tag_string
669676

670-
if event_type == TransactionEventType.started.value:
677+
if event_type == TransactionEventEnumType.started.value:
671678
self._tx_start_time = t
672679
tx_id: str = transaction_info["transaction_id"]
673680
self._metrics[csess.transaction_id.value].value = tx_id
@@ -678,7 +685,7 @@ def on_transaction_event(
678685
duration_minutes: int = ((t - self._tx_start_time).seconds + 59) // 60
679686
self._metrics[csess.session_time].value = duration_minutes
680687
self._metrics[csess.session_time].unit = UnitOfTime.MINUTES
681-
if event_type == TransactionEventType.ended.value:
688+
if event_type == TransactionEventEnumType.ended.value:
682689
self._metrics[csess.transaction_id.value].value = ""
683690
self._metrics[cstat.id_tag.value].value = ""
684691

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
colorlog==6.9.0
22
uv>=0.4
33
ruff==0.8.5
4-
ocpp==1.0.0
4+
ocpp==2.0.0
55
websockets==14.1
66
jsonschema==4.23.0
77
pre-commit==4.0.1

0 commit comments

Comments
 (0)