diff --git a/fhem/FHEM/10_RESIDENTS.pm b/fhem/FHEM/10_RESIDENTS.pm index 0fecdd753..51a7bba57 100644 --- a/fhem/FHEM/10_RESIDENTS.pm +++ b/fhem/FHEM/10_RESIDENTS.pm @@ -572,7 +572,7 @@ sub RESIDENTS_Set($@) { fhem "attr $wakeuptimerName room " . $attr{$name}{room} if ( defined( $attr{$name}{room} ) ); fhem -"attr $wakeuptimerName setList nextRun:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 reset:noArg stop:noArg"; +"attr $wakeuptimerName setList nextRun:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 reset:noArg trigger:noArg start:noArg stop:noArg"; fhem "attr $wakeuptimerName userattr wakeupUserdevice"; fhem "attr $wakeuptimerName sortby " . $sortby if ($sortby); diff --git a/fhem/FHEM/20_GUEST.pm b/fhem/FHEM/20_GUEST.pm index a2dc14654..cd0f85bed 100644 --- a/fhem/FHEM/20_GUEST.pm +++ b/fhem/FHEM/20_GUEST.pm @@ -766,7 +766,7 @@ sub GUEST_Set($@) { fhem "attr $wakeuptimerName room " . $attr{$name}{room} if ( defined( $attr{$name}{room} ) ); fhem -"attr $wakeuptimerName setList nextRun:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 reset:noArg stop:noArg"; +"attr $wakeuptimerName setList nextRun:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 reset:noArg trigger:noArg start:noArg stop:noArg"; fhem "attr $wakeuptimerName userattr wakeupUserdevice"; fhem "attr $wakeuptimerName sortby " . $sortby if ($sortby); diff --git a/fhem/FHEM/20_ROOMMATE.pm b/fhem/FHEM/20_ROOMMATE.pm index 867d108d1..b6a4e156d 100644 --- a/fhem/FHEM/20_ROOMMATE.pm +++ b/fhem/FHEM/20_ROOMMATE.pm @@ -748,7 +748,7 @@ sub ROOMMATE_Set($@) { fhem "attr $wakeuptimerName room " . $attr{$name}{room} if ( defined( $attr{$name}{room} ) ); fhem -"attr $wakeuptimerName setList nextRun:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 reset:noArg stop:noArg"; +"attr $wakeuptimerName setList nextRun:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 reset:noArg trigger:noArg start:noArg stop:noArg"; fhem "attr $wakeuptimerName userattr wakeupUserdevice"; fhem "attr $wakeuptimerName sortby " . $sortby if ($sortby); diff --git a/fhem/FHEM/RESIDENTStk.pm b/fhem/FHEM/RESIDENTStk.pm index 24c41fb39..0918983c0 100644 --- a/fhem/FHEM/RESIDENTStk.pm +++ b/fhem/FHEM/RESIDENTStk.pm @@ -45,7 +45,9 @@ sub RESIDENTStk_wakeupSet($$) { # filter non-registered notifies my @notify = split / /, $notifyValue; - if ( lc( $notify[0] ) !~ /off|nextrun|stop|reset|auto|([0-9]{2}:[0-9]{2})/ ) + if ( + lc( $notify[0] ) !~ + /off|nextrun|trigger|start|stop|reset|auto|([0-9]{2}:[0-9]{2})/ ) { Log3 $NAME, 5, "RESIDENTStk $NAME: received unspecified notify '" @@ -61,26 +63,28 @@ sub RESIDENTStk_wakeupSet($$) { $VALUE = $notify[0]; } - my $wakeupMacro = AttrVal( $NAME, "wakeupMacro", 0 ); - my $wakeupDefaultTime = AttrVal( $NAME, "wakeupDefaultTime", 0 ); - my $wakeupAtdevice = AttrVal( $NAME, "wakeupAtdevice", 0 ); - my $wakeupUserdevice = AttrVal( $NAME, "wakeupUserdevice", 0 ); - my $wakeupDays = AttrVal( $NAME, "wakeupDays", 0 ); - my $wakeupResetdays = AttrVal( $NAME, "wakeupResetdays", 0 ); - my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 ); - my $wakeupResetSwitcher = AttrVal( $NAME, "wakeupResetSwitcher", 0 ); - my $wakeupUserdevice = AttrVal( $NAME, "wakeupUserdevice", 0 ); - my $room = AttrVal( $NAME, "room", 0 ); - my $userattr = AttrVal( $NAME, "userattr", 0 ); - my $lastRun = ReadingsVal( $NAME, "lastRun", "07:00" ); - my $nextRun = ReadingsVal( $NAME, "nextRun", "07:00" ); - my $running = ReadingsVal( $NAME, "running", 0 ); - my $macroName = "Macro_" . $NAME; - my $atName = "at_" . $NAME; + my $wakeupMacro = AttrVal( $NAME, "wakeupMacro", 0 ); + my $wakeupDefaultTime = AttrVal( $NAME, "wakeupDefaultTime", 0 ); + my $wakeupAtdevice = AttrVal( $NAME, "wakeupAtdevice", 0 ); + my $wakeupUserdevice = AttrVal( $NAME, "wakeupUserdevice", 0 ); + my $wakeupDays = AttrVal( $NAME, "wakeupDays", "" ); + my $wakeupHolidays = AttrVal( $NAME, "wakeupHolidays", 0 ); + my $wakeupResetdays = AttrVal( $NAME, "wakeupResetdays", "" ); + my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 ); + my $wakeupEnforced = AttrVal( $NAME, "wakeupEnforced", 0 ); + my $wakeupResetSwitcher = AttrVal( $NAME, "wakeupResetSwitcher", 0 ); + my $holidayDevice = AttrVal( "global", "holiday2we", 0 ); + my $room = AttrVal( $NAME, "room", 0 ); + my $userattr = AttrVal( $NAME, "userattr", 0 ); + my $lastRun = ReadingsVal( $NAME, "lastRun", "07:00" ); + my $nextRun = ReadingsVal( $NAME, "nextRun", "07:00" ); + my $running = ReadingsVal( $NAME, "running", 0 ); + my $macroName = "Macro_" . $NAME; + my $atName = "at_" . $NAME; # check for required userattr attribute my $userattributes = -"wakeupOffset:slider,0,1,120 wakeupDefaultTime:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 wakeupMacro wakeupUserdevice wakeupAtdevice wakeupResetSwitcher wakeupResetdays:multiple-strict,0,1,2,3,4,5,6 wakeupDays:multiple-strict,0,1,2,3,4,5,6"; +"wakeupOffset:slider,0,1,120 wakeupDefaultTime:OFF,00:00,00:15,00:30,00:45,01:00,01:15,01:30,01:45,02:00,02:15,02:30,02:45,03:00,03:15,03:30,03:45,04:00,04:15,04:30,04:45,05:00,05:15,05:30,05:45,06:00,06:15,06:30,06:45,07:00,07:15,07:30,07:45,08:00,08:15,08:30,08:45,09:00,09:15,09:30,09:45,10:00,10:15,10:30,10:45,11:00,11:15,11:30,11:45,12:00,12:15,12:30,12:45,13:00,13:15,13:30,13:45,14:00,14:15,14:30,14:45,15:00,15:15,15:30,15:45,16:00,16:15,16:30,16:45,17:00,17:15,17:30,17:45,18:00,18:15,18:30,18:45,19:00,19:15,19:30,19:45,20:00,20:15,20:30,20:45,21:00,21:15,21:30,21:45,22:00,22:15,22:30,22:45,23:00,23:15,23:30,23:45 wakeupMacro wakeupUserdevice wakeupAtdevice wakeupResetSwitcher wakeupResetdays:multiple-strict,0,1,2,3,4,5,6 wakeupDays:multiple-strict,0,1,2,3,4,5,6 wakeupHolidays:andHoliday,orHoliday,andNoHoliday,orNoHoliday wakeupEnforced:0,1"; if ( !$userattr || $userattr ne $userattributes ) { Log3 $NAME, 4, "RESIDENTStk $NAME: adjusting dummy device for required attribute userattr"; @@ -113,47 +117,49 @@ sub RESIDENTStk_wakeupSet($$) { } if ( !defined( $defs{$wakeupMacro} ) ) { my $wakeUpMacroTemplate = "{\ -#\ -# This is an example wake-up program running within a period of 30 minutes:\ -# - drive shutters upwards slowly\ -# - light up a HUE bulb from 2000K to 6500K\ -# - have some voice notifications via SONOS\ -# - have some wake-up chill music via SONOS during program run\ -#\ -# Available wake-up variables:\ -# 1. \$EVTPART0 -> start or stop\ -# 2. \$EVTPART1 -> target wake-up time\ -# 2. \$EVTPART2 -> wake-up begin offset time\ -#\ +##\ +## This is an example wake-up program running within a period of 30 minutes:\ +## - drive shutters upwards slowly\ +## - light up a HUE bulb from 2000K to 6500K\ +## - have some voice notifications via SONOS\ +## - have some wake-up chill music via SONOS during program run\ +##\ +## Available wake-up variables:\ +## 1. \$EVTPART0 -> start or stop\ +## 2. \$EVTPART1 -> target wake-up time\ +## 3. \$EVTPART2 -> wake-up begin time considering wakeupOffset attribute\ +## 4. \$EVTPART3 -> enforced wakeup yes=1,no=0 from wakeupEnforced attribute\ +## 5. \$EVTPART4 -> device name of the user which called this macro\ +##\ \ -#------------------------------------------------------------------------------------\ -# DELETE TEMP. AT-COMMANDS POTENTIALLY CREATED EARLIER BY THIS SCRIPT\ -# Executed for start to cleanup in case this wake-up automation is re-started.\ -# Executed for stop to cleanup in case the user ends this automation earlier.\ -#\ +##------------------------------------------------------------------------------------\ +## DELETE TEMP. AT-COMMANDS POTENTIALLY CREATED EARLIER BY THIS SCRIPT\ +## Executed for start to cleanup in case this wake-up automation is re-started.\ +## Executed for stop to cleanup in case the user ends this automation earlier.\ +##\ for (my \$i=1;; \$i <= 10;; \$i++) {\ if (defined(\$defs{\"atTmp_\".\$i.\"_\".\$NAME})) {\ fhem \"delete atTmp_\".\$i.\"_\".\$NAME;;\ }\ }\ \ -#------------------------------------------------------------------------------------\ -# BEGIN WAKE-UP PROGRAM\ -# Run first automation commands and create temp. at-devices for lagging actions.\ -#\ +##------------------------------------------------------------------------------------\ +## BEGIN WAKE-UP PROGRAM\ +## Run first automation commands and create temp. at-devices for lagging actions.\ +##\ if (\$EVTPART0 eq \"start\") {\ - Log3 \$NAME, 3, \"\$NAME: Wake-up program started for \".\$EVTPART1;;\ + Log3 \$NAME, 3, \"\$NAME: Wake-up program started for \$EVTPART4 with target time \$EVTPART1\";;\ \ - fhem \"set BR_FloorLamp pct 1 : ct 2000 : transitiontime 0;; set BR_FloorLamp pct 90 : ct 5600 : transitiontime 1770\";;\ +# fhem \"set BR_FloorLamp:FILTER=onoff=0 pct 1 : ct 2000 : transitiontime 0;; set BR_FloorLamp:FILTER=pct=1 pct 90 : ct 5600 : transitiontime 1770\";;\ \ - fhem \"define atTmp_1_\$NAME at +00:10:00 set BR_Shutter pct 20\";;\ - fhem \"define atTmp_2_\$NAME at +00:20:00 set BR_Shutter pct 40\";;\ - fhem \"define atTmp_4_\$NAME at +00:30:00 set Sonos_Bedroom Speak 33 de |Hint| Es ist \".\$EVTPART1.\" Uhr, Zeit zum aufstehen!;;;; set BR_FloorLamp pct 100 60;;;; sleep 10;;;; set BR_Shutter pct 60;;;; set Sonos_Bedroom volume 10 10\";;\ +# fhem \"define atTmp_1_\$NAME at +00:10:00 set BR_Shutter:FILTER=pct<20 pct 20\";;\ +# fhem \"define atTmp_2_\$NAME at +00:20:00 set BR_Shutter:FILTER=pct<40 pct 40\";;\ +# fhem \"define atTmp_4_\$NAME at +00:30:00 set Sonos_Bedroom Speak 33 de |Hint| Es ist \".\$EVTPART1.\" Uhr, Zeit zum aufstehen!;;;; set BR_FloorLamp:FILTER=pct<100 pct 100 60;;;; sleep 10;;;; set BR_Shutter:FILTER=pct<60 pct 60;;;; set Sonos_Bedroom:FILTER=Volume<10 Volume 10 10\";;\ \ - # Working days only (Mon-Fri except bank holidays): do enforced wake-up actions\ - if (!\$we) {\ + # if wake-up should be enforced\ + if (\$EVTPART3) {\ Log (4, \"\$NAME: planning enforced wake-up\");;\ - fhem \"define atTmp_3_\$NAME at +00:25:00 set Sonos_Bedroom volume 2;;;; set Sonos_Bedroom Shuffle 1;;;; set Sonos_Bedroom StartFavourite Morning%%20Sounds;;;; sleep 4;;;; set Sonos_Bedroom volume 8 290\";;\ +# fhem \"define atTmp_3_\$NAME at +00:25:00 set Sonos_Bedroom:FILTER=Volume>2 Volume 2;;;; set Sonos_Bedroom:FILTER=Shuffle=0 Shuffle 1;;;; set Sonos_Bedroom StartFavourite Morning%%20Sounds;;;; sleep 4;;;; set Sonos_Bedroom Volume 8 290\";;\ }\ }\ \ @@ -162,19 +168,19 @@ if (\$EVTPART0 eq \"start\") {\ # Put some post wake-up tasks here like reminders after the actual wake-up period.\ #\ if (\$EVTPART0 eq \"stop\") {\ - Log3 \$NAME, 3, \"\$NAME: Wake-up program ended for \".\$EVTPART1;;\ + Log3 \$NAME, 3, \"\$NAME: Wake-up program ended for \$EVTPART4 with target time \$EVTPART1\";;\ \ - # Working days only (Mon-Fri except bank holidays): after only a small additional nap,\ - # get you out of bed :-)\ + # if wake-up should be enforced, auto-change user state from 'asleep' to 'awoken'\ + # after a small additional nap to kick you out of bed if user did not confirm to be awake :-)\ # An additional notify for user state 'awoken' may take further actions\ # and change to state 'home' afterwards.\ - if (!\$we) {\ - fhem \"define atTmp_5_\$NAME at +00:05:00 set rr_Julian:FILTER=STATE=asleep awoken\";;\ + if (\$EVTPART3) {\ + fhem \"define atTmp_5_\$NAME at +00:05:00 set \$EVTPART4:FILTER=STATE=asleep awoken\";;\ \ - # At weekend and bank holidays: be jentle and just set user state to 'home' after some\ + # Without enforced wake-up, be jentle and just set user state to 'home' after some\ # additional long nap time\ } else {\ - fhem \"define atTmp_5_\$NAME at +01:30:00 set rr_Julian:FILTER=STATE=asleep home\";;\ + fhem \"define atTmp_5_\$NAME at +01:30:00 set \$EVTPART4:FILTER=STATE=asleep home\";;\ }\ }\ \ @@ -213,9 +219,43 @@ if (\$EVTPART0 eq \"stop\") {\ "RESIDENTStk $NAME: WARNING - defined at-device '$wakeupAtdevice' is not an at-device!"; } + # verify holiday2we attribute + if ($wakeupHolidays) { + if ( !$holidayDevice ) { + Log3 $NAME, 3, +"RESIDENTStk $NAME: ERROR - wakeupHolidays set in this alarm clock but global attribute holiday2we not set!"; + return +"ERROR: wakeupHolidays set in this alarm clock but global attribute holiday2we not set!"; + } + elsif ( !defined( $defs{$holidayDevice} ) ) { + Log3 $NAME, 3, +"RESIDENTStk $NAME: ERROR - global attribute holiday2we has reference to non-existing device $holidayDevice"; + return +"ERROR: global attribute holiday2we has reference to non-existing device $holidayDevice"; + } + elsif ( $defs{$holidayDevice}{TYPE} ne "holiday" ) { + Log3 $NAME, 3, +"RESIDENTStk $NAME: ERROR - global attribute holiday2we seems to have invalid device reference - $holidayDevice is not of type 'holiday'"; + return +"ERROR: global attribute holiday2we seems to have invalid device reference - $holidayDevice is not of type 'holiday'"; + } + } + + # start + # + if ( $VALUE eq "start" ) { + RESIDENTStk_wakeupRun( $NAME, 1 ); + } + + # trigger + # + elsif ( $VALUE eq "trigger" ) { + RESIDENTStk_wakeupRun($NAME); + } + # stop # - if ( $VALUE eq "stop" && $running ) { + elsif ( $VALUE eq "stop" && $running ) { Log3 $NAME, 4, "RESIDENTStk $NAME: stopping wake-up program"; fhem "setreading $NAME running 0"; fhem "set $NAME nextRun $nextRun"; @@ -236,13 +276,15 @@ if (\$EVTPART0 eq \"stop\") {\ else { if ( defined( $notify[1] ) ) { Log3 $NAME, 4, -"RESIDENTStk $NAME: trigger $wakeupMacro (running=0,forced-stop=0)"; - fhem "trigger $wakeupMacro stop $lastRun $wakeupOffset"; +"RESIDENTStk $NAME: trigger $wakeupMacro stop $lastRun $wakeupOffset $wakeupEnforced $wakeupUserdevice"; + fhem +"trigger $wakeupMacro stop $lastRun $wakeupOffset $wakeupEnforced $wakeupUserdevice"; } else { Log3 $NAME, 4, -"RESIDENTStk $NAME: trigger $wakeupMacro (running=0,forced-stop=1)"; - fhem "trigger $wakeupMacro forced-stop $lastRun $wakeupOffset"; +"RESIDENTStk $NAME: trigger $wakeupMacro forced-stop $lastRun $wakeupOffset $wakeupEnforced $wakeupUserdevice"; + fhem +"trigger $wakeupMacro forced-stop $lastRun $wakeupOffset $wakeupEnforced $wakeupUserdevice"; } fhem "setreading $wakeupUserdevice:FILTER=wakeup=1 wakeup 0"; @@ -290,6 +332,13 @@ if (\$EVTPART0 eq \"stop\") {\ if ( ReadingsVal( $NAME, "nextRun", 0 ) ne $VALUE ); readingsEndUpdate( $defs{$NAME}, 1 ); + my $nextWakeup = RESIDENTStk_wakeupGetNext($wakeupUserdevice); + if ($nextWakeup) { + fhem "setreading $wakeupUserdevice:FILTER=nextWakeup!=$nextWakeup nextWakeup $nextWakeup"; + } else { + fhem "setreading $wakeupUserdevice:FILTER=nextWakeup!=OFF nextWakeup OFF"; + } + fhem "set $wakeupAtdevice modifyTimeSpec {RESIDENTStk_wakeupGetBegin(\"$NAME\")}"; @@ -306,21 +355,25 @@ if (\$EVTPART0 eq \"stop\") {\ # sub RESIDENTStk_wakeupGetBegin($) { my ($NAME) = @_; - my $defaultBeginTime = "05:00"; - my $wakeupDefaultTime = AttrVal( $NAME, "wakeupDefaultTime", $defaultBeginTime ); + my $defaultBeginTime = "05:00"; + my $wakeupDefaultTime = + AttrVal( $NAME, "wakeupDefaultTime", $defaultBeginTime ); my $nextRun = ReadingsVal( $NAME, "nextRun", $wakeupDefaultTime ); my $wakeupTime = ( - lc($nextRun) ne "off" - ? $nextRun - : ( lc($wakeupDefaultTime) ne "off" ? $wakeupDefaultTime : $defaultBeginTime ) ); + lc($nextRun) ne "off" ? $nextRun + : ( + lc($wakeupDefaultTime) ne "off" ? $wakeupDefaultTime + : $defaultBeginTime + ) + ); my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 ); my $return; # Recalculate new wake-up value - if ( $wakeupTime =~ /^([0-9]{2}:[0-9]{2})$/ ) { - my @time = split /:/, $wakeupTime; - - my $seconds = $time[0] * 3600 + $time[1] * 60 - $wakeupOffset * 60; + if ( $wakeupTime =~ /^([0-9]{2}:[0-9]{2})$/ + && looks_like_number($wakeupOffset) ) + { + my $seconds = RESIDENTStk_time2sec($wakeupTime) - $wakeupOffset * 60; if ( $seconds < 0 ) { $seconds = 86400 + $seconds } $return = RESIDENTStk_sec2time($seconds); @@ -332,41 +385,71 @@ sub RESIDENTStk_wakeupGetBegin($) { # # Use DUMMY device to run wakup event # -sub RESIDENTStk_wakeupRun($) { - my ($NAME) = @_; +sub RESIDENTStk_wakeupRun($;$) { + my ( $NAME, $forceRun ) = @_; - my $wakeupMacro = AttrVal( $NAME, "wakeupMacro", 0 ); - my $wakeupDefaultTime = AttrVal( $NAME, "wakeupDefaultTime", 0 ); - my $wakeupAtdevice = AttrVal( $NAME, "wakeupAtdevice", 0 ); - my $wakeupUserdevice = AttrVal( $NAME, "wakeupUserdevice", 0 ); - my $wakeupDays = AttrVal( $NAME, "wakeupDays", 0 ); - my $wakeupResetdays = AttrVal( $NAME, "wakeupResetdays", 0 ); - my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 ); - my $wakeupResetSwitcher = AttrVal( $NAME, "wakeupResetSwitcher", 0 ); + my $wakeupMacro = AttrVal( $NAME, "wakeupMacro", 0 ); + my $wakeupDefaultTime = AttrVal( $NAME, "wakeupDefaultTime", 0 ); + my $wakeupAtdevice = AttrVal( $NAME, "wakeupAtdevice", 0 ); + my $wakeupUserdevice = AttrVal( $NAME, "wakeupUserdevice", 0 ); + my $wakeupDays = AttrVal( $NAME, "wakeupDays", "" ); + my $wakeupHolidays = AttrVal( $NAME, "wakeupHolidays", 0 ); + my $wakeupResetdays = AttrVal( $NAME, "wakeupResetdays", "" ); + my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 ); + my $wakeupEnforced = AttrVal( $NAME, "wakeupEnforced", 0 ); + my $wakeupResetSwitcher = AttrVal( $NAME, "wakeupResetSwitcher", 0 ); + my $holidayDevice = AttrVal( "global", "holiday2we", 0 ); my $lastRun = ReadingsVal( $NAME, "lastRun", "07:00" ); my $nextRun = ReadingsVal( $NAME, "nextRun", "07:00" ); my $running = ReadingsVal( $NAME, "running", 0 ); my $wakeupUserdeviceWakeup = ReadingsVal( $wakeupUserdevice, "wakeup", 0 ); - my $room = AttrVal( $NAME, "room", 0 ); - my $running = 0; + my $room = AttrVal( $NAME, "room", 0 ); + my $running = 0; + my $holidayToday = ""; + + if ( $wakeupHolidays + && $holidayDevice + && defined( $defs{$holidayDevice} ) + && $defs{$holidayDevice}{TYPE} eq "holiday" ) + { + my $hdayTod = ReadingsVal( $holidayDevice, "state", "" ); + + if ( $hdayTod ne "none" && $hdayTod ne "" ) { $holidayToday = 1 } + else { $holidayToday = 0 } + } + else { + $wakeupHolidays = 0; + } my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = - localtime(time); + localtime( time + $wakeupOffset * 60 ); + + if ( $nextRun ne $hour . ":" . $min ) { + $lastRun = substr( + RESIDENTStk_sec2time( + RESIDENTStk_time2sec( $hour . ":" . $min ) - $wakeupOffset * 60 + ), + 0, -3 + ); + } + else { + $lastRun = $nextRun; + } my @days = ($wday); - if ($wakeupDays) { + if ( $wakeupDays ne "" ) { @days = split /,/, $wakeupDays; } my @rdays = ($wday); - if ($wakeupResetdays) { + if ( $wakeupResetdays ne "" ) { @rdays = split /,/, $wakeupResetdays; } if ( !defined( $defs{$NAME} ) ) { return "$NAME: Non existing device"; } - elsif ( lc($nextRun) eq "off" ) { + elsif ( lc($nextRun) eq "off" && !$forceRun ) { Log3 $NAME, 4, "RESIDENTStk $NAME: alarm set to OFF - not triggering wake-up program"; } @@ -385,15 +468,58 @@ sub RESIDENTStk_wakeupRun($) { elsif ( $defs{$wakeupUserdevice}{TYPE} eq "GUEST" && ReadingsVal( $wakeupUserdevice, "state", "" ) eq "none" ) { + Log3 $NAME, 4, +"RESIDENTStk $NAME: GUEST device $wakeupUserdevice has status value 'none' so let's disable this alarm timer"; fhem "set $NAME nextRun OFF"; return; } - elsif ($wday ~~ @days - && ReadingsVal( $wakeupUserdevice, "state", "" ) ne "absent" - && ReadingsVal( $wakeupUserdevice, "state", "" ) ne "gone" - && ReadingsVal( $wakeupUserdevice, "state", "" ) ne "gotosleep" - && ReadingsVal( $wakeupUserdevice, "state", "" ) ne "awoken" ) + elsif ( !$wakeupHolidays && !( $wday ~~ @days ) && !$forceRun ) { + Log3 $NAME, 4, +"RESIDENTStk $NAME: weekday restriction in use - not triggering wake-up program this time"; + } + elsif ( + $wakeupHolidays + && !$forceRun + && ( $wakeupHolidays eq "orHoliday" + || $wakeupHolidays eq "orNoHoliday" ) + && ( + !( $wday ~~ @days ) + && ( ( $wakeupHolidays eq "orHoliday" && !$holidayToday ) + || ( $wakeupHolidays eq "orNoHoliday" && $holidayToday ) ) + ) + ) { + Log3 $NAME, 4, +"RESIDENTStk $NAME: neither weekday nor holiday restriction matched - not triggering wake-up program this time"; + } + elsif ( + $wakeupHolidays + && !$forceRun + && ( $wakeupHolidays eq "andHoliday" + || $wakeupHolidays eq "andNoHoliday" ) + && ( + !( $wday ~~ @days ) + || ( ( $wakeupHolidays eq "andHoliday" && !$holidayToday ) + || ( $wakeupHolidays eq "andNoHoliday" && $holidayToday ) ) + ) + ) + { + Log3 $NAME, 4, +"RESIDENTStk $NAME: weekday restriction in conjunction with $wakeupHolidays in use - not triggering wake-up program this time"; + } + elsif (ReadingsVal( $wakeupUserdevice, "state", "" ) eq "absent" + || ReadingsVal( $wakeupUserdevice, "state", "" ) eq "gone" + || ReadingsVal( $wakeupUserdevice, "state", "" ) eq "gotosleep" + || ReadingsVal( $wakeupUserdevice, "state", "" ) eq "awoken" ) + { + Log3 $NAME, 4, +"RESIDENTStk $NAME: we should not start any wake-up program for resident device $wakeupUserdevice being in state '" + . ReadingsVal( $wakeupUserdevice, "state", "" ) + . "' - not triggering wake-up program this time"; + } + + # general conditions to trigger program fulfilled + else { if ( !$wakeupMacro ) { return "$NAME: missing attribute wakeupMacro"; } @@ -406,14 +532,18 @@ sub RESIDENTStk_wakeupRun($) { } elsif ($wakeupUserdeviceWakeup) { Log3 $NAME, 3, -"RESIDENTStk $NAME: Another wake-up program is already being executed, won't trigger $wakeupMacro"; +"RESIDENTStk $NAME: Another wake-up program is already being executed for device $wakeupUserdevice, won't trigger $wakeupMacro"; } else { Log3 $NAME, 4, "RESIDENTStk $NAME: trigger $wakeupMacro (running=1)"; - fhem "trigger $wakeupMacro start $nextRun $wakeupOffset"; + fhem +"trigger $wakeupMacro start $lastRun $wakeupOffset $wakeupEnforced $wakeupUserdevice"; + fhem "setreading $wakeupUserdevice lastWakeup $lastRun"; fhem "setreading $wakeupUserdevice wakeup 1"; - fhem "setreading $NAME lastRun $nextRun"; + fhem "setreading $wakeupUserdevice wakeup 0" + if ( !$wakeupOffset ); + fhem "setreading $NAME lastRun $lastRun"; if ( $wakeupOffset > 0 ) { my $wakeupStopAtdevice = $wakeupAtdevice . "_stop"; @@ -460,6 +590,10 @@ sub RESIDENTStk_wakeupRun($) { readingsEndUpdate( $defs{$NAME}, 1 ); } + if ( !$running ) { + fhem "setreading $NAME:FILTER=state!=$nextRun state $nextRun"; + } + return undef; } @@ -516,6 +650,183 @@ sub RESIDENTStk_AttrFnDummy(@) { return undef; } +##################################### +# GENERAL USER AUTOMATION FUNCTIONS +#------------------------------------ +# + +sub RESIDENTStk_wakeupGetNext($) { + my ($name) = @_; + + my $wakeupDeviceList = ( + AttrVal( $name, "rgr_wakeupDevice", 0 ) + ? AttrVal( $name, "rgr_wakeupDevice", 0 ) + : ( + AttrVal( $name, "rr_wakeupDevice", 0 ) + ? AttrVal( $name, "rr_wakeupDevice", 0 ) + : ( + AttrVal( $name, "rg_wakeupDevice", 0 ) + ? AttrVal( $name, "rg_wakeupDevice", 0 ) + : 0 + ) + ) + ); + + return "Device $name does not seem to have any wakeup devices registered." + if ( !$wakeupDeviceList ); + + my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = + localtime(time); + + my $wdayTomorrow = $wday + 1; + $wdayTomorrow = 0 if ( $wdayTomorrow == 7 ); + my $secNow = RESIDENTStk_time2sec( $hour . ":" . $min ) + $sec; + my $definitiveNextToday = 0; + my $definitiveNextTomorrow = 0; + + for my $wakeupDevice ( split /,/, $wakeupDeviceList ) { + + my $nextRun = ReadingsVal( $wakeupDevice, "nextRun", 0 ); + my $wakeupDays = AttrVal( $wakeupDevice, "wakeupDays", "" ); + my $holidayDevice = AttrVal( "global", "holiday2we", 0 ); + my $wakeupHolidays = AttrVal( $wakeupDevice, "wakeupHolidays", 0 ); + my $holidayToday = ""; + my $holidayTomorrow = ""; + + if ( $wakeupHolidays + && $holidayDevice + && defined( $defs{$holidayDevice} ) + && $defs{$holidayDevice}{TYPE} eq "holiday" ) + { + my $hdayTod = ReadingsVal( $holidayDevice, "state", "" ); + my $hdayTom = ReadingsVal( $holidayDevice, "tomorrow", "" ); + + if ( $hdayTod ne "none" && $hdayTod ne "" ) { $holidayToday = 1 } + else { $holidayToday = 0 } + + if ( $hdayTom ne "none" && $hdayTom ne "" ) { $holidayTomorrow = 1 } + else { $holidayTomorrow = 0 } + } + + my @days = ($wday); + if ( $wakeupDays ne "" ) { + @days = split /,/, $wakeupDays; + } + + my @daysTomorrow = ($wdayTomorrow); + if ( $wakeupDays ne "" ) { + @daysTomorrow = split /,/, $wakeupDays; + } + + if ( lc($nextRun) ne "off" && $nextRun =~ /^([0-9]{2}:[0-9]{2})$/ ) { + my $nextRunSec = RESIDENTStk_time2sec($nextRun); + + # still running today + if ( $nextRunSec > $secNow ) { + + # if today is in scope + if ( $wday ~~ @days ) { + + # if we need to consider holidays in addition + if ( + $wakeupHolidays + && ( $wakeupHolidays eq "andHoliday" && !$holidayToday ) + || ( $wakeupHolidays eq "andNoHoliday" + && $holidayToday ) + ) + { + next; + } + + # easy if there is no holiday dependency + elsif ( !$definitiveNextToday + || $nextRunSec < $definitiveNextToday ) + { + $definitiveNextToday = $nextRunSec; + } + + } + + # if we need to consider holidays in parallel to weekdays + if ( + $wakeupHolidays + && ( + ( $wakeupHolidays eq "orHoliday" && $holidayToday ) + || ( $wakeupHolidays eq "orNoHoliday" + && !$holidayToday ) + ) + ) + { + + if ( !$definitiveNextToday + || $nextRunSec < $definitiveNextToday ) + { + $definitiveNextToday = $nextRunSec; + } + + } + + } + + # running tomorrow + else { + + # if tomorrow is in scope + if ( $wdayTomorrow ~~ @daysTomorrow ) { + + # if we need to consider holidays in addition + if ( + $wakeupHolidays && ( $wakeupHolidays eq "andHoliday" + && !$holidayTomorrow ) + || ( $wakeupHolidays eq "andNoHoliday" + && $holidayTomorrow ) + ) + { + next; + } + + # easy if there is no holiday dependency + elsif ( !$definitiveNextTomorrow + || $nextRunSec < $definitiveNextTomorrow ) + { + $definitiveNextTomorrow = $nextRunSec; + } + + } + + # if we need to consider holidays in parallel to weekdays + if ( + $wakeupHolidays + && ( + ( $wakeupHolidays eq "orHoliday" && $holidayTomorrow ) + || ( $wakeupHolidays eq "orNoHoliday" + && !$holidayTomorrow ) + ) + ) + { + + if ( !$definitiveNextTomorrow + || $nextRunSec < $definitiveNextTomorrow ) + { + $definitiveNextTomorrow = $nextRunSec; + } + + } + + } + + } + } + + return substr( RESIDENTStk_sec2time($definitiveNextToday), 0, -3 ) + if ($definitiveNextToday); + + return substr( RESIDENTStk_sec2time($definitiveNextTomorrow), 0, -3 ) + if ($definitiveNextTomorrow); + + return; +} + ##################################### # GENERAL FUNCTIONS USED IN RESIDENTS, ROOMMATE, GUEST #------------------------------------ @@ -570,6 +881,13 @@ sub RESIDENTStk_sec2time($) { return "$hours:$minutes:$seconds"; } +sub RESIDENTStk_time2sec($) { + my ($timeString) = @_; + my @time = split /:/, $timeString; + + return $time[0] * 3600 + $time[1] * 60; +} + sub RESIDENTStk_InternalTimer($$$$$) { my ( $modifier, $tim, $callback, $hash, $waitIfInitNotDone ) = @_;