Skip to content

Commit c6933ef

Browse files
shankarithe-bay-kay
authored andcommitted
Enable AC ISO 15118 properly with two payment modes
- Use a nodered flow that only supports AC ISO 15118-2 EIM and PnC - Patch SwitchEV to plumb through the payment option to the ISO 15118 library by following the EnergyTransfer route #44 (comment) https://lfenergy.zulipchat.com/#narrow/stream/417677-EVerest.3A-Car-com.2E/topic/.E2.9C.94.20Update.20Node-red.20flows.20because.20of.20JsEvManager.20commit/near/443617217 - Enable `iso15118car` debug logging so that we can see the decoded EXI messages in the absence of https://lfenergy.zulipchat.com/#narrow/stream/417677-EVerest.3A-Car-com.2E/topic/EXI.20V2G.20Decoder.20Recommendations/near/442318988 - disable the maeve patches to remove the LB since it is already removed in the updated branch Testing done: ``` patching file docker-compose.yml Patching the CSMS to enable local mo root patching file 'config/manager/config.toml' Patching the CSMS to enable local mo root patching file 'manager/handlers/ocpp201/authorize.go' Starting the CSMS ``` ``` [+] Running 4/4 ✔ Container maeve-csms-firestore-1 Running 0.0s ✔ Container maeve-csms-mqtt-1 Healthy 0.1s ✔ Container maeve-csms-manager-1 Healthy 0.2s ✔ Container maeve-csms-gateway-1 Started 0.2s Waiting 5s for CSMS to start... MaEVe CSMS started, adding charge station with Security Profile 3 (note: profiles in MaEVe start with 0 so SP-2 == OCPP SP-3) Charge station added, adding user token API calls to CSMS finished, starting EVerest... ``` ``` ✔ Network everest-ac-demo_default Created 0.1s ✔ Container everest-ac-demo-mqtt-server-1 Healthy 0.1s ✔ Container everest-ac-demo-nodered-1 Healthy 0.2s ✔ Container everest-ac-demo-manager-1 Healthy 0.1s Successfully copied 60.9kB to everest-ac-demo-nodered-1:/config/config-sil-two-evse-flow.json everest-ac-demo-nodered-1 Successfully copied 6.66kB to everest-ac-demo-manager-1:/ext/source/config/config-sil-ocpp201-pnc.yaml Successfully copied 8.19kB to everest-ac-demo-manager-1:/tmp/ Successfully copied 3.58kB to everest-ac-demo-manager-1:/ext/source/build/dist/etc/everest/default_logging.cfg fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/main/x86_64/APKINDEX.tar.gz fetch https://dl-cdn.alpinelinux.org/alpine/v3.17/community/x86_64/APKINDEX.tar.gz fetch https://dl-cdn.alpinelinux.org/alpine/edge/testing/x86_64/APKINDEX.tar.gz (1/1) Installing patch (2.7.6-r9) Executing busybox-1.35.0-r29.trigger OK: 1379 MiB in 230 packages patching file source/build/dist/libexec/everest/3rd_party/josev/iso15118/evcc/controller/interface.py patching file source/build/dist/libexec/everest/3rd_party/josev/iso15118/evcc/controller/simulator.py patching file source/build/dist/libexec/everest/3rd_party/josev/iso15118/evcc/states/iso15118_2_states.py Successfully copied 29.2kB to everest-ac-demo-manager-1:/ext/source/build ``` ``` 2024-06-09 19:41:31.667368 [DEBG] iso15118_car pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Decoded message (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message":{"Header":{"SessionID":"04337FC4777FB77D"},"Body":{"ServiceDiscoveryRes":{"ResponseCode":"OK","PaymentOptionList":{"PaymentOption":["ExternalPayment","Contract"]},"ChargeService":{"ServiceID":1,"ServiceCategory":"EVCharging","FreeService":false,"SupportedEnergyTransferMode":{"EnergyTransferMode":["AC_single_phase_core","AC_three_phase_core"]}},"ServiceList":{"Service":[{"ServiceID":2,"ServiceName":"Certificate","ServiceCategory":"ContractCertificate","FreeService":true}]}}}}} 2024-06-09 19:41:31.670311 [WARN] iso15118_car pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: V2G_PAYMENT: in function read value from state AuthEnum.PNC_V2 2024-06-09 19:41:31.671413 [DEBG] iso15118_car pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "04337FC4777FB77D"}, "Body": {"PaymentServiceSelectionReq": {"SelectedPaymentOption": "Contract", "SelectedServiceList": {"SelectedService": [{"ServiceID": 1}]}}}}} 2024-06-09 19:41:34.155595 [INFO] ocpp:OCPP201 :: CSMS certificate status: Accepted 2024-06-09 19:41:34.159815 [INFO] auth:Auth :: Providing authorization to connector#1 2024-06-09 19:41:35.873697 [DEBG] iso15118_car pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Message to encode (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message": {"Header": {"SessionID": "04337FC4777FB77D"}, "Body": {"ChargeParameterDiscoveryReq": {"RequestedEnergyTransferMode": "AC_three_phase_core", "AC_EVChargeParameter": {"DepartureTime": 0, "EAmount": {"Value": 60, "Multiplier": 0, "Unit": "Wh"}, "EVMaxVoltage": {"Value": 400, "Multiplier": 0, "Unit": "V"}, "EVMaxCurrent": {"Value": 32000, "Multiplier": -3, "Unit": "A"}, "EVMinCurrent": {"Value": 10, "Multiplier": 0, "Unit": "A"}}}}}} 2024-06-09 19:41:36.948664 [DEBG] iso15118_car pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: Decoded message (ns=urn:iso:15118:2:2013:MsgDef): {"V2G_Message":{"Header":{"SessionID":"04337FC4777FB77D"},"Body":{"ChargeParameterDiscoveryRes":{"ResponseCode":"OK","EVSEProcessing":"Finished","SAScheduleList":{"SAScheduleTuple":[{"SAScheduleTupleID":1,"PMaxSchedule":{"PMaxScheduleEntry":[{"RelativeTimeInterval":{"start":0,"duration":86400},"PMax":{"Multiplier":0,"Unit":"W","Value":22080}}]}}]},"AC_EVSEChargeParameter":{"AC_EVSEStatus":{"NotificationMaxDelay":0,"EVSENotification":"None","RCD":false},"EVSENominalVoltage":{"Multiplier":-1,"Unit":"V","Value":2300},"EVSEMaxCurrent":{"Multiplier":-1,"Unit":"A","Value":320}}}}}} ``` Signed-off-by: Shankari <[email protected]> Signed-off-by: the-bay-kay <[email protected]>
1 parent 3f22b7d commit c6933ef

