2022-11-07 08:21:25 +00:00
|
|
|
# State machine for the car
|
|
|
|
#
|
|
|
|
#
|
|
|
|
|
|
|
|
#------------------------------------------------------------
|
|
|
|
|
|
|
|
import pyPlcTcpSocket
|
|
|
|
import time # for time.sleep()
|
2022-12-20 07:35:58 +00:00
|
|
|
from datetime import datetime
|
2023-04-05 19:01:43 +00:00
|
|
|
from helpers import prettyHexMessage, compactHexMessage, combineValueAndMultiplier
|
2022-11-07 12:38:06 +00:00
|
|
|
from exiConnector import * # for EXI data handling/converting
|
2022-11-16 18:33:37 +00:00
|
|
|
import json
|
2023-04-15 18:35:51 +00:00
|
|
|
from configmodule import getConfigValue, getConfigValueBool
|
2022-11-07 08:21:25 +00:00
|
|
|
|
2022-12-08 23:22:18 +00:00
|
|
|
|
2022-11-29 07:40:34 +00:00
|
|
|
stateNotYetInitialized = 0
|
|
|
|
stateConnecting = 1
|
|
|
|
stateConnected = 2
|
|
|
|
stateWaitForSupportedApplicationProtocolResponse = 3
|
|
|
|
stateWaitForSessionSetupResponse = 4
|
|
|
|
stateWaitForServiceDiscoveryResponse = 5
|
|
|
|
stateWaitForServicePaymentSelectionResponse = 6
|
2022-12-02 12:02:40 +00:00
|
|
|
stateWaitForContractAuthenticationResponse = 7
|
2022-11-29 07:40:34 +00:00
|
|
|
stateWaitForChargeParameterDiscoveryResponse = 8
|
|
|
|
stateWaitForCableCheckResponse = 9
|
|
|
|
stateWaitForPreChargeResponse = 10
|
|
|
|
stateWaitForPowerDeliveryResponse = 11
|
2022-12-08 23:22:18 +00:00
|
|
|
stateWaitForCurrentDemandResponse = 12
|
|
|
|
stateWaitForWeldingDetectionResponse = 13
|
|
|
|
stateWaitForSessionStopResponse = 14
|
|
|
|
stateChargingFinished = 15
|
2022-11-29 07:40:34 +00:00
|
|
|
stateSequenceTimeout = 99
|
|
|
|
|
2022-11-07 08:21:25 +00:00
|
|
|
|
2022-11-18 11:27:24 +00:00
|
|
|
dinEVSEProcessingType_Finished = "0"
|
|
|
|
dinEVSEProcessingType_Ongoing = "1"
|
|
|
|
|
2022-11-07 08:21:25 +00:00
|
|
|
class fsmPev():
|
2022-11-22 20:34:27 +00:00
|
|
|
def addToTrace(self, s):
|
2022-11-22 20:48:05 +00:00
|
|
|
self.callbackAddToTrace("[PEV] " + s)
|
2022-11-22 20:34:27 +00:00
|
|
|
|
2023-02-27 09:53:42 +00:00
|
|
|
def publishStatus(self, s, strAuxInfo1="", strAuxInfo2=""):
|
|
|
|
self.callbackShowStatus(s, "pevState", strAuxInfo1, strAuxInfo2)
|
2022-12-19 17:09:39 +00:00
|
|
|
|
2022-12-09 11:06:10 +00:00
|
|
|
def exiDecode(self, exidata, schema):
|
|
|
|
s = compactHexMessage(exidata)
|
2022-12-20 07:35:58 +00:00
|
|
|
strDateTime=datetime.today().strftime('%Y-%m-%dT%H:%M:%S.%f')
|
|
|
|
self.exiLogFile.write(strDateTime + "=" + schema + " " + s +"\n") # write the EXI data to the exiLogFile
|
2022-12-09 11:06:10 +00:00
|
|
|
return exiDecode(exidata, schema) # call the decoder
|
|
|
|
|
|
|
|
def exiEncode(self, input):
|
|
|
|
schema = input[0:2]
|
|
|
|
exidata = exiEncode(input) # call the encoder
|
|
|
|
s = exidata # it is already a hex string
|
2022-12-20 07:35:58 +00:00
|
|
|
strDateTime=datetime.today().strftime('%Y-%m-%dT%H:%M:%S.%f')
|
|
|
|
self.exiLogFile.write(strDateTime + "=" + schema + " " + s +"\n") # write the EXI data to the exiLogFile
|
2022-12-09 11:06:10 +00:00
|
|
|
return exidata
|
|
|
|
|
2023-04-11 20:09:26 +00:00
|
|
|
def prettifyState(self, statenumber):
|
|
|
|
s="unknownState"
|
|
|
|
if (statenumber == stateNotYetInitialized):
|
|
|
|
s = "NotYetInitialized"
|
|
|
|
if (statenumber == stateConnecting):
|
|
|
|
s = "Connecting"
|
|
|
|
if (statenumber == stateConnected):
|
|
|
|
s = "Connected"
|
|
|
|
if (statenumber == stateWaitForSupportedApplicationProtocolResponse):
|
|
|
|
s = "WaitForSupportedApplicationProtocolResponse"
|
|
|
|
if (statenumber == stateWaitForSessionSetupResponse):
|
|
|
|
s = "WaitForSessionSetupResponse"
|
|
|
|
if (statenumber == stateWaitForServiceDiscoveryResponse):
|
|
|
|
s = "WaitForServiceDiscoveryResponse"
|
|
|
|
if (statenumber == stateWaitForServicePaymentSelectionResponse):
|
|
|
|
s = "WaitForServicePaymentSelectionResponse"
|
|
|
|
if (statenumber == stateWaitForContractAuthenticationResponse):
|
|
|
|
s = "WaitForContractAuthenticationResponse"
|
|
|
|
if (statenumber == stateWaitForChargeParameterDiscoveryResponse):
|
|
|
|
s = "WaitForChargeParameterDiscoveryResponse"
|
|
|
|
if (statenumber == stateWaitForCableCheckResponse):
|
|
|
|
s = "WaitForCableCheckResponse"
|
|
|
|
if (statenumber == stateWaitForPreChargeResponse):
|
|
|
|
s = "WaitForPreChargeResponse"
|
|
|
|
if (statenumber == stateWaitForPowerDeliveryResponse):
|
|
|
|
s = "WaitForPowerDeliveryResponse"
|
|
|
|
if (statenumber == stateWaitForCurrentDemandResponse):
|
|
|
|
s = "WaitForCurrentDemandResponse"
|
|
|
|
if (statenumber == stateWaitForWeldingDetectionResponse):
|
|
|
|
s = "WaitForWeldingDetectionResponse"
|
|
|
|
if (statenumber == stateWaitForSessionStopResponse):
|
|
|
|
s = "WaitForSessionStopResponse"
|
|
|
|
if (statenumber == stateChargingFinished):
|
|
|
|
s = "ChargingFinished"
|
|
|
|
if (statenumber == stateSequenceTimeout):
|
|
|
|
s = "SequenceTimeout"
|
|
|
|
return s
|
|
|
|
|
2022-12-09 13:23:32 +00:00
|
|
|
def sendChargeParameterDiscoveryReq(self):
|
|
|
|
soc = str(self.hardwareInterface.getSoc())
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDE_"+self.sessionId + "_" + soc)) # EDE for Encode, Din, ChargeParameterDiscovery.
|
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
|
|
|
|
def sendCableCheckReq(self):
|
|
|
|
soc = str(self.hardwareInterface.getSoc())
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDF_"+self.sessionId + "_" + soc)) # EDF for Encode, Din, CableCheckReq
|
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
|
|
|
|
|
|
|
|
def sendCurrentDemandReq(self):
|
|
|
|
soc = str(self.hardwareInterface.getSoc())
|
2022-12-09 22:45:58 +00:00
|
|
|
EVTargetCurrent = str(self.hardwareInterface.getAccuMaxCurrent())
|
|
|
|
EVTargetVoltage = str(self.hardwareInterface.getAccuMaxVoltage())
|
2022-12-09 13:23:32 +00:00
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDI_"+self.sessionId + "_" + soc + "_" + EVTargetCurrent + "_" + EVTargetVoltage )) # EDI for Encode, Din, CurrentDemandReq
|
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
|
|
|
|
def sendWeldingDetectionReq(self):
|
|
|
|
soc = str(self.hardwareInterface.getSoc())
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDJ_"+self.sessionId + "_" + soc)) # EDI for Encode, Din, WeldingDetectionReq
|
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
|
2022-11-07 08:21:25 +00:00
|
|
|
def enterState(self, n):
|
2023-04-11 20:09:26 +00:00
|
|
|
self.addToTrace("from " + str(self.state) + ":" + self.prettifyState(self.state) + " entering " + str(n) + ":" + self.prettifyState(n))
|
2022-11-07 08:21:25 +00:00
|
|
|
self.state = n
|
|
|
|
self.cyclesInState = 0
|
|
|
|
|
|
|
|
def isTooLong(self):
|
|
|
|
# The timeout handling function.
|
2023-04-16 19:21:04 +00:00
|
|
|
limit = 33 # number of call cycles until timeout. Default 33 cycles with 30ms, means approx. 1 second.
|
2022-11-18 11:27:24 +00:00
|
|
|
if (self.state==stateWaitForCableCheckResponse):
|
2023-04-16 19:21:04 +00:00
|
|
|
limit = 30*33 # CableCheck may need some time. Wait at least 30s.
|
2022-11-18 11:27:24 +00:00
|
|
|
if (self.state==stateWaitForPreChargeResponse):
|
2023-04-16 19:21:04 +00:00
|
|
|
limit = 30*33 # PreCharge may need some time. Wait at least 30s.
|
|
|
|
if (self.state==stateWaitForPowerDeliveryResponse):
|
|
|
|
limit = 5*33 # PowerDelivery may need some time. Wait at least 5s. On Compleo charger, observed more than 1s until response.
|
2022-11-18 11:27:24 +00:00
|
|
|
return (self.cyclesInState > limit)
|
2022-11-07 08:21:25 +00:00
|
|
|
|
2022-11-29 07:40:34 +00:00
|
|
|
def stateFunctionNotYetInitialized(self):
|
|
|
|
pass # nothing to do, just wait for external event for re-initialization
|
|
|
|
|
|
|
|
def stateFunctionConnecting(self):
|
|
|
|
if (self.cyclesInState<30): # The first second in the state just do nothing.
|
|
|
|
return
|
2022-12-01 10:51:11 +00:00
|
|
|
evseIp = self.addressManager.getSeccIp() # the chargers IP address which was announced in SDP
|
|
|
|
seccTcpPort = self.addressManager.getSeccTcpPort() # the chargers TCP port which was announced in SDP
|
2023-03-20 20:32:57 +00:00
|
|
|
self.addToTrace("Checkpoint301: connecting")
|
2022-12-01 10:51:11 +00:00
|
|
|
self.Tcp.connect(evseIp, seccTcpPort) # This is a blocking call. If we come back, we are connected, or not.
|
2022-11-29 07:40:34 +00:00
|
|
|
if (not self.Tcp.isConnected):
|
|
|
|
# Bad case: Connection did not work. May happen if we are too fast and the charger needs more
|
|
|
|
# time until the socket is ready. Or the charger is defective. Or somebody pulled the plug.
|
|
|
|
# No matter what is the reason, we just try again and again. What else would make sense?
|
|
|
|
self.addToTrace("Connection failed. Will try again.")
|
|
|
|
self.reInit() # stay in same state, reset the cyclesInState and try again
|
|
|
|
return
|
|
|
|
else:
|
|
|
|
# Good case: We are connected. Change to the next state.
|
|
|
|
self.addToTrace("connected")
|
2022-12-19 17:09:39 +00:00
|
|
|
self.publishStatus("TCP connected")
|
|
|
|
self.isUserStopRequest = False
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateConnected)
|
|
|
|
return
|
|
|
|
|
|
|
|
def stateFunctionConnected(self):
|
|
|
|
# We have a freshly established TCP channel. We start the V2GTP/EXI communication now.
|
|
|
|
# We just use the initial request message from the Ioniq. It contains one entry: DIN.
|
2023-03-20 20:32:57 +00:00
|
|
|
self.addToTrace("Checkpoint400: Sending the initial SupportedApplicationProtocolReq")
|
2022-11-29 07:40:34 +00:00
|
|
|
self.Tcp.transmit(addV2GTPHeader(exiHexToByteArray(exiHexDemoSupportedApplicationProtocolRequestIoniq)))
|
2022-12-10 16:08:51 +00:00
|
|
|
self.hardwareInterface.resetSimulation()
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateWaitForSupportedApplicationProtocolResponse)
|
2022-11-07 08:21:25 +00:00
|
|
|
|
|
|
|
def stateFunctionWaitForSupportedApplicationProtocolResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("In state WaitForSupportedApplicationProtocolResponse, received " + prettyHexMessage(self.rxData))
|
2022-11-08 11:01:54 +00:00
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "Dh") # Decode Handshake-response
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (strConverterResult.find("supportedAppProtocolRes")>0):
|
|
|
|
# todo: check the request content, and fill response parameters
|
2022-12-19 17:09:39 +00:00
|
|
|
self.publishStatus("Schema negotiated")
|
2023-03-20 20:32:57 +00:00
|
|
|
self.addToTrace("Checkpoint403: Schema negotiated. And Checkpoint500: Will send SessionSetupReq")
|
2023-03-23 07:50:53 +00:00
|
|
|
self.addToTrace("EDA_"+self.evccid)
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDA_"+self.evccid)) # EDA for Encode, Din, SessionSetupReq
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
2022-11-08 21:53:18 +00:00
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.enterState(stateWaitForSessionSetupResponse)
|
|
|
|
if (self.isTooLong()):
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateSequenceTimeout)
|
2022-11-08 11:01:54 +00:00
|
|
|
|
|
|
|
def stateFunctionWaitForSessionSetupResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("In state WaitForSessionSetupResponse, received " + prettyHexMessage(self.rxData))
|
2022-11-08 21:53:18 +00:00
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (strConverterResult.find("SessionSetupRes")>0):
|
|
|
|
# todo: check the request content, and fill response parameters
|
2022-11-16 18:33:37 +00:00
|
|
|
try:
|
|
|
|
y = json.loads(strConverterResult)
|
|
|
|
strSessionId = y["header.SessionID"]
|
2023-03-20 20:32:57 +00:00
|
|
|
self.addToTrace("Checkpoint506: The Evse decided for SessionId " + strSessionId)
|
2022-12-19 17:09:39 +00:00
|
|
|
self.publishStatus("Session established")
|
2022-11-16 18:33:37 +00:00
|
|
|
self.sessionId = strSessionId
|
|
|
|
except:
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("ERROR: Could not decode the sessionID")
|
2022-11-24 06:46:45 +00:00
|
|
|
self.addToTrace("Will send ServiceDiscoveryReq")
|
2022-12-09 11:06:10 +00:00
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDB_"+self.sessionId)) # EDB for Encode, Din, ServiceDiscoveryRequest
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
2022-11-08 21:53:18 +00:00
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.enterState(stateWaitForServiceDiscoveryResponse)
|
|
|
|
if (self.isTooLong()):
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateSequenceTimeout)
|
2022-11-08 21:53:18 +00:00
|
|
|
|
|
|
|
def stateFunctionWaitForServiceDiscoveryResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("In state WaitForServiceDiscoveryResponse, received " + prettyHexMessage(self.rxData))
|
2022-11-08 21:53:18 +00:00
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (strConverterResult.find("ServiceDiscoveryRes")>0):
|
|
|
|
# todo: check the request content, and fill response parameters
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("ServDisc done")
|
2022-11-24 06:46:45 +00:00
|
|
|
self.addToTrace("Will send ServicePaymentSelectionReq")
|
2022-12-09 11:06:10 +00:00
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDC_"+self.sessionId)) # EDC for Encode, Din, ServicePaymentSelection
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
2022-11-08 21:53:18 +00:00
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.enterState(stateWaitForServicePaymentSelectionResponse)
|
|
|
|
if (self.isTooLong()):
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateSequenceTimeout)
|
2022-11-08 21:53:18 +00:00
|
|
|
|
|
|
|
def stateFunctionWaitForServicePaymentSelectionResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("In state WaitForServicePaymentSelectionResponse, received " + prettyHexMessage(self.rxData))
|
2022-11-08 21:53:18 +00:00
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (strConverterResult.find("ServicePaymentSelectionRes")>0):
|
|
|
|
# todo: check the request content, and fill response parameters
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("ServPaySel done")
|
2023-03-20 20:32:57 +00:00
|
|
|
self.addToTrace("Checkpoint530: Will send ContractAuthenticationReq")
|
2022-12-09 11:06:10 +00:00
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDL_"+self.sessionId)) # EDL for Encode, Din, ContractAuthenticationReq.
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
2022-11-08 21:53:18 +00:00
|
|
|
self.Tcp.transmit(msg)
|
2022-12-02 12:02:40 +00:00
|
|
|
self.numberOfContractAuthenticationReq = 1 # This is the first request.
|
|
|
|
self.enterState(stateWaitForContractAuthenticationResponse)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (self.isTooLong()):
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateSequenceTimeout)
|
2022-12-02 12:02:40 +00:00
|
|
|
|
|
|
|
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 = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-12-02 12:02:40 +00:00
|
|
|
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.
|
2022-12-19 17:09:39 +00:00
|
|
|
if (strConverterResult.find('"EVSEProcessing": "Finished"')>0):
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("Auth finished")
|
2023-03-26 00:19:32 +00:00
|
|
|
self.addToTrace("Checkpoint538: Auth is Finished. Will send ChargeParameterDiscoveryReq")
|
2022-12-09 13:23:32 +00:00
|
|
|
self.sendChargeParameterDiscoveryReq()
|
2022-12-02 13:56:38 +00:00
|
|
|
self.numberOfChargeParameterDiscoveryReq = 1 # first message
|
2022-12-02 12:02:40 +00:00
|
|
|
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.
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("Waiting f Auth")
|
2022-12-02 12:02:40 +00:00
|
|
|
self.addToTrace("Not (yet) finished. Will again send ContractAuthenticationReq #" + str(self.numberOfContractAuthenticationReq))
|
2022-12-09 11:06:10 +00:00
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDL_"+self.sessionId)) # EDL for Encode, Din, ContractAuthenticationReq.
|
2022-12-02 12:02:40 +00:00
|
|
|
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)
|
2022-11-08 11:01:54 +00:00
|
|
|
|
2022-11-08 21:53:18 +00:00
|
|
|
def stateFunctionWaitForChargeParameterDiscoveryResponse(self):
|
2022-12-02 13:56:38 +00:00
|
|
|
if (self.cyclesInState<30): # The first second in the state just do nothing.
|
|
|
|
return
|
2022-11-08 21:53:18 +00:00
|
|
|
if (len(self.rxData)>0):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("In state WaitForChargeParameterDiscoveryResponse, received " + prettyHexMessage(self.rxData))
|
2022-11-08 21:53:18 +00:00
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (strConverterResult.find("ChargeParameterDiscoveryRes")>0):
|
2022-12-02 13:56:38 +00:00
|
|
|
# We can have two cases here:
|
|
|
|
# (A) The charger needs more time to show the charge parameters.
|
|
|
|
# (B) The charger finished to tell the charge parameters.
|
2022-12-19 17:09:39 +00:00
|
|
|
if (strConverterResult.find('"EVSEProcessing": "Finished"')>0):
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("ChargeParams discovered")
|
2023-03-26 00:19:32 +00:00
|
|
|
self.addToTrace("Checkpoint550: It is Finished. Will change to state C and send CableCheckReq.")
|
2022-12-06 17:35:17 +00:00
|
|
|
# pull the CP line to state C here:
|
|
|
|
self.hardwareInterface.setStateC()
|
2022-12-09 13:23:32 +00:00
|
|
|
self.sendCableCheckReq()
|
2022-12-02 13:56:38 +00:00
|
|
|
self.numberOfCableCheckReq = 1 # This is the first request.
|
|
|
|
self.enterState(stateWaitForCableCheckResponse)
|
|
|
|
else:
|
|
|
|
# Not (yet) finished.
|
|
|
|
if (self.numberOfChargeParameterDiscoveryReq>=20): # approx 20 seconds, should be sufficient for the charger to find its parameters...
|
|
|
|
self.addToTrace("ChargeParameterDiscovery lasted too long. " + str(self.numberOfChargeParameterDiscoveryReq) + " Giving up.")
|
|
|
|
self.enterState(stateSequenceTimeout)
|
|
|
|
else:
|
|
|
|
# Try again.
|
|
|
|
self.numberOfChargeParameterDiscoveryReq += 1 # count the number of tries.
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("disc ChargeParams")
|
2022-12-02 13:56:38 +00:00
|
|
|
self.addToTrace("Not (yet) finished. Will again send ChargeParameterDiscoveryReq #" + str(self.numberOfChargeParameterDiscoveryReq))
|
2022-12-09 13:23:32 +00:00
|
|
|
self.sendChargeParameterDiscoveryReq()
|
2022-12-02 13:56:38 +00:00
|
|
|
# we stay in the same state
|
|
|
|
self.enterState(stateWaitForChargeParameterDiscoveryResponse)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (self.isTooLong()):
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateSequenceTimeout)
|
2022-11-08 21:53:18 +00:00
|
|
|
|
|
|
|
def stateFunctionWaitForCableCheckResponse(self):
|
2022-12-02 13:56:38 +00:00
|
|
|
if (self.cyclesInState<30): # The first second in the state just do nothing.
|
|
|
|
return
|
2022-11-08 21:53:18 +00:00
|
|
|
if (len(self.rxData)>0):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("In state WaitForCableCheckResponse, received " + prettyHexMessage(self.rxData))
|
2022-11-08 21:53:18 +00:00
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (strConverterResult.find("CableCheckRes")>0):
|
2022-11-18 11:27:24 +00:00
|
|
|
try:
|
|
|
|
y = json.loads(strConverterResult)
|
|
|
|
strResponseCode = y["ResponseCode"]
|
|
|
|
strEVSEProcessing = y["EVSEProcessing"]
|
2023-03-03 09:23:37 +00:00
|
|
|
self.addToTrace("The CableCheck result is " + strResponseCode + " " + strEVSEProcessing)
|
2022-11-18 11:27:24 +00:00
|
|
|
except:
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("ERROR: Could not decode the CableCheckRes")
|
2022-11-08 21:53:18 +00:00
|
|
|
# todo: check the request content, and fill response parameters
|
2022-11-18 11:27:24 +00:00
|
|
|
# We have two cases here:
|
|
|
|
# 1) The charger says "cable check is finished and cable ok", by setting ResponseCode=OK and EVSEProcessing=Finished.
|
|
|
|
# 2) Else: The charger says "need more time or cable not ok". In this case, we just run into timeout and start from the beginning.
|
2022-12-04 08:14:47 +00:00
|
|
|
if ((strEVSEProcessing=="Finished") and (strResponseCode=="OK")):
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("CbleChck done")
|
2022-11-24 06:46:45 +00:00
|
|
|
self.addToTrace("The EVSE says that the CableCheck is finished and ok.")
|
|
|
|
self.addToTrace("Will send PreChargeReq")
|
2022-12-09 13:23:32 +00:00
|
|
|
soc = self.hardwareInterface.getSoc()
|
|
|
|
EVTargetVoltage = self.hardwareInterface.getAccuVoltage()
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDG_"+self.sessionId+"_"+str(soc)+"_"+str(EVTargetVoltage))) # EDG for Encode, Din, PreChargeReq
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
2022-11-18 11:27:24 +00:00
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.enterState(stateWaitForPreChargeResponse)
|
|
|
|
else:
|
2022-12-02 13:56:38 +00:00
|
|
|
if (self.numberOfCableCheckReq>30): # approx 30s should be sufficient for cable check
|
|
|
|
self.addToTrace("CableCheck lasted too long. " + str(self.numberOfCableCheckReq) + " Giving up.")
|
|
|
|
self.enterState(stateSequenceTimeout)
|
|
|
|
else:
|
|
|
|
# cable check not yet finished or finished with bad result -> try again
|
|
|
|
self.numberOfCableCheckReq += 1
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("CbleChck ongoing", format(self.hardwareInterface.getInletVoltage(),".0f") + "V")
|
2022-12-02 13:56:38 +00:00
|
|
|
self.addToTrace("Will again send CableCheckReq")
|
2022-12-09 13:23:32 +00:00
|
|
|
self.sendCableCheckReq()
|
2022-12-02 13:56:38 +00:00
|
|
|
# stay in the same state
|
|
|
|
self.enterState(stateWaitForCableCheckResponse)
|
2022-11-18 11:27:24 +00:00
|
|
|
|
2022-11-08 21:53:18 +00:00
|
|
|
if (self.isTooLong()):
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateSequenceTimeout)
|
2022-11-08 21:53:18 +00:00
|
|
|
|
|
|
|
def stateFunctionWaitForPreChargeResponse(self):
|
2022-12-10 16:08:51 +00:00
|
|
|
self.hardwareInterface.simulatePreCharge()
|
2022-11-20 18:48:52 +00:00
|
|
|
if (self.DelayCycles>0):
|
|
|
|
self.DelayCycles-=1
|
|
|
|
return
|
2022-11-08 21:53:18 +00:00
|
|
|
if (len(self.rxData)>0):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("In state WaitForPreChargeResponse, received " + prettyHexMessage(self.rxData))
|
2022-11-08 21:53:18 +00:00
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
2022-11-08 21:53:18 +00:00
|
|
|
if (strConverterResult.find("PreChargeRes")>0):
|
2023-04-05 19:01:43 +00:00
|
|
|
u = 0 # a default voltage of 0V in case we cannot convert the actual value
|
|
|
|
try:
|
|
|
|
y = json.loads(strConverterResult)
|
|
|
|
strEVSEPresentVoltageValue = y["EVSEPresentVoltage.Value"]
|
|
|
|
strEVSEPresentVoltageMultiplier = y["EVSEPresentVoltage.Multiplier"]
|
|
|
|
u = combineValueAndMultiplier(strEVSEPresentVoltageValue, strEVSEPresentVoltageMultiplier)
|
|
|
|
self.callbackShowStatus(format(u,".1f"), "EVSEPresentVoltage")
|
|
|
|
except:
|
|
|
|
self.addToTrace("ERROR: Could not decode the PreChargeResponse")
|
|
|
|
self.addToTrace("PreChargeResponse received.")
|
2023-04-15 18:35:51 +00:00
|
|
|
if (getConfigValueBool("use_evsepresentvoltage_for_precharge_end")):
|
2023-04-05 19:01:43 +00:00
|
|
|
# We want to use the EVSEPresentVoltage, which was reported by the charger, as end-criteria for the precharging.
|
|
|
|
s = "EVSEPresentVoltage " + str(u) + "V, "
|
|
|
|
else:
|
|
|
|
# We want to use the physically measured inlet voltage as end-criteria for the precharging.
|
|
|
|
u = self.hardwareInterface.getInletVoltage()
|
|
|
|
s = "U_Inlet " + str(u) + "V, "
|
2022-12-10 16:08:51 +00:00
|
|
|
s= s + "U_Accu " + str(self.hardwareInterface.getAccuVoltage()) + "V"
|
|
|
|
self.addToTrace(s)
|
2023-04-15 18:35:51 +00:00
|
|
|
if (abs(u-self.hardwareInterface.getAccuVoltage()) < float(getConfigValue("u_delta_max_for_end_of_precharge"))):
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace("Difference between accu voltage and inlet voltage is small. Sending PowerDeliveryReq.")
|
2022-12-19 17:09:39 +00:00
|
|
|
self.publishStatus("PreCharge done")
|
|
|
|
if (self.isLightBulbDemo):
|
|
|
|
# For light-bulb-demo, nothing to do here.
|
|
|
|
self.addToTrace("This is a light bulb demo. Do not turn-on the relay at end of precharge.")
|
|
|
|
else:
|
|
|
|
# In real-world-case, turn the power relay on.
|
|
|
|
self.hardwareInterface.setPowerRelayOn()
|
2022-12-09 13:23:32 +00:00
|
|
|
soc = self.hardwareInterface.getSoc()
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDH_"+self.sessionId+"_"+ str(soc) + "_" + "1")) # EDH for Encode, Din, PowerDeliveryReq, ON
|
2022-12-08 23:22:18 +00:00
|
|
|
self.wasPowerDeliveryRequestedOn=True
|
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.enterState(stateWaitForPowerDeliveryResponse)
|
|
|
|
else:
|
2023-04-05 19:01:43 +00:00
|
|
|
self.publishStatus("PreChrge ongoing", format(u, ".0f") + "V")
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace("Difference too big. Continuing PreCharge.")
|
2022-12-09 13:23:32 +00:00
|
|
|
soc = self.hardwareInterface.getSoc()
|
|
|
|
EVTargetVoltage = self.hardwareInterface.getAccuVoltage()
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDG_"+self.sessionId+"_"+str(soc)+"_"+str(EVTargetVoltage))) # EDG for Encode, Din, PreChargeReq
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.DelayCycles=15 # wait with the next evaluation approx half a second
|
2022-11-08 21:53:18 +00:00
|
|
|
if (self.isTooLong()):
|
2022-11-29 07:40:34 +00:00
|
|
|
self.enterState(stateSequenceTimeout)
|
|
|
|
|
2022-12-08 23:22:18 +00:00
|
|
|
def stateFunctionWaitForPowerDeliveryResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
|
|
|
self.addToTrace("In state WaitForPowerDeliveryRes, received " + prettyHexMessage(self.rxData))
|
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
|
|
|
if (strConverterResult.find("PowerDeliveryRes")>0):
|
|
|
|
if (self.wasPowerDeliveryRequestedOn):
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("PwrDelvy ON success")
|
2023-03-26 00:19:32 +00:00
|
|
|
self.addToTrace("Checkpoint700: Starting the charging loop with CurrentDemandReq")
|
2022-12-09 13:23:32 +00:00
|
|
|
self.sendCurrentDemandReq()
|
2022-12-08 23:22:18 +00:00
|
|
|
self.enterState(stateWaitForCurrentDemandResponse)
|
|
|
|
else:
|
|
|
|
# We requested "OFF". So we turn-off the Relay and continue with the Welding detection.
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("PwrDelvry OFF success")
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace("Turning off the relay and starting the WeldingDetection")
|
|
|
|
self.hardwareInterface.setPowerRelayOff()
|
2022-12-19 17:09:39 +00:00
|
|
|
self.hardwareInterface.setRelay2Off()
|
|
|
|
self.isBulbOn = False
|
2022-12-09 13:23:32 +00:00
|
|
|
self.sendWeldingDetectionReq()
|
2022-12-08 23:22:18 +00:00
|
|
|
self.enterState(stateWaitForWeldingDetectionResponse)
|
|
|
|
if (self.isTooLong()):
|
|
|
|
self.enterState(stateSequenceTimeout)
|
|
|
|
|
|
|
|
def stateFunctionWaitForCurrentDemandResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
|
|
|
self.addToTrace("In state WaitForCurrentDemandRes, received " + prettyHexMessage(self.rxData))
|
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
|
|
|
if (strConverterResult.find("CurrentDemandRes")>0):
|
2023-04-05 19:01:43 +00:00
|
|
|
u = 0 # a default voltage of 0V in case we cannot convert the actual value
|
|
|
|
try:
|
|
|
|
y = json.loads(strConverterResult)
|
|
|
|
strEVSEPresentVoltageValue = y["EVSEPresentVoltage.Value"]
|
|
|
|
strEVSEPresentVoltageMultiplier = y["EVSEPresentVoltage.Multiplier"]
|
|
|
|
u = combineValueAndMultiplier(strEVSEPresentVoltageValue, strEVSEPresentVoltageMultiplier)
|
|
|
|
self.callbackShowStatus(format(u,".1f"), "EVSEPresentVoltage")
|
|
|
|
except:
|
|
|
|
self.addToTrace("ERROR: Could not decode the PreChargeResponse")
|
2023-04-15 18:35:51 +00:00
|
|
|
if (getConfigValueBool("use_physical_inlet_voltage_during_chargeloop")):
|
2023-04-05 19:01:43 +00:00
|
|
|
# Instead of using the voltage which is reported by the charger, use the physically measured.
|
|
|
|
u = self.hardwareInterface.getInletVoltage()
|
2022-12-08 23:22:18 +00:00
|
|
|
# as long as the accu is not full and no stop-demand from the user, we continue charging
|
2022-12-19 17:09:39 +00:00
|
|
|
if (self.hardwareInterface.getIsAccuFull() or self.isUserStopRequest):
|
|
|
|
if (self.hardwareInterface.getIsAccuFull()):
|
|
|
|
self.publishStatus("Accu full")
|
|
|
|
self.addToTrace("Accu is full. Sending PowerDeliveryReq Stop.")
|
|
|
|
else:
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("User req stop")
|
2022-12-19 17:09:39 +00:00
|
|
|
self.addToTrace("User requested stop. Sending PowerDeliveryReq Stop.")
|
2022-12-09 13:23:32 +00:00
|
|
|
soc = self.hardwareInterface.getSoc()
|
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDH_"+self.sessionId+"_"+ str(soc) + "_" + "0")) # EDH for Encode, Din, PowerDeliveryReq, OFF
|
2022-12-08 23:22:18 +00:00
|
|
|
self.wasPowerDeliveryRequestedOn=False
|
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.enterState(stateWaitForPowerDeliveryResponse)
|
|
|
|
else:
|
|
|
|
# continue charging loop
|
2023-04-05 19:01:43 +00:00
|
|
|
self.publishStatus("Charging", format(u, ".0f") + "V", format(self.hardwareInterface.getSoc(), ".1f") + "%")
|
2022-12-09 13:23:32 +00:00
|
|
|
self.sendCurrentDemandReq()
|
2022-12-08 23:22:18 +00:00
|
|
|
self.enterState(stateWaitForCurrentDemandResponse)
|
2022-12-19 17:09:39 +00:00
|
|
|
if (self.isLightBulbDemo):
|
2023-02-27 09:53:42 +00:00
|
|
|
if (self.cyclesLightBulbDelay<=33*2):
|
2022-12-19 17:09:39 +00:00
|
|
|
self.cyclesLightBulbDelay+=1
|
|
|
|
else:
|
|
|
|
if (not self.isBulbOn):
|
2023-02-27 09:53:42 +00:00
|
|
|
self.addToTrace("This is a light bulb demo. Turning-on the bulb when 2s in the main charging loop.")
|
2022-12-19 17:09:39 +00:00
|
|
|
self.hardwareInterface.setPowerRelayOn()
|
|
|
|
self.hardwareInterface.setRelay2On()
|
|
|
|
self.isBulbOn = True
|
2022-12-08 23:22:18 +00:00
|
|
|
if (self.isTooLong()):
|
|
|
|
self.enterState(stateSequenceTimeout)
|
|
|
|
|
|
|
|
def stateFunctionWaitForWeldingDetectionResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
|
|
|
self.addToTrace("In state WaitForWeldingDetectionResponse, received " + prettyHexMessage(self.rxData))
|
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
|
|
|
if (strConverterResult.find("WeldingDetectionRes")>0):
|
2022-12-09 13:23:32 +00:00
|
|
|
# todo: add real welding detection here, run in welding detection loop until finished.
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("WldingDet done")
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace("Sending SessionStopReq")
|
2022-12-09 11:06:10 +00:00
|
|
|
msg = addV2GTPHeader(self.exiEncode("EDK_"+self.sessionId)) # EDI for Encode, Din, SessionStopReq
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
|
|
|
self.Tcp.transmit(msg)
|
|
|
|
self.enterState(stateWaitForSessionStopResponse)
|
|
|
|
if (self.isTooLong()):
|
|
|
|
self.enterState(stateSequenceTimeout)
|
|
|
|
|
|
|
|
def stateFunctionWaitForSessionStopResponse(self):
|
|
|
|
if (len(self.rxData)>0):
|
|
|
|
self.addToTrace("In state WaitForSessionStopRes, received " + prettyHexMessage(self.rxData))
|
|
|
|
exidata = removeV2GTPHeader(self.rxData)
|
|
|
|
self.rxData = []
|
2022-12-09 11:06:10 +00:00
|
|
|
strConverterResult = self.exiDecode(exidata, "DD") # Decode DIN
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace(strConverterResult)
|
|
|
|
if (strConverterResult.find("SessionStopRes")>0):
|
|
|
|
# req -508
|
|
|
|
# Todo: close the TCP connection here.
|
|
|
|
# Todo: Unlock the connector lock.
|
2023-02-27 09:53:42 +00:00
|
|
|
self.publishStatus("Stopped normally")
|
2022-12-12 19:54:17 +00:00
|
|
|
self.hardwareInterface.setStateB()
|
2022-12-08 23:22:18 +00:00
|
|
|
self.addToTrace("Charging is finished")
|
|
|
|
self.enterState(stateChargingFinished)
|
|
|
|
if (self.isTooLong()):
|
|
|
|
self.enterState(stateSequenceTimeout)
|
|
|
|
|
|
|
|
def stateFunctionChargingFinished(self):
|
|
|
|
# charging is finished. Nothing to do. Just stay here, until we get re-initialized after a new SLAC/SDP.
|
|
|
|
pass
|
|
|
|
|
2022-11-29 07:40:34 +00:00
|
|
|
def stateFunctionSequenceTimeout(self):
|
|
|
|
# Here we end, if we run into a timeout in the state machine. This is an error case, and
|
|
|
|
# we should re-initalize and try again to get a communication.
|
|
|
|
# Todo: Maybe we want even inform the pyPlcHomeplug to do a new SLAC.
|
|
|
|
# For the moment, we just re-establish the TCP connection.
|
2022-12-19 17:09:39 +00:00
|
|
|
self.publishStatus("ERROR Timeout")
|
2022-11-29 07:40:34 +00:00
|
|
|
self.reInit()
|
2022-11-15 18:36:20 +00:00
|
|
|
|
|
|
|
|
2022-11-07 08:21:25 +00:00
|
|
|
stateFunctions = {
|
2022-11-29 07:40:34 +00:00
|
|
|
stateNotYetInitialized: stateFunctionNotYetInitialized,
|
|
|
|
stateConnecting: stateFunctionConnecting,
|
|
|
|
stateConnected: stateFunctionConnected,
|
2022-11-07 08:21:25 +00:00
|
|
|
stateWaitForSupportedApplicationProtocolResponse: stateFunctionWaitForSupportedApplicationProtocolResponse,
|
2022-11-08 11:01:54 +00:00
|
|
|
stateWaitForSessionSetupResponse: stateFunctionWaitForSessionSetupResponse,
|
2022-11-08 21:53:18 +00:00
|
|
|
stateWaitForServiceDiscoveryResponse: stateFunctionWaitForServiceDiscoveryResponse,
|
|
|
|
stateWaitForServicePaymentSelectionResponse: stateFunctionWaitForServicePaymentSelectionResponse,
|
2022-12-02 12:02:40 +00:00
|
|
|
stateWaitForContractAuthenticationResponse: stateFunctionWaitForContractAuthenticationResponse,
|
2022-11-08 21:53:18 +00:00
|
|
|
stateWaitForChargeParameterDiscoveryResponse: stateFunctionWaitForChargeParameterDiscoveryResponse,
|
|
|
|
stateWaitForCableCheckResponse: stateFunctionWaitForCableCheckResponse,
|
|
|
|
stateWaitForPreChargeResponse: stateFunctionWaitForPreChargeResponse,
|
2022-12-08 23:22:18 +00:00
|
|
|
stateWaitForPowerDeliveryResponse: stateFunctionWaitForPowerDeliveryResponse,
|
|
|
|
stateWaitForCurrentDemandResponse: stateFunctionWaitForCurrentDemandResponse,
|
|
|
|
stateWaitForWeldingDetectionResponse: stateFunctionWaitForWeldingDetectionResponse,
|
|
|
|
stateWaitForSessionStopResponse: stateFunctionWaitForSessionStopResponse,
|
|
|
|
stateChargingFinished: stateFunctionChargingFinished,
|
2022-11-29 07:40:34 +00:00
|
|
|
stateSequenceTimeout: stateFunctionSequenceTimeout
|
2022-11-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
2022-12-19 17:09:39 +00:00
|
|
|
def stopCharging(self):
|
|
|
|
# API function to stop the charging.
|
|
|
|
self.isUserStopRequest = True
|
|
|
|
|
2022-12-08 23:22:18 +00:00
|
|
|
|
2022-11-07 08:21:25 +00:00
|
|
|
def reInit(self):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("re-initializing fsmPev")
|
2022-11-29 07:40:34 +00:00
|
|
|
self.Tcp.disconnect()
|
2022-12-06 17:35:17 +00:00
|
|
|
self.hardwareInterface.setStateB()
|
2022-12-08 23:22:18 +00:00
|
|
|
self.hardwareInterface.setPowerRelayOff()
|
2022-12-19 17:09:39 +00:00
|
|
|
self.hardwareInterface.setRelay2Off()
|
|
|
|
self.isBulbOn = False
|
|
|
|
self.cyclesLightBulbDelay = 0
|
2022-11-29 07:40:34 +00:00
|
|
|
self.state = stateConnecting
|
2022-11-07 08:21:25 +00:00
|
|
|
self.cyclesInState = 0
|
|
|
|
self.rxData = []
|
|
|
|
|
2022-12-19 17:09:39 +00:00
|
|
|
def __init__(self, addressManager, callbackAddToTrace, hardwareInterface, callbackShowStatus):
|
2022-11-22 20:34:27 +00:00
|
|
|
self.callbackAddToTrace = callbackAddToTrace
|
2022-12-19 17:09:39 +00:00
|
|
|
self.callbackShowStatus = callbackShowStatus
|
2022-11-22 20:34:27 +00:00
|
|
|
self.addToTrace("initializing fsmPev")
|
2022-12-09 11:06:10 +00:00
|
|
|
self.exiLogFile = open('PevExiLog.txt', 'a')
|
|
|
|
self.exiLogFile.write("init\n")
|
2022-11-22 20:34:27 +00:00
|
|
|
self.Tcp = pyPlcTcpSocket.pyPlcTcpClientSocket(self.callbackAddToTrace)
|
2022-11-15 23:22:49 +00:00
|
|
|
self.addressManager = addressManager
|
2022-12-06 17:35:17 +00:00
|
|
|
self.hardwareInterface = hardwareInterface
|
2022-11-15 18:36:20 +00:00
|
|
|
self.state = stateNotYetInitialized
|
2022-11-16 18:33:37 +00:00
|
|
|
self.sessionId = "DEAD55AADEAD55AA"
|
2023-03-23 07:50:53 +00:00
|
|
|
self.evccid = addressManager.getLocalMacAsTwelfCharString()
|
2022-11-15 18:36:20 +00:00
|
|
|
self.cyclesInState = 0
|
2022-11-20 18:48:52 +00:00
|
|
|
self.DelayCycles = 0
|
2022-11-15 18:36:20 +00:00
|
|
|
self.rxData = []
|
2023-04-15 18:35:51 +00:00
|
|
|
self.isLightBulbDemo = getConfigValueBool("light_bulb_demo")
|
2022-12-19 17:09:39 +00:00
|
|
|
self.isBulbOn = False
|
|
|
|
self.cyclesLightBulbDelay = 0
|
|
|
|
self.isUserStopRequest = False
|
2022-11-15 18:36:20 +00:00
|
|
|
# we do NOT call the reInit, because we want to wait with the connection until external trigger comes
|
2022-11-07 08:21:25 +00:00
|
|
|
|
2022-12-09 11:06:10 +00:00
|
|
|
def __del__(self):
|
|
|
|
self.exiLogFile.write("closing\n")
|
|
|
|
self.exiLogFile.close()
|
|
|
|
|
2022-11-07 08:21:25 +00:00
|
|
|
def mainfunction(self):
|
|
|
|
#self.Tcp.mainfunction() # call the lower-level worker
|
|
|
|
if (self.Tcp.isRxDataAvailable()):
|
|
|
|
self.rxData = self.Tcp.getRxData()
|
2022-11-22 20:34:27 +00:00
|
|
|
#self.addToTrace("received " + prettyHexMessage(self.rxData))
|
2022-11-07 08:21:25 +00:00
|
|
|
# run the state machine:
|
|
|
|
self.cyclesInState += 1 # for timeout handling, count how long we are in a state
|
|
|
|
self.stateFunctions[self.state](self)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
print("Testing the pev state machine")
|
|
|
|
pev = fsmPev()
|
|
|
|
print("Press Ctrl-Break for aborting")
|
|
|
|
while (True):
|
|
|
|
time.sleep(0.1)
|
|
|
|
pev.mainfunction()
|
|
|
|
|
|
|
|
|