# [OSCAT Building] Save blind position in case of power failure



## dawrut (28 April 2021)

I'm using PFC200 and OSCAT Building library to automate my home. I got a question... How are you saving the position of the blind in case of a power failure? 


Function BLIND_CONTROL_S has built-in automatic calibration which is needed to know the position of the blind in case of power failure or PLC restart. In such a case, the blind goes up. Is there a way to store the current position so that after the power failure the blind won't go up?
I was trying to add the whole BLIND_CONTROL_S  function block to the VAR RETAIN PERSISTENT memory area but this didn't help. I was also trying to store the POS output of the BLIND_CONTROL_S (which is at the same time an input for the POS of the BLIND_INPUT) but this also doesn't stop blinds to go up in case of power failure. 


Any ideas?


----------



## ccore (29 April 2021)

Hi, 
Codesys 2.3 or e!Cockpit?


----------



## dawrut (29 April 2021)

e!Cockpit

But is there a difference?


----------



## oliver.tonn (29 April 2021)

dawrut schrieb:


> e!Cockpit
> 
> But is there a difference?


Yes, Codesys 2.3 is the older version and was labeled as I/O-Pro of WAGO.
The software based on Codesys 3.5 is named e!Cockpit


----------



## dawrut (29 April 2021)

oliver.tonn schrieb:


> Yes, Codesys 2.3 is the older version and was labeled as I/O-Pro of WAGO.
> The software based on Codesys 3.5 is named e!Cockpit



I understood. What I meant was that I don't think there is a difference how you would handle blinds on one environment or the other until you use OSCAT Building.


----------



## JSEngineering (30 April 2021)

Hi Dawrut,

But please consider that you might have the situation, that PLC is off, but the blind was still under power and was moved somehow else (manual mode, switch/pushbutton/weather automatic).
So maybe you might consider a "teaching" mode on first movement after startup of PLC.

Regards
     Jens


----------



## JSEngineering (30 April 2021)

Now read the article about the function.

There is clearly mentioned:


> For the first start and after a power failure, a calibration run is done automatically upwards.



So it does exactly what I proposed.
Most probably you can do whatever you want, the blind will never store the position - except you adapt the function yourself....

Add:


> The  module  supports  automatic  calibration,  which  can  cause,  after  a
> power failure, to move up all blinds, which is undesired some times in your
> absence. Therefore, in case of your absence the desired position of the
> blinds should be given to the input PI. The blinds move to up position for
> ...


----------



## dawrut (30 April 2021)

JSEngineering schrieb:


> Now read the article about the function.


I've read the documentation like 10 times  In my case there is no other option to move the blind then by PLC. PLC is triggering relays, without PLC the relay won't get the signal and the blind will stay where it was. I'm planning to add the weather station to e.g.: close the blinds in case of the strong wind but that will also be handled by PLC. 
That is why the PLC is the only source of truth and this is what I almost finish coding:

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
Will be doing some real testing today but so far it looks good in the simulation mode. 

Any other ideas? Other approaches?


----------

