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:
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
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); (*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); 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); 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); 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); 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);