File tree

4 files changed

+2405
-3
lines changed

4 files changed

+2405
-3
lines changed

demo-iso15118-2-ac-plus-ocpp.sh

+11-3
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ cd "${DEMO_DIR}" || exit 1
9292

9393
echo "Cloning EVerest from ${DEMO_REPO} into ${DEMO_DIR}/everest-demo"
9494
git clone --branch "${DEMO_BRANCH}" "${DEMO_REPO}" everest-demo
95+
# cp -r "${DEMO_REPO}" everest-demo
9596

9697
echo "Run with Edgeshark? $RUN_WITH_EDGESHARK"
9798

@@ -129,9 +130,6 @@ if [[ "$DEMO_VERSION" != v1.6j ]]; then
129130
fi
130131
else
131132
cp ../everest-demo/manager/cached_certs_correct_name_emaid.tar.gz .
132-
133-
echo "Patching the CSMS to disable load balancer"
134-
patch -p1 -i ../everest-demo/maeve/maeve-csms-no-lb.patch
135133
fi
136134

137135
# Set up certificates for SP2 and SP3
@@ -356,7 +354,17 @@ fi
356354

357355
pushd everest-demo || exit 1
358356
docker compose --project-name everest-ac-demo --file "${DEMO_COMPOSE_FILE_NAME}" up -d --wait
357+
358+
# Configure and restart nodered
359+
docker cp nodered/config/config-sil-iso15118-ac-flow.json everest-ac-demo-nodered-1:/config/config-sil-two-evse-flow.json
360+
docker restart everest-ac-demo-nodered-1
361+
362+
# Configure and restart EVerest
359363
docker cp config-sil-ocpp201-pnc.yaml everest-ac-demo-manager-1:/ext/source/config/config-sil-ocpp201-pnc.yaml
364+
docker cp manager/enable_payment_method.patch everest-ac-demo-manager-1:/tmp/
365+
docker cp manager/enable_evcc_logging.cfg everest-ac-demo-manager-1:/ext/source/build/dist/etc/everest/default_logging.cfg
366+
docker exec everest-ac-demo-manager-1 /bin/bash -c "apk add patch && cd /ext && patch -p0 -i /tmp/enable_payment_method.patch"
367+
360368
if [[ "$DEMO_VERSION" =~ sp2 || "$DEMO_VERSION" =~ sp3 ]]; then
361369
docker cp manager/cached_certs_correct_name_emaid.tar.gz everest-ac-demo-manager-1:/ext/source/build
362370
docker exec everest-ac-demo-manager-1 /bin/bash -c "pushd /ext/source/build && tar xf cached_certs_correct_name_emaid.tar.gz"

