mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-03-04 05:16:45 +00:00
RESIDENTS,ROOMMATE,GUEST: refactoring notification system and improved wakeuptimer
git-svn-id: https://svn.fhem.de/fhem/trunk@14011 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
1f52e62465
commit
591a2717a1
@ -1,60 +1,29 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Time::Local;
|
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
use Time::Local;
|
||||||
|
|
||||||
require RESIDENTStk;
|
require RESIDENTStk;
|
||||||
|
|
||||||
sub RESIDENTS_Set($@);
|
# initialize ##################################################################
|
||||||
sub RESIDENTS_Define($$);
|
|
||||||
sub RESIDENTS_Notify($$);
|
|
||||||
sub RESIDENTS_Attr(@);
|
|
||||||
sub RESIDENTS_Undefine($$);
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub RESIDENTS_Initialize($) {
|
sub RESIDENTS_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
Log3 $hash, 5, "RESIDENTS_Initialize: Entering";
|
|
||||||
|
|
||||||
$hash->{SetFn} = "RESIDENTS_Set";
|
|
||||||
$hash->{DefFn} = "RESIDENTS_Define";
|
$hash->{DefFn} = "RESIDENTS_Define";
|
||||||
$hash->{NotifyFn} = "RESIDENTS_Notify";
|
|
||||||
$hash->{AttrFn} = "RESIDENTS_Attr";
|
|
||||||
$hash->{UndefFn} = "RESIDENTS_Undefine";
|
$hash->{UndefFn} = "RESIDENTS_Undefine";
|
||||||
|
$hash->{SetFn} = "RESIDENTS_Set";
|
||||||
|
$hash->{AttrFn} = "RESIDENTS_Attr";
|
||||||
|
$hash->{NotifyFn} = "RESIDENTS_Notify";
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$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;
|
. $readingFnAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
# regular Fn ##################################################################
|
||||||
sub RESIDENTS_Define($$) {
|
sub RESIDENTS_Define($$) {
|
||||||
my ( $hash, $def ) = @_;
|
my ( $hash, $def ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -75,7 +44,7 @@ sub RESIDENTS_Define($$) {
|
|||||||
# run timers
|
# run timers
|
||||||
InternalTimer(
|
InternalTimer(
|
||||||
gettimeofday() + 15,
|
gettimeofday() + 15,
|
||||||
"RESIDENTS_StartInternalTimers",
|
"RESIDENTStk_RG_StartInternalTimers",
|
||||||
$hash, 0
|
$hash, 0
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -91,88 +60,10 @@ sub RESIDENTS_Define($$) {
|
|||||||
return undef;
|
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($$) {
|
sub RESIDENTS_Undefine($$) {
|
||||||
my ( $hash, $name ) = @_;
|
my ( $hash, $name ) = @_;
|
||||||
|
|
||||||
RESIDENTS_StopInternalTimers($hash);
|
RESIDENTStk_RG_StopInternalTimers($hash);
|
||||||
RESIDENTStk_findResidentSlaves($hash);
|
RESIDENTStk_findResidentSlaves($hash);
|
||||||
|
|
||||||
# delete child roommates
|
# delete child roommates
|
||||||
@ -204,132 +95,6 @@ sub RESIDENTS_Undefine($$) {
|
|||||||
return undef;
|
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($@) {
|
sub RESIDENTS_Set($@) {
|
||||||
my ( $hash, @a ) = @_;
|
my ( $hash, @a ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -570,8 +335,7 @@ sub RESIDENTS_Set($@) {
|
|||||||
# create
|
# create
|
||||||
elsif ( $a[1] eq "create" ) {
|
elsif ( $a[1] eq "create" ) {
|
||||||
if ( !defined( $a[2] ) || $a[2] !~ /^(wakeuptimer)$/i ) {
|
if ( !defined( $a[2] ) || $a[2] !~ /^(wakeuptimer)$/i ) {
|
||||||
return
|
return "Invalid 2nd argument, choose one of wakeuptimer ";
|
||||||
"Invalid 2nd argument, choose one of wakeuptimer ";
|
|
||||||
}
|
}
|
||||||
elsif ( $a[2] eq "wakeuptimer" ) {
|
elsif ( $a[2] eq "wakeuptimer" ) {
|
||||||
my $i = "1";
|
my $i = "1";
|
||||||
@ -639,12 +403,190 @@ sub RESIDENTS_Set($@) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
############################################################################################################
|
sub RESIDENTS_Attr(@) {
|
||||||
#
|
my ( $cmd, $name, $attribute, $value ) = @_;
|
||||||
# Begin of helper functions
|
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 (@) {
|
sub RESIDENTS_UpdateReadings (@) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -1511,96 +1453,7 @@ sub RESIDENTS_UpdateReadings (@) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# calculate duration timers
|
# calculate duration timers
|
||||||
RESIDENTS_DurationTimer( $hash, 1 );
|
RESIDENTStk_RG_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 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -1,60 +1,29 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Time::Local;
|
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
use Time::Local;
|
||||||
|
|
||||||
require RESIDENTStk;
|
require RESIDENTStk;
|
||||||
|
|
||||||
sub GUEST_Set($@);
|
# initialize ##################################################################
|
||||||
sub GUEST_Define($$);
|
|
||||||
sub GUEST_Notify($$);
|
|
||||||
sub GUEST_Attr(@);
|
|
||||||
sub GUEST_Undefine($$);
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub GUEST_Initialize($) {
|
sub GUEST_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
Log3 $hash, 5, "GUEST_Initialize: Entering";
|
|
||||||
|
|
||||||
$hash->{SetFn} = "GUEST_Set";
|
|
||||||
$hash->{DefFn} = "GUEST_Define";
|
$hash->{DefFn} = "GUEST_Define";
|
||||||
$hash->{NotifyFn} = "GUEST_Notify";
|
|
||||||
$hash->{AttrFn} = "GUEST_Attr";
|
|
||||||
$hash->{UndefFn} = "GUEST_Undefine";
|
$hash->{UndefFn} = "GUEST_Undefine";
|
||||||
|
$hash->{SetFn} = "GUEST_Set";
|
||||||
|
$hash->{AttrFn} = "RESIDENTStk_RG_Attr";
|
||||||
|
$hash->{NotifyFn} = "RESIDENTStk_RG_Notify";
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$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;
|
. $readingFnAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
# regular Fn ##################################################################
|
||||||
sub GUEST_Define($$) {
|
sub GUEST_Define($$) {
|
||||||
my ( $hash, $def ) = @_;
|
my ( $hash, $def ) = @_;
|
||||||
my @a = split( "[ \t][ \t]*", $def );
|
my @a = split( "[ \t][ \t]*", $def );
|
||||||
@ -69,6 +38,8 @@ sub GUEST_Define($$) {
|
|||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hash->{NOTIFYDEV} = "";
|
||||||
|
|
||||||
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
|
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
|
||||||
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
||||||
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
|
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
|
||||||
@ -111,7 +82,11 @@ sub GUEST_Define($$) {
|
|||||||
readingsEndUpdate( $hash, 1 );
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
# run timers
|
# run timers
|
||||||
InternalTimer( gettimeofday() + 15, "GUEST_StartInternalTimers", $hash, 0 );
|
InternalTimer(
|
||||||
|
gettimeofday() + 15,
|
||||||
|
"RESIDENTStk_RG_StartInternalTimers",
|
||||||
|
$hash, 0
|
||||||
|
);
|
||||||
|
|
||||||
# Injecting AttrFn for use with RESIDENTS Toolkit
|
# Injecting AttrFn for use with RESIDENTS Toolkit
|
||||||
if ( !defined( $modules{dummy}{AttrFn} ) ) {
|
if ( !defined( $modules{dummy}{AttrFn} ) ) {
|
||||||
@ -127,86 +102,10 @@ sub GUEST_Define($$) {
|
|||||||
return undef;
|
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($$) {
|
sub GUEST_Undefine($$) {
|
||||||
my ( $hash, $name ) = @_;
|
my ( $hash, $name ) = @_;
|
||||||
|
|
||||||
GUEST_StopInternalTimers($hash);
|
RESIDENTStk_RG_StopInternalTimers($hash);
|
||||||
|
|
||||||
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
||||||
my $old = $hash->{RESIDENTGROUPS};
|
my $old = $hash->{RESIDENTGROUPS};
|
||||||
@ -223,147 +122,8 @@ sub GUEST_Undefine($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
sub GUEST_Set($@);
|
||||||
sub GUEST_Notify($$) {
|
|
||||||
my ( $hash, $dev ) = @_;
|
|
||||||
my $devName = $dev->{NAME};
|
|
||||||
my $hashName = $hash->{NAME};
|
|
||||||
return if ( IsDisabled($hashName) or IsDisabled($devName) );
|
|
||||||
|
|
||||||
# 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($@) {
|
sub GUEST_Set($@) {
|
||||||
my ( $hash, @a ) = @_;
|
my ( $hash, @a ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -728,13 +488,13 @@ sub GUEST_Set($@) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# calculate duration timers
|
# calculate duration timers
|
||||||
GUEST_DurationTimer( $hash, $silent );
|
RESIDENTStk_RG_DurationTimer( $hash, $silent );
|
||||||
|
|
||||||
readingsEndUpdate( $hash, 1 );
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
# enable or disable AutoGone timer
|
# enable or disable AutoGone timer
|
||||||
if ( $newstate eq "absent" ) {
|
if ( $newstate eq "absent" ) {
|
||||||
GUEST_AutoGone($hash);
|
RESIDENTStk_RG_AutoGone($hash);
|
||||||
}
|
}
|
||||||
elsif ( $state eq "absent" ) {
|
elsif ( $state eq "absent" ) {
|
||||||
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
|
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
|
||||||
@ -888,7 +648,7 @@ sub GUEST_Set($@) {
|
|||||||
fhem "attr $wakeuptimerName room " . $attr{$name}{room}
|
fhem "attr $wakeuptimerName room " . $attr{$name}{room}
|
||||||
if ( defined( $attr{$name}{room} ) );
|
if ( defined( $attr{$name}{room} ) );
|
||||||
fhem
|
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 userattr wakeupUserdevice";
|
||||||
fhem "attr $wakeuptimerName sortby " . $sortby
|
fhem "attr $wakeuptimerName sortby " . $sortby
|
||||||
if ($sortby);
|
if ($sortby);
|
||||||
@ -960,132 +720,7 @@ sub GUEST_Set($@) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
############################################################################################################
|
# module Fn ####################################################################
|
||||||
#
|
|
||||||
# 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub GUEST_SetLocation($$$;$$$$$$) {
|
sub GUEST_SetLocation($$$;$$$$$$) {
|
||||||
my ( $name, $location, $trigger, $id, $time, $lat, $long, $address,
|
my ( $name, $location, $trigger, $id, $time, $lat, $long, $address,
|
||||||
$device ) = @_;
|
$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;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
@ -1,60 +1,29 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
package main;
|
package main;
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
use Time::Local;
|
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
use Time::Local;
|
||||||
|
|
||||||
require RESIDENTStk;
|
require RESIDENTStk;
|
||||||
|
|
||||||
sub ROOMMATE_Set($@);
|
# initialize ##################################################################
|
||||||
sub ROOMMATE_Define($$);
|
|
||||||
sub ROOMMATE_Notify($$);
|
|
||||||
sub ROOMMATE_Attr(@);
|
|
||||||
sub ROOMMATE_Undefine($$);
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub ROOMMATE_Initialize($) {
|
sub ROOMMATE_Initialize($) {
|
||||||
my ($hash) = @_;
|
my ($hash) = @_;
|
||||||
|
|
||||||
Log3 $hash, 5, "ROOMMATE_Initialize: Entering";
|
|
||||||
|
|
||||||
$hash->{SetFn} = "ROOMMATE_Set";
|
|
||||||
$hash->{DefFn} = "ROOMMATE_Define";
|
$hash->{DefFn} = "ROOMMATE_Define";
|
||||||
$hash->{NotifyFn} = "ROOMMATE_Notify";
|
|
||||||
$hash->{AttrFn} = "ROOMMATE_Attr";
|
|
||||||
$hash->{UndefFn} = "ROOMMATE_Undefine";
|
$hash->{UndefFn} = "ROOMMATE_Undefine";
|
||||||
|
$hash->{SetFn} = "ROOMMATE_Set";
|
||||||
|
$hash->{AttrFn} = "RESIDENTStk_RG_Attr";
|
||||||
|
$hash->{NotifyFn} = "RESIDENTStk_RG_Notify";
|
||||||
|
|
||||||
$hash->{AttrList} =
|
$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;
|
. $readingFnAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
# regular Fn ##################################################################
|
||||||
sub ROOMMATE_Define($$) {
|
sub ROOMMATE_Define($$) {
|
||||||
my ( $hash, $def ) = @_;
|
my ( $hash, $def ) = @_;
|
||||||
my @a = split( "[ \t][ \t]*", $def );
|
my @a = split( "[ \t][ \t]*", $def );
|
||||||
@ -70,6 +39,8 @@ sub ROOMMATE_Define($$) {
|
|||||||
return $msg;
|
return $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$hash->{NOTIFYDEV} = "";
|
||||||
|
|
||||||
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
|
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
|
||||||
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
||||||
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
|
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
|
||||||
@ -112,7 +83,7 @@ sub ROOMMATE_Define($$) {
|
|||||||
# run timers
|
# run timers
|
||||||
InternalTimer(
|
InternalTimer(
|
||||||
gettimeofday() + 15,
|
gettimeofday() + 15,
|
||||||
"ROOMMATE_StartInternalTimers",
|
"RESIDENTStk_RG_StartInternalTimers",
|
||||||
$hash, 0
|
$hash, 0
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -130,86 +101,10 @@ sub ROOMMATE_Define($$) {
|
|||||||
return undef;
|
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($$) {
|
sub ROOMMATE_Undefine($$) {
|
||||||
my ( $hash, $name ) = @_;
|
my ( $hash, $name ) = @_;
|
||||||
|
|
||||||
ROOMMATE_StopInternalTimers($hash);
|
RESIDENTStk_RG_StopInternalTimers($hash);
|
||||||
|
|
||||||
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
|
||||||
my $old = $hash->{RESIDENTGROUPS};
|
my $old = $hash->{RESIDENTGROUPS};
|
||||||
@ -226,149 +121,8 @@ sub ROOMMATE_Undefine($$) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
###################################
|
sub ROOMMATE_Set($@);
|
||||||
sub ROOMMATE_Notify($$) {
|
|
||||||
my ( $hash, $dev ) = @_;
|
|
||||||
my $devName = $dev->{NAME};
|
|
||||||
my $hashName = $hash->{NAME};
|
|
||||||
return if ( IsDisabled($hashName) or IsDisabled($devName) );
|
|
||||||
|
|
||||||
# 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($@) {
|
sub ROOMMATE_Set($@) {
|
||||||
my ( $hash, @a ) = @_;
|
my ( $hash, @a ) = @_;
|
||||||
my $name = $hash->{NAME};
|
my $name = $hash->{NAME};
|
||||||
@ -708,13 +462,13 @@ sub ROOMMATE_Set($@) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# calculate duration timers
|
# calculate duration timers
|
||||||
ROOMMATE_DurationTimer( $hash, $silent );
|
RESIDENTStk_RG_DurationTimer( $hash, $silent );
|
||||||
|
|
||||||
readingsEndUpdate( $hash, 1 );
|
readingsEndUpdate( $hash, 1 );
|
||||||
|
|
||||||
# enable or disable AutoGone timer
|
# enable or disable AutoGone timer
|
||||||
if ( $newstate eq "absent" ) {
|
if ( $newstate eq "absent" ) {
|
||||||
ROOMMATE_AutoGone($hash);
|
RESIDENTStk_RG_AutoGone($hash);
|
||||||
}
|
}
|
||||||
elsif ( $state eq "absent" ) {
|
elsif ( $state eq "absent" ) {
|
||||||
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
|
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
|
||||||
@ -870,7 +624,7 @@ sub ROOMMATE_Set($@) {
|
|||||||
fhem "attr $wakeuptimerName room " . $attr{$name}{room}
|
fhem "attr $wakeuptimerName room " . $attr{$name}{room}
|
||||||
if ( defined( $attr{$name}{room} ) );
|
if ( defined( $attr{$name}{room} ) );
|
||||||
fhem
|
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 userattr wakeupUserdevice";
|
||||||
fhem "attr $wakeuptimerName sortby " . $sortby
|
fhem "attr $wakeuptimerName sortby " . $sortby
|
||||||
if ($sortby);
|
if ($sortby);
|
||||||
@ -942,130 +696,7 @@ sub ROOMMATE_Set($@) {
|
|||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
############################################################################################################
|
# module Fn ####################################################################
|
||||||
#
|
|
||||||
# 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
###################################
|
|
||||||
sub ROOMMATE_SetLocation($$$;$$$$$$) {
|
sub ROOMMATE_SetLocation($$$;$$$$$$) {
|
||||||
my ( $name, $location, $trigger, $id, $time, $lat, $long, $address,
|
my ( $name, $location, $trigger, $id, $time, $lat, $long, $address,
|
||||||
$device ) = @_;
|
$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;
|
1;
|
||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
@ -1,31 +1,10 @@
|
|||||||
|
###############################################################################
|
||||||
# $Id$
|
# $Id$
|
||||||
##############################################################################
|
# package main;
|
||||||
#
|
# use strict;
|
||||||
# RESIDENTStk.pm
|
# use warnings;
|
||||||
# Additional functions for 10_RESIDENTS.pm, 20_ROOMMATE.pm, 20_GUEST.pm
|
# use Data::Dumper;
|
||||||
#
|
sub RESIDENTStk_Initialize() { }
|
||||||
# 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 <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
sub RESIDENTStk_Initialize() {
|
|
||||||
}
|
|
||||||
|
|
||||||
#####################################
|
#####################################
|
||||||
# PRE-DEFINITION: wakeuptimer
|
# PRE-DEFINITION: wakeuptimer
|
||||||
@ -40,20 +19,18 @@ sub RESIDENTStk_wakeupSet($$) {
|
|||||||
my ( $a, $h ) = parseParams($n);
|
my ( $a, $h ) = parseParams($n);
|
||||||
my $cmd = shift @$a;
|
my $cmd = shift @$a;
|
||||||
my $VALUE = join( " ", @$a );
|
my $VALUE = join( " ", @$a );
|
||||||
my $nextRun = ReadingsVal( $NAME, "nextRun", "07:00" );
|
|
||||||
|
$cmd =~ s/^state:\s*(.*)$/$1/;
|
||||||
|
return if ( $cmd =~ /^[A-Za-z]+:/ );
|
||||||
|
|
||||||
# filter non-registered notifies
|
# filter non-registered notifies
|
||||||
if ( $cmd !~
|
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,
|
Log3 $NAME, 6,
|
||||||
"RESIDENTStk $NAME: "
|
"RESIDENTStk $NAME: "
|
||||||
. "received unspecified notify '"
|
. "received unspecified notify '$cmd' - nothing to do";
|
||||||
. $cmd
|
|
||||||
. "' - nothing to do";
|
|
||||||
|
|
||||||
fhem "set $NAME nextRun $nextRun";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,7 +48,8 @@ m/^((?:next[rR]un)?\s*(off|OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?
|
|||||||
my $wakeupResetdays =
|
my $wakeupResetdays =
|
||||||
ReadingsVal( $NAME, "wakeupResetdays",
|
ReadingsVal( $NAME, "wakeupResetdays",
|
||||||
AttrVal( $NAME, "wakeupResetdays", "" ) );
|
AttrVal( $NAME, "wakeupResetdays", "" ) );
|
||||||
my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 );
|
my $wakeupOffset =
|
||||||
|
ReadingsVal( $NAME, "wakeupOffset", AttrVal( $NAME, "wakeupOffset", 0 ) );
|
||||||
my $wakeupEnforced =
|
my $wakeupEnforced =
|
||||||
ReadingsVal( $NAME, "wakeupEnforced",
|
ReadingsVal( $NAME, "wakeupEnforced",
|
||||||
AttrVal( $NAME, "wakeupEnforced", 0 ) );
|
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 $room = AttrVal( $NAME, "room", 0 );
|
||||||
my $userattr = AttrVal( $NAME, "userattr", 0 );
|
my $userattr = AttrVal( $NAME, "userattr", 0 );
|
||||||
my $lastRun = ReadingsVal( $NAME, "lastRun", "07:00" );
|
my $lastRun = ReadingsVal( $NAME, "lastRun", "07:00" );
|
||||||
|
my $nextRun = ReadingsVal( $NAME, "nextRun", "07:00" );
|
||||||
my $running = ReadingsVal( $NAME, "running", 0 );
|
my $running = ReadingsVal( $NAME, "running", 0 );
|
||||||
my $wakeupUserdeviceState = ReadingsVal( $wakeupUserdevice, "state", 0 );
|
my $wakeupUserdeviceState = ReadingsVal( $wakeupUserdevice, "state", 0 );
|
||||||
my $atName = "at_" . $NAME;
|
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
|
# check for required userattr attribute
|
||||||
my $userattributes =
|
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";
|
"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 {
|
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:
|
# conditional enforced wake-up:
|
||||||
# only if actual wake-up time is not wakeupDefaultTime
|
# only if actual wake-up time is not wakeupDefaultTime
|
||||||
if ( $wakeupEnforced == 2
|
elsif ($wakeupEnforced == 2
|
||||||
&& $wakeupDefaultTime
|
&& $wakeupDefaultTime
|
||||||
&& $wakeupDefaultTime ne $lastRun )
|
&& $wakeupDefaultTime ne $lastRun )
|
||||||
{
|
{
|
||||||
|
Log3 $NAME, 4,
|
||||||
|
"RESIDENTStk $NAME: "
|
||||||
|
. "Enforcing wake-up because wake-up is different from normal (wakeupDefaultTime=$wakeupDefaultTime =! lastRun=$lastRun)";
|
||||||
$wakeupEnforced = 1;
|
$wakeupEnforced = 1;
|
||||||
}
|
}
|
||||||
elsif ( $wakeupEnforced == 2 ) {
|
elsif ( $wakeupEnforced > 1 ) {
|
||||||
$wakeupEnforced = 0;
|
$wakeupEnforced = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -852,7 +850,7 @@ return;;\
|
|||||||
# wakeup attributes
|
# wakeup attributes
|
||||||
#
|
#
|
||||||
elsif ( $cmd =~
|
elsif ( $cmd =~
|
||||||
m/^(wakeupResetdays|wakeupDays|wakeupHolidays|wakeupEnforced|wakeupDefaultTime)$/
|
m/^(wakeupResetdays|wakeupDays|wakeupHolidays|wakeupEnforced|wakeupDefaultTime|wakeupOffset)$/
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Log3 $NAME, 4, "RESIDENTStk $NAME: " . "setting $1 to '$VALUE'";
|
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},
|
readingsBulkUpdateIfChanged( $defs{$wakeupUserdevice},
|
||||||
"nextWakeup", $nextWakeup );
|
"nextWakeup", $nextWakeup );
|
||||||
readingsEndUpdate( $defs{$wakeupUserdevice}, 1 );
|
readingsEndUpdate( $defs{$wakeupUserdevice}, 1 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return undef;
|
return undef;
|
||||||
@ -926,11 +923,20 @@ m/^(?:nextRun)?\s*(OFF|([\+\-])?(([0-9]{2}):([0-9]{2})|([1-9]+[0-9]*)))?$/i
|
|||||||
#
|
#
|
||||||
sub RESIDENTStk_wakeupGetBegin($;$) {
|
sub RESIDENTStk_wakeupGetBegin($;$) {
|
||||||
my ( $NAME, $wakeupAtdevice ) = @_;
|
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 $nextRun = ReadingsVal( $NAME, "nextRun", 0 );
|
||||||
my $wakeupDefaultTime =
|
my $wakeupDefaultTime =
|
||||||
ReadingsVal( $NAME, "wakeupDefaultTime",
|
ReadingsVal( $NAME, "wakeupDefaultTime",
|
||||||
AttrVal( $NAME, "wakeupDefaultTime", 0 ) );
|
AttrVal( $NAME, "wakeupDefaultTime", 0 ) );
|
||||||
my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 );
|
my $wakeupOffset =
|
||||||
|
ReadingsVal( $NAME, "wakeupOffset", AttrVal( $NAME, "wakeupOffset", 0 ) );
|
||||||
my $wakeupInitTime = (
|
my $wakeupInitTime = (
|
||||||
$wakeupDefaultTime && lc($wakeupDefaultTime) ne "off"
|
$wakeupDefaultTime && lc($wakeupDefaultTime) ne "off"
|
||||||
? $wakeupDefaultTime
|
? $wakeupDefaultTime
|
||||||
@ -1013,6 +1019,13 @@ sub RESIDENTStk_wakeupGetBegin($;$) {
|
|||||||
sub RESIDENTStk_wakeupRun($;$) {
|
sub RESIDENTStk_wakeupRun($;$) {
|
||||||
my ( $NAME, $forceRun ) = @_;
|
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 $wakeupMacro = AttrVal( $NAME, "wakeupMacro", 0 );
|
||||||
my $wakeupDefaultTime =
|
my $wakeupDefaultTime =
|
||||||
ReadingsVal( $NAME, "wakeupDefaultTime",
|
ReadingsVal( $NAME, "wakeupDefaultTime",
|
||||||
@ -1027,7 +1040,8 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
my $wakeupResetdays =
|
my $wakeupResetdays =
|
||||||
ReadingsVal( $NAME, "wakeupResetdays",
|
ReadingsVal( $NAME, "wakeupResetdays",
|
||||||
AttrVal( $NAME, "wakeupResetdays", "" ) );
|
AttrVal( $NAME, "wakeupResetdays", "" ) );
|
||||||
my $wakeupOffset = AttrVal( $NAME, "wakeupOffset", 0 );
|
my $wakeupOffset =
|
||||||
|
ReadingsVal( $NAME, "wakeupOffset", AttrVal( $NAME, "wakeupOffset", 0 ) );
|
||||||
my $wakeupEnforced =
|
my $wakeupEnforced =
|
||||||
ReadingsVal( $NAME, "wakeupEnforced",
|
ReadingsVal( $NAME, "wakeupEnforced",
|
||||||
AttrVal( $NAME, "wakeupEnforced", 0 ) );
|
AttrVal( $NAME, "wakeupEnforced", 0 ) );
|
||||||
@ -1092,18 +1106,10 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
if ( $wakeupResetdays ne "" );
|
if ( $wakeupResetdays ne "" );
|
||||||
my %rdays = map { $_ => 1 } @rdays;
|
my %rdays = map { $_ => 1 } @rdays;
|
||||||
|
|
||||||
if ( !IsDevice($NAME) ) {
|
if ( IsDisabled($wakeupDevice) ) {
|
||||||
return "$NAME: Non existing device";
|
|
||||||
}
|
|
||||||
elsif ( IsDisabled($wakeupDevice) ) {
|
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
"RESIDENTStk $NAME: "
|
"RESIDENTStk $NAME: "
|
||||||
. "device disabled - not triggering wake-up program";
|
. "wakeupDevice 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";
|
|
||||||
}
|
}
|
||||||
elsif ( !$wakeupUserdevice ) {
|
elsif ( !$wakeupUserdevice ) {
|
||||||
return "$NAME: missing attribute wakeupUserdevice";
|
return "$NAME: missing attribute wakeupUserdevice";
|
||||||
@ -1113,7 +1119,7 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
}
|
}
|
||||||
elsif ( !IsDevice( $wakeupUserdevice, "RESIDENTS|ROOMMATE|GUEST" ) ) {
|
elsif ( !IsDevice( $wakeupUserdevice, "RESIDENTS|ROOMMATE|GUEST" ) ) {
|
||||||
return "$NAME: "
|
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" )
|
elsif ( IsDevice( $wakeupUserdevice, "GUEST" )
|
||||||
&& $wakeupUserdeviceState eq "none" )
|
&& $wakeupUserdeviceState eq "none" )
|
||||||
@ -1124,9 +1130,23 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
fhem "set $NAME nextRun OFF";
|
fhem "set $NAME nextRun OFF";
|
||||||
return;
|
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}
|
&& !$days{$today}
|
||||||
&& !$forceRun )
|
&& ( $wakeupHolidays eq ""
|
||||||
|
|| $wakeupHolidays eq "andHoliday"
|
||||||
|
|| $wakeupHolidays eq "andNoHoliday" )
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Log3 $NAME, 4,
|
Log3 $NAME, 4,
|
||||||
"RESIDENTStk $NAME: "
|
"RESIDENTStk $NAME: "
|
||||||
@ -1134,39 +1154,19 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
}
|
}
|
||||||
elsif (
|
elsif (
|
||||||
!$forceRun
|
!$forceRun
|
||||||
&& ( $wakeupHolidays eq "orHoliday"
|
|
||||||
|| $wakeupHolidays eq "orNoHoliday" )
|
|
||||||
&& (
|
&& (
|
||||||
!$days{$today}
|
( $wakeupHolidays eq "andHoliday" && !$holidayToday )
|
||||||
&& (
|
|| ( $wakeupHolidays eq "andNoHoliday"
|
||||||
( $wakeupHolidays eq "orHoliday" && !$holidayToday )
|
&& $holidayToday )
|
||||||
|
|| ( $wakeupHolidays eq "orHoliday" && !$holidayToday )
|
||||||
|| ( $wakeupHolidays eq "orNoHoliday"
|
|| ( $wakeupHolidays eq "orNoHoliday"
|
||||||
&& $holidayToday )
|
&& $holidayToday )
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
Log3 $NAME, 4,
|
Log3 $NAME, 4,
|
||||||
"RESIDENTStk $NAME: "
|
"RESIDENTStk $NAME: "
|
||||||
. "neither weekday nor holiday restriction matched - not triggering wake-up program this time";
|
. "holiday restriction $wakeupHolidays in use - 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";
|
|
||||||
}
|
}
|
||||||
elsif ($wakeupUserdeviceState eq "absent"
|
elsif ($wakeupUserdeviceState eq "absent"
|
||||||
|| $wakeupUserdeviceState eq "gone"
|
|| $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)";
|
. "won't trigger wake-up program due to non-expired wakeupWaitPeriod threshold since lastAwake (expLastAwake=$expLastAwake > nowRunSec=$nowRunSec)";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
# conditional enforced wake-up:
|
# conditional enforced wake-up:
|
||||||
# only if actual wake-up time is
|
# only if actual wake-up time is
|
||||||
# earlier than wakeupDefaultTime
|
# earlier than wakeupDefaultTime
|
||||||
@ -1249,7 +1250,7 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
. "Enforcing wake-up because wake-up is different from normal (wakeupDefaultTime=$wakeupDefaultTime =! lastRun=$lastRun)";
|
. "Enforcing wake-up because wake-up is different from normal (wakeupDefaultTime=$wakeupDefaultTime =! lastRun=$lastRun)";
|
||||||
$wakeupEnforced = 1;
|
$wakeupEnforced = 1;
|
||||||
}
|
}
|
||||||
elsif ( $wakeupEnforced == 2 ) {
|
elsif ( $wakeupEnforced > 1 ) {
|
||||||
$wakeupEnforced = 0;
|
$wakeupEnforced = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1289,7 +1290,6 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
|
|
||||||
$running = 1;
|
$running = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1348,11 +1348,9 @@ sub RESIDENTStk_wakeupRun($;$) {
|
|||||||
sub RESIDENTStk_AttrFnDummy(@) {
|
sub RESIDENTStk_AttrFnDummy(@) {
|
||||||
my ( $cmd, $name, $aName, $aVal ) = @_;
|
my ( $cmd, $name, $aName, $aVal ) = @_;
|
||||||
|
|
||||||
# set attribute
|
|
||||||
if ( $init_done && $cmd eq "set" ) {
|
|
||||||
|
|
||||||
# wakeupResetSwitcher
|
# wakeupResetSwitcher
|
||||||
if ( $aName eq "wakeupResetSwitcher" ) {
|
if ( $aName eq "wakeupResetSwitcher" ) {
|
||||||
|
if ( $init_done && $cmd eq "set" ) {
|
||||||
if ( !IsDevice($aVal) ) {
|
if ( !IsDevice($aVal) ) {
|
||||||
my $alias = AttrVal( $name, "alias", 0 );
|
my $alias = AttrVal( $name, "alias", 0 );
|
||||||
my $group = AttrVal( $name, "group", 0 );
|
my $group = AttrVal( $name, "group", 0 );
|
||||||
@ -1360,7 +1358,7 @@ sub RESIDENTStk_AttrFnDummy(@) {
|
|||||||
|
|
||||||
fhem "define $aVal dummy";
|
fhem "define $aVal dummy";
|
||||||
fhem "attr $aVal "
|
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) {
|
if ($alias) {
|
||||||
fhem "attr $aVal alias $alias Reset";
|
fhem "attr $aVal alias $alias Reset";
|
||||||
}
|
}
|
||||||
@ -1381,14 +1379,12 @@ sub RESIDENTStk_AttrFnDummy(@) {
|
|||||||
Log3 $name, 3,
|
Log3 $name, 3,
|
||||||
"RESIDENTStk $name: new slave dummy device $aVal created";
|
"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;
|
return undef;
|
||||||
@ -1423,18 +1419,13 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
my $secNow = RESIDENTStk_time2sec( $hour . ":" . $min ) + $sec;
|
my $secNow = RESIDENTStk_time2sec( $hour . ":" . $min ) + $sec;
|
||||||
my $definitiveNextToday;
|
my $definitiveNextToday;
|
||||||
my $definitiveNextTomorrow;
|
my $definitiveNextTomorrow;
|
||||||
my $definitiveNextTodayDev = 0;
|
my $definitiveNextTodayDev;
|
||||||
my $definitiveNextTomorrowDev = 0;
|
my $definitiveNextTomorrowDev;
|
||||||
|
|
||||||
my $holidayDevice = AttrVal( "global", "holiday2we", 0 );
|
my $holidayDevice = AttrVal( "global", "holiday2we", 0 );
|
||||||
|
|
||||||
# check for each registered wake-up device
|
# check for each registered wake-up device
|
||||||
for my $wakeupDevice ( split /,/, $wakeupDeviceList ) {
|
for my $wakeupDevice ( split /,/, $wakeupDeviceList ) {
|
||||||
next if !$wakeupDevice;
|
|
||||||
|
|
||||||
my $ltoday = $today;
|
|
||||||
my $ltomorrow = $tomorrow;
|
|
||||||
|
|
||||||
if ( !IsDevice($wakeupDevice) ) {
|
if ( !IsDevice($wakeupDevice) ) {
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
"RESIDENTStk $name: "
|
"RESIDENTStk $name: "
|
||||||
@ -1454,25 +1445,16 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
|
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
elsif ( IsDisabled($wakeupDevice) ) {
|
|
||||||
Log3 $name, 4,
|
|
||||||
"RESIDENTStk $name: "
|
|
||||||
. "00 - ignoring disabled wakeupDevice $wakeupDevice";
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log3 $name, 4,
|
my $wakeupAtdevice = AttrVal( $wakeupDevice, "wakeupAtdevice", undef );
|
||||||
"RESIDENTStk $name: "
|
my $wakeupOffset =
|
||||||
. "00 - checking for next wake-up candidate $wakeupDevice";
|
ReadingsVal( $wakeupDevice, "wakeupOffset",
|
||||||
|
AttrVal( $wakeupDevice, "wakeupOffset", 0 ) );
|
||||||
my $nextRun = ReadingsVal( $wakeupDevice, "nextRun", 0 );
|
|
||||||
my $wakeupAtdevice = AttrVal( $wakeupDevice, "wakeupAtdevice", 0 );
|
|
||||||
my $wakeupOffset = AttrVal( $wakeupDevice, "wakeupOffset", 0 );
|
|
||||||
my $wakeupAtNTM = (
|
my $wakeupAtNTM = (
|
||||||
IsDevice($wakeupAtdevice)
|
IsDevice($wakeupAtdevice)
|
||||||
&& defined( $defs{$wakeupAtdevice}{NTM} )
|
&& defined( $defs{$wakeupAtdevice}{NTM} )
|
||||||
? substr( $defs{$wakeupAtdevice}{NTM}, 0, -3 )
|
? substr( $defs{$wakeupAtdevice}{NTM}, 0, -3 )
|
||||||
: 0
|
: undef
|
||||||
);
|
);
|
||||||
my $wakeupDays =
|
my $wakeupDays =
|
||||||
ReadingsVal( $wakeupDevice, "wakeupDays",
|
ReadingsVal( $wakeupDevice, "wakeupDays",
|
||||||
@ -1483,11 +1465,31 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
my $holidayToday = 0;
|
my $holidayToday = 0;
|
||||||
my $holidayTomorrow = 0;
|
my $holidayTomorrow = 0;
|
||||||
my $nextRunSrc;
|
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
|
# get holiday status for today and tomorrow
|
||||||
if ( $wakeupHolidays ne ""
|
if ( $wakeupHolidays eq "" ) {
|
||||||
&& IsDevice( $holidayDevice, "holiday" ) )
|
Log3 $name, 4,
|
||||||
{
|
"RESIDENTStk $wakeupDevice: 01 - Not considering any holidays";
|
||||||
|
}
|
||||||
|
elsif ( IsDevice( $holidayDevice, "holiday" ) ) {
|
||||||
$holidayToday = 1
|
$holidayToday = 1
|
||||||
unless (
|
unless (
|
||||||
ReadingsVal( $holidayDevice, "state", "none" ) eq "none" );
|
ReadingsVal( $holidayDevice, "state", "none" ) eq "none" );
|
||||||
@ -1497,11 +1499,7 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
|
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
"RESIDENTStk $wakeupDevice: "
|
"RESIDENTStk $wakeupDevice: "
|
||||||
. "01 - Holidays to be considered - today=$holidayToday tomorrow=$holidayTomorrow";
|
. "01 - Holidays to be considered ($wakeupHolidays) - holidayToday=$holidayToday holidayTomorrow=$holidayTomorrow";
|
||||||
}
|
|
||||||
else {
|
|
||||||
Log3 $name, 4,
|
|
||||||
"RESIDENTStk $wakeupDevice: 01 - Not considering any holidays";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# set day scope for today
|
# set day scope for today
|
||||||
@ -1516,15 +1514,6 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
if ( $wakeupDays ne "" );
|
if ( $wakeupDays ne "" );
|
||||||
my %daysTomorrow = map { $_ => 1 } @daysTomorrow;
|
my %daysTomorrow = map { $_ => 1 } @daysTomorrow;
|
||||||
|
|
||||||
if ( lc($nextRun) eq "off"
|
|
||||||
|| $nextRun !~ /^([0-9]{2}:[0-9]{2})$/ )
|
|
||||||
{
|
|
||||||
Log3 $name, 4,
|
|
||||||
"RESIDENTStk $wakeupDevice: " . "02 - set to OFF so no candidate";
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
"RESIDENTStk $wakeupDevice: "
|
"RESIDENTStk $wakeupDevice: "
|
||||||
. "02 - possible candidate found - weekdayToday=$ltoday weekdayTomorrow=$ltomorrow";
|
. "02 - possible candidate found - weekdayToday=$ltoday weekdayTomorrow=$ltomorrow";
|
||||||
@ -1610,9 +1599,12 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
$definitiveNextToday = $nextRunSec;
|
$definitiveNextToday = $nextRunSec;
|
||||||
$definitiveNextTodayDev = $wakeupDevice;
|
$definitiveNextTodayDev = $wakeupDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
elsif ($wakeupHolidays eq ""
|
||||||
|
|| $wakeupHolidays eq "andHoliday"
|
||||||
|
|| $wakeupHolidays eq "andNoHoliday" )
|
||||||
|
{
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
"RESIDENTStk $wakeupDevice: "
|
"RESIDENTStk $wakeupDevice: "
|
||||||
. "05 - won't be running today anymore based on weekday decision";
|
. "05 - won't be running today anymore based on weekday decision";
|
||||||
@ -1620,10 +1612,9 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# if we need to consider holidays in parallel to weekdays
|
# if we need to consider holidays in parallel to weekdays
|
||||||
if ( ( $wakeupHolidays eq "orHoliday" && $holidayToday )
|
elsif (( $wakeupHolidays eq "orHoliday" && !$holidayToday )
|
||||||
|| ( $wakeupHolidays eq "orNoHoliday" && !$holidayToday ) )
|
|| ( $wakeupHolidays eq "orNoHoliday" && $holidayToday ) )
|
||||||
{
|
{
|
||||||
|
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
"RESIDENTStk $wakeupDevice: "
|
"RESIDENTStk $wakeupDevice: "
|
||||||
. "06 - won't be running today based on holiday decision";
|
. "06 - won't be running today based on holiday decision";
|
||||||
@ -1640,7 +1631,6 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
$definitiveNextToday = $nextRunSec;
|
$definitiveNextToday = $nextRunSec;
|
||||||
$definitiveNextTodayDev = $wakeupDevice;
|
$definitiveNextTodayDev = $wakeupDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# running later
|
# running later
|
||||||
@ -1654,10 +1644,7 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
|
|
||||||
# if we need to consider holidays in addition
|
# if we need to consider holidays in addition
|
||||||
if (
|
if (
|
||||||
(
|
( $wakeupHolidays eq "andHoliday" && !$holidayTomorrow )
|
||||||
$wakeupHolidays eq "andHoliday"
|
|
||||||
&& !$holidayTomorrow
|
|
||||||
)
|
|
||||||
|| ( $wakeupHolidays eq "andNoHoliday"
|
|| ( $wakeupHolidays eq "andNoHoliday"
|
||||||
&& $holidayTomorrow )
|
&& $holidayTomorrow )
|
||||||
)
|
)
|
||||||
@ -1678,9 +1665,12 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
$definitiveNextTomorrow = $nextRunSec;
|
$definitiveNextTomorrow = $nextRunSec;
|
||||||
$definitiveNextTomorrowDev = $wakeupDevice;
|
$definitiveNextTomorrowDev = $wakeupDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
elsif ($wakeupHolidays eq ""
|
||||||
|
|| $wakeupHolidays eq "andHoliday"
|
||||||
|
|| $wakeupHolidays eq "andNoHoliday" )
|
||||||
|
{
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
"RESIDENTStk $wakeupDevice: "
|
"RESIDENTStk $wakeupDevice: "
|
||||||
. "05 - won't be running tomorrow based on weekday decision";
|
. "05 - won't be running tomorrow based on weekday decision";
|
||||||
@ -1688,10 +1678,10 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# if we need to consider holidays in parallel to weekdays
|
# if we need to consider holidays in parallel to weekdays
|
||||||
if (
|
elsif (
|
||||||
( $wakeupHolidays eq "orHoliday" && $holidayTomorrow )
|
( $wakeupHolidays eq "orHoliday" && !$holidayTomorrow )
|
||||||
|| ( $wakeupHolidays eq "orNoHoliday"
|
|| ( $wakeupHolidays eq "orNoHoliday"
|
||||||
&& !$holidayTomorrow )
|
&& $holidayTomorrow )
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
Log3 $name, 4,
|
Log3 $name, 4,
|
||||||
@ -1700,6 +1690,7 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# easy if there is no holiday dependency
|
||||||
elsif ( !$definitiveNextTomorrow
|
elsif ( !$definitiveNextTomorrow
|
||||||
|| $nextRunSec < $definitiveNextTomorrow )
|
|| $nextRunSec < $definitiveNextTomorrow )
|
||||||
{
|
{
|
||||||
@ -1709,9 +1700,6 @@ sub RESIDENTStk_wakeupGetNext($;$) {
|
|||||||
$definitiveNextTomorrow = $nextRunSec;
|
$definitiveNextTomorrow = $nextRunSec;
|
||||||
$definitiveNextTomorrowDev = $wakeupDevice;
|
$definitiveNextTomorrowDev = $wakeupDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($wakeupOffset) {
|
if ($wakeupOffset) {
|
||||||
@ -1900,11 +1888,30 @@ sub RESIDENTStk_RemoveInternalTimer($$) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub RESIDENTStk_findResidentSlaves($) {
|
sub RESIDENTStk_RG_StartInternalTimers($$) {
|
||||||
my ($hash) = @_;
|
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
|
return
|
||||||
unless ( ref($hash) eq "HASH" && defined( $hash->{NAME} ) );
|
unless ( ref($hash) eq "HASH" && defined( $hash->{NAME} ) );
|
||||||
|
|
||||||
|
$hash->{NOTIFYDEV} = "";
|
||||||
|
|
||||||
delete $hash->{ROOMMATES};
|
delete $hash->{ROOMMATES};
|
||||||
foreach ( devspec2array("TYPE=ROOMMATE") ) {
|
foreach ( devspec2array("TYPE=ROOMMATE") ) {
|
||||||
next
|
next
|
||||||
@ -1928,6 +1935,386 @@ sub RESIDENTStk_findResidentSlaves($) {
|
|||||||
$hash->{GUESTS} .= "," if ( $hash->{GUESTS} );
|
$hash->{GUESTS} .= "," if ( $hash->{GUESTS} );
|
||||||
$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;
|
1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user