We use cookies to personalise content and ads, to provide social media features and to analyse our traffic. We also share information about your use of our site with our social media, advertising and analytics partners who may combine it with other information that you've provided to them or that they've collected from your use of their services.

Complex example - Bathroom (Lights and a heater)

Settings and hardware

In my bathroom there are 6 ceiling lights (arranged in two rows, 3 in each, grouped into: 4x corner lights and 2x middle lights), mirror light and lights above the hot tub.  Additionally an air heater is plugged into a dedicated socket in the corner.  It enables a quick increasing of the air temperature.  Consequently I have 4 light circuits and 1 socket circuit.  Additionally a movement sensor is available through the house alarm installation.

As to the wall-mounted switches - inside a 2-button, 4-circuit group switch made by Berker is installed.  On the outside 2x 2-button switches are available.  For the use in the 2nd part of this article the buttons were numbered as follows:

Lacznik1Lacznik2

Functionality

Outside switches: the first button (11) turns on the 4x ceiling lights, the second button (22) turns on the 4x ceiling lights and the mirror light, the third button (33) turns on the mirror light and the forth is not used in the context of bathroom - it controls the light in the lobby.  The lights are therefore turned-on by function like: 'some light', 'a lot of light', 'just the mirror' and not circuit-by-circuit.  On the way out (when turning the lights off) - the first and the second button turn of the 4x ceiling lights, which while going off, turn off the other lights.  One does need to think, which button does what.

Inside switches: the first button (1) when pressed shortly controls (turns on and off) the 4x ceiling lights, the sencond button (2) when pressed shortly controls the 2x ceiling lights, the third button (3) controls the light above the hot-tub and the fourth button (4) controls the light above the mirror; the first button (1) when pressed long controls the air-heater, the second button (2) when pressed long turns off and on the timers automatically switching off lights if no movement is detected (availability of a timer-ignoring switch is necessary if you think about spending long motionless minutes in hot water of your hot tub...).

Movement sensor: if a movement is detected, it is after sunset and no light is on, a dedicated light is turned on (which one - depends on the configuration - in our case the light above the mirror) and the timer is set on (currently 2 min.).  Each movement resets the timer.  After 2 minutes of no motion all lights are turned off provided that the timer-ignoring flag is not active.

If a light is turned on manually another timer is set on (currently 20 min.).  Each movement reset the timer.  If a light was turned on manually after a lamp was switched on automatically (as described above), the 'shorter' timer is deactivated and the 'longer' timer takes over.  After 20 minutes of no motion all lights are turned off provided that the timer-ignoring flag is not active. 

The air-heater is turned on by a long press of the first button (1).  If no lights are on it will work for 10 minutes.  If before the 10-minute period passes a light is turned on or if the heater was switched on while a light was on, it will go automatically off when the last light is switchedoff.  Additionally a schedule can be set to program a time-depending activation and deactivation of the heater.

 

The code, in variable definitions:

VAR
	Move_Laz : R_TRIG;
	SWITCH_IN1, SWITCH_IN2 : Fb_ShortLong:=(uiTS_10tel_s:=1)
	
	LIGHT_1L_ALLOFFSIGN : F_TRIG;
	LIGHT_1L1_ONSIGN : R_TRIG;
	LIGHT_1L_AUTOOFF :BOOL:=TRUE;
	LIGHT_1L_SWITCHES :BOOL;
	LIGHT_1L_MovementInDarkness :R_TRIG;
	LIGHT_1L_GUARDSIGN :F_TRIG;
	LIGHT_1L_IgnoreGuard :SR;
