diff --git a/.gitignore b/.gitignore index 952c272..10e0d50 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ +.* /__pycache__/ /doc/*.jar *.bat PevExiLog*.txt +pyPlc.ini +/log diff --git a/doc/pyPlc.ini.template b/doc/pyPlc.ini.template new file mode 100644 index 0000000..7884ebe --- /dev/null +++ b/doc/pyPlc.ini.template @@ -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 + diff --git a/fsmPev.py b/fsmPev.py index 262dbf5..3ca4b57 100644 --- a/fsmPev.py +++ b/fsmPev.py @@ -24,11 +24,12 @@ stateWaitForContractAuthenticationResponse = 7 stateWaitForChargeParameterDiscoveryResponse = 8 stateWaitForCableCheckResponse = 9 stateWaitForPreChargeResponse = 10 -stateWaitForPowerDeliveryResponse = 11 -stateWaitForCurrentDemandResponse = 12 -stateWaitForWeldingDetectionResponse = 13 -stateWaitForSessionStopResponse = 14 -stateChargingFinished = 15 +stateWaitForContactorsClosed = 11 +stateWaitForPowerDeliveryResponse = 12 +stateWaitForCurrentDemandResponse = 13 +stateWaitForWeldingDetectionResponse = 14 +stateWaitForSessionStopResponse = 15 +stateChargingFinished = 16 stateSequenceTimeout = 99 @@ -81,6 +82,8 @@ class fsmPev(): s = "WaitForCableCheckResponse" if (statenumber == stateWaitForPreChargeResponse): s = "WaitForPreChargeResponse" + if (statenumber == stateWaitForContactorsClosed): + s = "WaitForContactorsClosed" if (statenumber == stateWaitForPowerDeliveryResponse): s = "WaitForPowerDeliveryResponse" if (statenumber == stateWaitForCurrentDemandResponse): @@ -408,20 +411,17 @@ class fsmPev(): s= s + "U_Accu " + str(self.hardwareInterface.getAccuVoltage()) + "V" self.addToTrace(s) 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") 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.addToTrace("Checkpoint590: Turning the contactors on.") self.hardwareInterface.setPowerRelayOn() - 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) + self.DelayCycles = 10 # 10*33ms = 330ms waiting for contactors + self.enterState(stateWaitForContactorsClosed) else: self.publishStatus("PreChrge ongoing", format(u, ".0f") + "V") self.addToTrace("Difference too big. Continuing PreCharge.") @@ -434,6 +434,28 @@ class fsmPev(): if (self.isTooLong()): 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): if (len(self.rxData)>0): self.addToTrace("In state WaitForPowerDeliveryRes, received " + prettyHexMessage(self.rxData)) @@ -568,6 +590,7 @@ class fsmPev(): stateWaitForChargeParameterDiscoveryResponse: stateFunctionWaitForChargeParameterDiscoveryResponse, stateWaitForCableCheckResponse: stateFunctionWaitForCableCheckResponse, stateWaitForPreChargeResponse: stateFunctionWaitForPreChargeResponse, + stateWaitForContactorsClosed: stateFunctionWaitForContactorsClosed, stateWaitForPowerDeliveryResponse: stateFunctionWaitForPowerDeliveryResponse, stateWaitForCurrentDemandResponse: stateFunctionWaitForCurrentDemandResponse, stateWaitForWeldingDetectionResponse: stateFunctionWaitForWeldingDetectionResponse, diff --git a/hardwareInterface.py b/hardwareInterface.py index 2a7e172..ecb4595 100644 --- a/hardwareInterface.py +++ b/hardwareInterface.py @@ -89,6 +89,9 @@ class hardwareInterface(): self.addToTrace("Switching Relay2 OFF.") self.outvalue &= ~4 + def getPowerRelayConfirmation(self): + return 1 # todo: self.contactor_confirmed + def getInletVoltage(self): # uncomment this line, to take the simulated inlet voltage instead of the really measured # self.inletVoltage = self.simulatedInletVoltage diff --git a/pyPlc.ini b/pyPlc.ini index e996739..a3b4640 100644 --- a/pyPlc.ini +++ b/pyPlc.ini @@ -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 # before the resistive load is connected. -light_bulb_demo = yes +light_bulb_demo = no # SOC simulation. # In PevMode, simulate a rising SOC while charging. @@ -28,14 +28,21 @@ soc_simulation = yes # 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 -# Either the high-voltage dieter from https://github.com/uhi22/dieter, which is connected on serial port. -# Or "none", if no measurement is intended. +# 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: @@ -53,3 +60,16 @@ use_physical_inlet_voltage_during_chargeloop = no # 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 +