PevMode: added contractAuthentication

This commit is contained in:
uhi22 2022-12-02 13:02:40 +01:00
parent a9b6e826cd
commit 0f7c7122b5
5 changed files with 1450 additions and 16 deletions

20
doc/bug_analysis.md Normal file
View file

@ -0,0 +1,20 @@
# Open issues
## Issue12: Alpi reports "sequence error" for CableCheck
- with version v0.3.
- maybe he expects the state C, or something is wrong with the sequence before.
# Closed issues
## [Solved] Issue10: Alpi says SequenceError in ChargeParameterDiscoveryRes
- ServicePaymentSelectionRes says "ResponseCode": "OK", and has no more fields.
- Afterwards we send ChargeParameterDiscoveryReq and get ChargeParameterDiscoveryRes containing "ResponseCode": "FAILED_SequenceError".
- Analysis: In the ISO case, the ChargeParameterDiscoveryReq comes after the AuthorizationRes with EVSEProcessing=Finished. But we are using DIN, and here there is no AuthorizationRes, but ContractAuthentication instead. But, this does not
have a field EVSEProcessing. And in DIN, we have dinContractAuthenticationResType, which contains ResponseCode and EVSEProcessing (see OpenV2G, dinEXIDatatypes.h).
- Solution: Send ContractAuthenticationReq after ServicePaymentSelectionRes, and repeat it until it says "finished". Test pass with v0.3.
## [Solved] Issue11: TCP connection fails on Alpi
- Observation: On Alpitronics, the SDP works, but the TCP connect fails. The connection is rejected by the charger.
- Root cause: We used fixed port 15118 for the TCP. This is not intended, even it works on other chargers (ABB).
- Solution: use the TCP port, which was announced in the SDP response.
- Test pass with version v0.2-9-ga9b6e82.

View file

@ -27,15 +27,16 @@ Test results tbd
Test site: e.g. https://www.goingelectric.de/stromtankstellen/Deutschland/Ingolstadt/Dehner-Garten-Center-Degenhartstrasse-Degenhartstrasse-2/71112/
Test results of version v0.2
Test results of version v0.3
- [x] SLAC
- [x] SDP
- [ ] TCP connection
- [ ] EXI
- [ ] DIN SupportedApplicationProtocol
- [ ] DIN SessionSetup
- [ ] DIN ServiceDiscovery
- [ ] DIN ChargeParameterDiscovery
- [x] TCP connection
- [x] EXI
- [x] DIN SupportedApplicationProtocol
- [x] DIN SessionSetup
- [x] DIN ServiceDiscovery
- [x] DIN ChargeParameterDiscovery
- [x] DIN ContractAuthentication
- [ ] DIN CableCheck
- [ ] DIN PreCharge
- [ ] DIN PowerDelivery, CurrentDemand

View file

