Changes after BMS EMS connection test with uniper

- Added EMS heartbeat timeout
- Removed commented code
- Fixed BMS Error DC-Switch: Was true when switch was ok and vice versa
This commit is contained in:
Matthias Heisig
2025-06-19 19:10:26 +02:00
parent b6791f7951
commit e6802b87b4
5 changed files with 99 additions and 134 deletions

View File

@@ -266,6 +266,9 @@ VAR_GLOBAL PERSISTENT
// Balancing factor
rBalancingFactor : REAL := 20.0;
// Timeout heartbeat from EMS
timEMSHeartbeatTimeout : TIME := t#5s;
// Dummy to deactivate functions
{attribute 'analysis' := '-33'}
xDummy : BOOL := FALSE;

File diff suppressed because one or more lines are too long

View File

@@ -16,11 +16,6 @@ VAR
{attribute 'OPC.UA.DA' := '0'}
_afbStrings : ARRAY[0..1] OF FB_String[('String 1'), ('String 2')];
// Variable to detect charge status change
//_eLastChargeStatus : E_CHARGE_STATUS;
// Variable to detect battery status change
//_eLastBatteryStatus : E_BATTERY_STATUS;
// Battery shutdown due to error
_xErrorShutdown : BOOL := FALSE;
@@ -66,7 +61,8 @@ VAR
_fbEtherCATErrorString2 : FB_TcAlarm;
_stECString2ErrSI : FB_TcSourceInfo;
// EMS heartbeat alarm
_fbEMSHeartbeatAlarm : FB_TcAlarm;
// First cycle tag
_xFirstCycle : BOOL := TRUE;
@@ -77,6 +73,21 @@ VAR
// Timer for ADS read
_timADSReadTimer : TON;
// Old EMS lifecount message
_udiLastEMSLifeMessage : UDINT;
// No change in life counter from EMS detected
_xNoEMSLifeMessageChange : BOOL;
// EMS heartbeat not ok signal
_xEMSHeartbeatNotOK : BOOL;
// Error signal for no EMS Heartbeat
_fbEMSHeartbeatTimeout : FB_ReleaseSignal;
// Release EMS heartbeat timeout signal
_xReleaseEMSHeartbeatError : BOOL;
// Release manual mode
_xReleaseManualMode : BOOL;
@@ -129,9 +140,6 @@ VAR
// Hardware reset button rising edge trigger
_fbRTrigHardwareAck : R_TRIG;
// DEBUG
_ModbusDebugTest : ST_MODBUS_REG_11;
_fbStringReadyTimeout : TON;
// Sum of voltage of all active strings
@@ -155,11 +163,6 @@ VAR
_rMaxCurrentInverterDCVoltage : REAL;
_rMinCurrentInverterDCVoltage : REAL;
_fbModbusRead : FB_MBReadRegs;
// _fbModbusWrite : FB_MBWriteSingleReg;
// _fbModbusWriteMult : FB_MBWriteRegs;
//_wLength : WORD := 49;
xDebugTest : BOOL;
_wDebug1 : WORD;
_wDebug2 : WORD;
@@ -173,59 +176,10 @@ VAR
_rPowerDH : REAL;
_fbTONDHCycleTime : TON := (PT := T#15M);
//_uiTest : UINT := 1;
//_diTest : DINT := 123;
//_fbKaco : FB_PowerSupplyKaco('Kaco');
//_xEnableKaco : BOOL;
END_VAR
]]></Declaration>
<Implementation>
<ST><![CDATA[(*
IF xDebugTest THEN
(*
_fbModbusWrite(
sIPAddr:= '127.0.0.1',
nTCPPort:= 502,
nUnitID:= 16#FF,
nMBAddr:= 13004,
nValue:= 1,
bExecute:= TRUE,
tTimeout:= T#10S,
bBusy=> ,
bError=> ,
nErrId=> );
IF (NOT _fbModbusWrite.bBusy) THEN
xDebugTest := FALSE;
_fbModbusWrite(bExecute := FALSE);
END_IF
*)
_fbModbusWriteMult(
sIPAddr:= '127.0.0.1',
nTCPPort:= 502,
nUnitID:= 16#FF,
nQuantity:= 2,
nMBAddr:= 12000,
cbLength:= SIZEOF(_diTest),
pSrcAddr:= ADR(_diTest),
bExecute:= TRUE,
tTimeout:= T#10S,
bBusy=> ,
bError=> ,
nErrId=> );
IF (NOT _fbModbusWriteMult.bBusy) THEN
xDebugTest := FALSE;
_fbModbusWriteMult(bExecute := FALSE);
END_IF
END_IF
*)
IF _xFirstCycle THEN
<ST><![CDATA[IF _xFirstCycle THEN
_xFirstCycle := FALSE;
_xGetPowerMeterData := TRUE;
@@ -248,6 +202,8 @@ IF _xFirstCycle THEN
_afbStrings[0].Name := 'String 1';
_afbStrings[1].Name := 'String 2';
_fbEMSHeartbeatAlarm.CreateEx(stEventEntry := TC_EVENTS.BMSEvents.EMSHeartbeatTimeout, TRUE, 0);
END_IF
// Reset error flag
@@ -396,7 +352,7 @@ END_IF
// Handle string 1 modbus error and warning
GVL_MODBUS.stBMSErrorReg.wStringErrorActive.0 := _afbStrings[0].xError;
GVL_MODBUS.stBMSErrorReg.wStringWarningActive.0 := _afbStrings[0].xWarning;
GVL_MODBUS.stBMSErrorReg.wBMSErrorActive.stBitmap.bDCSwitchS1 := _afbStrings[0].xRepairSwitchOk;
GVL_MODBUS.stBMSErrorReg.wBMSErrorActive.stBitmap.bDCSwitchS1 := (NOT _afbStrings[0].xRepairSwitchOk);
GVL_MODBUS.stBMSErrorReg.wBMSWarningActive.stBitmap.bSafetyIntlkString1 := (NOT _afbStrings[0].xSafetyIntlksOk);
@@ -426,7 +382,7 @@ END_IF
// Handle string 1 modbus error and warning
GVL_MODBUS.stBMSErrorReg.wStringErrorActive.1 := _afbStrings[1].xError;
GVL_MODBUS.stBMSErrorReg.wStringWarningActive.1 := _afbStrings[1].xWarning;
GVL_MODBUS.stBMSErrorReg.wBMSErrorActive.stBitmap.bDCSwitchS2 := _afbStrings[1].xRepairSwitchOk;
GVL_MODBUS.stBMSErrorReg.wBMSErrorActive.stBitmap.bDCSwitchS2 := (NOT _afbStrings[1].xRepairSwitchOk);
GVL_MODBUS.stBMSErrorReg.wBMSWarningActive.stBitmap.bSafetyIntlkString2 := (NOT _afbStrings[1].xSafetyIntlksOk);
// Copy general error to modbus error register
@@ -575,21 +531,35 @@ _fbADSReader(
ERR=> ,
ERRID=> );
_fbModbusRead(
sIPAddr:= '127.0.0.1',
nTCPPort:= 502,
nUnitID:= 16#FF,
nQuantity:= 48,
nMBAddr:= 11000,
cbLength:= SIZEOF(_ModbusDebugTest),
pDestAddr:= ADR(_ModbusDebugTest),
bExecute:= xDebugTest,
tTimeout:= T#5S,
bBusy=> ,
bError=> ,
nErrId=> ,
cbRead=> );
// Check for change in life count messages
// If changed, we have a valid communication with the EMS
IF ABS(GVL_MODBUS.stModbusEMSComm.stModbusReg11.udiLifeMessage - _udiLastEMSLifeMessage) > 0 THEN
_xNoEMSLifeMessageChange := FALSE;
ELSE
_xNoEMSLifeMessageChange := TRUE;
END_IF
_udiLastEMSLifeMessage := GVL_MODBUS.stModbusEMSComm.stModbusReg11.udiLifeMessage;
// Create Heartbeat timeout signal with delay
_fbEMSHeartbeatTimeout(
xSignal:= _xNoEMSLifeMessageChange,
xRelease:= _xReleaseEMSHeartbeatError,
timOnDelay:= GVL_CONFIG.timEMSHeartbeatTimeout,
timOffDelay:= T#0S,
xReleaseSignal=> _xEMSHeartbeatNotOK);
// EMS Heartbeat timeout error message handling
IF _xEMSHeartbeatNotOK AND (NOT _fbEMSHeartbeatAlarm.bRaised) THEN
_fbEMSHeartbeatAlarm.Raise(0);
END_IF
IF (NOT _xEMSHeartbeatNotOK) AND _fbEMSHeartbeatAlarm.bRaised THEN
_fbEMSHeartbeatAlarm.Clear(0, FALSE);
END_IF
IF _xConfirmAlarms AND _fbEMSHeartbeatAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation THEN
_fbEMSHeartbeatAlarm.Confirm(0);
END_IF
// ===============================
// Copy data to modbus registers
@@ -622,7 +592,16 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
_rAutoPowerRequest := DINT_TO_REAL(GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower);
_xReleaseEMSHeartbeatError := TRUE;
// Only set power to EMS requested power if the EMS heartbeat is ok
// Otherwise shutdown battery
IF (NOT _xEMSHeartbeatNotOK) THEN
_rAutoPowerRequest := DINT_TO_REAL(GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower);
ELSE
_rAutoPowerRequest := 0;
END_IF
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
END_IF
@@ -633,6 +612,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
_xReleaseEMSHeartbeatError := FALSE;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.TESTING;
_rAutoPowerRequest := DINT_TO_REAL(GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic);
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
@@ -645,6 +625,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := TRUE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := TRUE;
_xReleaseEMSHeartbeatError := FALSE;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.MAINTENANCE;
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
@@ -656,6 +637,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := TRUE;
_xReleaseManualMode := FALSE;
_xReleaseEMSHeartbeatError := FALSE;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.MAINTENANCE;
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
@@ -667,6 +649,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
_xReleaseEMSHeartbeatError := FALSE;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.TESTING;
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
@@ -678,6 +661,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
_xReleaseEMSHeartbeatError := FALSE;
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
_xStartBalancing := FALSE;
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
@@ -689,6 +673,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
_xReleaseEMSHeartbeatError := FALSE;
//IF (_iState <> 30) OR GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic = 0 THEN
_rAutoPowerRequest := DINT_TO_REAL(GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic);
//END_IF
@@ -703,6 +688,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
_xReleaseEMSHeartbeatError := FALSE;
GVL_MODBUS.stModbusEMSComm.stModbusReg11.eBatteryStatus := E_BATTERY_STATUS.MAINTENANCE;
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
@@ -714,6 +700,7 @@ CASE _eBMSControlMode OF
_xAllComponentsToManualMode := FALSE;
_xInSafetyCheckMode := FALSE;
_xReleaseManualMode := FALSE;
_xReleaseEMSHeartbeatError := FALSE;
// Goto error state if a string has an error
IF _xStringsErrorActive THEN
@@ -769,9 +756,6 @@ CASE _eBMSControlMode OF
END_IF
END_CASE
//IF (_iState <> 30) OR GVL_SCADA.stAutomaticModeHMI.diSetpointAutomatic = 0 THEN
//END_IF
IF (GVL_SCADA.eRequestedControlMode <> _eBMSControlMode) AND (GVL_SCADA.xCanChangeControlMode) THEN
_eBMSControlMode := GVL_SCADA.eRequestedControlMode;
END_IF
@@ -833,23 +817,7 @@ IF _xConfirmAlarms OR _rtHardwareResetButton.Q THEN
_xConfirmAlarms := FALSE;
END_IF
_fbPowerMeter24V();
// _fbKaco(
// sInverterIPAddr:= '192.168.42.14',
// xEnable:= _xEnableKaco,
// rPower:= 0.0,
// xReset:= _xConfirmAlarms,
// rMaxBattPower:= 10_000,
// uiMinDisVoltage := ,
// uiMaxChaVoltage := ,
// uiMaxDisCurrent := ,
// uiMaxChaCurrent := ,
// xActive=> ,
// xError=> ,
// xHeartbeatOk=> ,
// stCurrentValues=> ,
// );]]></ST>
_fbPowerMeter24V();]]></ST>
</Implementation>
<Action Name="SM_AUTO" Id="{b5166e16-4fea-442b-9560-02c156f9a9ad}">
<Implementation>
@@ -861,7 +829,7 @@ _fbPowerMeter24V();
END_IF
// Wait for power command
IF (ABS(_rAutoPowerRequest) > DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) AND (NOT _xStringsErrorActive) AND _xStringsAllInAutomaticMode THEN
IF (ABS(_rAutoPowerRequest) > DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) AND (NOT _xStringsErrorActive) AND _xStringsAllInAutomaticMode AND (NOT _xEMSHeartbeatNotOK) THEN
_iState := 5;
_xCanChangeMode := FALSE;
_xErrorShutdown := FALSE;
@@ -903,7 +871,7 @@ _fbPowerMeter24V();
END_IF
IF (ABS(_rAutoPowerRequest) < DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) THEN
IF (ABS(_rAutoPowerRequest) < DINT_TO_REAL(GVL_CONFIG.diMinimumAbsPowerForEnable)) OR _xEMSHeartbeatNotOK THEN
_fbStringReadyTimeout(IN := FALSE);
_xEnableString := FALSE;
_xCanChangeMode := TRUE;
@@ -913,7 +881,7 @@ _fbPowerMeter24V();
30: // String and inverter enabled
// Set inverter power to modbus requested power
_rPowerInverter := _rAutoPowerRequest;//DINT_TO_REAL(GVL_MODBUS.stModbusEMSComm.stModbusReg12.diSetpointActivePower);
_rPowerInverter := _rAutoPowerRequest;
// Check if the battery should still be active
IF (_rAutoPowerRequest = 0.0) THEN
@@ -1017,7 +985,7 @@ _fbPowerMeter24V();
END_IF
// Check for errors
IF _xStringsErrorActive THEN
IF _xStringsErrorActive OR _xEMSHeartbeatNotOK THEN
_xEnableString := FALSE;
_xErrorShutdown := TRUE;
_tonBeginShutdown(In := FALSE);
@@ -1049,7 +1017,7 @@ _fbPowerMeter24V();
END_IF
40: // Wait for inverter discharge done
IF _xStringsShutdownDischargeAllowed THEN
IF _xStringsShutdownDischargeAllowed OR _xEMSHeartbeatNotOK THEN
_rPowerInverter := GVL_CONFIG.rAbsShutdownDischargePower;
ELSE
_xGetPowerMeterData := TRUE;

View File

@@ -269,7 +269,7 @@
</System>
<Plc>
<Project GUID="{9AE64910-5EB2-4866-93FD-EFE059C38C36}" Name="PLC" PrjFilePath="PLC\PLC.plcproj" TmcFilePath="PLC\PLC.tmc" ReloadTmc="true" AmsPort="851" FileArchiveSettings="#x000e" CopyTmcToTarget="true" CopyTpyToTarget="false" SymbolicMapping="true">
<Instance Id="#x08502000" TcSmClass="TComPlcObjDef" KeepUnrestoredLinks="2" TmcHash="{B6610D51-FC43-AAD1-46A6-1C271CAEF439}" TmcPath="PLC\PLC.tmc">
<Instance Id="#x08502000" TcSmClass="TComPlcObjDef" KeepUnrestoredLinks="2" TmcHash="{DB0C6B7B-135C-3497-0B32-96858A1635E6}" TmcPath="PLC\PLC.tmc">
<Name>PLC Instance</Name>
<CLSID ClassFactory="TcPlc30">{08500001-0000-0000-F000-000000000064}</CLSID>
<Vars VarGrpType="2" AreaNo="1">

View File

@@ -66,7 +66,7 @@
</Hides>
</DataType>
<DataType>
<Name GUID="{58BB5280-6EA8-4841-8B84-F66A8442CCAE}">BMSEvents</Name>
<Name GUID="{533FD64E-DB47-4CEE-B1FE-56FF11855B32}">BMSEvents</Name>
<DisplayName TxtId=""><![CDATA[String event class]]></DisplayName>
<EventId>
<Name Id="1">NotAllCompInAuto</Name>
@@ -133,6 +133,11 @@
<DisplayName TxtId=""><![CDATA[{} - DCCB could not be closed in time]]></DisplayName>
<Severity>Error</Severity>
</EventId>
<EventId>
<Name Id="14">EMSHeartbeatTimeout</Name>
<DisplayName TxtId=""><![CDATA[Lost connection to EMS]]></DisplayName>
<Severity>Error</Severity>
</EventId>
<Hides>
<Hide GUID="{1D326C00-DF37-4B94-8E0D-C22524EB2E89}"/>
<Hide GUID="{E7132508-795D-4A6C-AFB1-FED6C1DE44FD}"/>
@@ -154,6 +159,7 @@
<Hide GUID="{F05A8F7C-1061-4AE4-AAAC-173C036FF4FC}"/>
<Hide GUID="{99721C04-AF32-4BF0-BB6B-A59D0F9957F2}"/>
<Hide GUID="{4B5D56D2-4431-41C5-8F0A-06E1FC56151A}"/>
<Hide GUID="{58BB5280-6EA8-4841-8B84-F66A8442CCAE}"/>
</Hides>
</DataType>
<DataType>