fix: pevmode: wait for contactors closed (in work). feature: more config options

This commit is contained in:
uhi22 2023-05-03 21:25:01 +02:00
parent 893ade2e9f
commit 14b1cdb2ff
5 changed files with 141 additions and 15 deletions

3
.gitignore vendored
View file

@ -1,4 +1,7 @@
.*
/__pycache__/ /__pycache__/
/doc/*.jar /doc/*.jar
*.bat *.bat
PevExiLog*.txt PevExiLog*.txt
pyPlc.ini
/log

77
doc/pyPlc.ini.template Normal file
View file

@ -0,0 +1,77 @@
# This is the template file pyPlc.ini.template.
# Copy this file in the same folder like the pyPlc.py, and rename it to pyPlc.ini
[general]
# mode can be either PevMode to use as car, or EvseMode to use as charger
mode = PevMode
# Simulation without modem
# For development purposes, make it possible to run two instances (pev and evse) on one machine, without
# a modem connected. This feature is not tested since a long time, most likely does not work as intended.
# todo: replace isSimulationMode by this setting
is_simulation_without_modems = false
# The Ethernet interface. Usually eth0 on Raspberry.
# Todo: This setting is considered only on linux. Find a clean solution for windows is to be done.
eth_interface = eth0
# If a display is connected via serial line, e.g. an WIFI-KIT-32 running the software from https://github.com/uhi22/SerialToOLED
display_via_serial = yes
# LightBulbDemo turns on the relay with a short delay in the charging loop, to stabilize the voltage
# before the resistive load is connected.
light_bulb_demo = no
# SOC simulation.
# In PevMode, simulate a rising SOC while charging.
soc_simulation = yes
# Device selection for the digital outputs, for CP state and power relays
# Possible options:
# dieter: Serial controlled device, which controls the digital outputs. E.g. arduino from https://github.com/uhi22/dieter
# beaglebone: GPIO pins of the beagleBone, as used in https://github.com/jsphuebner/pyPLC/tree/beaglebone
# celeron55device: Serial controlled device as used in https://openinverter.org/forum/viewtopic.php?p=56192#p56192
digital_output_device = dieter
#digital_output_device = beaglebone
#digital_output_device = celeron55device
# Device to read the physically measured inlet voltage in PevMode
# Possible options:
# dieter: The high-voltage dieter from https://github.com/uhi22/dieter, which is connected on serial port.
# none: if no measurement is intended.
# celeron55device: as used in https://openinverter.org/forum/viewtopic.php?p=56192#p56192
#analog_input_device = dieter
analog_input_device = none
#analog_input_device = celeron55device
# Criteria for ending the PreCharge phase in PevMode
# Possible options:
# yes: use the EVSEPresentVoltage which is reported by the charger, to decide the end of the precharge
# no: use the physically measured inlet voltage to decide the end of the precharge
use_evsepresentvoltage_for_precharge_end = yes
# Use the physically measured inlet voltage to show on display during the charge loop.
# If false, we are showing the EVSEPresentVoltage which is reported by the charger.
use_physical_inlet_voltage_during_chargeloop = no
# Voltage threshold for the end-of-precharge decision
# This is the maximum difference voltage between the charger voltage and the accu voltage. If the actual voltage
# difference is lower than this threshold, we will close the power relay, to connect the accu to the charger.
# Unit: volt
u_delta_max_for_end_of_precharge = 10
# Added by celeron55
# The serial port and baud rate used for communication. Used
# for serial devices like Dieter, OLED-Display and
# celeron55's measuring and switching device
serial_port = /dev/ttyS1
serial_baud = 115200
# The target voltage used in the CurrentDemandRequest.
# This is a value for first try-outs. Better would
# be if the BMS would provide the value.
# 11 * 6 * 4.1V = 66 * 4.1V = 270V
charge_target_voltage = 270

View file

@ -24,11 +24,12 @@ stateWaitForContractAuthenticationResponse = 7
stateWaitForChargeParameterDiscoveryResponse = 8 stateWaitForChargeParameterDiscoveryResponse = 8
stateWaitForCableCheckResponse = 9 stateWaitForCableCheckResponse = 9
stateWaitForPreChargeResponse = 10 stateWaitForPreChargeResponse = 10
stateWaitForPowerDeliveryResponse = 11 stateWaitForContactorsClosed = 11
stateWaitForCurrentDemandResponse = 12 stateWaitForPowerDeliveryResponse = 12
stateWaitForWeldingDetectionResponse = 13 stateWaitForCurrentDemandResponse = 13
stateWaitForSessionStopResponse = 14 stateWaitForWeldingDetectionResponse = 14
stateChargingFinished = 15 stateWaitForSessionStopResponse = 15
stateChargingFinished = 16
stateSequenceTimeout = 99 stateSequenceTimeout = 99
@ -81,6 +82,8 @@ class fsmPev():
s = "WaitForCableCheckResponse" s = "WaitForCableCheckResponse"
if (statenumber == stateWaitForPreChargeResponse): if (statenumber == stateWaitForPreChargeResponse):
s = "WaitForPreChargeResponse" s = "WaitForPreChargeResponse"
if (statenumber == stateWaitForContactorsClosed):
s = "WaitForContactorsClosed"
if (statenumber == stateWaitForPowerDeliveryResponse): if (statenumber == stateWaitForPowerDeliveryResponse):
s = "WaitForPowerDeliveryResponse" s = "WaitForPowerDeliveryResponse"
if (statenumber == stateWaitForCurrentDemandResponse): if (statenumber == stateWaitForCurrentDemandResponse):
@ -408,20 +411,17 @@ class fsmPev():
s= s + "U_Accu " + str(self.hardwareInterface.getAccuVoltage()) + "V" s= s + "U_Accu " + str(self.hardwareInterface.getAccuVoltage()) + "V"
self.addToTrace(s) self.addToTrace(s)
if (abs(u-self.hardwareInterface.getAccuVoltage()) < float(getConfigValue("u_delta_max_for_end_of_precharge"))): if (abs(u-self.hardwareInterface.getAccuVoltage()) < float(getConfigValue("u_delta_max_for_end_of_precharge"))):
self.addToTrace("Difference between accu voltage and inlet voltage is small. Sending PowerDeliveryReq.") self.addToTrace("Difference between accu voltage and inlet voltage is small.")
self.publishStatus("PreCharge done") self.publishStatus("PreCharge done")
if (self.isLightBulbDemo): if (self.isLightBulbDemo):
# For light-bulb-demo, nothing to do here. # 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.") self.addToTrace("This is a light bulb demo. Do not turn-on the relay at end of precharge.")
else: else:
# In real-world-case, turn the power relay on. # In real-world-case, turn the power relay on.
self.addToTrace("Checkpoint590: Turning the contactors on.")
self.hardwareInterface.setPowerRelayOn() self.hardwareInterface.setPowerRelayOn()
soc = self.hardwareInterface.getSoc() self.DelayCycles = 10 # 10*33ms = 330ms waiting for contactors
msg = addV2GTPHeader(self.exiEncode("EDH_"+self.sessionId+"_"+ str(soc) + "_" + "1")) # EDH for Encode, Din, PowerDeliveryReq, ON self.enterState(stateWaitForContactorsClosed)
self.wasPowerDeliveryRequestedOn=True
self.addToTrace("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForPowerDeliveryResponse)
else: else:
self.publishStatus("PreChrge ongoing", format(u, ".0f") + "V") self.publishStatus("PreChrge ongoing", format(u, ".0f") + "V")
self.addToTrace("Difference too big. Continuing PreCharge.") self.addToTrace("Difference too big. Continuing PreCharge.")
@ -434,6 +434,28 @@ class fsmPev():
if (self.isTooLong()): if (self.isTooLong()):
self.enterState(stateSequenceTimeout) self.enterState(stateSequenceTimeout)
def stateFunctionWaitForContactorsClosed(self):
if (self.DelayCycles>0):
self.DelayCycles-=1
return
if (self.isLightBulbDemo):
readyForNextState=1 # if it's just a bulb demo, we do not wait for contactor, because it is not switched in this moment.
else:
readyForNextState = self.hardwareInterface.getPowerRelayConfirmation() # check if the contactor is closed
if (readyForNextState):
self.addToTrace("Contactors are confirmed to be closed.")
self.publishStatus("Contactors ON")
if (readyForNextState):
self.addToTrace("Sending PowerDeliveryReq.")
soc = self.hardwareInterface.getSoc()
msg = addV2GTPHeader(self.exiEncode("EDH_"+self.sessionId+"_"+ str(soc) + "_" + "1")) # EDH for Encode, Din, PowerDeliveryReq, ON
self.wasPowerDeliveryRequestedOn=True
self.addToTrace("responding " + prettyHexMessage(msg))
self.Tcp.transmit(msg)
self.enterState(stateWaitForPowerDeliveryResponse)
if (self.isTooLong()):
self.enterState(stateSequenceTimeout)
def stateFunctionWaitForPowerDeliveryResponse(self): def stateFunctionWaitForPowerDeliveryResponse(self):
if (len(self.rxData)>0): if (len(self.rxData)>0):
self.addToTrace("In state WaitForPowerDeliveryRes, received " + prettyHexMessage(self.rxData)) self.addToTrace("In state WaitForPowerDeliveryRes, received " + prettyHexMessage(self.rxData))
@ -568,6 +590,7 @@ class fsmPev():
stateWaitForChargeParameterDiscoveryResponse: stateFunctionWaitForChargeParameterDiscoveryResponse, stateWaitForChargeParameterDiscoveryResponse: stateFunctionWaitForChargeParameterDiscoveryResponse,
stateWaitForCableCheckResponse: stateFunctionWaitForCableCheckResponse, stateWaitForCableCheckResponse: stateFunctionWaitForCableCheckResponse,
stateWaitForPreChargeResponse: stateFunctionWaitForPreChargeResponse, stateWaitForPreChargeResponse: stateFunctionWaitForPreChargeResponse,
stateWaitForContactorsClosed: stateFunctionWaitForContactorsClosed,
stateWaitForPowerDeliveryResponse: stateFunctionWaitForPowerDeliveryResponse, stateWaitForPowerDeliveryResponse: stateFunctionWaitForPowerDeliveryResponse,
stateWaitForCurrentDemandResponse: stateFunctionWaitForCurrentDemandResponse, stateWaitForCurrentDemandResponse: stateFunctionWaitForCurrentDemandResponse,
stateWaitForWeldingDetectionResponse: stateFunctionWaitForWeldingDetectionResponse, stateWaitForWeldingDetectionResponse: stateFunctionWaitForWeldingDetectionResponse,

View file

@ -89,6 +89,9 @@ class hardwareInterface():
self.addToTrace("Switching Relay2 OFF.") self.addToTrace("Switching Relay2 OFF.")
self.outvalue &= ~4 self.outvalue &= ~4
def getPowerRelayConfirmation(self):
return 1 # todo: self.contactor_confirmed
def getInletVoltage(self): def getInletVoltage(self):
# uncomment this line, to take the simulated inlet voltage instead of the really measured # uncomment this line, to take the simulated inlet voltage instead of the really measured
# self.inletVoltage = self.simulatedInletVoltage # self.inletVoltage = self.simulatedInletVoltage

View file

@ -18,7 +18,7 @@ display_via_serial = yes
# LightBulbDemo turns on the relay with a short delay in the charging loop, to stabilize the voltage # LightBulbDemo turns on the relay with a short delay in the charging loop, to stabilize the voltage
# before the resistive load is connected. # before the resistive load is connected.
light_bulb_demo = yes light_bulb_demo = no
# SOC simulation. # SOC simulation.
# In PevMode, simulate a rising SOC while charging. # In PevMode, simulate a rising SOC while charging.
@ -28,14 +28,21 @@ soc_simulation = yes
# Possible options: # Possible options:
# dieter: Serial controlled device, which controls the digital outputs. E.g. arduino from https://github.com/uhi22/dieter # dieter: Serial controlled device, which controls the digital outputs. E.g. arduino from https://github.com/uhi22/dieter
# beaglebone: GPIO pins of the beagleBone, as used in https://github.com/jsphuebner/pyPLC/tree/beaglebone # beaglebone: GPIO pins of the beagleBone, as used in https://github.com/jsphuebner/pyPLC/tree/beaglebone
# celeron55device: Serial controlled device as used in https://openinverter.org/forum/viewtopic.php?p=56192#p56192
digital_output_device = dieter digital_output_device = dieter
#digital_output_device = beaglebone #digital_output_device = beaglebone
#digital_output_device = celeron55device
# Device to read the physically measured inlet voltage in PevMode # Device to read the physically measured inlet voltage in PevMode
# Either the high-voltage dieter from https://github.com/uhi22/dieter, which is connected on serial port. # Possible options:
# Or "none", if no measurement is intended. # dieter: The high-voltage dieter from https://github.com/uhi22/dieter, which is connected on serial port.
# none: if no measurement is intended.
# celeron55device: as used in https://openinverter.org/forum/viewtopic.php?p=56192#p56192
#analog_input_device = dieter #analog_input_device = dieter
analog_input_device = none analog_input_device = none
#analog_input_device = celeron55device
# Criteria for ending the PreCharge phase in PevMode # Criteria for ending the PreCharge phase in PevMode
# Possible options: # Possible options:
@ -53,3 +60,16 @@ use_physical_inlet_voltage_during_chargeloop = no
# Unit: volt # Unit: volt
u_delta_max_for_end_of_precharge = 10 u_delta_max_for_end_of_precharge = 10
# Added by celeron55
# The serial port and baud rate used for communication. Used
# for serial devices like Dieter, OLED-Display and
# celeron55's measuring and switching device
serial_port = /dev/ttyS1
serial_baud = 115200
# The target voltage used in the CurrentDemandRequest.
# This is a value for first try-outs. Better would
# be if the BMS would provide the value.
# 11 * 6 * 4.1V = 66 * 4.1V = 270V
charge_target_voltage = 270