@ -17,7 +17,7 @@ stateWaitForSupportedApplicationProtocolResponse = 3
stateWaitForSessionSetupResponse = 4
stateWaitForServiceDiscoveryResponse = 5
stateWaitForServicePaymentSelectionResponse = 6
stateWaitForAuthorizationResponse = 7
stateWaitForContractAuthenticationResponse = 7
stateWaitForChargeParameterDiscoveryResponse = 8
stateWaitForCableCheckResponse = 9
stateWaitForPreChargeResponse = 10
@ -142,13 +142,51 @@ class fsmPev():
self.addToTrace(strConverterResult)
if (strConverterResult.find("ServicePaymentSelectionRes")>0):
# todo: check the request content, and fill response parameters
self.addToTrace("Will send ChargeParameterDiscoveryReq")
msg = addV2GTPHeader(exiEncode("EDE_"+self.sessionId)) # EDE for Encode, Din, ChargeParameterDiscovery. We ignore Authorization, not specified in DIN.
self.addToTrace("Will send ContractAuthenticationReq")
msg = addV2GTPHeader(exiEncode("EDL_"+self.sessionId)) # EDL for Encode, Din, ContractAuthenticationReq.
self.addToTrace("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForChargeParameterDiscoveryResponse)
self.numberOfContractAuthenticationReq = 1 # This is the first request.
self.enterState(stateWaitForContractAuthenticationResponse)
if (self.isTooLong()):
self.enterState(stateSequenceTimeout)
def stateFunctionWaitForContractAuthenticationResponse(self):
if (self.cyclesInState<30): # The first second in the state just do nothing.
return
if (len(self.rxData)>0):
self.addToTrace("In state WaitForContractAuthentication, received " + prettyHexMessage(self.rxData))
exidata = removeV2GTPHeader(self.rxData)
self.rxData = []
strConverterResult = exiDecode(exidata, "DD") # Decode DIN
self.addToTrace(strConverterResult)
if (strConverterResult.find("ContractAuthenticationRes")>0):
# In normal case, we can have two results here: either the Authentication is needed (the user
# needs to authorize by RFID card or app, or something like this.
# Or, the authorization is finished. This is shown by EVSEProcessing=Finished.
if (strConverterResult.find('"EVSEProcessing": "Finished"')>0):
self.addToTrace("It is Finished. Will send ChargeParameterDiscoveryReq")
msg = addV2GTPHeader(exiEncode("EDE_"+self.sessionId)) # EDE for Encode, Din, ChargeParameterDiscovery.
self.addToTrace("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForChargeParameterDiscoveryResponse)
else:
# Not (yet) finished.
if (self.numberOfContractAuthenticationReq>=120): # approx 120 seconds, maybe the user searches two minutes for his RFID card...
self.addToTrace("Authentication lasted too long. " + str(self.numberOfContractAuthenticationReq) + " Giving up.")
self.enterState(stateSequenceTimeout)
else:
# Try again.
self.numberOfContractAuthenticationReq += 1 # count the number of tries.
self.addToTrace("Not (yet) finished. Will again send ContractAuthenticationReq #" + str(self.numberOfContractAuthenticationReq))
msg = addV2GTPHeader(exiEncode("EDL_"+self.sessionId)) # EDL for Encode, Din, ContractAuthenticationReq.
self.addToTrace("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
# We just stay in the same state, until the timeout elapses.
self.enterState(stateWaitForContractAuthenticationResponse)
if (self.isTooLong()):
# The timeout in case if nothing is received at all.
self.enterState(stateSequenceTimeout)
def stateFunctionWaitForChargeParameterDiscoveryResponse(self):
if (len(self.rxData)>0):
@ -159,6 +197,8 @@ class fsmPev():
self.addToTrace(strConverterResult)
if (strConverterResult.find("ChargeParameterDiscoveryRes")>0):
# todo: check the request content, and fill response parameters
# todo: if the response is "OK", pull the CP line to state C here.
# self.hardwareInterface.changeToStateC()
self.addToTrace("Will send CableCheckReq")
msg = addV2GTPHeader(exiEncode("EDF_"+self.sessionId)) # EDF for Encode, Din, CableCheck
self.addToTrace("responding " + prettyHexMessage(msg))
@ -240,6 +280,7 @@ class fsmPev():
stateWaitForSessionSetupResponse: stateFunctionWaitForSessionSetupResponse,
stateWaitForServiceDiscoveryResponse: stateFunctionWaitForServiceDiscoveryResponse,
stateWaitForServicePaymentSelectionResponse: stateFunctionWaitForServicePaymentSelectionResponse,
stateWaitForContractAuthenticationResponse: stateFunctionWaitForContractAuthenticationResponse,
stateWaitForChargeParameterDiscoveryResponse: stateFunctionWaitForChargeParameterDiscoveryResponse,
stateWaitForCableCheckResponse: stateFunctionWaitForCableCheckResponse,
stateWaitForPreChargeResponse: stateFunctionWaitForPreChargeResponse,

View file

@ -168,11 +168,14 @@ a new, non-zero SessionID. This SessionID is used in all the upcoming messages f
36. The charger confirms with ServiceDiscoveryResponse. This contains the offered services and payment options. Usually it says which type
of charging the charger supports (e.g. AC 1phase, AC 3phase, or DC according CCS https://en.wikipedia.org/wiki/IEC_62196#FF), and that
the payment should be handled externally by the user, or by the car.
37. The car sends PaymentServiceSelectionRequest. Usually (in non-plug-and-charge case), the car says "I cannot pay, something else should
37. The car sends ServicePaymentSelectionRequest. Usually (in non-plug-and-charge case), the car says "I cannot pay, something else should
handle the payment", by setting paymentOption=ExternalPayment. Optionally it could announce other services than charging, e.g. internet access.
38. The charger confirms with PaymentServiceSelectionResponse.
39. The car sends AuthorizationRequest. In non-plug-and-charge case this is most likely not containing relevant data.
40. The charger confirms with AuthorizationResponse.
38. The charger confirms with ServicePaymentSelectionResponse.
39. The car sends ContractAuthenticationRequest. In non-plug-and-charge case this is most likely not containing relevant data.
40. The charger confirms with ContractAuthenticationResponse. In case, the user needs to authenticate before charging, this
response does NOT yet say EVSEProcessing=Finished. The car repeats the request.
41. The user authorizes, e.g. with RFID card or app or however.
42. The charger sends ContractAuthenticationResponse with EVSEProcessing=Finished.
41. The car sends ChargeParameterRequest. This contains the wanted RequestedEnergyTransferMode, e.g. to select
DC or AC and which power pins are used. The car announces the maximum current limit and the maximum voltage limit.
42. The charger confirms with ChargeParameterResponse. The contains the limits from charger side, e.g. min and max voltage,
@ -282,10 +285,13 @@ is not yet implemented.
- The TCP port, which is announced in the SDP response, is ignored. This can be the root cause of failing TCP connection on Alpitronics.
- The SLAC timing includes too long wait times. This may be the root cause for failing SLAC on Supercharger and Compleo.
### 2022-12-02 v0.3 On Alpitonics until ChargeParameterDiscovery
- TCP connection works now on Alpitronics charger
- ContractAuthentication loop works
### Ongoing improvements
- SLAC timing: improvement to be tested.
- TCP port from SDP response: bugfix to be tested.
### Test results on real-world chargers

File diff suppressed because it is too large Load diff