manager/enable_evcc_logging.cfg

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# for documentation on this file format see:
2+
# https://www.boost.org/doc/libs/1_54_0/libs/log/doc/html/log/detailed/utilities.html#log.detailed.utilities.setup.filter_formatter
3+
4+
[Core]
5+
DisableLogging=false
6+
7+
# To get debug logs of only one module, add the "%Process% contains" filter, e.g.:
8+
#
9+
# "(%Process% contains OCPP201 and %Severity% >= DEBG)"
10+
#
11+
# whereas "OCPP201" is the value of the field `active_modules.NAME.module` in the respective /config/config-*.yaml.
12+
Filter="%Severity% >= INFO or (%Process% contains iso15118_car and %Severity% >= DEBG)"
13+
14+
[Sinks.Console]
15+
Destination=Console
16+
# Filter="%Target% contains \"MySink1\""
17+
Format="%TimeStamp% [%Severity%] \033[1;32m%Process%\033[0m \033[1;36m%function%\033[0m \033[1;30m%file%:\033[0m\033[1;32m%line%\033[0m: %Message%"
18+
Asynchronous=false
19+
AutoFlush=true
20+
SeverityStringColorDebug="\033[1;30m"
21+
SeverityStringColorInfo="\033[1;37m"
22+
SeverityStringColorWarning="\033[1;33m"
23+
SeverityStringColorError="\033[1;31m"
24+
SeverityStringColorCritical="\033[1;35m"

manager/enable_payment_method.patch

