mirror of
https://github.com/uhi22/pyPLC.git
synced 2024-11-20 01:13:58 +00:00
Merge pull request #3 from ArendJanKramer/master
Added SoC callback feature, fixed socket re-opening error
This commit is contained in:
commit
6c5c2b6af6
7 changed files with 140 additions and 57 deletions
|
@ -66,8 +66,8 @@ class addressManager():
|
||||||
else:
|
else:
|
||||||
lines = result.stdout.split("\n")
|
lines = result.stdout.split("\n")
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if (line.find("inet6")>0):
|
if (line.strip().find("inet6")>0):
|
||||||
k = line.find(" fe80::") # the beginning of the IPv6
|
k = line.strip().find("fe80::") # the beginning of the IPv6
|
||||||
if (k>0):
|
if (k>0):
|
||||||
sIpWithText = line[k+1:]
|
sIpWithText = line[k+1:]
|
||||||
x = sIpWithText.find(" ") # the space is the end of the IPv6
|
x = sIpWithText.find(" ") # the space is the end of the IPv6
|
||||||
|
|
|
@ -94,3 +94,7 @@ testsuite_enable = No
|
||||||
# If this is activated, the pyPlc will send all logging messages also to the network interface,
|
# If this is activated, the pyPlc will send all logging messages also to the network interface,
|
||||||
# in form of UDP Syslog messages. For details see in udplog.py.
|
# in form of UDP Syslog messages. For details see in udplog.py.
|
||||||
udp_syslog_enable = Yes
|
udp_syslog_enable = Yes
|
||||||
|
|
||||||
|
# REST callback for SoC states. Comment out to disable. Do not leave a trailing slash
|
||||||
|
soc_callback_enabled = False
|
||||||
|
soc_callback_endpoint = http://1.1.1.1
|
46
evseNoGui.py
Normal file
46
evseNoGui.py
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
|
||||||
|
# The non-GUI variant of the PEV side
|
||||||
|
|
||||||
|
import time
|
||||||
|
import pyPlcWorker
|
||||||
|
from configmodule import getConfigValue, getConfigValueBool
|
||||||
|
from pyPlcModes import *
|
||||||
|
import sys # for argv
|
||||||
|
import requests
|
||||||
|
|
||||||
|
startTime_ms = round(time.time()*1000)
|
||||||
|
|
||||||
|
def cbAddToTrace(s):
|
||||||
|
currentTime_ms = round(time.time()*1000)
|
||||||
|
dT_ms = currentTime_ms - startTime_ms
|
||||||
|
print("[" + str(dT_ms) + "ms] " + s)
|
||||||
|
|
||||||
|
def cbShowStatus(s, selection=""):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
soc_callback_enabled = getConfigValueBool("soc_callback_enabled")
|
||||||
|
soc_callback_url = getConfigValue("soc_callback_endpoint") if soc_callback_enabled else ""
|
||||||
|
|
||||||
|
def socStatusCallback(remaining_soc: int, full_soc: int = -1, bulk_soc: int = -1, origin: str = ""):
|
||||||
|
print(f"Received SoC status from {origin}.\n"
|
||||||
|
f" Remaining {remaining_soc}% \n"
|
||||||
|
f" Full at {full_soc}%\n"
|
||||||
|
f" Bulk at {bulk_soc}%")
|
||||||
|
if soc_callback_enabled:
|
||||||
|
requests.post(f"{soc_callback_url}/modem?remaining_soc={remaining_soc}&full_soc={full_soc}&bulk_soc={bulk_soc}")
|
||||||
|
|
||||||
|
myMode = C_EVSE_MODE
|
||||||
|
|
||||||
|
print("starting in EVSE_MODE")
|
||||||
|
print("press Ctrl-C to exit")
|
||||||
|
|
||||||
|
worker=pyPlcWorker.pyPlcWorker(cbAddToTrace, cbShowStatus, myMode, 0, socStatusCallback)
|
||||||
|
|
||||||
|
nMainloops=0
|
||||||
|
while (1):
|
||||||
|
time.sleep(.03) # 'do some calculation'
|
||||||
|
nMainloops+=1
|
||||||
|
worker.mainfunction()
|
||||||
|
|
||||||
|
#---------------------------------------------------------------
|
112
fsmEvse.py
112
fsmEvse.py
|
@ -7,9 +7,10 @@
|
||||||
import pyPlcTcpSocket
|
import pyPlcTcpSocket
|
||||||
import time # for time.sleep()
|
import time # for time.sleep()
|
||||||
from helpers import prettyHexMessage, combineValueAndMultiplier
|
from helpers import prettyHexMessage, combineValueAndMultiplier
|
||||||
from mytestsuite import *
|
from mytestsuite import *
|
||||||
from random import random
|
from random import random
|
||||||
from exiConnector import * # for EXI data handling/converting
|
from exiConnector import * # for EXI data handling/converting
|
||||||
|
import requests
|
||||||
|
|
||||||
stateWaitForSupportedApplicationProtocolRequest = 0
|
stateWaitForSupportedApplicationProtocolRequest = 0
|
||||||
stateWaitForSessionSetupRequest = 1
|
stateWaitForSessionSetupRequest = 1
|
||||||
|
@ -27,19 +28,23 @@ class fsmEvse():
|
||||||
|
|
||||||
def publishStatus(self, s):
|
def publishStatus(self, s):
|
||||||
self.callbackShowStatus(s, "evseState")
|
self.callbackShowStatus(s, "evseState")
|
||||||
|
|
||||||
|
def publishSoCs(self, remaining_soc: int, full_soc: int = -1, bulk_soc: int = -1, origin: str = ""):
|
||||||
|
if self.callbackSoCStatus is not None:
|
||||||
|
self.callbackSoCStatus(remaining_soc, full_soc, bulk_soc, origin)
|
||||||
|
|
||||||
def enterState(self, n):
|
def enterState(self, n):
|
||||||
self.addToTrace("from " + str(self.state) + " entering " + str(n))
|
self.addToTrace("from " + str(self.state) + " entering " + str(n))
|
||||||
if (self.state!=0) and (n==0):
|
if (self.state!=0) and (n==0):
|
||||||
self.publishStatus("Waiting f AppHandShake")
|
self.publishStatus("Waiting f AppHandShake")
|
||||||
self.state = n
|
self.state = n
|
||||||
self.cyclesInState = 0
|
self.cyclesInState = 0
|
||||||
|
|
||||||
def isTooLong(self):
|
def isTooLong(self):
|
||||||
# The timeout handling function.
|
# The timeout handling function.
|
||||||
return (self.cyclesInState > 100) # 100*33ms=3.3s
|
return (self.cyclesInState > 100) # 100*33ms=3.3s
|
||||||
|
|
||||||
|
|
||||||
def stateFunctionWaitForSupportedApplicationProtocolRequest(self):
|
def stateFunctionWaitForSupportedApplicationProtocolRequest(self):
|
||||||
if (len(self.rxData)>0):
|
if (len(self.rxData)>0):
|
||||||
self.addToTrace("In state WaitForSupportedApplicationProtocolRequest, received " + prettyHexMessage(self.rxData))
|
self.addToTrace("In state WaitForSupportedApplicationProtocolRequest, received " + prettyHexMessage(self.rxData))
|
||||||
|
@ -58,7 +63,7 @@ class fsmEvse():
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.publishStatus("Schema negotiated")
|
self.publishStatus("Schema negotiated")
|
||||||
self.enterState(stateWaitForSessionSetupRequest)
|
self.enterState(stateWaitForSessionSetupRequest)
|
||||||
|
|
||||||
def stateFunctionWaitForSessionSetupRequest(self):
|
def stateFunctionWaitForSessionSetupRequest(self):
|
||||||
if (len(self.rxData)>0):
|
if (len(self.rxData)>0):
|
||||||
self.simulatedPresentVoltage = 0
|
self.simulatedPresentVoltage = 0
|
||||||
|
@ -80,7 +85,7 @@ class fsmEvse():
|
||||||
self.enterState(stateWaitForServiceDiscoveryRequest)
|
self.enterState(stateWaitForServiceDiscoveryRequest)
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
def stateFunctionWaitForServiceDiscoveryRequest(self):
|
def stateFunctionWaitForServiceDiscoveryRequest(self):
|
||||||
if (len(self.rxData)>0):
|
if (len(self.rxData)>0):
|
||||||
self.addToTrace("In state WaitForServiceDiscoveryRequest, received " + prettyHexMessage(self.rxData))
|
self.addToTrace("In state WaitForServiceDiscoveryRequest, received " + prettyHexMessage(self.rxData))
|
||||||
|
@ -100,7 +105,7 @@ class fsmEvse():
|
||||||
self.enterState(stateWaitForServicePaymentSelectionRequest)
|
self.enterState(stateWaitForServicePaymentSelectionRequest)
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
def stateFunctionWaitForServicePaymentSelectionRequest(self):
|
def stateFunctionWaitForServicePaymentSelectionRequest(self):
|
||||||
if (len(self.rxData)>0):
|
if (len(self.rxData)>0):
|
||||||
self.addToTrace("In state WaitForServicePaymentSelectionRequest, received " + prettyHexMessage(self.rxData))
|
self.addToTrace("In state WaitForServicePaymentSelectionRequest, received " + prettyHexMessage(self.rxData))
|
||||||
|
@ -120,7 +125,7 @@ class fsmEvse():
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified. The Ioniq sends PowerDeliveryReq as next.
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified. The Ioniq sends PowerDeliveryReq as next.
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
def stateFunctionWaitForFlexibleRequest(self):
|
def stateFunctionWaitForFlexibleRequest(self):
|
||||||
if (len(self.rxData)>0):
|
if (len(self.rxData)>0):
|
||||||
self.addToTrace("In state WaitForFlexibleRequest, received " + prettyHexMessage(self.rxData))
|
self.addToTrace("In state WaitForFlexibleRequest, received " + prettyHexMessage(self.rxData))
|
||||||
|
@ -130,15 +135,26 @@ class fsmEvse():
|
||||||
self.addToTrace(strConverterResult)
|
self.addToTrace(strConverterResult)
|
||||||
if (strConverterResult.find("PowerDeliveryReq")>0):
|
if (strConverterResult.find("PowerDeliveryReq")>0):
|
||||||
# todo: check the request content, and fill response parameters
|
# todo: check the request content, and fill response parameters
|
||||||
|
self.addToTrace("Received PowerDeliveryReq. Extracting SoC parameters")
|
||||||
|
info = json.loads(strConverterResult)
|
||||||
|
remaining_soc = int(info.get("EVRESSSOC", -1))
|
||||||
|
self.publishSoCs(remaining_soc, origin="PowerDeliveryReq")
|
||||||
msg = addV2GTPHeader(exiEncode("EDh")) # EDh for Encode, Din, PowerDeliveryResponse
|
msg = addV2GTPHeader(exiEncode("EDh")) # EDh for Encode, Din, PowerDeliveryResponse
|
||||||
if (testsuite_faultinjection_is_triggered(TC_EVSE_ResponseCode_Failed_for_PowerDeliveryRes)):
|
if (testsuite_faultinjection_is_triggered(TC_EVSE_ResponseCode_Failed_for_PowerDeliveryRes)):
|
||||||
# send a PowerDeliveryResponse with Responsecode Failed
|
# send a PowerDeliveryResponse with Responsecode Failed
|
||||||
msg = addV2GTPHeader("809a0125e6cecc51408420400000")
|
msg = addV2GTPHeader("809a0125e6cecc51408420400000")
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("PowerDelivery")
|
self.publishStatus("PowerDelivery")
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
if (strConverterResult.find("ChargeParameterDiscoveryReq")>0):
|
if (strConverterResult.find("ChargeParameterDiscoveryReq")>0):
|
||||||
|
self.addToTrace("Received ChargeParameterDiscoveryReq. Extracting SoC parameters via DC")
|
||||||
|
info = json.loads(strConverterResult)
|
||||||
|
remaining_soc = int(info.get("DC_EVStatus.EVRESSSOC", -1))
|
||||||
|
full_soc = int(info.get("FullSOC", -1))
|
||||||
|
bulk_soc = int(info.get("BulkSOC", -1))
|
||||||
|
self.publishSoCs(remaining_soc, full_soc, bulk_soc, origin="ChargeParameterDiscoveryReq")
|
||||||
|
|
||||||
# todo: check the request content, and fill response parameters
|
# todo: check the request content, and fill response parameters
|
||||||
msg = addV2GTPHeader(exiEncode("EDe")) # EDe for Encode, Din, ChargeParameterDiscoveryResponse
|
msg = addV2GTPHeader(exiEncode("EDe")) # EDe for Encode, Din, ChargeParameterDiscoveryResponse
|
||||||
if (testsuite_faultinjection_is_triggered(TC_EVSE_ResponseCode_ServiceSelectionInvalid_for_ChargeParameterDiscovery)):
|
if (testsuite_faultinjection_is_triggered(TC_EVSE_ResponseCode_ServiceSelectionInvalid_for_ChargeParameterDiscovery)):
|
||||||
|
@ -146,11 +162,16 @@ class fsmEvse():
|
||||||
msg = addV2GTPHeader("809a0125e6cecd50810001ec00201004051828758405500080000101844138101c2432c04081436c900c0c000041435ecc044606000200")
|
msg = addV2GTPHeader("809a0125e6cecd50810001ec00201004051828758405500080000101844138101c2432c04081436c900c0c000041435ecc044606000200")
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("ChargeParamDiscovery")
|
self.publishStatus("ChargeParamDiscovery")
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
if (strConverterResult.find("CableCheckReq")>0):
|
if (strConverterResult.find("CableCheckReq")>0):
|
||||||
# todo: check the request content, and fill response parameters
|
# todo: check the request content, and fill response parameters
|
||||||
# todo: make a real cable check, and while it is ongoing, send "Ongoing".
|
# todo: make a real cable check, and while it is ongoing, send "Ongoing".
|
||||||
|
self.addToTrace("Received CableCheckReq. Extracting SoC parameters via DC")
|
||||||
|
info = json.loads(strConverterResult)
|
||||||
|
remaining_soc = int(info.get("DC_EVStatus.EVRESSSOC", -1))
|
||||||
|
self.publishSoCs(remaining_soc, -1, -1, origin="CableCheckReq")
|
||||||
|
|
||||||
msg = addV2GTPHeader(exiEncode("EDf")) # EDf for Encode, Din, CableCheckResponse
|
msg = addV2GTPHeader(exiEncode("EDf")) # EDf for Encode, Din, CableCheckResponse
|
||||||
if (testsuite_faultinjection_is_triggered(TC_EVSE_ResponseCode_Failed_for_CableCheckRes)):
|
if (testsuite_faultinjection_is_triggered(TC_EVSE_ResponseCode_Failed_for_CableCheckRes)):
|
||||||
# send a CableCheckResponse with Responsecode Failed
|
# send a CableCheckResponse with Responsecode Failed
|
||||||
|
@ -158,7 +179,7 @@ class fsmEvse():
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("CableCheck")
|
self.publishStatus("CableCheck")
|
||||||
if (not testsuite_faultinjection_is_triggered(TC_EVSE_Timeout_during_CableCheck)):
|
if (not testsuite_faultinjection_is_triggered(TC_EVSE_Timeout_during_CableCheck)):
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
if (strConverterResult.find("PreChargeReq")>0):
|
if (strConverterResult.find("PreChargeReq")>0):
|
||||||
# check the request content, and fill response parameters
|
# check the request content, and fill response parameters
|
||||||
|
@ -191,8 +212,8 @@ class fsmEvse():
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("PreCharging " + strPresentVoltage)
|
self.publishStatus("PreCharging " + strPresentVoltage)
|
||||||
if (not testsuite_faultinjection_is_triggered(TC_EVSE_Timeout_during_PreCharge)):
|
if (not testsuite_faultinjection_is_triggered(TC_EVSE_Timeout_during_PreCharge)):
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
if (strConverterResult.find("ContractAuthenticationReq")>0):
|
if (strConverterResult.find("ContractAuthenticationReq")>0):
|
||||||
# todo: check the request content, and fill response parameters
|
# todo: check the request content, and fill response parameters
|
||||||
msg = addV2GTPHeader(exiEncode("EDl")) # EDl for Encode, Din, ContractAuthenticationResponse
|
msg = addV2GTPHeader(exiEncode("EDl")) # EDl for Encode, Din, ContractAuthenticationResponse
|
||||||
|
@ -201,8 +222,8 @@ class fsmEvse():
|
||||||
msg = addV2GTPHeader("809a021a3b7c417774813310c0A200")
|
msg = addV2GTPHeader("809a021a3b7c417774813310c0A200")
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("ContractAuthentication")
|
self.publishStatus("ContractAuthentication")
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
if (strConverterResult.find("CurrentDemandReq")>0):
|
if (strConverterResult.find("CurrentDemandReq")>0):
|
||||||
# check the request content, and fill response parameters
|
# check the request content, and fill response parameters
|
||||||
uTarget = 220 # default in case we cannot decode the requested voltage
|
uTarget = 220 # default in case we cannot decode the requested voltage
|
||||||
|
@ -212,8 +233,14 @@ class fsmEvse():
|
||||||
strEVTargetVoltageMultiplier = y["EVTargetVoltage.Multiplier"]
|
strEVTargetVoltageMultiplier = y["EVTargetVoltage.Multiplier"]
|
||||||
uTarget = combineValueAndMultiplier(strEVTargetVoltageValue, strEVTargetVoltageMultiplier)
|
uTarget = combineValueAndMultiplier(strEVTargetVoltageValue, strEVTargetVoltageMultiplier)
|
||||||
self.addToTrace("EV wants EVTargetVoltage " + str(uTarget))
|
self.addToTrace("EV wants EVTargetVoltage " + str(uTarget))
|
||||||
strSoc = y["DC_EVStatus.EVRESSSOC"]
|
|
||||||
self.callbackShowStatus(strSoc, "soc")
|
remaining_soc = int(y.get("DC_EVStatus.EVRESSSOC", -1))
|
||||||
|
full_soc = int(y.get("FullSOC", -1))
|
||||||
|
bulk_soc = int(y.get("BulkSOC", -1))
|
||||||
|
self.publishSoCs(remaining_soc, full_soc, bulk_soc, origin="CurrentDemandReq")
|
||||||
|
|
||||||
|
self.callbackShowStatus(str(remaining_soc), "soc")
|
||||||
|
|
||||||
except:
|
except:
|
||||||
self.addToTrace("ERROR: Could not decode the CurrentDemandReq")
|
self.addToTrace("ERROR: Could not decode the CurrentDemandReq")
|
||||||
self.simulatedPresentVoltage = uTarget + 3*random() # The charger provides the voltage which is demanded by the car.
|
self.simulatedPresentVoltage = uTarget + 3*random() # The charger provides the voltage which is demanded by the car.
|
||||||
|
@ -233,40 +260,40 @@ class fsmEvse():
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("CurrentDemand")
|
self.publishStatus("CurrentDemand")
|
||||||
if (not testsuite_faultinjection_is_triggered(TC_EVSE_Timeout_during_CurrentDemand)):
|
if (not testsuite_faultinjection_is_triggered(TC_EVSE_Timeout_during_CurrentDemand)):
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
if (strConverterResult.find("WeldingDetectionReq")>0):
|
if (strConverterResult.find("WeldingDetectionReq")>0):
|
||||||
# todo: check the request content, and fill response parameters
|
# todo: check the request content, and fill response parameters
|
||||||
msg = addV2GTPHeader(exiEncode("EDj")) # EDj for Encode, Din, WeldingDetectionRes
|
msg = addV2GTPHeader(exiEncode("EDj")) # EDj for Encode, Din, WeldingDetectionRes
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("WeldingDetection")
|
self.publishStatus("WeldingDetection")
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
if (strConverterResult.find("SessionStopReq")>0):
|
if (strConverterResult.find("SessionStopReq")>0):
|
||||||
# todo: check the request content, and fill response parameters
|
# todo: check the request content, and fill response parameters
|
||||||
msg = addV2GTPHeader(exiEncode("EDk")) # EDk for Encode, Din, SessionStopRes
|
msg = addV2GTPHeader(exiEncode("EDk")) # EDk for Encode, Din, SessionStopRes
|
||||||
self.addToTrace("responding " + prettyHexMessage(msg))
|
self.addToTrace("responding " + prettyHexMessage(msg))
|
||||||
self.publishStatus("SessionStop")
|
self.publishStatus("SessionStop")
|
||||||
self.Tcp.transmit(msg)
|
self.Tcp.transmit(msg)
|
||||||
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
self.enterState(stateWaitForFlexibleRequest) # todo: not clear, what is specified in DIN
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
def stateFunctionWaitForChargeParameterDiscoveryRequest(self):
|
def stateFunctionWaitForChargeParameterDiscoveryRequest(self):
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
def stateFunctionWaitForCableCheckRequest(self):
|
def stateFunctionWaitForCableCheckRequest(self):
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
def stateFunctionWaitForPreChargeRequest(self):
|
def stateFunctionWaitForPreChargeRequest(self):
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
def stateFunctionWaitForPowerDeliveryRequest(self):
|
def stateFunctionWaitForPowerDeliveryRequest(self):
|
||||||
if (len(self.rxData)>0):
|
if (len(self.rxData)>0):
|
||||||
self.addToTrace("In state WaitForPowerDeliveryRequest, received " + prettyHexMessage(self.rxData))
|
self.addToTrace("In state WaitForPowerDeliveryRequest, received " + prettyHexMessage(self.rxData))
|
||||||
|
@ -275,9 +302,9 @@ class fsmEvse():
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
if (self.isTooLong()):
|
if (self.isTooLong()):
|
||||||
self.enterState(0)
|
self.enterState(0)
|
||||||
|
|
||||||
|
|
||||||
stateFunctions = {
|
stateFunctions = {
|
||||||
stateWaitForSupportedApplicationProtocolRequest: stateFunctionWaitForSupportedApplicationProtocolRequest,
|
stateWaitForSupportedApplicationProtocolRequest: stateFunctionWaitForSupportedApplicationProtocolRequest,
|
||||||
stateWaitForSessionSetupRequest: stateFunctionWaitForSessionSetupRequest,
|
stateWaitForSessionSetupRequest: stateFunctionWaitForSessionSetupRequest,
|
||||||
stateWaitForServiceDiscoveryRequest: stateFunctionWaitForServiceDiscoveryRequest,
|
stateWaitForServiceDiscoveryRequest: stateFunctionWaitForServiceDiscoveryRequest,
|
||||||
|
@ -288,15 +315,15 @@ class fsmEvse():
|
||||||
stateWaitForPreChargeRequest: stateFunctionWaitForPreChargeRequest,
|
stateWaitForPreChargeRequest: stateFunctionWaitForPreChargeRequest,
|
||||||
stateWaitForPowerDeliveryRequest: stateFunctionWaitForPowerDeliveryRequest,
|
stateWaitForPowerDeliveryRequest: stateFunctionWaitForPowerDeliveryRequest,
|
||||||
}
|
}
|
||||||
|
|
||||||
def reInit(self):
|
def reInit(self):
|
||||||
self.addToTrace("re-initializing fsmEvse")
|
self.addToTrace("re-initializing fsmEvse")
|
||||||
self.state = 0
|
self.state = 0
|
||||||
self.cyclesInState = 0
|
self.cyclesInState = 0
|
||||||
self.rxData = []
|
self.rxData = []
|
||||||
self.simulatedPresentVoltage = 0
|
self.simulatedPresentVoltage = 0
|
||||||
self.Tcp.resetTheConnection()
|
self.Tcp.resetTheConnection()
|
||||||
|
|
||||||
def socketStateNotification(self, notification):
|
def socketStateNotification(self, notification):
|
||||||
if (notification==0):
|
if (notification==0):
|
||||||
# The TCP informs us, that the connection is broken.
|
# The TCP informs us, that the connection is broken.
|
||||||
|
@ -311,12 +338,13 @@ class fsmEvse():
|
||||||
# The TCP informs us, that a connection is established.
|
# The TCP informs us, that a connection is established.
|
||||||
self.publishStatus("TCP connected")
|
self.publishStatus("TCP connected")
|
||||||
|
|
||||||
def __init__(self, addressManager, callbackAddToTrace, hardwareInterface, callbackShowStatus):
|
def __init__(self, addressManager, callbackAddToTrace, hardwareInterface, callbackShowStatus, callbackSoCStatus = None):
|
||||||
self.callbackAddToTrace = callbackAddToTrace
|
self.callbackAddToTrace = callbackAddToTrace
|
||||||
self.callbackShowStatus = callbackShowStatus
|
self.callbackShowStatus = callbackShowStatus
|
||||||
|
self.callbackSoCStatus = callbackSoCStatus
|
||||||
#todo self.addressManager = addressManager
|
#todo self.addressManager = addressManager
|
||||||
#todo self.hardwareInterface = hardwareInterface
|
#todo self.hardwareInterface = hardwareInterface
|
||||||
self.addToTrace("initializing fsmEvse")
|
self.addToTrace("initializing fsmEvse")
|
||||||
self.faultInjectionDelayUntilSocketOpen_s = 0
|
self.faultInjectionDelayUntilSocketOpen_s = 0
|
||||||
if (self.faultInjectionDelayUntilSocketOpen_s>0):
|
if (self.faultInjectionDelayUntilSocketOpen_s>0):
|
||||||
self.addToTrace("Fault injection: waiting " + str(self.faultInjectionDelayUntilSocketOpen_s) + " s until opening the TCP socket.")
|
self.addToTrace("Fault injection: waiting " + str(self.faultInjectionDelayUntilSocketOpen_s) + " s until opening the TCP socket.")
|
||||||
|
@ -325,7 +353,7 @@ class fsmEvse():
|
||||||
self.state = 0
|
self.state = 0
|
||||||
self.cyclesInState = 0
|
self.cyclesInState = 0
|
||||||
self.rxData = []
|
self.rxData = []
|
||||||
|
|
||||||
def mainfunction(self):
|
def mainfunction(self):
|
||||||
self.Tcp.mainfunction() # call the lower-level worker
|
self.Tcp.mainfunction() # call the lower-level worker
|
||||||
if (self.Tcp.isRxDataAvailable()):
|
if (self.Tcp.isRxDataAvailable()):
|
||||||
|
@ -334,8 +362,8 @@ class fsmEvse():
|
||||||
# run the state machine:
|
# run the state machine:
|
||||||
self.cyclesInState += 1 # for timeout handling, count how long we are in a state
|
self.cyclesInState += 1 # for timeout handling, count how long we are in a state
|
||||||
self.stateFunctions[self.state](self)
|
self.stateFunctions[self.state](self)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("Testing the evse state machine")
|
print("Testing the evse state machine")
|
||||||
evse = fsmEvse()
|
evse = fsmEvse()
|
||||||
|
@ -343,5 +371,5 @@ if __name__ == "__main__":
|
||||||
while (True):
|
while (True):
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
evse.mainfunction()
|
evse.mainfunction()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1020,7 +1020,7 @@ class pyPlcHomeplug():
|
||||||
|
|
||||||
|
|
||||||
def findEthernetAdaptor(self):
|
def findEthernetAdaptor(self):
|
||||||
self.strInterfaceName="eth0" # default, if the real is not found
|
self.strInterfaceName="eth1" # default, if the real is not found
|
||||||
#print("Interfaces:\n" + '\n'.join(pcap.findalldevs()))
|
#print("Interfaces:\n" + '\n'.join(pcap.findalldevs()))
|
||||||
for i in range(0, 10):
|
for i in range(0, 10):
|
||||||
strInterfaceName = pcap.ex_name("eth"+str(i))
|
strInterfaceName = pcap.ex_name("eth"+str(i))
|
||||||
|
|
|
@ -52,7 +52,7 @@ class pyPlcTcpClientSocket():
|
||||||
#print(host[0:5].lower())
|
#print(host[0:5].lower())
|
||||||
if (host[0:5].lower()=="fe80:"):
|
if (host[0:5].lower()=="fe80:"):
|
||||||
#print("This is a link local address. We need to add %eth0 at the end.")
|
#print("This is a link local address. We need to add %eth0 at the end.")
|
||||||
host = host + "%eth0"
|
host = host + "%eth1"
|
||||||
socket_addr = socket.getaddrinfo(host,port,socket.AF_INET6,socket.SOCK_DGRAM,socket.SOL_UDP)[0][4]
|
socket_addr = socket.getaddrinfo(host,port,socket.AF_INET6,socket.SOCK_DGRAM,socket.SOL_UDP)[0][4]
|
||||||
|
|
||||||
#print(socket_addr)
|
#print(socket_addr)
|
||||||
|
@ -182,6 +182,10 @@ class pyPlcTcpServerSocket():
|
||||||
# in case of a broken connection, here we try to start it again
|
# in case of a broken connection, here we try to start it again
|
||||||
self.addToTrace("Trying to reset the TCP socket")
|
self.addToTrace("Trying to reset the TCP socket")
|
||||||
# Todo: how to "reset" the socket?
|
# Todo: how to "reset" the socket?
|
||||||
|
try:
|
||||||
|
self.ourSocket.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
self.ourSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
|
self.ourSocket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM, 0)
|
||||||
self.ourSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
self.ourSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
self.ourSocket.bind((self.ipAdress, self.tcpPort))
|
self.ourSocket.bind((self.ipAdress, self.tcpPort))
|
||||||
|
@ -297,7 +301,7 @@ def testClientSocket():
|
||||||
#c.connect('fe80::e0ad:99ac:52eb:85d3', 15118)
|
#c.connect('fe80::e0ad:99ac:52eb:85d3', 15118)
|
||||||
#c.connect('fe80::e0ad:99ac:52eb:9999', 15118)
|
#c.connect('fe80::e0ad:99ac:52eb:9999', 15118)
|
||||||
#c.connect('localhost', 15118)
|
#c.connect('localhost', 15118)
|
||||||
c.connect('fe80::c690:83f3:fbcb:980e', 15118)
|
c.connect('fe80::407d:89f9:f6c2:6ee0', 15118)
|
||||||
print("connected="+str(c.isConnected))
|
print("connected="+str(c.isConnected))
|
||||||
if (c.isConnected):
|
if (c.isConnected):
|
||||||
print("sending something to the server")
|
print("sending something to the server")
|
||||||
|
|
|
@ -15,17 +15,18 @@ import time
|
||||||
import subprocess
|
import subprocess
|
||||||
import hardwareInterface
|
import hardwareInterface
|
||||||
import connMgr
|
import connMgr
|
||||||
|
|
||||||
|
|
||||||
class pyPlcWorker():
|
class pyPlcWorker():
|
||||||
def __init__(self, callbackAddToTrace=None, callbackShowStatus=None, mode=C_EVSE_MODE, isSimulationMode=0):
|
def __init__(self, callbackAddToTrace=None, callbackShowStatus=None, mode=C_EVSE_MODE, isSimulationMode=0, callbackSoC=None):
|
||||||
print("initializing pyPlcWorker")
|
print("initializing pyPlcWorker")
|
||||||
self.nMainFunctionCalls=0
|
self.nMainFunctionCalls=0
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.strUserAction = ""
|
self.strUserAction = ""
|
||||||
self.addressManager = addressManager.addressManager()
|
self.addressManager = addressManager.addressManager()
|
||||||
self.callbackAddToTrace = callbackAddToTrace
|
self.callbackAddToTrace = callbackAddToTrace
|
||||||
self.callbackShowStatus = callbackShowStatus
|
self.callbackShowStatus = callbackShowStatus
|
||||||
|
self.callbackSoC = callbackSoC
|
||||||
self.oldAvlnStatus = 0
|
self.oldAvlnStatus = 0
|
||||||
self.isSimulationMode = isSimulationMode
|
self.isSimulationMode = isSimulationMode
|
||||||
self.connMgr = connMgr.connMgr(self.workerAddToTrace, self.showStatus)
|
self.connMgr = connMgr.connMgr(self.workerAddToTrace, self.showStatus)
|
||||||
|
@ -38,9 +39,9 @@ class pyPlcWorker():
|
||||||
strLabel = str(subprocess.check_output(["git", "describe", "--tags"], text=True).strip())
|
strLabel = str(subprocess.check_output(["git", "describe", "--tags"], text=True).strip())
|
||||||
except:
|
except:
|
||||||
strLabel = "(unknown version. 'git describe --tags' failed.)"
|
strLabel = "(unknown version. 'git describe --tags' failed.)"
|
||||||
self.workerAddToTrace("[pyPlcWorker] Software version " + strLabel)
|
self.workerAddToTrace("[pyPlcWorker] Software version " + strLabel)
|
||||||
if (self.mode == C_EVSE_MODE):
|
if (self.mode == C_EVSE_MODE):
|
||||||
self.evse = fsmEvse.fsmEvse(self.addressManager, self.workerAddToTrace, self.hardwareInterface, self.showStatus)
|
self.evse = fsmEvse.fsmEvse(self.addressManager, self.workerAddToTrace, self.hardwareInterface, self.showStatus, self.callbackSoC)
|
||||||
if (self.mode == C_PEV_MODE):
|
if (self.mode == C_PEV_MODE):
|
||||||
self.pev = fsmPev.fsmPev(self.addressManager, self.connMgr, self.workerAddToTrace, self.hardwareInterface, self.showStatus)
|
self.pev = fsmPev.fsmPev(self.addressManager, self.connMgr, self.workerAddToTrace, self.hardwareInterface, self.showStatus)
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
|
@ -49,14 +50,14 @@ class pyPlcWorker():
|
||||||
del(self.pev)
|
del(self.pev)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def workerAddToTrace(self, s):
|
def workerAddToTrace(self, s):
|
||||||
# The central logging function. All logging messages from the different parts of the project
|
# The central logging function. All logging messages from the different parts of the project
|
||||||
# shall come here.
|
# shall come here.
|
||||||
#print("workerAddToTrace " + s)
|
#print("workerAddToTrace " + s)
|
||||||
self.callbackAddToTrace(s) # give the message to the upper level, eg for console log.
|
self.callbackAddToTrace(s) # give the message to the upper level, eg for console log.
|
||||||
self.hp.printToUdp(s) # give the message to the udp for remote logging.
|
self.hp.printToUdp(s) # give the message to the udp for remote logging.
|
||||||
|
|
||||||
def showStatus(self, s, selection = "", strAuxInfo1="", strAuxInfo2=""):
|
def showStatus(self, s, selection = "", strAuxInfo1="", strAuxInfo2=""):
|
||||||
self.callbackShowStatus(s, selection)
|
self.callbackShowStatus(s, selection)
|
||||||
if (selection == "pevState"):
|
if (selection == "pevState"):
|
||||||
|
@ -70,7 +71,7 @@ class pyPlcWorker():
|
||||||
return
|
return
|
||||||
if (self.connMgr.getConnectionLevel()<50):
|
if (self.connMgr.getConnectionLevel()<50):
|
||||||
self.oldAvlnStatus = 0
|
self.oldAvlnStatus = 0
|
||||||
|
|
||||||
def mainfunction(self):
|
def mainfunction(self):
|
||||||
self.nMainFunctionCalls+=1
|
self.nMainFunctionCalls+=1
|
||||||
#self.showStatus("pyPlcWorker loop " + str(self.nMainFunctionCalls))
|
#self.showStatus("pyPlcWorker loop " + str(self.nMainFunctionCalls))
|
||||||
|
@ -83,7 +84,7 @@ class pyPlcWorker():
|
||||||
self.evse.mainfunction() # call the evse state machine
|
self.evse.mainfunction() # call the evse state machine
|
||||||
if (self.mode == C_PEV_MODE):
|
if (self.mode == C_PEV_MODE):
|
||||||
self.pev.mainfunction() # call the pev state machine
|
self.pev.mainfunction() # call the pev state machine
|
||||||
|
|
||||||
def handleUserAction(self, strAction):
|
def handleUserAction(self, strAction):
|
||||||
self.strUserAction = strAction
|
self.strUserAction = strAction
|
||||||
print("user action " + strAction)
|
print("user action " + strAction)
|
||||||
|
@ -112,7 +113,7 @@ class pyPlcWorker():
|
||||||
if (strAction == "L"):
|
if (strAction == "L"):
|
||||||
print("switching to LISTEN mode")
|
print("switching to LISTEN mode")
|
||||||
self.mode = C_LISTEN_MODE
|
self.mode = C_LISTEN_MODE
|
||||||
self.hp.enterListenMode()
|
self.hp.enterListenMode()
|
||||||
if (hasattr(self, 'evse')):
|
if (hasattr(self, 'evse')):
|
||||||
print("deleting evse")
|
print("deleting evse")
|
||||||
del self.evse
|
del self.evse
|
||||||
|
|
Loading…
Reference in a new issue