END_VAR
VAR PERSISTENT
	LIGHT_1L1, LIGHT_1L2, LIGHT_1L3, LIGHT_1L4: Fb_LatchingRelay;
	SOCKET_1L1 : Fb_LatchingRelay;
	LIGHT_1L_GUARD : TOF_1:=(PT:=T#2m);
	LIGHT_1L_GUARD2 : TOF_1:=(PT:=T#20m);
	SOCKET_1L1_GUARD : TON:=(PT:=T#10m);
END_VAR
VAR RETAIN PERSISTENT
	LIGHT_1L_AutoON : ARRAY[0..3] OF BOOL:= FALSE, FALSE, FALSE, TRUE;
END_VAR

Where:

  • Mov_Laz - a movement-signaling trigger ,
  • SWITH_IN... - function blocks from the Building_common.lib recognizing the short/long button presses
  • LIGHT_1L_ALLOFFSIGN - F_TRIG signaling when the last light goes off,
  • LIGHT_1L1_OFFSIGN - F_TRIG signaling when the 4x ceiling light goes off,
  • LIGHT_1L_AUTOOFF - a variable informing if the automated turning off is at all active, controlled from the visualization, 
  • LIGHT_1L_SWITCHES - a variable adding all the button, used to simplify the following code, 
  • LIGHT_1L_MovementInDarkness - R_TRIG signaling movement when lights are off, used to simplify the following code,
  • LIGHT_1L_GUARDSIGN  - F_TRIG signaling timers going off,
  • LIGHT_1L_IgnoreGuard - a variable used to ignore the timers switching off the lights,
  • LIGHT_1L... - Function block from Building_common.lib controlling the lights,
  • SOCKET_1L1 - as above,
  • LIGHT_1L_GUARD.... - Resettable function blocks from OSCAT library measuring time,
  • SOCKET_1L1_GUARD  - Turn On Delay watching over the on-time of the heater, 
  • LIGHT_1L_AutoON - An array with variables showing which lights are to be automatically turned on, set through a visualization.

It might be surprising that some variables are placed in the RETAIN i RETAIN PERSISTENT part of the definitions.  In case of power delivery failure I want the circuits to return to their previous status - the same lights should be on.  Consequently the same timers must watch over them to switch them off if there is no movement.

In the program code:

(*Movement sensor*)
Move_Laz(CLK:=RS232.Sensors[1]);

(*Short/Long Swittches*)
SWITCH_IN1(xSwitch:=IN1);
SWITCH_IN2(xSwitch:=IN2);

(*Guards and groupped variables*)
LIGHT_1L_ALLOFFSIGN(CLK:=OUT1 OR OUT2 OR OUT3 OR OUT4);
LIGHT_1L1_OFFSIGN(CLK:=OUT1);
LIGHT_1L_SWITCHES:=SWITCH_IN1.xShort OR SWITCH_IN2.xShort OR IN3 OR IN4 OR IN11 OR IN22 OR IN33;
LIGHT_1L_MovementInDarkness(CLK:=Move_Laz.Q AND NIGHT AND NOT LIGHT_1L_GUARD2.Q);
LIGHT_1L_IgnoreGuard(SET1:=SWITCH_IN2.xLong, RESET:=LIGHT_1L_ALLOFFSIGN.Q); 
LIGHT_1L_GUARD(xSwitch:=LIGHT_1L_MovementInDarkness.Q, xStop:=LIGHT_1L_SWITCHES OR LIGHT_1L_ALLOFFSIGN.Q);
LIGHT_1L_GUARD2(xSwitch:=(LIGHT_1L_SWITCHES OR (Move_Laz.Q AND NOT LIGHT_1L_GUARD.Q)) 
	AND LIGHT_1L_AUTOOFF, xStop:=LIGHT_1L_ALLOFFSIGN.Q); 
LIGHT_1L_GUARDSIGN(CLK:=LIGHT_1L_GUARD.Q OR LIGHT_1L_GUARD2.Q);

(*Light 1, 4x ceiling lamps*)
LIGHT_1L1(xSwitch:=SWITCH_IN1.xShort OR IN11 OR IN22 OR VIS_L_1L1);
LIGHT_1L1(xCentOFF:= (LIGHT_1L_GUARDSIGN.Q AND NOT LIGHT_1L_IgnoreGuard.Q1) OR HomeSleep);
LIGHT_1L1(xCentON:=LIGHT_1L_MovementInDarkness.Q AND LIGHT_1L_AutoON[0]);
OUT1:=LIGHT_1L1.xActuator;

(*Light 1, 2x ceiling lamps*)
LIGHT_1L2(xSwitch:=SWITCH_IN2.xShort OR VIS_L_1L2);
LIGHT_1L2(xCentOFF:=LIGHT_1L1_OFFSIGN.Q OR (LIGHT_1L_GUARDSIGN.Q
	AND NOT LIGHT_1L_IgnoreGuard.Q1) OR HomeSleep);
LIGHT_1L2(xCentON:=LIGHT_1L_MovementInDarkness.Q AND LIGHT_1L_AutoON[1]);
OUT2:=LIGHT_1L2.xActuator;

(*2 lights over the hot-tub*)
LIGHT_1L3(xSwitch:=SWITCH_IN3 OR VIS_L_1L3);
LIGHT_1L3(xCentOFF:= LIGHT_1L1_OFFSIGN.Q OR (LIGHT_1L_GUARDSIGN.Q
	AND NOT LIGHT_1L_IgnoreGuard.Q1) OR HomeSleep);
LIGHT_1L3( xCentON:=LIGHT_1L_MovementInDarkness.Q AND LIGHT_1L_AutoON[2]);
OUT3:=LIGHT_1L3.xActuator;

(*Light over the mirror*)
LIGHT_1L4(xSwitch:=IN4 OR IN22 OR IN33 VIS_L_1L4);
LIGHT_1L4(xCentOFF:=LIGHT_1L1_OFFSIGN.Q OR (LIGHT_1L_GUARDSIGN.Q
	AND NOT LIGHT_1L_IgnoreGuard.Q1) OR HomeSleep);
LIGHT_1L4(xCentON:=LIGHT_1L_MovementInDarkness.Q AND LIGHT_1L_AutoON[3]);
OUT4:=LIGHT_1L4.xActuator;

(*Additional bathroom heater*)
SOCKET_1L1_GUARD(IN:=OUT5);
SOCKET_1L1(xSwitch:=SWITCH_IN1.xLong OR VIS_S_1L1);
SOCKET_1L1(xCentOFF:=LIGHT_1L_ALLOFFSIGN.Q OR (SOCKET_1L1_GUARD.Q
	AND NOT (OUT1 OR OUT2 OR OUT3 OR OUT4)));
OUT5:=SOCKET_1L1.xActuator OR (Timers.Heater_WeeklySchedule_1.xSwitchChannel AND NOT ON_HOLIDAY);

Gdzie:

  • All variables VIS_XXX_XX are type BOOL and are used through a visualization,
  • Row 2. R_TRIG listens of a status change of a 2nd element form the Sensors array used in a separate process dedicated to RS232 communication with the alarm system.
  • Row 10. The first light (4x ceiling lights) is seen as the main.  When it is switched off, all the others go off. It simplifies turning light off while leaving,
  • Row 12. A variable added only to simplify the later code - it sums up all the button presses,
  • Row 19. LIGHT_1L_GUARD is a timer measuring time of no motion after the lights were turned on automatically.   It is deactivated if a button is pressed or the last light goes off,
  • Row 21. LIGHT_1L_GUARD2 is a timer measuring the time of no motion after the lights were turned on manually.  It is deactivated when the last light goes off, 
  • Row 24. LIGHT_1L_GUARDSIGN collects the signals from the Timers 
  • Row 65. Timers.Heater_WeeklySchedule_1 is a scheduler type FbScheduleWeekly used in a separate process.  The variable ON_HOLIDAY allows to change the program behavior during a holiday leave.