IBN changes

added sync units for cabinet temperature, changes in modbus interface to EMS (1.0.4 and 1.0.5), added error counter to modbus communication, lot of changes to kaco (faults, consecutive errors, bms error messages), isolation error ledge, allowed startbalancing when on shutdown, tower light integration
This commit is contained in:
Markus.Neukirch
2025-09-05 14:24:37 +02:00
parent 69749409a3
commit f0e6143997
33 changed files with 1321 additions and 955 deletions

View File

@@ -82,7 +82,7 @@ VAR
_fbReadACValues : FB_MBReadRegs;
// Time for polling for current dc values and check for inverter error
_timPollingDelay : TIME := T#500MS;
_timPollingDelay : TIME := T#1S;
// Time for setting the current power
_timSetPowerDelay : TIME := T#250MS;
@@ -101,6 +101,12 @@ VAR
// Inverter alarm
_fbErrorInverterAlarm : FB_TcAlarm;
// Error when reading cyclic data
_fbCyclicDataAlarm : FB_TcAlarm;
// Error when reading heartbeat
_fbHeartBeatAlarm : FB_TcAlarm;
// Flag if battery limits have been set
_xBatteryLimitsSet : BOOL := FALSE;
@@ -143,12 +149,48 @@ VAR
// Current PCU state and alarm messages
_stPCUState : ST_KACU_PCU;
// Current PCU cabinet temperature
_iCabTemp : INT;
// Current PCU state and alarm messages
_stPCUStateDebug : ST_KACU_PCU;
// Current PCU state and alarm messages
_stPCUStateDebug2 : ST_KACU_PCU;
_iCurrentErrorCountHB : UDINT := 0; // Error count since last successfull read on writeRequestedState
_iErrorCountHB : UDINT := 0; // Total error count on writeRequestedState
_iErrorIDHB : UDINT := 0; // Error ID on writeRequestedState
_iCurrentErrorCountWRS : UDINT := 0; // Error count since last successfull read on writeRequestedState
_iErrorCountWRS : UDINT := 0; // Total error count on writeRequestedState
_iErrorIDWRS : UDINT := 0; // Error ID on writeRequestedState
_iCurrentErrorCountWPC : UDINT := 0; // Error count since last successfull read on writePowerCommand
_iErrorCountWPC : UDINT := 0; // Total error count on writePowerCommand
_iErrorIDWPC : UDINT := 0; // Error ID on writePowerCommand
_iCurrentErrorCountRCS : UDINT := 0; // Error count since last successfull read on readCurrentState
_iErrorCountRCS : UDINT := 0; // Total error count on readCurrentState
_iErrorIDRCS : UDINT := 0; // Error ID on readCurrentState
_iCurrentErrorCountRPCUS : UDINT := 0; // Error count since last successfull read on readPCUState
_iErrorCountRPCUS : UDINT := 0; // Total error count on readPCUState
_iErrorIDRPCUS : UDINT := 0; // Error ID on readPCUState
_iErrorCountRDCV : UDINT := 0; // Total error count on readDCValues
_iErrorIDRDCV : UDINT := 0; // Error ID on readDCValues
_iErrorCountRACV : UDINT := 0; // Total error count on readACValues
_iErrorIDRACV : UDINT := 0; // Error ID on readACValues
_xResetCounter : BOOL := FALSE; // Reset error counter
// Error during cyclic reading
_xErrorCyclicData : BOOL;
_xErrorCyclicDataLedge : BOOL; // cyclic data ledge
_xHeartBeatNOK : BOOL; // heartbeat error ledge
// Internal inverter error
_xErrorInverter : BOOL;
// Inverterfault (introduced by NA-Schutz)
_xFaultInverter : BOOL;
// Inverter name for alarm message
_sName : STRING;
END_VAR
@@ -331,7 +373,7 @@ CASE _iState OF
// Dont set inverter into off state when an internal error occured
// because this will reset the error message
IF _xErrorInverter THEN
IF _xErrorInverter OR _xErrorCyclicData OR (NOT xHeartbeatOk) THEN
_iWSetPct := 0;
_iState := 1000;
END_IF
@@ -341,9 +383,12 @@ CASE _iState OF
_iState := 1001;
1001: // Error state, wait for reset
IF xReset AND (NOT xEnable) AND (NOT _xErrorCyclicData) AND (NOT _xErrorInverter) THEN
IF xReset AND (NOT xEnable) AND (NOT _xErrorInverter) AND (NOT _xErrorCyclicData) AND xHeartbeatOk THEN
_eRequestedState := OFF;
xError := FALSE;
_xFaultInverter := FALSE;
_xErrorCyclicDataLedge := FALSE;
_xHeartBeatNOK := FALSE;
_iState := 0;
END_IF
@@ -382,18 +427,44 @@ END_VAR]]></Declaration>
// Create inverter main alarm
_fbErrorInverterAlarm.CreateEx(stEventEntry := TC_EVENTS.Inverter.InverterError, bWithConfirmation := TRUE, 0);
_fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);
// Create inverter heartbeat alarm
_fbHeartBeatAlarm.CreateEx(stEventEntry := TC_EVENTS.Inverter.InverterHeartbeatError, bWithConfirmation := TRUE, 0);
_fbHeartBeatAlarm.ipArguments.Clear().AddString(_sName);
// Create inverter cyclic data alarm
_fbCyclicDataAlarm.CreateEx(stEventEntry := TC_EVENTS.Inverter.InverterCyclicError, bWithConfirmation := TRUE, 0);
_fbCyclicDataAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
</Implementation>
</Method>
<Action Name="HandleCyclicData" Id="{4343583a-b80a-437e-8fc8-9963ab894fbc}">
<Implementation>
<ST><![CDATA[// Reset error flags on reset command
IF _xErrorCyclicData AND xReset THEN
_xErrorCyclicData := FALSE;
<ST><![CDATA[IF _xResetCounter THEN
_xResetCounter := FALSE;
_iCurrentErrorCountHB := 0;
_iErrorCountHB := 0;
_iErrorIDHB := 0;
_iCurrentErrorCountWRS := 0;
_iErrorCountWRS := 0;
_iErrorIDWRS := 0;
_iCurrentErrorCountWPC := 0;
_iErrorCountWPC := 0;
_iErrorIDWPC := 0;
_iCurrentErrorCountRCS := 0;
_iErrorCountRCS := 0;
_iErrorIDRCS := 0;
_iCurrentErrorCountRPCUS := 0;
_iErrorCountRPCUS := 0;
_iErrorIDRPCUS := 0;
_iErrorCountRDCV := 0;
_iErrorIDRDCV := 0;
_iErrorCountRACV := 0;
_iErrorIDRACV := 0;
END_IF
// Fetch cyclic data with polling timer
_tonPollingTimer(IN := TRUE);
_tonPollingTimer(IN := TRUE, PT := _timPollingDelay);
// Write requested state
_fbWriteRequestedState(
@@ -408,8 +479,14 @@ _fbWriteRequestedState(
bError=> ,
nErrId=> );
IF (NOT _fbWriteRequestedState.bBusy) AND _fbWriteRequestedState.bError THEN
_xErrorCyclicData := TRUE;
IF (NOT _fbWriteRequestedState.bBusy) THEN
IF _fbWriteRequestedState.bError THEN
_iCurrentErrorCountWRS := _iCurrentErrorCountWRS + 1;
_iErrorCountWRS := _iErrorCountWRS + 1;
_iErrorIDWRS := _fbWriteRequestedState.nErrId;
ELSE
_iCurrentErrorCountWRS := 0;
END_IF
END_IF
@@ -428,8 +505,14 @@ _fbWritePowerCommand(
bError=> ,
nErrId=> );
IF (NOT _fbWritePowerCommand.bBusy) AND _fbWritePowerCommand.bError THEN
_xErrorCyclicData := TRUE;
IF (NOT _fbWritePowerCommand.bBusy) THEN
IF _fbWritePowerCommand.bError THEN
_iCurrentErrorCountWPC := _iCurrentErrorCountWPC + 1;
_iErrorCountWPC := _iErrorCountWPC + 1;
_iErrorIDWPC := _fbWritePowerCommand.nErrId;
ELSE
_iCurrentErrorCountWPC := 0;
END_IF
END_IF
@@ -449,8 +532,14 @@ _fbReadCurrentState(
nErrId=> ,
cbRead=> );
IF (NOT _fbReadCurrentState.bBusy) AND _fbReadCurrentState.bError THEN
_xErrorCyclicData := TRUE;
IF (NOT _fbReadCurrentState.bBusy) THEN
IF _fbReadCurrentState.bError THEN
_iCurrentErrorCountRCS := _iCurrentErrorCountRCS + 1;
_iErrorCountRCS := _iErrorCountRCS + 1;
_iErrorIDRCS := _fbReadCurrentState.nErrId;
ELSE
_iCurrentErrorCountRCS := 0;
END_IF
END_IF
IF _eCurrentState = E_KACO_CURRENT_STATE.GRID_CONNECTED OR _eCurrentState = E_KACO_CURRENT_STATE.THROTTLED THEN
@@ -476,16 +565,35 @@ _fbReadPCUState(
nErrId=> ,
cbRead=> );
IF (NOT _fbReadPCUState.bBusy) AND _fbReadPCUState.bError THEN
_xErrorCyclicData := TRUE;
IF (NOT _fbReadPCUState.bBusy) THEN
IF _fbReadPCUState.bError THEN
_iCurrentErrorCountRPCUS := _iCurrentErrorCountRPCUS + 1;
_iErrorCountRPCUS := _iErrorCountRPCUS + 1;
_iErrorIDRPCUS := _fbReadPCUState.nErrId;
IF _iCurrentErrorCountRPCUS >= GVL_CONFIG.udiMaxConsecutiveInvError THEN
_xErrorCyclicData := TRUE;
END_IF
ELSE
_iCurrentErrorCountRPCUS := 0;
END_IF
END_IF
IF (_stPCUState.ePCUState = E_KACO_PCU_STATE.ERROR) OR (_stPCUState.ePCUError <> E_KACO_PCU_ERROR.NO_EVENT) THEN
_xErrorInverter := TRUE;
IF ((_stPCUState.ePCUState = E_KACO_PCU_STATE.ERROR) OR (_stPCUState.ePCUError <> E_KACO_PCU_ERROR.NO_EVENT)) AND (_stPCUState.ePCUError <> 11) THEN
// ignore undervoltage error when not enabled
_stPCUStateDebug := _stPCUState;
IF NOT xReleasePower AND _stPCUState.ePCUError = E_KACO_PCU_ERROR.UNDER_VOLT THEN
_xErrorInverter := FALSE;
ELSE
_xErrorInverter := TRUE;
_stPCUStateDebug2 := _stPCUState;
END_IF
ELSE
_xErrorInverter := FALSE;
END_IF
IF _eCurrentState = E_KACO_CURRENT_STATE.FAULT AND xReleasePower THEN
_xErrorInverter := TRUE;
END_IF
// Read current dc values
_fbReadDCValues(
@@ -516,6 +624,8 @@ IF (NOT _fbReadDCValues.bBusy) THEN
stCurrentValues.rActDCCurrent := 0.0;
stCurrentValues.rActDCVoltage := 0.0;
stCurrentValues.rActDCPower := 0.0;
_iErrorCountRDCV := _iErrorCountRDCV + 1;
_iErrorIDRDCV := _fbReadDCValues.nErrId;
END_IF
END_IF
@@ -561,9 +671,39 @@ IF (NOT _fbReadACValues.bBusy) THEN
stCurrentValues.rActApparentPower := 0.0;
stCurrentValues.rActReactivePower := 0.0;
stCurrentValues.rActPowerFactor := 0.0;
_iErrorCountRACV := _iErrorCountRACV + 1;
_iErrorIDRACV := _fbReadACValues.nErrId;
END_IF
END_IF
IF _iCurrentErrorCountRPCUS >= GVL_CONFIG.udiMaxConsecutiveInvError OR
_iCurrentErrorCountRCS >= GVL_CONFIG.udiMaxConsecutiveInvError OR
_iCurrentErrorCountWPC >= GVL_CONFIG.udiMaxConsecutiveInvError OR
_iCurrentErrorCountWRS >= GVL_CONFIG.udiMaxConsecutiveInvError OR
_iCurrentErrorCountHB >= GVL_CONFIG.udiMaxConsecutiveInvError THEN
_xErrorCyclicData := TRUE;
ELSE
_xErrorCyclicData := FALSE;
END_IF
// set fault flag when error active
IF _xErrorCyclicData THEN
_xErrorCyclicDataLedge := TRUE;
END_IF
// handle alarm
IF _xErrorCyclicData AND NOT _fbCyclicDataAlarm.bRaised THEN
_fbCyclicDataAlarm.Raise();
END_IF
IF NOT _xErrorCyclicData AND _fbCyclicDataAlarm.bRaised THEN
_fbCyclicDataAlarm.Clear(0, FALSE);
END_IF
IF _fbCyclicDataAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xReset THEN
_fbCyclicDataAlarm.Confirm(0);
END_IF
// Reset polling timer
IF _tonPollingTimer.Q THEN
_tonPollingTimer(IN := FALSE);
@@ -572,12 +712,7 @@ END_IF]]></ST>
</Action>
<Action Name="HandleHeartbeat" Id="{eeb5f65a-fd91-4c22-ab2e-3080c24e87fb}">
<Implementation>
<ST><![CDATA[// Reset hearbeat signal only with reset signal
IF (NOT xHeartbeatOk) AND xReset THEN
xHeartbeatOk := TRUE;
END_IF
// Self resetting watchdog timer
<ST><![CDATA[// Self resetting watchdog timer
_tonWatchdogResetTimer(IN := TRUE);
// Timeout should be less than timer interval
@@ -595,9 +730,37 @@ _fbWriteHearbeatRegister(
// Because there is no heartbeat register to read,
// we will use a successfull write as a valid heartbeat signal
IF _fbWriteHearbeatRegister.bError THEN
xHeartbeatOk := FALSE;
xError := TRUE;
IF NOT _fbWriteHearbeatRegister.bBusy THEN
IF _fbWriteHearbeatRegister.bError THEN
_iCurrentErrorCountHB := _iCurrentErrorCountHB + 1;
_iErrorCountHB := _iErrorCountHB + 1;
_iErrorIDHB := _fbWriteHearbeatRegister.nErrId;
IF _iCurrentErrorCountHB >= GVL_CONFIG.udiMaxConsecutiveInvError THEN
xHeartbeatOk := FALSE;
xError := TRUE;
END_IF
ELSE
_iCurrentErrorCountHB := 0;
xHeartbeatOk := TRUE;
END_IF
END_IF
// set fault flag when error active
IF NOT xHeartbeatOk THEN
_xHeartBeatNOK := TRUE;
END_IF
// handle alarm
IF NOT xHeartbeatOk AND NOT _fbHeartBeatAlarm.bRaised THEN
_fbHeartBeatAlarm.Raise();
END_IF
IF xHeartbeatOk AND _fbHeartBeatAlarm.bRaised THEN
_fbHeartBeatAlarm.Clear(0, FALSE);
END_IF
IF _fbHeartBeatAlarm.eConfirmationState = TcEventConfirmationState.WaitForConfirmation AND xReset THEN
_fbHeartBeatAlarm.Confirm(0);
END_IF
// Reset timer
@@ -640,7 +803,7 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbReadRegisters(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nUnitID:= 16#01, // 16#FF for Modbus TCP
nQuantity:= 2,
nMBAddr:= BATTERY_LIMIT_SF_START,
cbLength:= SIZEOF(_arBattScalingFactors),
@@ -668,7 +831,7 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbWriteRegisters(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nUnitID:= 16#01, // 16#FF for Modbus TCP
nQuantity:= 6,
nMBAddr:= BATTERY_SET_LIMITS_START,
cbLength:= SIZEOF(_auiBatteryLimitValues),
@@ -695,7 +858,7 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nUnitID:= 16#01, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= DIS_MIN_V,
cbLength:= SIZEOF(uiMinDisVoltage),
@@ -723,7 +886,7 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nUnitID:= 16#01, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= CHA_MAX_V,
cbLength:= SIZEOF(uiMaxChaVoltage),
@@ -751,7 +914,7 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nUnitID:= 16#01, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= CHA_MAX_A,
cbLength:= SIZEOF(uiMaxChaCurrent),
@@ -779,7 +942,7 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbWriteRegister(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nUnitID:= 16#01, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= DIS_MAX_A,
cbLength:= SIZEOF(uiMaxDisCurrent),
@@ -808,7 +971,7 @@ _fbErrorInverterAlarm.ipArguments.Clear().AddString(_sName);]]></ST>
_fbWriteRegisters(
sIPAddr:= sInverterIPAddr,
nTCPPort:= 502,
nUnitID:= 16#FF, // 16#FF for Modbus TCP
nUnitID:= 16#01, // 16#FF for Modbus TCP
nQuantity:= 1,
nMBAddr:= EN_LIMIT,
cbLength:= SIZEOF(_uiEnableLimit),