+114
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
--- ext-switchev-iso15118/iso15118/evcc/controller/interface.py
2+
+++ source/build/dist/libexec/everest/3rd_party/josev/iso15118/evcc/controller/interface.py
3+
@@ -109,6 +109,15 @@
4+
raise NotImplementedError
5+
6+
@abstractmethod
7+
+ async def get_selected_auth_option(
8+
+ self, protocol: Protocol
9+
+ ) -> AuthEnum:
10+
+ """
11+
+ Gets the auth transfer mode requested for the current charging session.
12+
+ """
13+
+ raise NotImplementedError
14+
+
15+
+ @abstractmethod
16+
async def get_energy_transfer_mode(
17+
self, protocol: Protocol
18+
) -> EnergyTransferModeEnum:
19+
--- ext-switchev-iso15118/iso15118/evcc/controller/simulator.py
20+
+++ source/build/dist/libexec/everest/3rd_party/josev/iso15118/evcc/controller/simulator.py
21+
@@ -53,6 +53,7 @@
22+
SAScheduleTupleEntry as SAScheduleTupleEntryDINSPEC,
23+
)
24+
from iso15118.shared.messages.enums import (
25+
+ AuthEnum,
26+
ControlMode,
27+
DCEVErrorCode,
28+
EnergyTransferModeEnum,
29+
@@ -233,11 +234,18 @@
30+
logger.error(f"Invalid protocol '{protocol}', can't determine EVCCID")
31+
raise InvalidProtocolError
32+
33+
+ async def get_selected_auth_option(
34+
+ self, protocol: Protocol
35+
+ ) -> AuthEnum:
36+
+ """Overrides EVControllerInterface.get_selected_auth_option()."""
37+
+ return AuthEnum(EVEREST_EV_STATE.PaymentOption)
38+
+
39+
async def get_energy_transfer_mode(
40+
self, protocol: Protocol
41+
) -> EnergyTransferModeEnum:
42+
"""Overrides EVControllerInterface.get_energy_transfer_mode()."""
43+
return EnergyTransferModeEnum(EVEREST_EV_STATE.EnergyTransferMode)
44+
+
45+
46+
async def get_supported_energy_services(self) -> List[ServiceV20]:
47+
"""Overrides EVControllerInterface.get_energy_transfer_service()."""
48+
--- ext-switchev-iso15118/iso15118/evcc/states/iso15118_2_states.py
49+
+++ source/build/dist/libexec/everest/3rd_party/josev/iso15118/evcc/states/iso15118_2_states.py
50+
@@ -193,8 +193,9 @@
51+
self.stop_state_machine("ChargeService not offered")
52+
return
53+
54+
- self.select_auth_mode(service_discovery_res.auth_option_list.auth_options)
55+
+ logger.warn("received auth options list %s" % service_discovery_res.auth_option_list.auth_options)
56+
await self.select_services(service_discovery_res)
57+
+ await self.select_auth_mode(service_discovery_res.auth_option_list.auth_options)
58+
await self.select_energy_transfer_mode()
59+
60+
charge_service: ChargeService = service_discovery_res.charge_service
61+
@@ -262,12 +263,13 @@
62+
self.comm_session.selected_energy_mode.value.startswith("AC")
63+
)
64+
65+
- def select_auth_mode(self, auth_option_list: List[AuthEnum]):
66+
+ async def select_auth_mode(self, auth_option_list: List[AuthEnum]):
67+
"""
68+
Check if an authorization mode (aka payment option in ISO 15118-2) was
69+
saved from a previously paused communication session and reuse for
70+
resumed session, otherwise request from EV controller.
71+
"""
72+
+ logger.warn("V2G_PAYMENT: in function received auth options list %s" % auth_option_list)
73+
if evcc_settings.ev_session_context.selected_auth_option:
74+
logger.debug(
75+
"Reusing authorization option "
76+
@@ -279,15 +281,30 @@
77+
)
78+
evcc_settings.ev_session_context.selected_auth_option = None
79+
else:
80+
- # Choose Plug & Charge (pnc) or External Identification Means (eim)
81+
- # as the selected authorization option. The car manufacturer might
82+
- # have a mechanism to determine a user-defined or default
83+
- # authorization option. This implementation favors pnc, but
84+
- # feel free to change if need be.
85+
- if AuthEnum.PNC_V2 in auth_option_list and self.comm_session.is_tls:
86+
- self.comm_session.selected_auth_option = AuthEnum.PNC_V2
87+
+ logger.warn("V2G_PAYMENT: about to read value from state")
88+
+ self.comm_session.selected_auth_option = (
89+
+ await self.comm_session.ev_controller.get_selected_auth_option(
90+
+ Protocol.ISO_15118_2
91+
+ )
92+
+ )
93+
+ logger.warn("V2G_PAYMENT: in function read value from state %s" % self.comm_session.selected_auth_option)
94+
+ if self.comm_session.selected_auth_option is not None:
95+
+ logger.debug(
96+
+ "V2G_PAYMENT: Found Payment Option %s passed in from the PyJoseV module, using it" % self.comm_session.selected_auth_option
97+
+ )
98+
else:
99+
- self.comm_session.selected_auth_option = AuthEnum.EIM_V2
100+
+ logger.debug(
101+
+ "V2G_PAYMENT: No previous paused session, no PaymentOption set, using TLS flag %s to decide auth method" % self.comm_session.is_tls
102+
+ )
103+
+ # Choose Plug & Charge (pnc) or External Identification Means (eim)
104+
+ # as the selected authorization option. The car manufacturer might
105+
+ # have a mechanism to determine a user-defined or default
106+
+ # authorization option. This implementation favors pnc, but
107+
+ # feel free to change if need be.
108+
+ if AuthEnum.PNC_V2 in auth_option_list and self.comm_session.is_tls:
109+
+ self.comm_session.selected_auth_option = AuthEnum.PNC_V2
110+
+ else:
111+
+ self.comm_session.selected_auth_option = AuthEnum.EIM_V2
112+
113+
async def select_services(self, service_discovery_res: ServiceDiscoveryRes):
114+
"""

0 commit comments

Comments
 (0)