diff --git a/fhem/FHEM/10_RESIDENTS.pm b/fhem/FHEM/10_RESIDENTS.pm
index 572ad3ff9..4d85f1c85 100644
--- a/fhem/FHEM/10_RESIDENTS.pm
+++ b/fhem/FHEM/10_RESIDENTS.pm
@@ -1,60 +1,29 @@
+###############################################################################
# $Id$
-##############################################################################
-#
-# 10_RESIDENTS.pm
-# An FHEM Perl module to ease resident administration.
-#
-# Copyright by Julian Pawlowski
-# e-mail: julian.pawlowski at gmail.com
-#
-# This file is part of fhem.
-#
-# Fhem is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# Fhem is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with fhem. If not, see .
-#
-##############################################################################
-
package main;
-
use strict;
use warnings;
-use Time::Local;
use Data::Dumper;
+use Time::Local;
+
require RESIDENTStk;
-sub RESIDENTS_Set($@);
-sub RESIDENTS_Define($$);
-sub RESIDENTS_Notify($$);
-sub RESIDENTS_Attr(@);
-sub RESIDENTS_Undefine($$);
-
-###################################
+# initialize ##################################################################
sub RESIDENTS_Initialize($) {
my ($hash) = @_;
- Log3 $hash, 5, "RESIDENTS_Initialize: Entering";
-
- $hash->{SetFn} = "RESIDENTS_Set";
$hash->{DefFn} = "RESIDENTS_Define";
- $hash->{NotifyFn} = "RESIDENTS_Notify";
- $hash->{AttrFn} = "RESIDENTS_Attr";
$hash->{UndefFn} = "RESIDENTS_Undefine";
+ $hash->{SetFn} = "RESIDENTS_Set";
+ $hash->{AttrFn} = "RESIDENTS_Attr";
+ $hash->{NotifyFn} = "RESIDENTS_Notify";
+
$hash->{AttrList} =
-"disable:1,0 rgr_showAllStates:0,1 rgr_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone rgr_lang:EN,DE rgr_noDuration:0,1 rgr_wakeupDevice "
+"disable:1,0 disabledForIntervals do_not_notify:1,0 rgr_showAllStates:0,1 rgr_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone rgr_lang:EN,DE rgr_noDuration:0,1 rgr_wakeupDevice "
. $readingFnAttributes;
}
-###################################
+# regular Fn ##################################################################
sub RESIDENTS_Define($$) {
my ( $hash, $def ) = @_;
my $name = $hash->{NAME};
@@ -75,7 +44,7 @@ sub RESIDENTS_Define($$) {
# run timers
InternalTimer(
gettimeofday() + 15,
- "RESIDENTS_StartInternalTimers",
+ "RESIDENTStk_RG_StartInternalTimers",
$hash, 0
);
@@ -91,88 +60,10 @@ sub RESIDENTS_Define($$) {
return undef;
}
-###################################
-sub RESIDENTS_Attr(@) {
- my ( $cmd, $name, $attribute, $value ) = @_;
- my $hash = $defs{$name};
- my $prefix = "rgr_";
- return unless ($init_done);
-
- Log3 $name, 5, "RESIDENTS $name: called function RESIDENTS_Attr()";
-
- if ( $attribute eq "disable" ) {
- if ( $value and $value == 1 ) {
- $hash->{STATE} = "disabled";
- RESIDENTS_StopInternalTimers($hash);
- }
- elsif ( $cmd eq "del" or !$value ) {
- evalStateFormat($hash);
- RESIDENTS_StartInternalTimers( $hash, 1 );
- }
- }
-
- elsif ( $attribute eq $prefix . "noDuration" ) {
- if ($value) {
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
- }
- elsif ( !$value ) {
- RESIDENTS_DurationTimer($hash);
- }
- }
-
- elsif ( $attribute eq $prefix . "lang" ) {
- my $lang =
- $cmd eq "set" ? uc($value) : AttrVal( "global", "language", "EN" );
-
- # for initial define, ensure fallback to EN
- $lang = "EN"
- if ( $cmd eq "init" && $lang !~ /^EN|DE$/i );
-
- if ( $lang eq "DE" ) {
- $attr{$name}{alias} = "Bewohner"
- if ( !defined( $attr{$name}{alias} )
- || $attr{$name}{alias} eq "Residents" );
- $attr{$name}{group} = "Haus Status"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Home State" );
- $attr{$name}{devStateIcon} =
-'.*zuhause:status_available:absent .*anwesend:status_available:absent .*abwesend:status_away_1:home .*verreist:status_standby:home .*keine:control_building_empty .*bettfertig:status_night:asleep .*schlaeft:status_night:awoken .*schläft:status_night:awoken .*aufgestanden:status_available:home .*:user_unknown:home';
- $attr{$name}{eventMap} =
-"home:zuhause absent:abwesend gone:verreist none:keine gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
- $attr{$name}{widgetOverride} =
-"state:zuhause,bettfertig,schläft,aufgestanden,abwesend,verreist";
- }
- elsif ( $lang eq "EN" ) {
- $attr{$name}{alias} = "Residents"
- if ( !defined( $attr{$name}{alias} )
- || $attr{$name}{alias} eq "Bewohner" );
- $attr{$name}{group} = "Home State"
- if ( !defined( $attr{$name}{group} )
- || $attr{$name}{group} eq "Haus Status" );
- $attr{$name}{devStateIcon} =
-'.*home:status_available:absent .*absent:status_away_1:home .*gone:status_standby:home .*none:control_building_empty .*gotosleep:status_night:asleep .*asleep:status_night:awoken .*awoken:status_available:home .*:user_unknown:home';
- delete $attr{$name}{eventMap}
- if ( defined( $attr{$name}{eventMap} ) );
- delete $attr{$name}{widgetOverride}
- if ( defined( $attr{$name}{widgetOverride} ) );
- }
- else {
- return "Unsupported language $lang";
- }
-
- evalStateFormat($hash);
- }
-
- return if ( IsDisabled($name) );
- return;
-}
-
-###################################
sub RESIDENTS_Undefine($$) {
my ( $hash, $name ) = @_;
- RESIDENTS_StopInternalTimers($hash);
+ RESIDENTStk_RG_StopInternalTimers($hash);
RESIDENTStk_findResidentSlaves($hash);
# delete child roommates
@@ -204,132 +95,6 @@ sub RESIDENTS_Undefine($$) {
return undef;
}
-###################################
-sub RESIDENTS_Notify($$) {
- my ( $hash, $dev ) = @_;
- my $devName = $dev->{NAME};
- my $hashName = $hash->{NAME};
- return unless ( $devName ne $hashName ); # only foreign events
- return if ( IsDisabled($hashName) or IsDisabled($devName) );
- return
- unless ( IsDevice( $devName, "ROOMMATE|GUEST|dummy" ) );
-
- my @registeredRoommates =
- split( /,/, $hash->{ROOMMATES} )
- if ( defined( $hash->{ROOMMATES} )
- && $hash->{ROOMMATES} ne "" );
-
- my @registeredGuests =
- split( /,/, $hash->{GUESTS} )
- if ( defined( $hash->{GUESTS} )
- && $hash->{GUESTS} ne "" );
-
- my @registeredWakeupdevs =
- split( /,/, $attr{$hashName}{rgr_wakeupDevice} )
- if ( defined( $attr{$hashName}{rgr_wakeupDevice} )
- && $attr{$hashName}{rgr_wakeupDevice} ne "" );
-
- # process only registered ROOMMATE or GUEST devices
- if ( ( @registeredRoommates && grep { /^$devName$/ } @registeredRoommates )
- || ( @registeredGuests && grep { /^$devName$/ } @registeredGuests ) )
- {
-
- return
- if ( !$dev->{CHANGED} ); # Some previous notify deleted the array.
-
- readingsBeginUpdate($hash);
-
- foreach my $change ( @{ $dev->{CHANGED} } ) {
-
- Log3 $hash, 5,
- "RESIDENTS " . $hashName . ": processing change $change";
-
- # state changed
- if ( $change !~ /:/
- || $change =~ /wayhome:/
- || $change =~ /wakeup:/ )
- {
- Log3 $hash, 4,
- "RESIDENTS "
- . $hashName . ": "
- . $devName
- . ": notify about change to $change";
-
- RESIDENTS_UpdateReadings($hash);
- }
-
- # activity
- if ( $change !~ /:/ ) {
-
- # get user realname
- my $realname =
- AttrVal( $devName,
- AttrVal( $devName, "rr_realname", "group" ), $devName );
- $realname =
- AttrVal( $devName,
- AttrVal( $devName, "rg_realname", "alias" ), $devName )
- if ( $dev->{TYPE} eq "GUEST" );
-
- # update statistics
- readingsBulkUpdate( $hash, "lastActivity",
- ReadingsVal( $devName, "state", $change ) );
- readingsBulkUpdate( $hash, "lastActivityBy", $realname );
- readingsBulkUpdate( $hash, "lastActivityByDev", $devName );
-
- }
-
- }
-
- readingsEndUpdate( $hash, 1 );
-
- return;
- }
-
- # if we have registered wakeup devices
- if (@registeredWakeupdevs) {
-
- # if this is a notification of a registered wakeup device
- if ( grep { /^$devName$/ } @registeredWakeupdevs ) {
-
- # Some previous notify deleted the array.
- return
- if ( !$dev->{CHANGED} );
-
- foreach my $change ( @{ $dev->{CHANGED} } ) {
- RESIDENTStk_wakeupSet( $devName, $change );
- }
-
- return;
- }
-
- # process sub-child notifies: *_wakeupDevice
- foreach my $wakeupDev (@registeredWakeupdevs) {
-
- # if this is a notification of a registered sub dummy device
- # of one of our wakeup devices
- if ( defined( $attr{$wakeupDev}{wakeupResetSwitcher} )
- && $attr{$wakeupDev}{wakeupResetSwitcher} eq $devName
- && $defs{$devName}{TYPE} eq "dummy" )
- {
-
- # Some previous notify deleted the array.
- return
- if ( !$dev->{CHANGED} );
-
- foreach my $change ( @{ $dev->{CHANGED} } ) {
- RESIDENTStk_wakeupSet( $wakeupDev, $change )
- if ( $change ne "off" );
- }
-
- last;
- }
- }
- }
-
- return;
-}
-
-###################################
sub RESIDENTS_Set($@) {
my ( $hash, @a ) = @_;
my $name = $hash->{NAME};
@@ -570,8 +335,7 @@ sub RESIDENTS_Set($@) {
# create
elsif ( $a[1] eq "create" ) {
if ( !defined( $a[2] ) || $a[2] !~ /^(wakeuptimer)$/i ) {
- return
- "Invalid 2nd argument, choose one of wakeuptimer ";
+ return "Invalid 2nd argument, choose one of wakeuptimer ";
}
elsif ( $a[2] eq "wakeuptimer" ) {
my $i = "1";
@@ -639,12 +403,190 @@ sub RESIDENTS_Set($@) {
return undef;
}
-############################################################################################################
-#
-# Begin of helper functions
-#
-############################################################################################################
+sub RESIDENTS_Attr(@) {
+ my ( $cmd, $name, $attribute, $value ) = @_;
+ my $hash = $defs{$name};
+ my $prefix = "rgr_";
+ Log3 $name, 5, "RESIDENTS $name: called function RESIDENTS_Attr()";
+
+ if ( $attribute eq "rgr_wakeupDevice" ) {
+ return "Value for $attribute has invalid format"
+ unless ( $value =~ /^([a-zA-Z\d._]+,?)([a-zA-Z\d._]+,?)*$/ );
+
+ RESIDENTStk_findResidentSlaves( $hash, $value );
+ }
+
+ elsif ( !$init_done ) {
+ return undef;
+ }
+
+ elsif ( $attribute eq "disable" ) {
+ if ( $value and $value == 1 ) {
+ $hash->{STATE} = "disabled";
+ RESIDENTStk_RG_StopInternalTimers($hash);
+ }
+ elsif ( $cmd eq "del" or !$value ) {
+ evalStateFormat($hash);
+ RESIDENTStk_RG_StartInternalTimers( $hash, 1 );
+ }
+ }
+
+ elsif ( $attribute eq $prefix . "noDuration" ) {
+ if ($value) {
+ delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
+ RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
+ }
+ elsif ( !$value ) {
+ RESIDENTStk_RG_DurationTimer($hash);
+ }
+ }
+
+ elsif ( $attribute eq $prefix . "lang" ) {
+ my $lang =
+ $cmd eq "set" ? uc($value) : AttrVal( "global", "language", "EN" );
+
+ # for initial define, ensure fallback to EN
+ $lang = "EN"
+ if ( $cmd eq "init" && $lang !~ /^EN|DE$/i );
+
+ if ( $lang eq "DE" ) {
+ $attr{$name}{alias} = "Bewohner"
+ if ( !defined( $attr{$name}{alias} )
+ || $attr{$name}{alias} eq "Residents" );
+ $attr{$name}{group} = "Haus Status"
+ if ( !defined( $attr{$name}{group} )
+ || $attr{$name}{group} eq "Home State" );
+ $attr{$name}{devStateIcon} =
+'.*zuhause:status_available:absent .*anwesend:status_available:absent .*abwesend:status_away_1:home .*verreist:status_standby:home .*keine:control_building_empty .*bettfertig:status_night:asleep .*schlaeft:status_night:awoken .*schläft:status_night:awoken .*aufgestanden:status_available:home .*:user_unknown:home';
+ $attr{$name}{eventMap} =
+"home:zuhause absent:abwesend gone:verreist none:keine gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
+ $attr{$name}{widgetOverride} =
+"state:zuhause,bettfertig,schläft,aufgestanden,abwesend,verreist";
+ }
+ elsif ( $lang eq "EN" ) {
+ $attr{$name}{alias} = "Residents"
+ if ( !defined( $attr{$name}{alias} )
+ || $attr{$name}{alias} eq "Bewohner" );
+ $attr{$name}{group} = "Home State"
+ if ( !defined( $attr{$name}{group} )
+ || $attr{$name}{group} eq "Haus Status" );
+ $attr{$name}{devStateIcon} =
+'.*home:status_available:absent .*absent:status_away_1:home .*gone:status_standby:home .*none:control_building_empty .*gotosleep:status_night:asleep .*asleep:status_night:awoken .*awoken:status_available:home .*:user_unknown:home';
+ delete $attr{$name}{eventMap}
+ if ( defined( $attr{$name}{eventMap} ) );
+ delete $attr{$name}{widgetOverride}
+ if ( defined( $attr{$name}{widgetOverride} ) );
+ }
+ else {
+ return "Unsupported language $lang";
+ }
+
+ evalStateFormat($hash);
+ }
+
+ return undef;
+}
+
+sub RESIDENTS_Notify($$) {
+ my ( $hash, $dev ) = @_;
+ my $name = $hash->{NAME};
+ my $prefix = RESIDENTStk_GetPrefixFromType($name);
+ my $devName = $dev->{NAME};
+ my $devType = GetType($devName);
+ return "" if ( IsDisabled($name) or IsDisabled($devName) );
+
+ # process only ROOMMATE or GUEST devices
+ if ( $devType =~ /^ROOMMATE|GUEST$/ ) {
+
+ my $events = deviceEvents( $dev, 1 );
+ return "" unless ($events);
+
+ readingsBeginUpdate($hash);
+
+ foreach my $event ( @{$events} ) {
+ next unless ( defined($event) );
+
+ Log3 $hash, 5, "RESIDENTS " . $name . ": processing event - $event";
+
+ # state changed
+ if ( $event =~ /^state:/
+ || $event =~ /^wayhome:/
+ || $event =~ /^wakeup:/ )
+ {
+ RESIDENTS_UpdateReadings($hash);
+ }
+
+ # activity
+ if ( $event =~ /^state:/ ) {
+
+ # get user realname
+ my $aliasAttr = "group";
+ $aliasAttr = "alias" if ( $prefix eq "rg_" );
+ my $realname =
+ AttrVal( $devName,
+ AttrVal( $devName, $prefix . "realname", $aliasAttr ),
+ $devName );
+
+ # update statistics
+ readingsBulkUpdate( $hash, "lastActivity",
+ ReadingsVal( $devName, "state", $event ) );
+ readingsBulkUpdate( $hash, "lastActivityBy", $realname );
+ readingsBulkUpdate( $hash, "lastActivityByDev", $devName );
+
+ }
+ }
+
+ readingsEndUpdate( $hash, 1 );
+
+ return "";
+ }
+
+ delete $dev->{CHANGEDWITHSTATE};
+ my $events = deviceEvents( $dev, 1 );
+ return "" unless ($events);
+
+ # process wakeup devices
+ my @registeredWakeupdevs =
+ split( ',', AttrVal( $name, $prefix . "wakeupDevice", "" ) );
+ if (@registeredWakeupdevs) {
+
+ # if this is a notification of a registered wakeup device
+ if ( grep { m/^$devName$/ } @registeredWakeupdevs ) {
+
+ foreach my $event ( @{$events} ) {
+ next unless ( defined($event) );
+ RESIDENTStk_wakeupSet( $devName, $event );
+ }
+
+ return "";
+ }
+
+ # process sub-child notifies: *_wakeupDevice
+ foreach my $wakeupDev (@registeredWakeupdevs) {
+
+ # if this is a notification of a registered sub dummy device
+ # of one of our wakeup devices
+ if ( AttrVal( $wakeupDev, "wakeupResetSwitcher", "" ) eq $devName
+ && IsDevice( $devName, "dummy" ) )
+ {
+ foreach my $event ( @{$events} ) {
+ next unless ( defined($event) );
+ RESIDENTStk_wakeupSet( $wakeupDev, $event )
+ unless ( $event =~ /^(?:state:\s*)?off$/i );
+ }
+
+ return "";
+ }
+ }
+
+ return "";
+ }
+
+ return "";
+}
+
+# module Fn ####################################################################
sub RESIDENTS_UpdateReadings (@) {
my ($hash) = @_;
my $name = $hash->{NAME};
@@ -1511,96 +1453,7 @@ sub RESIDENTS_UpdateReadings (@) {
}
# calculate duration timers
- RESIDENTS_DurationTimer( $hash, 1 );
-}
-
-sub RESIDENTS_DurationTimer($;$) {
- my ( $mHash, @a ) = @_;
- my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
- my $name = $hash->{NAME};
- my $silent = ( defined( $a[0] ) && $a[0] eq "1" ) ? 1 : 0;
- my $timestampNow = gettimeofday();
- my $diff;
- my $durPresence = "0";
- my $durAbsence = "0";
- my $durSleep = "0";
- my $noDuration = AttrVal( $name, "rgr_noDuration", 0 );
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
-
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
-
- return if ( IsDisabled($name) || $noDuration );
-
- # presence timer
- if ( ReadingsVal( $name, "presence", "absent" ) eq "present"
- && ReadingsVal( $name, "lastArrival", "-" ) ne "-" )
- {
- $durPresence =
- $timestampNow -
- time_str2num( ReadingsVal( $name, "lastArrival", "" ) );
- }
-
- # absence timer
- if ( ReadingsVal( $name, "presence", "present" ) eq "absent"
- && ReadingsVal( $name, "lastDeparture", "-" ) ne "-" )
- {
- $durAbsence =
- $timestampNow -
- time_str2num( ReadingsVal( $name, "lastDeparture", "" ) );
- }
-
- # sleep timer
- if ( ReadingsVal( $name, "state", "home" ) eq "asleep"
- && ReadingsVal( $name, "lastSleep", "-" ) ne "-" )
- {
- $durSleep =
- $timestampNow - time_str2num( ReadingsVal( $name, "lastSleep", "" ) );
- }
-
- my $durPresence_hr =
- ( $durPresence > 0 )
- ? RESIDENTStk_sec2time($durPresence)
- : "00:00:00";
- my $durPresence_cr =
- ( $durPresence > 60 ) ? int( $durPresence / 60 + 0.5 ) : 0;
- my $durAbsence_hr =
- ( $durAbsence > 0 ) ? RESIDENTStk_sec2time($durAbsence) : "00:00:00";
- my $durAbsence_cr =
- ( $durAbsence > 60 ) ? int( $durAbsence / 60 + 0.5 ) : 0;
- my $durSleep_hr =
- ( $durSleep > 0 ) ? RESIDENTStk_sec2time($durSleep) : "00:00:00";
- my $durSleep_cr = ( $durSleep > 60 ) ? int( $durSleep / 60 + 0.5 ) : 0;
-
- readingsBeginUpdate($hash) if ( !$silent );
- readingsBulkUpdateIfChanged( $hash, "durTimerPresence_cr",
- $durPresence_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerPresence", $durPresence_hr );
- readingsBulkUpdateIfChanged( $hash, "durTimerAbsence_cr", $durAbsence_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerAbsence", $durAbsence_hr );
- readingsBulkUpdateIfChanged( $hash, "durTimerSleep_cr", $durSleep_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerSleep", $durSleep_hr );
- readingsEndUpdate( $hash, 1 ) if ( !$silent );
-
- $hash->{DURATIONTIMER} = $timestampNow + 60;
-
- RESIDENTStk_InternalTimer( "DurationTimer", $hash->{DURATIONTIMER},
- "RESIDENTS_DurationTimer", $hash, 1 );
-
- return undef;
-}
-
-sub RESIDENTS_StartInternalTimers($$) {
- my ($hash) = @_;
-
- RESIDENTS_DurationTimer($hash);
-}
-
-sub RESIDENTS_StopInternalTimers($) {
- my ($hash) = @_;
-
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
-
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
+ RESIDENTStk_RG_DurationTimer( $hash, 1 );
}
1;
diff --git a/fhem/FHEM/20_GUEST.pm b/fhem/FHEM/20_GUEST.pm
index 3f85b739c..e94b94cd4 100644
--- a/fhem/FHEM/20_GUEST.pm
+++ b/fhem/FHEM/20_GUEST.pm
@@ -1,60 +1,29 @@
+###############################################################################
# $Id$
-##############################################################################
-#
-# 20_GUEST.pm
-# Submodule of 10_RESIDENTS.
-#
-# Copyright by Julian Pawlowski
-# e-mail: julian.pawlowski at gmail.com
-#
-# This file is part of fhem.
-#
-# Fhem is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# Fhem is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with fhem. If not, see .
-#
-##############################################################################
-
package main;
-
use strict;
use warnings;
-use Time::Local;
use Data::Dumper;
+use Time::Local;
+
require RESIDENTStk;
-sub GUEST_Set($@);
-sub GUEST_Define($$);
-sub GUEST_Notify($$);
-sub GUEST_Attr(@);
-sub GUEST_Undefine($$);
-
-###################################
+# initialize ##################################################################
sub GUEST_Initialize($) {
my ($hash) = @_;
- Log3 $hash, 5, "GUEST_Initialize: Entering";
-
- $hash->{SetFn} = "GUEST_Set";
$hash->{DefFn} = "GUEST_Define";
- $hash->{NotifyFn} = "GUEST_Notify";
- $hash->{AttrFn} = "GUEST_Attr";
$hash->{UndefFn} = "GUEST_Undefine";
+ $hash->{SetFn} = "GUEST_Set";
+ $hash->{AttrFn} = "RESIDENTStk_RG_Attr";
+ $hash->{NotifyFn} = "RESIDENTStk_RG_Notify";
+
$hash->{AttrList} =
-"disable:1,0 rg_locationHome rg_locationWayhome rg_locationUnderway rg_autoGoneAfter:0,12,16,24,26,28,30,36,48,60 rg_showAllStates:0,1 rg_realname:group,alias rg_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone rg_locations rg_moods rg_moodDefault rg_moodSleepy rg_noDuration:0,1 rg_wakeupDevice rg_geofenceUUIDs rg_presenceDevices rg_lang:EN,DE "
+"disable:1,0 disabledForIntervals do_not_notify:1,0 rg_locationHome rg_locationWayhome rg_locationUnderway rg_autoGoneAfter:0,12,16,24,26,28,30,36,48,60 rg_showAllStates:0,1 rg_realname:group,alias rg_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone rg_locations rg_moods rg_moodDefault rg_moodSleepy rg_noDuration:0,1 rg_wakeupDevice rg_geofenceUUIDs rg_presenceDevices rg_lang:EN,DE "
. $readingFnAttributes;
}
-###################################
+# regular Fn ##################################################################
sub GUEST_Define($$) {
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );
@@ -69,6 +38,8 @@ sub GUEST_Define($$) {
return $msg;
}
+ $hash->{NOTIFYDEV} = "";
+
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
@@ -111,7 +82,11 @@ sub GUEST_Define($$) {
readingsEndUpdate( $hash, 1 );
# run timers
- InternalTimer( gettimeofday() + 15, "GUEST_StartInternalTimers", $hash, 0 );
+ InternalTimer(
+ gettimeofday() + 15,
+ "RESIDENTStk_RG_StartInternalTimers",
+ $hash, 0
+ );
# Injecting AttrFn for use with RESIDENTS Toolkit
if ( !defined( $modules{dummy}{AttrFn} ) ) {
@@ -127,86 +102,10 @@ sub GUEST_Define($$) {
return undef;
}
-###################################
-sub GUEST_Attr(@) {
- my ( $cmd, $name, $attribute, $value ) = @_;
- my $hash = $defs{$name};
- my $prefix = "rg_";
- return unless ($init_done);
-
- Log3 $name, 5, "GUEST $name: called function GUEST_Attr()";
-
- if ( $attribute eq "disable" ) {
- if ( $value and $value == 1 ) {
- $hash->{STATE} = "disabled";
- GUEST_StopInternalTimers($hash);
- }
- elsif ( $cmd eq "del" or !$value ) {
- evalStateFormat($hash);
- GUEST_StartInternalTimers( $hash, 1 );
- }
- }
-
- elsif ( $attribute eq $prefix . "autoGoneAfter" ) {
- if ($value) {
- GUEST_AutoGone($hash);
- }
- elsif ( !$value ) {
- delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
- RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
- }
- }
-
- elsif ( $attribute eq $prefix . "noDuration" ) {
- if ($value) {
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
- }
- elsif ( !$value ) {
- GUEST_DurationTimer($hash);
- }
- }
-
- elsif ( $attribute eq $prefix . "lang" ) {
- my $lang =
- $cmd eq "set" ? uc($value) : AttrVal( "global", "language", "EN" );
-
- # for initial define, ensure fallback to EN
- $lang = "EN"
- if ( $cmd eq "init" && $lang !~ /^EN|DE$/i );
-
- if ( $lang eq "DE" ) {
- $attr{$name}{devStateIcon} =
-'.*zuhause:user_available:absent .*anwesend:user_available:absent .*abwesend:user_away:home .*keiner:control_building_empty:home .*bettfertig:scene_toilet:asleep .*schlaeft:scene_sleeping:awoken .*schläft:scene_sleeping:awoken .*aufgestanden:scene_sleeping_alternat:home .*:user_unknown:home';
- $attr{$name}{eventMap} =
-"home:zuhause absent:abwesend none:keiner gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
- $attr{$name}{widgetOverride} =
- "state:zuhause,bettfertig,schläft,aufgestanden,abwesend,keiner";
- }
- elsif ( $lang eq "EN" ) {
- $attr{$name}{devStateIcon} =
-'.*home:user_available:absent .*absent:user_away:home .*none:control_building_empty:home .*gotosleep:scene_toilet:asleep .*asleep:scene_sleeping:awoken .*awoken:scene_sleeping_alternat:home .*:user_unknown:home';
- delete $attr{$name}{eventMap}
- if ( defined( $attr{$name}{eventMap} ) );
- delete $attr{$name}{widgetOverride}
- if ( defined( $attr{$name}{widgetOverride} ) );
- }
- else {
- return "Unsupported language $lang";
- }
-
- evalStateFormat($hash);
- }
-
- return if ( IsDisabled($name) );
- return;
-}
-
-###################################
sub GUEST_Undefine($$) {
my ( $hash, $name ) = @_;
- GUEST_StopInternalTimers($hash);
+ RESIDENTStk_RG_StopInternalTimers($hash);
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
my $old = $hash->{RESIDENTGROUPS};
@@ -223,147 +122,8 @@ sub GUEST_Undefine($$) {
return undef;
}
-###################################
-sub GUEST_Notify($$) {
- my ( $hash, $dev ) = @_;
- my $devName = $dev->{NAME};
- my $hashName = $hash->{NAME};
- return if ( IsDisabled($hashName) or IsDisabled($devName) );
+sub GUEST_Set($@);
- # process global:INITIALIZED
- if ( $dev->{NAME} eq "global"
- && grep( m/^INITIALIZED$/, @{ $dev->{CHANGED} } ) )
- {
-
- my @registeredWakeupdevs =
- split( /,/, AttrVal( $hashName, "rg_wakeupDevice", 0 ) );
-
- # if we have registered wakeup devices
- if (@registeredWakeupdevs) {
-
- # look for at devices for each wakeup device
- foreach my $wakeupDev (@registeredWakeupdevs) {
- my $wakeupAtdevice = AttrVal( $wakeupDev, "wakeupAtdevice", 0 );
-
- # make sure computeAfterInit is set at at-device
- # and re-calculate on our own this time
- if ( IsDevice( $wakeupAtdevice, "at" )
- && AttrVal( $wakeupAtdevice, "computeAfterInit", 0 ) ne
- "1" )
- {
- Log3 $wakeupDev, 3,
-"RESIDENTStk $wakeupDev: Correcting '$wakeupAtdevice' attribute computeAfterInit required for correct recalculation after reboot";
- fhem "attr $wakeupAtdevice computeAfterInit 1";
-
- my $command;
- ( $command, undef ) =
- split( "[ \t]+", $defs{$wakeupAtdevice}{DEF}, 2 );
- $command =~ s/^[*+]//;
- return at_Set( $defs{$wakeupAtdevice},
- ( $wakeupAtdevice, "modifyTimeSpec", $command ) );
- }
- }
- }
- }
-
- # process child notifies
- elsif ( $devName ne $hashName ) {
- my @registeredWakeupdevs =
- split( ',', AttrVal( $hashName, "rg_wakeupDevice", "" ) );
- my @presenceDevices =
- split( ',', AttrVal( $hashName, "rg_presenceDevices", "" ) );
-
- # if we have registered wakeup devices
- if (@registeredWakeupdevs) {
-
- # if this is a notification of a registered wakeup device
- if ( grep { /^$devName$/ } @registeredWakeupdevs ) {
-
- # Some previous notify deleted the array.
- return
- if ( !$dev->{CHANGED} );
-
- foreach my $change ( @{ $dev->{CHANGED} } ) {
- RESIDENTStk_wakeupSet( $devName, $change );
- }
-
- return;
- }
-
- # process sub-child notifies: *_wakeupDevice
- foreach my $wakeupDev (@registeredWakeupdevs) {
-
- # if this is a notification of a registered sub dummy device
- # of one of our wakeup devices
- if (
- AttrVal( $wakeupDev, "wakeupResetSwitcher", "" ) eq $devName
- && $dev->{TYPE} eq "dummy" )
- {
-
- # Some previous notify deleted the array.
- return
- if ( !$dev->{CHANGED} );
-
- foreach my $change ( @{ $dev->{CHANGED} } ) {
- RESIDENTStk_wakeupSet( $wakeupDev, $change )
- if ( $change ne "off" );
- }
-
- last;
- }
- }
- }
-
- # process PRESENCE
- if ( @presenceDevices
- && grep { /^[\s\t ]*$devName(:[A-Za-z\d_\.\-\/]*)?[\s\t ]*$/ }
- @presenceDevices )
- {
-
- my $counter = {
- absent => 0,
- present => 0,
- };
-
- foreach (@presenceDevices) {
- my $r = "presence";
- my $d = $_;
- if ( $d =~
-m/^[\s\t ]*([A-Za-z\d_\.\-\/]+):([A-Za-z\d_\.\-\/]+)?[\s\t ]*$/
- )
- {
- $d = $1;
- $r = $2;
- }
-
- my $presenceState =
- ReadingsVal( $d, $r, ReadingsVal( $d, "state", "" ) );
- next
- unless ( $presenceState =~
-m/^(0|false|absent|disappeared|unavailable|unreachable|disconnected)|(1|true|present|appeared|available|reachable|connected|)$/i
- );
-
- $counter->{absent}++ if ($1);
- $counter->{present}++ if ($2);
- }
-
- if ( $counter->{absent} && !$counter->{present} ) {
- Log3 $hashName, 4,
- "GUEST $hashName: Syncing status with $devName = absent";
- fhem "set $hashName:FILTER=presence=present absent";
- }
- elsif ( $counter->{present} ) {
- Log3 $hashName, 4,
- "GUEST $hashName: Syncing status with $devName = present";
- fhem "set $hashName:FILTER=presence=absent home";
- }
- }
- }
-
- return;
-}
-
-###################################
sub GUEST_Set($@) {
my ( $hash, @a ) = @_;
my $name = $hash->{NAME};
@@ -728,13 +488,13 @@ sub GUEST_Set($@) {
}
# calculate duration timers
- GUEST_DurationTimer( $hash, $silent );
+ RESIDENTStk_RG_DurationTimer( $hash, $silent );
readingsEndUpdate( $hash, 1 );
# enable or disable AutoGone timer
if ( $newstate eq "absent" ) {
- GUEST_AutoGone($hash);
+ RESIDENTStk_RG_AutoGone($hash);
}
elsif ( $state eq "absent" ) {
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
@@ -888,7 +648,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 trigger:noArg start:noArg stop:noArg end:noArg 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 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,3";
+"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 end:noArg 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 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,3";
fhem "attr $wakeuptimerName userattr wakeupUserdevice";
fhem "attr $wakeuptimerName sortby " . $sortby
if ($sortby);
@@ -960,132 +720,7 @@ sub GUEST_Set($@) {
return undef;
}
-############################################################################################################
-#
-# Begin of helper functions
-#
-############################################################################################################
-
-###################################
-sub GUEST_AutoGone($;$) {
- my ( $mHash, @a ) = @_;
- my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
- my $name = $hash->{NAME};
- my $autoGoneAfter = AttrVal( $hash->{NAME}, "rg_autoGoneAfter", 16 );
- delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
-
- RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
-
- return if ( IsDisabled($name) );
-
- if ( ReadingsVal( $name, "state", "home" ) eq "absent" ) {
- my ( $date, $time, $y, $m, $d, $hour, $min, $sec, $timestamp,
- $timeDiff );
- my $timestampNow = gettimeofday();
-
- ( $date, $time ) = split( ' ', $hash->{READINGS}{state}{TIME} );
- ( $y, $m, $d ) = split( '-', $date );
- ( $hour, $min, $sec ) = split( ':', $time );
- $m -= 01;
- $timestamp = timelocal( $sec, $min, $hour, $d, $m, $y );
- $timeDiff = $timestampNow - $timestamp;
-
- if ( $timeDiff >= $autoGoneAfter * 3600 ) {
- Log3 $name, 3,
- "GUEST $name: AutoGone timer changed state to 'gone'";
- GUEST_Set( $hash, $name, "silentSet", "state", "gone" );
- }
- else {
- my $runtime = $timestamp + $autoGoneAfter * 3600;
- $hash->{AUTOGONE} = $runtime;
- Log3 $name, 4, "GUEST $name: AutoGone timer scheduled: $runtime";
- RESIDENTStk_InternalTimer( "AutoGone", $runtime, "GUEST_AutoGone",
- $hash, 1 );
- }
- }
-
- return undef;
-}
-
-###################################
-sub GUEST_DurationTimer($;$) {
- my ( $mHash, @a ) = @_;
- my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
- my $name = $hash->{NAME};
- my $state = ReadingsVal( $name, "state", "initialized" );
- my $silent = ( defined( $a[0] ) && $a[0] eq "1" ) ? 1 : 0;
- my $timestampNow = gettimeofday();
- my $diff;
- my $durPresence = "0";
- my $durAbsence = "0";
- my $durSleep = "0";
- my $noDuration = AttrVal( $name, "rg_noDuration", 0 );
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
-
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
-
- return if ( IsDisabled($name) || $noDuration );
-
- # presence timer
- if ( ReadingsVal( $name, "presence", "absent" ) eq "present"
- && ReadingsVal( $name, "lastArrival", "-" ) ne "-" )
- {
- $durPresence =
- $timestampNow -
- time_str2num( ReadingsVal( $name, "lastArrival", "" ) );
- }
-
- # absence timer
- if ( ReadingsVal( $name, "presence", "present" ) eq "absent"
- && ReadingsVal( $name, "lastDeparture", "-" ) ne "-" )
- {
- $durAbsence =
- $timestampNow -
- time_str2num( ReadingsVal( $name, "lastDeparture", "" ) );
- }
-
- # sleep timer
- if ( ReadingsVal( $name, "state", "home" ) eq "asleep"
- && ReadingsVal( $name, "lastSleep", "-" ) ne "-" )
- {
- $durSleep =
- $timestampNow - time_str2num( ReadingsVal( $name, "lastSleep", "" ) );
- }
-
- my $durPresence_hr =
- ( $durPresence > 0 )
- ? RESIDENTStk_sec2time($durPresence)
- : "00:00:00";
- my $durPresence_cr =
- ( $durPresence > 60 ) ? int( $durPresence / 60 + 0.5 ) : 0;
- my $durAbsence_hr =
- ( $durAbsence > 0 ) ? RESIDENTStk_sec2time($durAbsence) : "00:00:00";
- my $durAbsence_cr =
- ( $durAbsence > 60 ) ? int( $durAbsence / 60 + 0.5 ) : 0;
- my $durSleep_hr =
- ( $durSleep > 0 ) ? RESIDENTStk_sec2time($durSleep) : "00:00:00";
- my $durSleep_cr = ( $durSleep > 60 ) ? int( $durSleep / 60 + 0.5 ) : 0;
-
- readingsBeginUpdate($hash) if ( !$silent );
- readingsBulkUpdateIfChanged( $hash, "durTimerPresence_cr",
- $durPresence_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerPresence", $durPresence_hr );
- readingsBulkUpdateIfChanged( $hash, "durTimerAbsence_cr", $durAbsence_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerAbsence", $durAbsence_hr );
- readingsBulkUpdateIfChanged( $hash, "durTimerSleep_cr", $durSleep_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerSleep", $durSleep_hr );
- readingsEndUpdate( $hash, 1 ) if ( !$silent );
-
- $hash->{DURATIONTIMER} = $timestampNow + 60;
-
- RESIDENTStk_InternalTimer( "DurationTimer", $hash->{DURATIONTIMER},
- "GUEST_DurationTimer", $hash, 1 )
- if ( $state ne "none" );
-
- return undef;
-}
-
-###################################
+# module Fn ####################################################################
sub GUEST_SetLocation($$$;$$$$$$) {
my ( $name, $location, $trigger, $id, $time, $lat, $long, $address,
$device ) = @_;
@@ -1272,25 +907,6 @@ sub GUEST_SetLocation($$$;$$$$$$) {
}
-###################################
-sub GUEST_StartInternalTimers($$) {
- my ($hash) = @_;
-
- GUEST_AutoGone($hash);
- GUEST_DurationTimer($hash);
-}
-
-###################################
-sub GUEST_StopInternalTimers($) {
- my ($hash) = @_;
-
- delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
-
- RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
-}
-
1;
=pod
diff --git a/fhem/FHEM/20_ROOMMATE.pm b/fhem/FHEM/20_ROOMMATE.pm
index 38d8a0e50..fa47e3dbe 100644
--- a/fhem/FHEM/20_ROOMMATE.pm
+++ b/fhem/FHEM/20_ROOMMATE.pm
@@ -1,60 +1,29 @@
+###############################################################################
# $Id$
-##############################################################################
-#
-# 20_ROOMMATE.pm
-# Submodule of 10_RESIDENTS.
-#
-# Copyright by Julian Pawlowski
-# e-mail: julian.pawlowski at gmail.com
-#
-# This file is part of fhem.
-#
-# Fhem is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# Fhem is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with fhem. If not, see .
-#
-##############################################################################
-
package main;
-
use strict;
use warnings;
-use Time::Local;
use Data::Dumper;
+use Time::Local;
+
require RESIDENTStk;
-sub ROOMMATE_Set($@);
-sub ROOMMATE_Define($$);
-sub ROOMMATE_Notify($$);
-sub ROOMMATE_Attr(@);
-sub ROOMMATE_Undefine($$);
-
-###################################
+# initialize ##################################################################
sub ROOMMATE_Initialize($) {
my ($hash) = @_;
- Log3 $hash, 5, "ROOMMATE_Initialize: Entering";
-
- $hash->{SetFn} = "ROOMMATE_Set";
$hash->{DefFn} = "ROOMMATE_Define";
- $hash->{NotifyFn} = "ROOMMATE_Notify";
- $hash->{AttrFn} = "ROOMMATE_Attr";
$hash->{UndefFn} = "ROOMMATE_Undefine";
+ $hash->{SetFn} = "ROOMMATE_Set";
+ $hash->{AttrFn} = "RESIDENTStk_RG_Attr";
+ $hash->{NotifyFn} = "RESIDENTStk_RG_Notify";
+
$hash->{AttrList} =
-"disable:1,0 rr_locationHome rr_locationWayhome rr_locationUnderway rr_autoGoneAfter:0,12,16,24,26,28,30,36,48,60 rr_showAllStates:0,1 rr_realname:group,alias rr_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone rr_locations rr_moods rr_moodDefault rr_moodSleepy rr_passPresenceTo rr_noDuration:0,1 rr_wakeupDevice rr_geofenceUUIDs rr_presenceDevices rr_lang:EN,DE "
+"disable:1,0 disabledForIntervals do_not_notify:1,0 rr_locationHome rr_locationWayhome rr_locationUnderway rr_autoGoneAfter:0,12,16,24,26,28,30,36,48,60 rr_showAllStates:0,1 rr_realname:group,alias rr_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone rr_locations rr_moods rr_moodDefault rr_moodSleepy rr_passPresenceTo rr_noDuration:0,1 rr_wakeupDevice rr_geofenceUUIDs rr_presenceDevices rr_lang:EN,DE "
. $readingFnAttributes;
}
-###################################
+# regular Fn ##################################################################
sub ROOMMATE_Define($$) {
my ( $hash, $def ) = @_;
my @a = split( "[ \t][ \t]*", $def );
@@ -70,6 +39,8 @@ sub ROOMMATE_Define($$) {
return $msg;
}
+ $hash->{NOTIFYDEV} = "";
+
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
@@ -112,7 +83,7 @@ sub ROOMMATE_Define($$) {
# run timers
InternalTimer(
gettimeofday() + 15,
- "ROOMMATE_StartInternalTimers",
+ "RESIDENTStk_RG_StartInternalTimers",
$hash, 0
);
@@ -130,86 +101,10 @@ sub ROOMMATE_Define($$) {
return undef;
}
-###################################
-sub ROOMMATE_Attr(@) {
- my ( $cmd, $name, $attribute, $value ) = @_;
- my $hash = $defs{$name};
- my $prefix = "rr_";
- return unless ($init_done);
-
- Log3 $name, 5, "ROOMMATE $name: called function ROOMMATE_Attr()";
-
- if ( $attribute eq "disable" ) {
- if ( $value and $value == 1 ) {
- $hash->{STATE} = "disabled";
- ROOMMATE_StopInternalTimers($hash);
- }
- elsif ( $cmd eq "del" or !$value ) {
- evalStateFormat($hash);
- ROOMMATE_StartInternalTimers( $hash, 1 );
- }
- }
-
- elsif ( $attribute eq $prefix . "autoGoneAfter" ) {
- if ($value) {
- ROOMMATE_AutoGone($hash);
- }
- elsif ( !$value ) {
- delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
- RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
- }
- }
-
- elsif ( $attribute eq $prefix . "noDuration" ) {
- if ($value) {
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
- }
- elsif ( !$value ) {
- ROOMMATE_DurationTimer($hash);
- }
- }
-
- elsif ( $attribute eq $prefix . "lang" ) {
- my $lang =
- $cmd eq "set" ? uc($value) : AttrVal( "global", "language", "EN" );
-
- # for initial define, ensure fallback to EN
- $lang = "EN"
- if ( $cmd eq "init" && $lang !~ /^EN|DE$/i );
-
- if ( $lang eq "DE" ) {
- $attr{$name}{devStateIcon} =
-'.*zuhause:user_available:absent .*anwesend:user_available:absent .*abwesend:user_away:home .*verreist:user_ext_away:home .*bettfertig:scene_toilet:asleep .*schlaeft:scene_sleeping:awoken .*schläft:scene_sleeping:awoken .*aufgestanden:scene_sleeping_alternat:home .*:user_unknown:home';
- $attr{$name}{eventMap} =
-"home:zuhause absent:abwesend gone:verreist gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
- $attr{$name}{widgetOverride} =
-"state:zuhause,bettfertig,schläft,aufgestanden,abwesend,verreist";
- }
- elsif ( $lang eq "EN" ) {
- $attr{$name}{devStateIcon} =
-'.*home:user_available:absent .*absent:user_away:home .*gone:user_ext_away:home .*gotosleep:scene_toilet:asleep .*asleep:scene_sleeping:awoken .*awoken:scene_sleeping_alternat:home .*:user_unknown:home';
- delete $attr{$name}{eventMap}
- if ( defined( $attr{$name}{eventMap} ) );
- delete $attr{$name}{widgetOverride}
- if ( defined( $attr{$name}{widgetOverride} ) );
- }
- else {
- return "Unsupported language $lang";
- }
-
- evalStateFormat($hash);
- }
-
- return if ( IsDisabled($name) );
- return;
-}
-
-###################################
sub ROOMMATE_Undefine($$) {
my ( $hash, $name ) = @_;
- ROOMMATE_StopInternalTimers($hash);
+ RESIDENTStk_RG_StopInternalTimers($hash);
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
my $old = $hash->{RESIDENTGROUPS};
@@ -226,149 +121,8 @@ sub ROOMMATE_Undefine($$) {
return undef;
}
-###################################
-sub ROOMMATE_Notify($$) {
- my ( $hash, $dev ) = @_;
- my $devName = $dev->{NAME};
- my $hashName = $hash->{NAME};
- return if ( IsDisabled($hashName) or IsDisabled($devName) );
+sub ROOMMATE_Set($@);
- # process global:INITIALIZED
- if ( $dev->{NAME} eq "global"
- && grep( m/^INITIALIZED$/, @{ $dev->{CHANGED} } ) )
- {
-
- my @registeredWakeupdevs =
- split( /,/, AttrVal( $hashName, "rr_wakeupDevice", 0 ) );
-
- # if we have registered wakeup devices
- if (@registeredWakeupdevs) {
-
- # look for at devices for each wakeup device
- foreach my $wakeupDev (@registeredWakeupdevs) {
- my $wakeupAtdevice = AttrVal( $wakeupDev, "wakeupAtdevice", 0 );
-
- # make sure computeAfterInit is set at at-device
- # and re-calculate on our own this time
- if ( IsDevice( $wakeupAtdevice, "at" )
- && AttrVal( $wakeupAtdevice, "computeAfterInit", 0 ) ne
- "1" )
- {
- Log3 $wakeupDev, 3,
-"RESIDENTStk $wakeupDev: Correcting '$wakeupAtdevice' attribute computeAfterInit required for correct recalculation after reboot";
- fhem "attr $wakeupAtdevice computeAfterInit 1";
-
- my $command;
- ( $command, undef ) =
- split( "[ \t]+", $defs{$wakeupAtdevice}{DEF}, 2 );
- $command =~ s/^[*+]//;
- return at_Set( $defs{$wakeupAtdevice},
- ( $wakeupAtdevice, "modifyTimeSpec", $command ) );
- }
- }
- }
- }
-
- # process child notifies
- elsif ( $devName ne $hashName ) {
- my @registeredWakeupdevs =
- split( ',', AttrVal( $hashName, "rr_wakeupDevice", "" ) );
- my @presenceDevices =
- split( ',', AttrVal( $hashName, "rr_presenceDevices", "" ) );
-
- # if we have registered wakeup devices
- if (@registeredWakeupdevs) {
-
- # if this is a notification of a registered wakeup device
- if ( grep { /^$devName$/ } @registeredWakeupdevs ) {
-
- # Some previous notify deleted the array.
- return
- if ( !$dev->{CHANGED} );
-
- foreach my $change ( @{ $dev->{CHANGED} } ) {
- RESIDENTStk_wakeupSet( $devName, $change );
- }
-
- return;
- }
-
- # process sub-child notifies: *_wakeupDevice
- foreach my $wakeupDev (@registeredWakeupdevs) {
-
- # if this is a notification of a registered sub dummy device
- # of one of our wakeup devices
- if (
- AttrVal( $wakeupDev, "wakeupResetSwitcher", "" ) eq $devName
- && $dev->{TYPE} eq "dummy" )
- {
-
- # Some previous notify deleted the array.
- return
- if ( !$dev->{CHANGED} );
-
- foreach my $change ( @{ $dev->{CHANGED} } ) {
- RESIDENTStk_wakeupSet( $wakeupDev, $change )
- if ( $change ne "off" );
- }
-
- last;
- }
- }
- }
-
- # process PRESENCE
- if ( @presenceDevices
- && grep { /^[\s\t ]*$devName(:[A-Za-z\d_\.\-\/]*)?[\s\t ]*$/ }
- @presenceDevices )
- {
-
- my $counter = {
- absent => 0,
- present => 0,
- };
-
- for (@presenceDevices) {
- my $r = "presence";
- my $d = $_;
- if ( $d =~
-m/^[\s\t ]*([A-Za-z\d_\.\-\/]+):([A-Za-z\d_\.\-\/]+)?[\s\t ]*$/
- )
- {
- $d = $1;
- $r = $2;
- }
-
- my $presenceState =
- ReadingsVal( $d, $r, ReadingsVal( $d, "state", "" ) );
- next
- unless ( $presenceState =~
-m/^(0|false|absent|disappeared|unavailable|unreachable|disconnected)|(1|true|present|appeared|available|reachable|connected|)$/i
- );
-
- $counter->{absent}++ if ($1);
- $counter->{present}++ if ($2);
- }
-
- if ( $counter->{absent} && !$counter->{present} ) {
- Log3 $hashName, 4,
- "ROOMMATE $hashName: "
- . "Syncing status with $devName = absent";
- fhem "set $hashName:FILTER=presence=present absent";
- }
- elsif ( $counter->{present} ) {
- Log3 $hashName, 4,
- "ROOMMATE $hashName: "
- . "Syncing status with $devName = present";
- fhem "set $hashName:FILTER=presence=absent home";
- }
- }
- }
-
- return;
-}
-
-###################################
sub ROOMMATE_Set($@) {
my ( $hash, @a ) = @_;
my $name = $hash->{NAME};
@@ -708,13 +462,13 @@ sub ROOMMATE_Set($@) {
}
# calculate duration timers
- ROOMMATE_DurationTimer( $hash, $silent );
+ RESIDENTStk_RG_DurationTimer( $hash, $silent );
readingsEndUpdate( $hash, 1 );
# enable or disable AutoGone timer
if ( $newstate eq "absent" ) {
- ROOMMATE_AutoGone($hash);
+ RESIDENTStk_RG_AutoGone($hash);
}
elsif ( $state eq "absent" ) {
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
@@ -870,7 +624,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 trigger:noArg start:noArg stop:noArg end:noArg 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 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,3";
+"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 end:noArg 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 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,3";
fhem "attr $wakeuptimerName userattr wakeupUserdevice";
fhem "attr $wakeuptimerName sortby " . $sortby
if ($sortby);
@@ -942,130 +696,7 @@ sub ROOMMATE_Set($@) {
return undef;
}
-############################################################################################################
-#
-# Begin of helper functions
-#
-############################################################################################################
-
-###################################
-sub ROOMMATE_AutoGone($;$) {
- my ( $mHash, @a ) = @_;
- my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
- my $name = $hash->{NAME};
- my $autoGoneAfter = AttrVal( $hash->{NAME}, "rr_autoGoneAfter", 36 );
- delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
-
- RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
-
- return if ( IsDisabled($name) || !$autoGoneAfter );
-
- if ( ReadingsVal( $name, "state", "home" ) eq "absent" ) {
- my ( $date, $time, $y, $m, $d, $hour, $min, $sec, $timestamp,
- $timeDiff );
- my $timestampNow = gettimeofday();
-
- ( $date, $time ) = split( ' ', $hash->{READINGS}{state}{TIME} );
- ( $y, $m, $d ) = split( '-', $date );
- ( $hour, $min, $sec ) = split( ':', $time );
- $m -= 01;
- $timestamp = timelocal( $sec, $min, $hour, $d, $m, $y );
- $timeDiff = $timestampNow - $timestamp;
-
- if ( $timeDiff >= $autoGoneAfter * 3600 ) {
- Log3 $name, 3,
- "ROOMMATE $name: AutoGone timer changed state to 'gone'";
- ROOMMATE_Set( $hash, $name, "silentSet", "state", "gone" );
- }
- else {
- my $runtime = $timestamp + $autoGoneAfter * 3600;
- $hash->{AUTOGONE} = $runtime;
- Log3 $name, 4, "ROOMMATE $name: AutoGone timer scheduled: $runtime";
- RESIDENTStk_InternalTimer( "AutoGone", $runtime,
- "ROOMMATE_AutoGone", $hash, 1 );
- }
- }
-
- return undef;
-}
-
-###################################
-sub ROOMMATE_DurationTimer($;$) {
- my ( $mHash, @a ) = @_;
- my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
- my $name = $hash->{NAME};
- my $silent = ( defined( $a[0] ) && $a[0] eq "1" ) ? 1 : 0;
- my $timestampNow = gettimeofday();
- my $diff;
- my $durPresence = "0";
- my $durAbsence = "0";
- my $durSleep = "0";
- my $noDuration = AttrVal( $name, "rr_noDuration", 0 );
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
-
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
-
- return if ( IsDisabled($name) || $noDuration );
-
- # presence timer
- if ( ReadingsVal( $name, "presence", "absent" ) eq "present"
- && ReadingsVal( $name, "lastArrival", "-" ) ne "-" )
- {
- $durPresence =
- $timestampNow -
- time_str2num( ReadingsVal( $name, "lastArrival", "" ) );
- }
-
- # absence timer
- if ( ReadingsVal( $name, "presence", "present" ) eq "absent"
- && ReadingsVal( $name, "lastDeparture", "-" ) ne "-" )
- {
- $durAbsence =
- $timestampNow -
- time_str2num( ReadingsVal( $name, "lastDeparture", "" ) );
- }
-
- # sleep timer
- if ( ReadingsVal( $name, "state", "home" ) eq "asleep"
- && ReadingsVal( $name, "lastSleep", "-" ) ne "-" )
- {
- $durSleep =
- $timestampNow - time_str2num( ReadingsVal( $name, "lastSleep", "" ) );
- }
-
- my $durPresence_hr =
- ( $durPresence > 0 )
- ? RESIDENTStk_sec2time($durPresence)
- : "00:00:00";
- my $durPresence_cr =
- ( $durPresence > 60 ) ? int( $durPresence / 60 + 0.5 ) : 0;
- my $durAbsence_hr =
- ( $durAbsence > 0 ) ? RESIDENTStk_sec2time($durAbsence) : "00:00:00";
- my $durAbsence_cr =
- ( $durAbsence > 60 ) ? int( $durAbsence / 60 + 0.5 ) : 0;
- my $durSleep_hr =
- ( $durSleep > 0 ) ? RESIDENTStk_sec2time($durSleep) : "00:00:00";
- my $durSleep_cr = ( $durSleep > 60 ) ? int( $durSleep / 60 + 0.5 ) : 0;
-
- readingsBeginUpdate($hash) if ( !$silent );
- readingsBulkUpdateIfChanged( $hash, "durTimerPresence_cr",
- $durPresence_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerPresence", $durPresence_hr );
- readingsBulkUpdateIfChanged( $hash, "durTimerAbsence_cr", $durAbsence_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerAbsence", $durAbsence_hr );
- readingsBulkUpdateIfChanged( $hash, "durTimerSleep_cr", $durSleep_cr );
- readingsBulkUpdateIfChanged( $hash, "durTimerSleep", $durSleep_hr );
- readingsEndUpdate( $hash, 1 ) if ( !$silent );
-
- $hash->{DURATIONTIMER} = $timestampNow + 60;
-
- RESIDENTStk_InternalTimer( "DurationTimer", $hash->{DURATIONTIMER},
- "ROOMMATE_DurationTimer", $hash, 1 );
-
- return undef;
-}
-
-###################################
+# module Fn ####################################################################
sub ROOMMATE_SetLocation($$$;$$$$$$) {
my ( $name, $location, $trigger, $id, $time, $lat, $long, $address,
$device ) = @_;
@@ -1254,25 +885,6 @@ sub ROOMMATE_SetLocation($$$;$$$$$$) {
}
-###################################
-sub ROOMMATE_StartInternalTimers($$) {
- my ($hash) = @_;
-
- ROOMMATE_AutoGone($hash);
- ROOMMATE_DurationTimer($hash);
-}
-
-###################################
-sub ROOMMATE_StopInternalTimers($) {
- my ($hash) = @_;
-
- delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
- delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
-
- RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
- RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
-}
-
1;
=pod
diff --git a/fhem/FHEM/RESIDENTStk.pm b/fhem/FHEM/RESIDENTStk.pm
index f91415fd1..aea2b8e94 100644
--- a/fhem/FHEM/RESIDENTStk.pm
+++ b/fhem/FHEM/RESIDENTStk.pm
@@ -1,31 +1,10 @@
+###############################################################################
# $Id$
-##############################################################################
-#
-# RESIDENTStk.pm
-# Additional functions for 10_RESIDENTS.pm, 20_ROOMMATE.pm, 20_GUEST.pm
-#
-# Copyright by Julian Pawlowski
-# e-mail: julian.pawlowski at gmail.com
-#
-# This file is part of fhem.
-#
-# Fhem is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# Fhem is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with fhem. If not, see .
-#
-##############################################################################
-
-sub RESIDENTStk_Initialize() {
-}
+# package main;
+# use strict;
+# use warnings;
+# use Data::Dumper;
+sub RESIDENTStk_Initialize() { }
#####################################
# PRE-DEFINITION: wakeuptimer
@@ -38,22 +17,20 @@ sub RESIDENTStk_Initialize() {
sub RESIDENTStk_wakeupSet($$) {
my ( $NAME, $n ) = @_;
my ( $a, $h ) = parseParams($n);
- my $cmd = shift @$a;
- my $VALUE = join( " ", @$a );
- my $nextRun = ReadingsVal( $NAME, "nextRun", "07:00" );
+ my $cmd = shift @$a;
+ my $VALUE = join( " ", @$a );
+
+ $cmd =~ s/^state:\s*(.*)$/$1/;
+ return if ( $cmd =~ /^[A-Za-z]+:/ );
# filter non-registered notifies
if ( $cmd !~
-m/^((?:next[rR]un)?\s*(off|OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?|trigger|start|stop|end|reset|auto|wakeupResetdays|wakeupDays|wakeupHolidays|wakeupEnforced|wakeupDefaultTime)$/i
+m/^((?:next[rR]un)?\s*(off|OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?|trigger|start|stop|end|reset|auto|wakeupResetdays|wakeupDays|wakeupHolidays|wakeupEnforced|wakeupDefaultTime|wakeupOffset)$/i
)
{
Log3 $NAME, 6,
- "RESIDENTStk $NAME: "
- . "received unspecified notify '"
- . $cmd
- . "' - nothing to do";
-
- fhem "set $NAME nextRun $nextRun";
+ "RESIDENTStk $NAME: "
+ . "received unspecified notify '$cmd' - nothing to do";
return;
}
@@ -71,7 +48,8 @@ m/^((?:next[rR]un)?\s*(off|OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?
my $wakeupResetdays =
ReadingsVal( $NAME, "wakeupResetdays",
AttrVal( $NAME, "wakeupResetdays", "" ) );
- my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 );
+ my $wakeupOffset =
+ ReadingsVal( $NAME, "wakeupOffset", AttrVal( $NAME, "wakeupOffset", 0 ) );
my $wakeupEnforced =
ReadingsVal( $NAME, "wakeupEnforced",
AttrVal( $NAME, "wakeupEnforced", 0 ) );
@@ -80,6 +58,7 @@ m/^((?:next[rR]un)?\s*(off|OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?
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 $wakeupUserdeviceState = ReadingsVal( $wakeupUserdevice, "state", 0 );
my $atName = "at_" . $NAME;
@@ -114,6 +93,8 @@ m/^((?:next[rR]un)?\s*(off|OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?
);
}
+ RESIDENTStk_findDummySlaves($wakeupUserdevice);
+
# 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,3 wakeupWaitPeriod:slider,0,1,360";
@@ -788,15 +769,32 @@ return;;\
}
else {
+ # conditional enforced wake-up:
+ # only if actual wake-up time is
+ # earlier than wakeupDefaultTime
+ if ( $wakeupEnforced == 3
+ && $wakeupDefaultTime
+ && RESIDENTStk_time2sec($wakeupDefaultTime) >
+ RESIDENTStk_time2sec($lastRun) )
+ {
+ Log3 $NAME, 4,
+ "RESIDENTStk $NAME: "
+ . "Enforcing wake-up because wake-up time is earlier than normal (wakeupDefaultTime=$wakeupDefaultTime > lastRun=$lastRun)";
+ $wakeupEnforced = 1;
+ }
+
# conditional enforced wake-up:
# only if actual wake-up time is not wakeupDefaultTime
- if ( $wakeupEnforced == 2
+ elsif ($wakeupEnforced == 2
&& $wakeupDefaultTime
&& $wakeupDefaultTime ne $lastRun )
{
+ Log3 $NAME, 4,
+ "RESIDENTStk $NAME: "
+ . "Enforcing wake-up because wake-up is different from normal (wakeupDefaultTime=$wakeupDefaultTime =! lastRun=$lastRun)";
$wakeupEnforced = 1;
}
- elsif ( $wakeupEnforced == 2 ) {
+ elsif ( $wakeupEnforced > 1 ) {
$wakeupEnforced = 0;
}
@@ -852,7 +850,7 @@ return;;\
# wakeup attributes
#
elsif ( $cmd =~
-m/^(wakeupResetdays|wakeupDays|wakeupHolidays|wakeupEnforced|wakeupDefaultTime)$/
+m/^(wakeupResetdays|wakeupDays|wakeupHolidays|wakeupEnforced|wakeupDefaultTime|wakeupOffset)$/
)
{
Log3 $NAME, 4, "RESIDENTStk $NAME: " . "setting $1 to '$VALUE'";
@@ -915,7 +913,6 @@ m/^(?:nextRun)?\s*(OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?$/i
readingsBulkUpdateIfChanged( $defs{$wakeupUserdevice},
"nextWakeup", $nextWakeup );
readingsEndUpdate( $defs{$wakeupUserdevice}, 1 );
-
}
return undef;
@@ -926,11 +923,20 @@ m/^(?:nextRun)?\s*(OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?$/i
#
sub RESIDENTStk_wakeupGetBegin($;$) {
my ( $NAME, $wakeupAtdevice ) = @_;
+
+ unless ( IsDevice($NAME) ) {
+ Log3 $NAME, 3,
+ "RESIDENTStk $NAME: "
+ . "Run function RESIDENTStk_wakeupGetBegin() for non-existing device!";
+ return "$NAME: Non-existing device";
+ }
+
my $nextRun = ReadingsVal( $NAME, "nextRun", 0 );
my $wakeupDefaultTime =
ReadingsVal( $NAME, "wakeupDefaultTime",
AttrVal( $NAME, "wakeupDefaultTime", 0 ) );
- my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 );
+ my $wakeupOffset =
+ ReadingsVal( $NAME, "wakeupOffset", AttrVal( $NAME, "wakeupOffset", 0 ) );
my $wakeupInitTime = (
$wakeupDefaultTime && lc($wakeupDefaultTime) ne "off"
? $wakeupDefaultTime
@@ -1013,6 +1019,13 @@ sub RESIDENTStk_wakeupGetBegin($;$) {
sub RESIDENTStk_wakeupRun($;$) {
my ( $NAME, $forceRun ) = @_;
+ unless ( IsDevice($NAME) ) {
+ Log3 $NAME, 3,
+ "RESIDENTStk $NAME: "
+ . "Run function RESIDENTStk_wakeupRun() for non-existing device!";
+ return "$NAME: Non-existing device";
+ }
+
my $wakeupMacro = AttrVal( $NAME, "wakeupMacro", 0 );
my $wakeupDefaultTime =
ReadingsVal( $NAME, "wakeupDefaultTime",
@@ -1027,7 +1040,8 @@ sub RESIDENTStk_wakeupRun($;$) {
my $wakeupResetdays =
ReadingsVal( $NAME, "wakeupResetdays",
AttrVal( $NAME, "wakeupResetdays", "" ) );
- my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 );
+ my $wakeupOffset =
+ ReadingsVal( $NAME, "wakeupOffset", AttrVal( $NAME, "wakeupOffset", 0 ) );
my $wakeupEnforced =
ReadingsVal( $NAME, "wakeupEnforced",
AttrVal( $NAME, "wakeupEnforced", 0 ) );
@@ -1092,18 +1106,10 @@ sub RESIDENTStk_wakeupRun($;$) {
if ( $wakeupResetdays ne "" );
my %rdays = map { $_ => 1 } @rdays;
- if ( !IsDevice($NAME) ) {
- return "$NAME: Non existing device";
- }
- elsif ( IsDisabled($wakeupDevice) ) {
+ if ( IsDisabled($wakeupDevice) ) {
Log3 $name, 4,
"RESIDENTStk $NAME: "
- . "device disabled - not triggering wake-up program";
- }
- elsif ( lc($nextRun) eq "off" && !$forceRun ) {
- Log3 $NAME, 4,
- "RESIDENTStk $NAME: "
- . "alarm set to OFF - not triggering wake-up program";
+ . "wakeupDevice disabled - not triggering wake-up program";
}
elsif ( !$wakeupUserdevice ) {
return "$NAME: missing attribute wakeupUserdevice";
@@ -1113,7 +1119,7 @@ sub RESIDENTStk_wakeupRun($;$) {
}
elsif ( !IsDevice( $wakeupUserdevice, "RESIDENTS|ROOMMATE|GUEST" ) ) {
return "$NAME: "
- . "device $wakeupUserdevice is not of type RESIDENTS, ROOMMATE or GUEST";
+ . "wakeupUserdevice $wakeupUserdevice is not of type RESIDENTS, ROOMMATE or GUEST";
}
elsif ( IsDevice( $wakeupUserdevice, "GUEST" )
&& $wakeupUserdeviceState eq "none" )
@@ -1124,9 +1130,23 @@ sub RESIDENTStk_wakeupRun($;$) {
fhem "set $NAME nextRun OFF";
return;
}
- elsif ($wakeupHolidays eq ""
+ elsif ( IsDisabled($wakeupUserdevice) ) {
+ Log3 $name, 4,
+ "RESIDENTStk $NAME: "
+ . "wakeupUserdevice disabled - not triggering wake-up program";
+ }
+ elsif ( lc($nextRun) eq "off" && !$forceRun ) {
+ Log3 $NAME, 4,
+ "RESIDENTStk $NAME: "
+ . "wakeup timer set to OFF - not triggering wake-up program";
+ }
+ elsif (
+ !$forceRun
&& !$days{$today}
- && !$forceRun )
+ && ( $wakeupHolidays eq ""
+ || $wakeupHolidays eq "andHoliday"
+ || $wakeupHolidays eq "andNoHoliday" )
+ )
{
Log3 $NAME, 4,
"RESIDENTStk $NAME: "
@@ -1134,39 +1154,19 @@ sub RESIDENTStk_wakeupRun($;$) {
}
elsif (
!$forceRun
- && ( $wakeupHolidays eq "orHoliday"
- || $wakeupHolidays eq "orNoHoliday" )
&& (
- !$days{$today}
- && (
- ( $wakeupHolidays eq "orHoliday" && !$holidayToday )
- || ( $wakeupHolidays eq "orNoHoliday"
- && $holidayToday )
- )
+ ( $wakeupHolidays eq "andHoliday" && !$holidayToday )
+ || ( $wakeupHolidays eq "andNoHoliday"
+ && $holidayToday )
+ || ( $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 (
- !$forceRun
- && ( $wakeupHolidays eq "andHoliday"
- || $wakeupHolidays eq "andNoHoliday" )
- && (
- !$days{$today}
- || (
- ( $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";
+ . "holiday restriction $wakeupHolidays in use - not triggering wake-up program this time";
}
elsif ($wakeupUserdeviceState eq "absent"
|| $wakeupUserdeviceState eq "gone"
@@ -1224,6 +1224,7 @@ sub RESIDENTStk_wakeupRun($;$) {
. "won't trigger wake-up program due to non-expired wakeupWaitPeriod threshold since lastAwake (expLastAwake=$expLastAwake > nowRunSec=$nowRunSec)";
}
else {
+
# conditional enforced wake-up:
# only if actual wake-up time is
# earlier than wakeupDefaultTime
@@ -1249,7 +1250,7 @@ sub RESIDENTStk_wakeupRun($;$) {
. "Enforcing wake-up because wake-up is different from normal (wakeupDefaultTime=$wakeupDefaultTime =! lastRun=$lastRun)";
$wakeupEnforced = 1;
}
- elsif ( $wakeupEnforced == 2 ) {
+ elsif ( $wakeupEnforced > 1 ) {
$wakeupEnforced = 0;
}
@@ -1289,7 +1290,6 @@ sub RESIDENTStk_wakeupRun($;$) {
$running = 1;
}
-
}
}
@@ -1348,11 +1348,9 @@ sub RESIDENTStk_wakeupRun($;$) {
sub RESIDENTStk_AttrFnDummy(@) {
my ( $cmd, $name, $aName, $aVal ) = @_;
- # set attribute
- if ( $init_done && $cmd eq "set" ) {
-
- # wakeupResetSwitcher
- if ( $aName eq "wakeupResetSwitcher" ) {
+ # wakeupResetSwitcher
+ if ( $aName eq "wakeupResetSwitcher" ) {
+ if ( $init_done && $cmd eq "set" ) {
if ( !IsDevice($aVal) ) {
my $alias = AttrVal( $name, "alias", 0 );
my $group = AttrVal( $name, "group", 0 );
@@ -1360,7 +1358,7 @@ sub RESIDENTStk_AttrFnDummy(@) {
fhem "define $aVal dummy";
fhem "attr $aVal "
- . "comment Auto-created by RESIDENTS Toolkit: easy between on/off for auto time reset of wake-up timer $NAME";
+ . "comment Auto-created by RESIDENTS Toolkit: easy switch between on/off for auto time reset of wake-up timer $NAME";
if ($alias) {
fhem "attr $aVal alias $alias Reset";
}
@@ -1381,14 +1379,12 @@ sub RESIDENTStk_AttrFnDummy(@) {
Log3 $name, 3,
"RESIDENTStk $name: new slave dummy device $aVal created";
}
- elsif ( !IsDevice( $aVal, "dummy" ) ) {
- Log3 $name, 3,
- "RESIDENTStk $name: "
- . "Defined device name in attr $aName is not a dummy device";
- return "Existing device $aVal is not a dummy!";
- }
}
+ my $wakeupUserdevice = AttrVal( $name, "wakeupUserdevice", undef );
+ if ( IsDevice( $wakeupUserdevice, "ROOMMATE|GUEST" ) ) {
+ RESIDENTStk_findDummySlaves($wakeupUserdevice);
+ }
}
return undef;
@@ -1423,18 +1419,13 @@ sub RESIDENTStk_wakeupGetNext($;$) {
my $secNow = RESIDENTStk_time2sec( $hour . ":" . $min ) + $sec;
my $definitiveNextToday;
my $definitiveNextTomorrow;
- my $definitiveNextTodayDev = 0;
- my $definitiveNextTomorrowDev = 0;
+ my $definitiveNextTodayDev;
+ my $definitiveNextTomorrowDev;
my $holidayDevice = AttrVal( "global", "holiday2we", 0 );
# check for each registered wake-up device
for my $wakeupDevice ( split /,/, $wakeupDeviceList ) {
- next if !$wakeupDevice;
-
- my $ltoday = $today;
- my $ltomorrow = $tomorrow;
-
if ( !IsDevice($wakeupDevice) ) {
Log3 $name, 4,
"RESIDENTStk $name: "
@@ -1454,25 +1445,16 @@ sub RESIDENTStk_wakeupGetNext($;$) {
next;
}
- elsif ( IsDisabled($wakeupDevice) ) {
- Log3 $name, 4,
- "RESIDENTStk $name: "
- . "00 - ignoring disabled wakeupDevice $wakeupDevice";
- next;
- }
- Log3 $name, 4,
- "RESIDENTStk $name: "
- . "00 - checking for next wake-up candidate $wakeupDevice";
-
- my $nextRun = ReadingsVal( $wakeupDevice, "nextRun", 0 );
- my $wakeupAtdevice = AttrVal( $wakeupDevice, "wakeupAtdevice", 0 );
- my $wakeupOffset = AttrVal( $wakeupDevice, "wakeupOffset", 0 );
- my $wakeupAtNTM = (
+ my $wakeupAtdevice = AttrVal( $wakeupDevice, "wakeupAtdevice", undef );
+ my $wakeupOffset =
+ ReadingsVal( $wakeupDevice, "wakeupOffset",
+ AttrVal( $wakeupDevice, "wakeupOffset", 0 ) );
+ my $wakeupAtNTM = (
IsDevice($wakeupAtdevice)
&& defined( $defs{$wakeupAtdevice}{NTM} )
? substr( $defs{$wakeupAtdevice}{NTM}, 0, -3 )
- : 0
+ : undef
);
my $wakeupDays =
ReadingsVal( $wakeupDevice, "wakeupDays",
@@ -1483,11 +1465,31 @@ sub RESIDENTStk_wakeupGetNext($;$) {
my $holidayToday = 0;
my $holidayTomorrow = 0;
my $nextRunSrc;
+ my $nextRun = ReadingsVal( $wakeupDevice, "nextRun", undef );
+ my $ltoday = $today;
+ my $ltomorrow = $tomorrow;
+
+ if ( IsDisabled($wakeupDevice)
+ || !$nextRun
+ || lc($nextRun) eq "off"
+ || $nextRun !~ /^([0-9]{2}:[0-9]{2})$/ )
+ {
+ Log3 $name, 4,
+ "RESIDENTStk $name: "
+ . "00 - ignoring disabled wakeupDevice $wakeupDevice";
+ next;
+ }
+
+ Log3 $name, 4,
+ "RESIDENTStk $name: "
+ . "00 - checking for next wake-up candidate $wakeupDevice";
# get holiday status for today and tomorrow
- if ( $wakeupHolidays ne ""
- && IsDevice( $holidayDevice, "holiday" ) )
- {
+ if ( $wakeupHolidays eq "" ) {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: 01 - Not considering any holidays";
+ }
+ elsif ( IsDevice( $holidayDevice, "holiday" ) ) {
$holidayToday = 1
unless (
ReadingsVal( $holidayDevice, "state", "none" ) eq "none" );
@@ -1497,11 +1499,7 @@ sub RESIDENTStk_wakeupGetNext($;$) {
Log3 $name, 4,
"RESIDENTStk $wakeupDevice: "
- . "01 - Holidays to be considered - today=$holidayToday tomorrow=$holidayTomorrow";
- }
- else {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: 01 - Not considering any holidays";
+ . "01 - Holidays to be considered ($wakeupHolidays) - holidayToday=$holidayToday holidayTomorrow=$holidayTomorrow";
}
# set day scope for today
@@ -1516,117 +1514,78 @@ sub RESIDENTStk_wakeupGetNext($;$) {
if ( $wakeupDays ne "" );
my %daysTomorrow = map { $_ => 1 } @daysTomorrow;
- if ( lc($nextRun) eq "off"
- || $nextRun !~ /^([0-9]{2}:[0-9]{2})$/ )
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "02 - possible candidate found - weekdayToday=$ltoday weekdayTomorrow=$ltomorrow";
+
+ my $nextRunSec;
+ my $nextRunSecTarget;
+
+ # Use direct information from at-device if possible
+ if ( $wakeupAtNTM
+ && $wakeupAtNTM =~ /^([0-9]{2}:[0-9]{2})$/ )
{
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: " . "02 - set to OFF so no candidate";
- next;
- }
- else {
+ $nextRunSrc = "at";
+ $nextRunSec = RESIDENTStk_time2sec($wakeupAtNTM);
+ $nextRunSecTarget = $nextRunSec + $wakeupOffset * 60;
+
+ if ( $wakeupOffset && $nextRunSecTarget >= 86400 ) {
+ $nextRunSecTarget -= 86400;
+
+ $ltoday++;
+ $ltoday = $ltoday - 7
+ if ( $ltoday > 6 );
+
+ $ltomorrow++;
+ $ltomorrow = $ltomorrow - 7
+ if ( $ltomorrow > 6 );
+ }
Log3 $name, 4,
"RESIDENTStk $wakeupDevice: "
- . "02 - possible candidate found - weekdayToday=$ltoday weekdayTomorrow=$ltomorrow";
+ . "03 - considering at-device value wakeupAtNTM=$wakeupAtNTM wakeupOffset=$wakeupOffset nextRunSec=$nextRunSec nextRunSecTarget=$nextRunSecTarget";
+ }
+ else {
+ $nextRunSrc = "dummy";
+ $nextRunSecTarget = RESIDENTStk_time2sec($nextRun);
+ $nextRunSec = $nextRunSecTarget - $wakeupOffset * 60;
- my $nextRunSec;
- my $nextRunSecTarget;
+ if ( $wakeupOffset && $nextRunSec < 0 ) {
+ $nextRunSec += 86400;
- # Use direct information from at-device if possible
- if ( $wakeupAtNTM
- && $wakeupAtNTM =~ /^([0-9]{2}:[0-9]{2})$/ )
- {
- $nextRunSrc = "at";
- $nextRunSec = RESIDENTStk_time2sec($wakeupAtNTM);
- $nextRunSecTarget = $nextRunSec + $wakeupOffset * 60;
+ $ltoday--;
+ $ltoday = $ltoday + 7
+ if ( $ltoday < 0 );
- if ( $wakeupOffset && $nextRunSecTarget >= 86400 ) {
- $nextRunSecTarget -= 86400;
-
- $ltoday++;
- $ltoday = $ltoday - 7
- if ( $ltoday > 6 );
-
- $ltomorrow++;
- $ltomorrow = $ltomorrow - 7
- if ( $ltomorrow > 6 );
- }
-
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "03 - considering at-device value wakeupAtNTM=$wakeupAtNTM wakeupOffset=$wakeupOffset nextRunSec=$nextRunSec nextRunSecTarget=$nextRunSecTarget";
- }
- else {
- $nextRunSrc = "dummy";
- $nextRunSecTarget = RESIDENTStk_time2sec($nextRun);
- $nextRunSec = $nextRunSecTarget - $wakeupOffset * 60;
-
- if ( $wakeupOffset && $nextRunSec < 0 ) {
- $nextRunSec += 86400;
-
- $ltoday--;
- $ltoday = $ltoday + 7
- if ( $ltoday < 0 );
-
- $ltomorrow--;
- $ltomorrow = $ltomorrow + 7
- if ( $ltomorrow < 0 );
- }
-
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "03 - considering dummy-device value nextRun=$nextRun wakeupOffset=$wakeupOffset nextRunSec=$nextRunSec nextRunSecTarget=$nextRunSecTarget (wakeupAtNTM=$wakeupAtNTM)";
+ $ltomorrow--;
+ $ltomorrow = $ltomorrow + 7
+ if ( $ltomorrow < 0 );
}
- # still running today
- if ( $nextRunSec > $secNow ) {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "04 - this is a candidate for today - weekdayToday=$ltoday";
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "03 - considering dummy-device value nextRun=$nextRun wakeupOffset=$wakeupOffset nextRunSec=$nextRunSec nextRunSecTarget=$nextRunSecTarget (wakeupAtNTM=$wakeupAtNTM)";
+ }
- # if today is in scope
- if ( $days{$ltoday} ) {
+ # still running today
+ if ( $nextRunSec > $secNow ) {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "04 - this is a candidate for today - weekdayToday=$ltoday";
- # if we need to consider holidays in addition
- if (
- ( $wakeupHolidays eq "andHoliday" && !$holidayToday )
- || ( $wakeupHolidays eq "andNoHoliday"
- && $holidayToday )
- )
- {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "05 - no run today due to holiday based on combined weekday and holiday decision";
- next;
- }
+ # if today is in scope
+ if ( $days{$ltoday} ) {
- # easy if there is no holiday dependency
- elsif ( !$definitiveNextToday
- || $nextRunSec < $definitiveNextToday )
- {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "05 - until now, will be NEXT WAKE-UP RUN today based on weekday decision";
- $definitiveNextToday = $nextRunSec;
- $definitiveNextTodayDev = $wakeupDevice;
- }
-
- }
- else {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "05 - won't be running today anymore based on weekday decision";
- next;
- }
-
- # if we need to consider holidays in parallel to weekdays
- if ( ( $wakeupHolidays eq "orHoliday" && $holidayToday )
- || ( $wakeupHolidays eq "orNoHoliday" && !$holidayToday ) )
+ # if we need to consider holidays in addition
+ if (
+ ( $wakeupHolidays eq "andHoliday" && !$holidayToday )
+ || ( $wakeupHolidays eq "andNoHoliday"
+ && $holidayToday )
+ )
{
-
Log3 $name, 4,
"RESIDENTStk $wakeupDevice: "
- . "06 - won't be running today based on holiday decision";
+ . "05 - no run today due to holiday based on combined weekday and holiday decision";
next;
}
@@ -1636,82 +1595,111 @@ sub RESIDENTStk_wakeupGetNext($;$) {
{
Log3 $name, 4,
"RESIDENTStk $wakeupDevice: "
- . "06 - until now, will be NEXT WAKE-UP RUN today based on holiday decision";
+ . "05 - until now, will be NEXT WAKE-UP RUN today based on weekday decision";
$definitiveNextToday = $nextRunSec;
$definitiveNextTodayDev = $wakeupDevice;
}
-
}
- # running later
- else {
+ elsif ($wakeupHolidays eq ""
+ || $wakeupHolidays eq "andHoliday"
+ || $wakeupHolidays eq "andNoHoliday" )
+ {
Log3 $name, 4,
"RESIDENTStk $wakeupDevice: "
- . "04 - this is a candidate for tomorrow or later - weekdayTomorrow=$ltomorrow";
+ . "05 - won't be running today anymore based on weekday decision";
+ next;
+ }
- # if tomorrow is in scope
- if ( $daysTomorrow{$ltomorrow} ) {
+ # if we need to consider holidays in parallel to weekdays
+ elsif (( $wakeupHolidays eq "orHoliday" && !$holidayToday )
+ || ( $wakeupHolidays eq "orNoHoliday" && $holidayToday ) )
+ {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "06 - won't be running today based on holiday decision";
+ next;
+ }
- # if we need to consider holidays in addition
- if (
- (
- $wakeupHolidays eq "andHoliday"
- && !$holidayTomorrow
- )
- || ( $wakeupHolidays eq "andNoHoliday"
- && $holidayTomorrow )
- )
- {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "05 - no run tomorrow due to holiday based on combined weekday and holiday decision";
- next;
- }
+ # easy if there is no holiday dependency
+ elsif ( !$definitiveNextToday
+ || $nextRunSec < $definitiveNextToday )
+ {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "06 - until now, will be NEXT WAKE-UP RUN today based on holiday decision";
+ $definitiveNextToday = $nextRunSec;
+ $definitiveNextTodayDev = $wakeupDevice;
+ }
+ }
- # easy if there is no holiday dependency
- elsif ( !$definitiveNextTomorrow
- || $nextRunSec < $definitiveNextTomorrow )
- {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "05 - until now, will be NEXT WAKE-UP RUN tomorrow based on weekday decision";
- $definitiveNextTomorrow = $nextRunSec;
- $definitiveNextTomorrowDev = $wakeupDevice;
- }
+ # running later
+ else {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "04 - this is a candidate for tomorrow or later - weekdayTomorrow=$ltomorrow";
- }
- else {
- Log3 $name, 4,
- "RESIDENTStk $wakeupDevice: "
- . "05 - won't be running tomorrow based on weekday decision";
- next;
- }
+ # if tomorrow is in scope
+ if ( $daysTomorrow{$ltomorrow} ) {
- # if we need to consider holidays in parallel to weekdays
+ # if we need to consider holidays in addition
if (
- ( $wakeupHolidays eq "orHoliday" && $holidayTomorrow )
- || ( $wakeupHolidays eq "orNoHoliday"
- && !$holidayTomorrow )
+ ( $wakeupHolidays eq "andHoliday" && !$holidayTomorrow )
+ || ( $wakeupHolidays eq "andNoHoliday"
+ && $holidayTomorrow )
)
{
Log3 $name, 4,
"RESIDENTStk $wakeupDevice: "
- . "06 - won't be running tomorrow based on holiday decision";
+ . "05 - no run tomorrow due to holiday based on combined weekday and holiday decision";
next;
}
+ # easy if there is no holiday dependency
elsif ( !$definitiveNextTomorrow
|| $nextRunSec < $definitiveNextTomorrow )
{
Log3 $name, 4,
"RESIDENTStk $wakeupDevice: "
- . "06 - until now, will be NEXT WAKE-UP RUN tomorrow based on holiday decision";
+ . "05 - until now, will be NEXT WAKE-UP RUN tomorrow based on weekday decision";
$definitiveNextTomorrow = $nextRunSec;
$definitiveNextTomorrowDev = $wakeupDevice;
}
-
}
+ elsif ($wakeupHolidays eq ""
+ || $wakeupHolidays eq "andHoliday"
+ || $wakeupHolidays eq "andNoHoliday" )
+ {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "05 - won't be running tomorrow based on weekday decision";
+ next;
+ }
+
+ # if we need to consider holidays in parallel to weekdays
+ elsif (
+ ( $wakeupHolidays eq "orHoliday" && !$holidayTomorrow )
+ || ( $wakeupHolidays eq "orNoHoliday"
+ && $holidayTomorrow )
+ )
+ {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "06 - won't be running tomorrow based on holiday decision";
+ next;
+ }
+
+ # easy if there is no holiday dependency
+ elsif ( !$definitiveNextTomorrow
+ || $nextRunSec < $definitiveNextTomorrow )
+ {
+ Log3 $name, 4,
+ "RESIDENTStk $wakeupDevice: "
+ . "06 - until now, will be NEXT WAKE-UP RUN tomorrow based on holiday decision";
+ $definitiveNextTomorrow = $nextRunSec;
+ $definitiveNextTomorrowDev = $wakeupDevice;
+ }
}
if ($wakeupOffset) {
@@ -1900,11 +1888,30 @@ sub RESIDENTStk_RemoveInternalTimer($$) {
}
}
-sub RESIDENTStk_findResidentSlaves($) {
+sub RESIDENTStk_RG_StartInternalTimers($$) {
my ($hash) = @_;
+
+ RESIDENTStk_RG_AutoGone($hash);
+ RESIDENTStk_RG_DurationTimer($hash);
+}
+
+sub RESIDENTStk_RG_StopInternalTimers($) {
+ my ($hash) = @_;
+
+ delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
+ delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
+
+ RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
+ RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
+}
+
+sub RESIDENTStk_findResidentSlaves($;$) {
+ my ( $hash, $rgr_wakeupDevice ) = @_;
return
unless ( ref($hash) eq "HASH" && defined( $hash->{NAME} ) );
+ $hash->{NOTIFYDEV} = "";
+
delete $hash->{ROOMMATES};
foreach ( devspec2array("TYPE=ROOMMATE") ) {
next
@@ -1928,6 +1935,386 @@ sub RESIDENTStk_findResidentSlaves($) {
$hash->{GUESTS} .= "," if ( $hash->{GUESTS} );
$hash->{GUESTS} .= $_;
}
+
+ $hash->{NOTIFYDEV} = $hash->{ROOMMATES} if ( $hash->{ROOMMATES} );
+ $hash->{NOTIFYDEV} .= "," if ( $hash->{NOTIFYDEV} ne "" );
+ $hash->{NOTIFYDEV} .= $hash->{GUESTS} if ( $hash->{GUESTS} );
+
+ RESIDENTStk_findDummySlaves( $hash->{NAME} );
+}
+
+sub RESIDENTStk_findDummySlaves($;$$) {
+ my ( $name, $wakeupDevice, $presenceDevices ) = @_;
+ my $hash = $defs{$name};
+ my $TYPE = GetType($name);
+ my $prefix = RESIDENTStk_GetPrefixFromType($name);
+
+ $wakeupDevice = AttrVal( $name, $prefix . "wakeupDevice", undef )
+ unless ( !$init_done || $wakeupDevice );
+ $presenceDevices = AttrVal( $name, $prefix . "presenceDevices", undef )
+ unless ( !$init_done || $presenceDevices );
+
+ $hash->{NOTIFYDEV} = "global" unless ( $prefix eq "rgr_" );
+
+ if ($wakeupDevice) {
+ $hash->{NOTIFYDEV} .= "," if ( $hash->{NOTIFYDEV} ne "" );
+ $hash->{NOTIFYDEV} .= $wakeupDevice;
+
+ my @wakeupdevs =
+ split( ',', $wakeupDevice );
+
+ foreach (@wakeupdevs) {
+ my $rsw;
+ next unless ( IsDevice($_) );
+
+ $rsw = AttrVal( $_, "wakeupResetSwitcher", "" ) if ($init_done);
+
+ if ( $rsw =~ /^[a-zA-Z\d._]+$/ ) {
+ $hash->{NOTIFYDEV} .= "," if ( $hash->{NOTIFYDEV} ne "" );
+ $hash->{NOTIFYDEV} .= $rsw;
+ }
+ }
+ }
+
+ if ($presenceDevices) {
+ $hash->{NOTIFYDEV} .= "," if ( $hash->{NOTIFYDEV} ne "" );
+ $hash->{NOTIFYDEV} .= $presenceDevices;
+ }
+}
+
+sub RESIDENTStk_GetPrefixFromType($) {
+ my ($name) = @_;
+ return "rgr_" if ( GetType($name) eq "RESIDENTS" );
+ return "rr_" if ( GetType($name) eq "ROOMMATE" );
+ return "rg_" if ( GetType($name) eq "GUEST" );
+ return "";
+}
+
+sub RESIDENTStk_RG_Attr(@) {
+ my ( $cmd, $name, $attribute, $value ) = @_;
+ my $hash = $defs{$name};
+ my $prefix = RESIDENTStk_GetPrefixFromType($name);
+
+ if ( $attribute eq $prefix . "wakeupDevice"
+ || $attribute eq $prefix . "presenceDevices" )
+ {
+ return "Value for $attribute has invalid format"
+ unless ( $cmd eq "del"
+ || $value =~ /^([a-zA-Z\d._]+,?)([a-zA-Z\d._]+,?)*$/ );
+
+ $value = "" if ( $cmd eq "del" );
+
+ my $wakeupDevice =
+ $attribute eq $prefix . "wakeupDevice"
+ ? $value
+ : AttrVal( $name, $prefix . "wakeupDevice", undef );
+ my $presenceDevices =
+ $attribute eq $prefix . "presenceDevices"
+ ? $value
+ : AttrVal( $name, $prefix . "presenceDevices", undef );
+
+ RESIDENTStk_findDummySlaves( $name, $wakeupDevice, $presenceDevices );
+ }
+
+ elsif ( !$init_done ) {
+ return undef;
+ }
+
+ elsif ( $attribute eq "disable" ) {
+ if ( $value and $value == 1 ) {
+ $hash->{STATE} = "disabled";
+ RESIDENTStk_RG_StopInternalTimers($hash);
+ }
+ elsif ( $cmd eq "del" or !$value ) {
+ evalStateFormat($hash);
+ RESIDENTStk_RG_StartInternalTimers( $hash, 1 );
+ }
+ }
+
+ elsif ( $attribute eq $prefix . "autoGoneAfter" ) {
+ if ($value) {
+ RESIDENTStk_RG_AutoGone($hash);
+ }
+ elsif ( !$value ) {
+ delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
+ RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
+ }
+ }
+
+ elsif ( $attribute eq $prefix . "noDuration" ) {
+ if ($value) {
+ delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
+ RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
+ }
+ elsif ( !$value ) {
+ RESIDENTStk_RG_DurationTimer($hash);
+ }
+ }
+
+ elsif ( $attribute eq $prefix . "lang" ) {
+ my $lang =
+ $cmd eq "set" ? uc($value) : AttrVal( "global", "language", "EN" );
+
+ # for initial define, ensure fallback to EN
+ $lang = "EN"
+ if ( $cmd eq "init" && $lang !~ /^EN|DE$/i );
+
+ if ( $lang eq "DE" ) {
+ $attr{$name}{devStateIcon} =
+'.*zuhause:user_available:absent .*anwesend:user_available:absent .*abwesend:user_away:home .*verreist:user_ext_away:home .*bettfertig:scene_toilet:asleep .*schlaeft:scene_sleeping:awoken .*schläft:scene_sleeping:awoken .*aufgestanden:scene_sleeping_alternat:home .*:user_unknown:home';
+ $attr{$name}{eventMap} =
+"home:zuhause absent:abwesend gone:verreist gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
+ $attr{$name}{widgetOverride} =
+"state:zuhause,bettfertig,schläft,aufgestanden,abwesend,verreist";
+ }
+ elsif ( $lang eq "EN" ) {
+ $attr{$name}{devStateIcon} =
+'.*home:user_available:absent .*absent:user_away:home .*gone:user_ext_away:home .*gotosleep:scene_toilet:asleep .*asleep:scene_sleeping:awoken .*awoken:scene_sleeping_alternat:home .*:user_unknown:home';
+ delete $attr{$name}{eventMap}
+ if ( defined( $attr{$name}{eventMap} ) );
+ delete $attr{$name}{widgetOverride}
+ if ( defined( $attr{$name}{widgetOverride} ) );
+ }
+ else {
+ return "Unsupported language $lang";
+ }
+
+ evalStateFormat($hash);
+ }
+
+ return undef;
+}
+
+sub RESIDENTStk_RG_Notify($$) {
+ my ( $hash, $dev ) = @_;
+ my $name = $hash->{NAME};
+ my $TYPE = GetType($name);
+ my $prefix = RESIDENTStk_GetPrefixFromType($name);
+ my $devName = $dev->{NAME};
+ return "" if ( IsDisabled($name) or IsDisabled($devName) );
+
+ if ( $devName eq "global" ) {
+ my $events = deviceEvents( $dev, 0 );
+ return ""
+ unless ( $events && grep( m/^INITIALIZED|REREADCFG$/, @{$events} ) );
+ RESIDENTStk_findDummySlaves($name);
+ return "";
+ }
+
+ delete $dev->{CHANGEDWITHSTATE};
+ my $events = deviceEvents( $dev, 1 );
+ return "" unless ($events);
+
+ # process wakeup devices
+ my @registeredWakeupdevs =
+ split( ',', AttrVal( $name, $prefix . "wakeupDevice", "" ) );
+ if (@registeredWakeupdevs) {
+
+ # if this is a notification of a registered wakeup device
+ if ( grep { m/^$devName$/ } @registeredWakeupdevs ) {
+
+ foreach my $event ( @{$events} ) {
+ next unless ( defined($event) );
+ RESIDENTStk_wakeupSet( $devName, $event );
+ }
+
+ return "";
+ }
+
+ # process sub-child notifies: *_wakeupDevice
+ foreach my $wakeupDev (@registeredWakeupdevs) {
+
+ # if this is a notification of a registered sub dummy device
+ # of one of our wakeup devices
+ if ( AttrVal( $wakeupDev, "wakeupResetSwitcher", "" ) eq $devName
+ && IsDevice( $devName, "dummy" ) )
+ {
+ foreach my $event ( @{$events} ) {
+ next unless ( defined($event) );
+ RESIDENTStk_wakeupSet( $wakeupDev, $event )
+ unless ( $event =~ /^(?:state:\s*)?off$/i );
+ }
+
+ return "";
+ }
+ }
+
+ return "";
+ }
+
+ # process PRESENCE
+ my @presenceDevices =
+ split( ',', AttrVal( $name, $prefix . "presenceDevices", "" ) );
+ if ( @presenceDevices
+ && grep { /^[\s\t ]*$devName(:[A-Za-z\d_\.\-\/]*)?[\s\t ]*$/ }
+ @presenceDevices )
+ {
+
+ my $counter = {
+ absent => 0,
+ present => 0,
+ };
+
+ for (@presenceDevices) {
+ my $r = "presence";
+ my $d = $_;
+ if ( $d =~
+ m/^[\s\t ]*([A-Za-z\d_\.\-\/]+):([A-Za-z\d_\.\-\/]+)?[\s\t ]*$/
+ )
+ {
+ $d = $1;
+ $r = $2;
+ }
+
+ my $presenceState =
+ ReadingsVal( $d, $r, ReadingsVal( $d, "state", "" ) );
+ next
+ unless ( $presenceState =~
+m/^(0|false|absent|disappeared|unavailable|unreachable|disconnected)|(1|true|present|appeared|available|reachable|connected|)$/i
+ );
+
+ $counter->{absent}++ if ($1);
+ $counter->{present}++ if ($2);
+ }
+
+ if ( $counter->{absent} && !$counter->{present} ) {
+ Log3 $name, 4,
+ "$TYPE $name: " . "Syncing status with $devName = absent";
+ fhem "set $name:FILTER=presence=present absent";
+ }
+ elsif ( $counter->{present} ) {
+ Log3 $name, 4,
+ "$TYPE $name: " . "Syncing status with $devName = present";
+ fhem "set $name:FILTER=presence=absent home";
+ }
+
+ return "";
+ }
+
+ return "";
+}
+
+sub RESIDENTStk_RG_AutoGone($;$) {
+ my ( $mHash, @a ) = @_;
+ my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
+ my $name = $hash->{NAME};
+ my $TYPE = GetType($name);
+ my $prefix = RESIDENTStk_GetPrefixFromType($name);
+ my $autoGoneAfter = AttrVal( $hash->{NAME}, $prefix . "autoGoneAfter", 36 );
+ delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
+
+ RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
+
+ return if ( IsDisabled($name) || !$autoGoneAfter );
+
+ if ( ReadingsVal( $name, "state", "home" ) eq "absent" ) {
+ my ( $date, $time, $y, $m, $d, $hour, $min, $sec, $timestamp,
+ $timeDiff );
+ my $timestampNow = gettimeofday();
+
+ ( $date, $time ) = split( ' ', $hash->{READINGS}{state}{TIME} );
+ ( $y, $m, $d ) = split( '-', $date );
+ ( $hour, $min, $sec ) = split( ':', $time );
+ $m -= 01;
+ $timestamp = timelocal( $sec, $min, $hour, $d, $m, $y );
+ $timeDiff = $timestampNow - $timestamp;
+
+ if ( $timeDiff >= $autoGoneAfter * 3600 ) {
+ Log3 $name, 3,
+ "$TYPE $name: AutoGone timer changed state to 'gone'";
+ &{ $TYPE . "_Set" }( $hash, $name, "silentSet", "state", "gone" );
+ }
+ else {
+ my $runtime = $timestamp + $autoGoneAfter * 3600;
+ $hash->{AUTOGONE} = $runtime;
+ Log3 $name, 4, "$TYPE $name: AutoGone timer scheduled: $runtime";
+ RESIDENTStk_InternalTimer( "AutoGone", $runtime,
+ "RESIDENTStk_RG_AutoGone", $hash, 1 );
+ }
+ }
+
+ return undef;
+}
+
+sub RESIDENTStk_RG_DurationTimer($;$) {
+ my ( $mHash, @a ) = @_;
+ my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
+ my $name = $hash->{NAME};
+ my $TYPE = GetType($name);
+ my $prefix = RESIDENTStk_GetPrefixFromType($name);
+ my $silent = ( defined( $a[0] ) && $a[0] eq "1" ) ? 1 : 0;
+ my $timestampNow = gettimeofday();
+ my $diff;
+ my $durPresence = "0";
+ my $durAbsence = "0";
+ my $durSleep = "0";
+ my $noDuration = AttrVal( $name, $prefix . "noDuration", 0 );
+ delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
+
+ RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
+
+ return if ( IsDisabled($name) || $noDuration );
+
+ # presence timer
+ if ( ReadingsVal( $name, "presence", "absent" ) eq "present"
+ && ReadingsVal( $name, "lastArrival", "-" ) ne "-" )
+ {
+ $durPresence =
+ $timestampNow -
+ time_str2num( ReadingsVal( $name, "lastArrival", "" ) );
+ }
+
+ # absence timer
+ if ( ReadingsVal( $name, "presence", "present" ) eq "absent"
+ && ReadingsVal( $name, "lastDeparture", "-" ) ne "-" )
+ {
+ $durAbsence =
+ $timestampNow -
+ time_str2num( ReadingsVal( $name, "lastDeparture", "" ) );
+ }
+
+ # sleep timer
+ if ( ReadingsVal( $name, "state", "home" ) eq "asleep"
+ && ReadingsVal( $name, "lastSleep", "-" ) ne "-" )
+ {
+ $durSleep =
+ $timestampNow - time_str2num( ReadingsVal( $name, "lastSleep", "" ) );
+ }
+
+ my $durPresence_hr =
+ ( $durPresence > 0 )
+ ? RESIDENTStk_sec2time($durPresence)
+ : "00:00:00";
+ my $durPresence_cr =
+ ( $durPresence > 60 ) ? int( $durPresence / 60 + 0.5 ) : 0;
+ my $durAbsence_hr =
+ ( $durAbsence > 0 ) ? RESIDENTStk_sec2time($durAbsence) : "00:00:00";
+ my $durAbsence_cr =
+ ( $durAbsence > 60 ) ? int( $durAbsence / 60 + 0.5 ) : 0;
+ my $durSleep_hr =
+ ( $durSleep > 0 ) ? RESIDENTStk_sec2time($durSleep) : "00:00:00";
+ my $durSleep_cr = ( $durSleep > 60 ) ? int( $durSleep / 60 + 0.5 ) : 0;
+
+ readingsBeginUpdate($hash) if ( !$silent );
+ readingsBulkUpdateIfChanged( $hash, "durTimerPresence_cr",
+ $durPresence_cr );
+ readingsBulkUpdateIfChanged( $hash, "durTimerPresence", $durPresence_hr );
+ readingsBulkUpdateIfChanged( $hash, "durTimerAbsence_cr", $durAbsence_cr );
+ readingsBulkUpdateIfChanged( $hash, "durTimerAbsence", $durAbsence_hr );
+ readingsBulkUpdateIfChanged( $hash, "durTimerSleep_cr", $durSleep_cr );
+ readingsBulkUpdateIfChanged( $hash, "durTimerSleep", $durSleep_hr );
+ readingsEndUpdate( $hash, 1 ) if ( !$silent );
+
+ $hash->{DURATIONTIMER} = $timestampNow + 60;
+
+ RESIDENTStk_InternalTimer(
+ "DurationTimer",
+ $hash->{DURATIONTIMER},
+ "RESIDENTStk_RG_DurationTimer",
+ $hash, 1
+ );
+
+ return undef;
}
1;