diff --git a/fhem/FHEM/10_RESIDENTS.pm b/fhem/FHEM/10_RESIDENTS.pm index e448868a5..3fb820e6c 100644 --- a/fhem/FHEM/10_RESIDENTS.pm +++ b/fhem/FHEM/10_RESIDENTS.pm @@ -649,11 +649,15 @@ sub RESIDENTS_Set($@) { sub RESIDENTS_UpdateReadings (@) { my ($hash) = @_; - my $state = - ( defined $hash->{READINGS}{state}{VAL} ) ? $hash->{READINGS}{state}{VAL} - : ( defined $hash->{STATE} ) ? $hash->{STATE} - : "undefined"; my $name = $hash->{NAME}; + my $state = + ( defined( $hash->{READINGS}{state}{VAL} ) ) + ? $hash->{READINGS}{state}{VAL} + : "none"; + my $presence = + ( defined( $hash->{READINGS}{presence}{VAL} ) ) + ? $hash->{READINGS}{presence}{VAL} + : "absent"; my $state_home = 0; my $state_gotosleep = 0; @@ -671,7 +675,6 @@ sub RESIDENTS_UpdateReadings (@) { my $wayhome = 0; my $wakeup = 0; my $newstate; - my $presence = "absent"; my @registeredRoommates = split( /,/, $hash->{ROOMMATES} ) @@ -925,35 +928,48 @@ sub RESIDENTS_UpdateReadings (@) { $newstate = "unspecified"; } - # stop any running wakeup-timers in case user went away - if ( $newstate eq "away" || $newstate eq "gone"|| $newstate eq "none" ) { - my $wakeupDeviceList = AttrVal( $name, "rgr_wakeupDevice", 0 ); - - for my $wakeupDevice ( split /,/, $wakeupDeviceList ) { - next if !$wakeupDevice; - - if ( defined( $defs{$wakeupDevice} ) && $defs{$wakeupDevice}{TYPE} eq "dummy" ) { - fhem "set $wakeupDevice:FILTER=running!=0 stop"; - } - } - } - # calculate presence state - $presence = "present" - if ( $newstate ne "gone" - && $newstate ne "none" - && $newstate ne "absent" ); + my $newpresence = + ( $newstate ne "none" && $newstate ne "gone" && $newstate ne "absent" ) + ? "present" + : "absent"; Log3 $name, 4, -"RESIDENTS $name: calculation result - residentsTotal:$state_total residentsTotalGuests:$state_totalGuests residentsTotalGuestsPresent:$state_totalGuestsPresent residentsTotalGuestsAbsent:$state_totalGuestsAbsent residentsTotalPresent:$state_totalPresent residentsTotalAbsent:$state_totalAbsent residentsHome:$state_home residentsGotosleep:$state_gotosleep residentsAsleep:$state_asleep residentsAwoken:$state_awoken residentsAbsent:$state_absent residentsGone:$state_gone presence:$presence state:$newstate"; +"RESIDENTS $name: calculation result - residentsTotal:$state_total residentsTotalGuests:$state_totalGuests residentsTotalGuestsPresent:$state_totalGuestsPresent residentsTotalGuestsAbsent:$state_totalGuestsAbsent residentsTotalPresent:$state_totalPresent residentsTotalAbsent:$state_totalAbsent residentsHome:$state_home residentsGotosleep:$state_gotosleep residentsAsleep:$state_asleep residentsAwoken:$state_awoken residentsAbsent:$state_absent residentsGone:$state_gone presence:$newpresence state:$newstate"; # safe current time my $datetime = FmtDateTime(time); # if state changed - if ( !defined( $hash->{READINGS}{state}{VAL} ) - || $state ne $newstate ) - { + if ( $state ne $newstate ) { + + # stop any running wakeup-timers in case state changed + my $wakeupState = AttrVal( $name, "wakeup", 0 ); + if ($wakeupState) { + my $wakeupDeviceList = AttrVal( $name, "rgr_wakeupDevice", 0 ); + + for my $wakeupDevice ( split /,/, $wakeupDeviceList ) { + next if !$wakeupDevice; + + if ( defined( $defs{$wakeupDevice} ) + && $defs{$wakeupDevice}{TYPE} eq "dummy" ) + { + # forced-stop only if resident is not present anymore + my $wakeupNormalStop; + if ( $newstate ne "gone" + && $newstate ne "none" + && $newstate ne "absent" ) + { + $wakeupNormalStop = + AttrVal( $wakeupDevice, "lastRun", "00:00" ); + } + + fhem +"set $wakeupDevice:FILTER=running!=0 stop $wakeupNormalStop"; + } + } + } + # if newstate is asleep, start sleep timer readingsBulkUpdate( $hash, "lastSleep", $datetime ) if ( $newstate eq "asleep" ); @@ -984,10 +1000,8 @@ sub RESIDENTS_UpdateReadings (@) { } # if presence changed - if ( !defined( $hash->{READINGS}{presence}{VAL} ) - || $hash->{READINGS}{presence}{VAL} ne $presence ) - { - readingsBulkUpdate( $hash, "presence", $presence ); + if ( $newpresence ne $presence ) { + readingsBulkUpdate( $hash, "presence", $newpresence ); # update statistics if ( $presence eq "present" ) { @@ -1304,6 +1318,9 @@ sub RESIDENTS_UpdateReadings (@) {
  • wakeupUserdevice - backlink to RESIDENTS, ROOMMATE or GUEST device to check it's status (mandatory)
  • +
  • + wakeupWaitPeriod - waiting period threshold in minutes until wake-up program may be triggered again, e.g. if you manually set an earlier wake-up time than normal while using wakeupDefaultTime. Does not apply in case wake-up time was changed during this period; defaults to 360 minutes / 6h (optional) +
  • @@ -1567,6 +1584,9 @@ sub RESIDENTS_UpdateReadings (@) {
  • wakeupUserdevice - Backlink zum RESIDENTS, ROOMMATE oder GUEST Gerät, um dessen Status zu prüfen (notwendig)
  • +
  • + wakeupWaitPeriod - Schwelle der Wartezeit in Minuten bis das Weckprogramm erneut ausgeführt werden kann, z.B. wenn manuell eine frühere Weckzeit gesetzt wurde als normal während wakeupDefaultTime verwendet wird. Greift nicht, wenn die Weckzeit während dieser Zeit geändert wurde; Standard ist 360 Minuten / 6h (optional) +
  • diff --git a/fhem/FHEM/20_GUEST.pm b/fhem/FHEM/20_GUEST.pm index 61eee0477..7dd425727 100644 --- a/fhem/FHEM/20_GUEST.pm +++ b/fhem/FHEM/20_GUEST.pm @@ -388,6 +388,7 @@ sub GUEST_Set($@) { Log3 $name, 2, "GUEST set $name " . $newstate if ( !$silent ); + # if state changed if ( $state ne $newstate ) { readingsBeginUpdate($hash); @@ -463,19 +464,6 @@ sub GUEST_Set($@) { ); } - # stop any running wakeup-timers in case user went away - if ( $newstate eq "away" || $newstate eq "gone" ) { - my $wakeupDeviceList = AttrVal( $name, "rg_wakeupDevice", 0 ); - - for my $wakeupDevice ( split /,/, $wakeupDeviceList ) { - next if !$wakeupDevice; - - if ( defined( $defs{$wakeupDevice} ) && $defs{$wakeupDevice}{TYPE} eq "dummy" ) { - fhem "set $wakeupDevice:FILTER=running!=0 stop"; - } - } - } - # calculate presence state my $newpresence = ( $newstate ne "none" @@ -484,6 +472,28 @@ sub GUEST_Set($@) { ? "present" : "absent"; + # stop any running wakeup-timers in case state changed + my $wakeupState = AttrVal( $name, "wakeup", 0 ); + if ($wakeupState) { + my $wakeupDeviceList = AttrVal( $name, "rg_wakeupDevice", 0 ); + + for my $wakeupDevice ( split /,/, $wakeupDeviceList ) { + next if !$wakeupDevice; + + if ( defined( $defs{$wakeupDevice} ) + && $defs{$wakeupDevice}{TYPE} eq "dummy" ) + { + my $wakeupNormalStop; + $wakeupNormalStop = + AttrVal( $wakeupDevice, "lastRun", "00:00" ) + if ( $newpresence eq "present" ); + + fhem +"set $wakeupDevice:FILTER=running!=0 stop $wakeupNormalStop"; + } + } + } + # if presence changed if ( $newpresence ne $presence ) { readingsBulkUpdate( $hash, "presence", $newpresence ); diff --git a/fhem/FHEM/20_ROOMMATE.pm b/fhem/FHEM/20_ROOMMATE.pm index 0ccf0aa04..ced2fa8e8 100644 --- a/fhem/FHEM/20_ROOMMATE.pm +++ b/fhem/FHEM/20_ROOMMATE.pm @@ -389,6 +389,7 @@ sub ROOMMATE_Set($@) { Log3 $name, 2, "ROOMMATE set $name " . $newstate if ( !$silent ); + # if state changed if ( $state ne $newstate ) { readingsBeginUpdate($hash); @@ -464,19 +465,6 @@ sub ROOMMATE_Set($@) { ) ); } - - # stop any running wakeup-timers in case user went away - if ( $newstate eq "away" || $newstate eq "gone"|| $newstate eq "none" ) { - my $wakeupDeviceList = AttrVal( $name, "rr_wakeupDevice", 0 ); - - for my $wakeupDevice ( split /,/, $wakeupDeviceList ) { - next if !$wakeupDevice; - - if ( defined( $defs{$wakeupDevice} ) && $defs{$wakeupDevice}{TYPE} eq "dummy" ) { - fhem "set $wakeupDevice:FILTER=running!=0 stop"; - } - } - } # calculate presence state my $newpresence = @@ -486,6 +474,28 @@ sub ROOMMATE_Set($@) { ? "present" : "absent"; + # stop any running wakeup-timers in case state changed + my $wakeupState = AttrVal( $name, "wakeup", 0 ); + if ($wakeupState) { + my $wakeupDeviceList = AttrVal( $name, "rr_wakeupDevice", 0 ); + + for my $wakeupDevice ( split /,/, $wakeupDeviceList ) { + next if !$wakeupDevice; + + if ( defined( $defs{$wakeupDevice} ) + && $defs{$wakeupDevice}{TYPE} eq "dummy" ) + { + my $wakeupNormalStop; + $wakeupNormalStop = + AttrVal( $wakeupDevice, "lastRun", "00:00" ) + if ( $newpresence eq "present" ); + + fhem +"set $wakeupDevice:FILTER=running!=0 stop $wakeupNormalStop"; + } + } + } + # if presence changed if ( $newpresence ne $presence ) { readingsBulkUpdate( $hash, "presence", $newpresence ); diff --git a/fhem/FHEM/RESIDENTStk.pm b/fhem/FHEM/RESIDENTStk.pm index 37f6dddb9..9a445a854 100644 --- a/fhem/FHEM/RESIDENTStk.pm +++ b/fhem/FHEM/RESIDENTStk.pm @@ -90,7 +90,7 @@ sub RESIDENTStk_wakeupSet($$) { # 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 wakeupHolidays:andHoliday,orHoliday,andNoHoliday,orNoHoliday wakeupEnforced:0,1,2"; +"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,2 wakeupWaitPeriod:slider,0,1,360"; if ( !$userattr || $userattr ne $userattributes ) { Log3 $NAME, 4, "RESIDENTStk $NAME: adjusting dummy device for required attribute userattr"; @@ -914,13 +914,18 @@ sub RESIDENTStk_wakeupRun($;$) { my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 ); my $wakeupEnforced = AttrVal( $NAME, "wakeupEnforced", 0 ); my $wakeupResetSwitcher = AttrVal( $NAME, "wakeupResetSwitcher", 0 ); + my $wakeupWaitPeriod = AttrVal( $NAME, "wakeupWaitPeriod", 360 ); my $holidayDevice = AttrVal( "global", "holiday2we", 0 ); my $lastRun = ReadingsVal( $NAME, "lastRun", "06:00" ); + my $lastRunTimestamp = + ReadingsTimestamp( $NAME, "lastRun", "1970-01-01 00:00:00" ); my $nextRun = ReadingsVal( $NAME, "nextRun", "06:00" ); - my $running = ReadingsVal( $NAME, "running", 0 ); + my $nextRunTimestamp = + ReadingsTimestamp( $NAME, "nextRun", "1970-01-01 00:00:00" ); my $wakeupUserdeviceWakeup = ReadingsVal( $wakeupUserdevice, "wakeup", 0 ); my $room = AttrVal( $NAME, "room", 0 ); my $running = 0; + my $preventRun = 0; my $holidayToday = ""; if ( $wakeupHolidays @@ -939,11 +944,19 @@ sub RESIDENTStk_wakeupRun($;$) { my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime( time + $wakeupOffset * 60 ); + $mon += 01; $hour = "0" . $hour if ( $hour < 10 ); $min = "0" . $min if ( $min < 10 ); my $nowRun = $hour . ":" . $min; + my $nowRunSec = + RESIDENTStk_Datetime2Timestamp( $year . "-" + . $mon . "-" + . $mday . " " + . $hour . ":" + . $min . ":" + . $sec ); if ( $nextRun ne $nowRun ) { $lastRun = $nowRun; @@ -954,6 +967,24 @@ sub RESIDENTStk_wakeupRun($;$) { Log3 $NAME, 4, "RESIDENTStk $NAME: lastRun = nextRun = $lastRun"; } + # do not run if wakeupWaitPeriod expiration was not reached yet + my $expLastRun = + RESIDENTStk_Datetime2Timestamp($lastRunTimestamp) - 1 + + $wakeupOffset * 60 + + $wakeupWaitPeriod * 60; + my $expNextRun = RESIDENTStk_Datetime2Timestamp($nextRunTimestamp) - 1 + + $wakeupWaitPeriod * 60; + if ( $expLastRun > $nowRunSec + && $expNextRun < time() ) + { + $preventRun = 1; + } + else { + Log3 $NAME, 5, +"RESIDENTStk $NAME: wakeupWaitPeriod threshold reached (expLastRun=$expLastRun nowRunSec=$nowRunSec expNextRun=$expNextRun localtime=" + . time() . ")"; + } + my @days = ($wday); if ( $wakeupDays ne "" ) { @days = split /,/, $wakeupDays; @@ -1053,6 +1084,11 @@ sub RESIDENTStk_wakeupRun($;$) { Log3 $NAME, 3, "RESIDENTStk $NAME: Another wake-up program is already being executed for device $wakeupUserdevice, won't trigger $wakeupMacro"; } + elsif ( $preventRun && !$forceRun ) { + Log3 $NAME, 4, +"RESIDENTStk $NAME: won't trigger wake-up program due to non-expired wakeupWaitPeriod threshold since lastRun (expLastRun=$expLastRun nowRunSec=$nowRunSec expNextRun=$expNextRun localtime=" + . time() . ")"; + } else { # conditional enforced wake-up: # only if actual wake-up time is not wakeupDefaultTime