I started to do small POC, I almost finish coding and what I have is:
- I'm storing the output POS of the BLIND_CONTROL in the PERSISTENT memory area of the PLC
- In the first PLC cycle after power failure I'm putting that value to the PI input variable of the BLIND_CONTROL - this will cause that during the calibration the blinds will go up and then come back to the previous position. Almost done but still, blinds will unnecessary goes up as I know the position!
- In order to stop the physicals move of the blinds I'm using TON which will allow to set up PLC outputs (which triggers relays) after 90s so when the calibration is done by BLIND_CONTROL - so I've no blinds movement.
The code looks like this (without sunset and sunrise calculation code):
FUNCTION_BLOCK Blind
VAR_INPUT
xBlindDown: BOOL;
xBlindUp: BOOL;
xAutoSunset: BOOL := FALSE;
xAutoSunrise: BOOL := FALSE;
tMaxRuntime: TIME := T#32S;
tTimeUp: TIME := T#30S;
tTimeDown: TIME := T#30S;
END_VAR
VAR_OUTPUT
xBlindControlUp: BOOL;
xBlindControlDown: BOOL;
END_VAR
VAR_IN_OUT
PersistentData: BlindData; //this data is stored in VAR RETAIN PERSISTENT in the PLC_PRG
END_VAR
VAR
_oBlindInput: OSCAT_BUILDING.BLIND_INPUT := (MAX_RUNTIME := tMaxRuntime, MANUAL_TIMEOUT := T#2M);
_oBlindNight: OSCAT_BUILDING.BLIND_NIGHT;
_oBlindSecurity: OSCAT_BUILDING.BLIND_SECURITY;
_oBlindControl: OSCAT_BUILDING.BLIND_CONTROL_S;
_xInitPosition: BOOL := FALSE;
_byBlindControlPosition: BYTE;
_calibrationBlocker: TON;
_xMasterMode: BOOL := FALSE;
END_VAR
_calibrationBlocker(IN := TRUE, PT := T#90S);
_oBlindInput(
POS:= PersistentData.byCurrentPosition,
S1:= xBlindUp,
S2:= xBlindDown,
MASTER_MODE := _xMasterMode
);
_oBlindNight(
UP := _oBlindInput.QU,
DN := _oBlindInput.QD,
S_IN := _oBlindInput.STATUS,
PI := _oBlindInput.PO,
DTIN := _dtCurrentDateTimeUTC,
SUNRISE := _oSunTime.SUN_RISE,
SUNSET := _oSunTime.SUN_SET,
E_NIGHT := xAutoSunset,
E_DAY := xAutoSunrise
);
_oBlindSecurity(
UP := _oBlindNight.QU,
DN := _oBlindNight.QD,
S_IN := _oBlindNight.STATUS,
PI := _oBlindNight.PO,
);
IF (NOT _xInitPosition) THEN
// in the first cycle lets read last position saved before the power failure and set it to _oBlindControl PI input
// this will casue the _oBlindControl to move to last position after calibration
// we are reading the position only onece - in the first cycle after the power is back
_byBlindControlPosition := PersistentData.byCurrentPosition;
END_IF
IF (_calibrationBlocker.Q) THEN
// then, after calibration, just read the position from previous block (standard behaviour)
_byBlindControlPosition := _oBlindSecurity.PO;
// switch master mode back to true, initially it is false because we need to transfer PersistentData.byCurrentPosition change to all
// the block (when the _oBlindControl is calibrating)
_xMasterMode := TRUE;
END_IF
_xInitPosition := TRUE;
_oBlindControl(
T_UP := tTimeUp,
T_DN := tTimeDown,
UP := _oBlindSecurity.QU,
DN := _oBlindSecurity.QD,
S_IN := _oBlindSecurity.STATUS,
PI := _byBlindControlPosition,
POS => PersistentData.byCurrentPosition
);
// set outputs after the calibration (when _calibrationBlocker.Q is TRUE after 90 seconds)
// we don't need real calibration as we are saving last know position (before the power failure/full download) in PersistentData.byCurrentPosition
xBlindControlDown := _oBlindControl.MD AND _calibrationBlocker.Q;
xBlindControlUp := _oBlindControl.MU AND _calibrationBlocker.Q;
What I have is:
- BLIND_CONTROL is doing calibration without physical movement of the blinds movement is not needed because I remember the position
- BLIND_CONTROL after doing this "virtual" calibration will move gets back to the previously remembered position which I push to the PI input
I Will be doing some real testing today but so far it looks good in the simulation model.
Is the MASTER_MODE := TRUE actually needed in the BLIND_INPUT? What it actually does?
Any other ideas? Other approaches?