2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-07 16:59:18 +00:00

10_RESIDENTS,20_ROOMMATE,20_GUEST: implement dynamic slave handling; remove experimental dependencies

git-svn-id: https://svn.fhem.de/fhem/trunk@13608 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
jpawlowski 2017-03-05 13:02:40 +00:00
parent 63b1893132
commit 737af5ee5f
4 changed files with 171 additions and 334 deletions

View File

@ -32,8 +32,6 @@ use Time::Local;
use Data::Dumper;
require RESIDENTStk;
no if $] >= 5.017011, warnings => 'experimental';
sub RESIDENTS_Set($@);
sub RESIDENTS_Define($$);
sub RESIDENTS_Notify($$);
@ -62,8 +60,6 @@ sub RESIDENTS_Define($$) {
Log3 $name, 5, "RESIDENTS $name: called function RESIDENTS_Define()";
$hash->{TYPE} = "RESIDENTS";
# set default settings on first define
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
$attr{$name}{alias} = "Residents";
@ -91,6 +87,8 @@ sub RESIDENTS_Define($$) {
sub RESIDENTS_Undefine($$) {
my ( $hash, $name ) = @_;
RESIDENTStk_findResidentSlaves($hash);
# delete child roommates
if ( defined( $hash->{ROOMMATES} )
&& $hash->{ROOMMATES} ne "" )
@ -125,135 +123,139 @@ sub RESIDENTS_Notify($$) {
my ( $hash, $dev ) = @_;
my $devName = $dev->{NAME};
my $hashName = $hash->{NAME};
return unless ( $devName ne $hashName ); # only foreign events
return
unless ( defined( $defs{$devName} )
&& defined( $defs{$devName}{TYPE} )
&& $defs{$devName}{TYPE} =~ /^(ROOMMATE|GUEST|DUMMY)$/ );
# process child notifies
if ( $devName ne $hashName ) {
my @registeredRoommates =
split( /,/, $hash->{ROOMMATES} )
if ( defined( $hash->{ROOMMATES} )
&& $hash->{ROOMMATES} ne "" );
RESIDENTStk_findResidentSlaves($hash);
my @registeredGuests =
split( /,/, $hash->{GUESTS} )
if ( defined( $hash->{GUESTS} )
&& $hash->{GUESTS} ne "" );
my @registeredRoommates =
split( /,/, $hash->{ROOMMATES} )
if ( defined( $hash->{ROOMMATES} )
&& $hash->{ROOMMATES} ne "" );
my @registeredWakeupdevs =
split( /,/, $attr{$hashName}{rgr_wakeupDevice} )
if ( defined( $attr{$hashName}{rgr_wakeupDevice} )
&& $attr{$hashName}{rgr_wakeupDevice} ne "" );
my @registeredGuests =
split( /,/, $hash->{GUESTS} )
if ( defined( $hash->{GUESTS} )
&& $hash->{GUESTS} ne "" );
# process only registered ROOMMATE or GUEST devices
if ( ( @registeredRoommates && $devName ~~ @registeredRoommates )
|| ( @registeredGuests && $devName ~~ @registeredGuests ) )
{
my @registeredWakeupdevs =
split( /,/, $attr{$hashName}{rgr_wakeupDevice} )
if ( defined( $attr{$hashName}{rgr_wakeupDevice} )
&& $attr{$hashName}{rgr_wakeupDevice} ne "" );
return
if ( !$dev->{CHANGED} ); # Some previous notify deleted the array.
# process only registered ROOMMATE or GUEST devices
if ( ( @registeredRoommates && grep { /^$devName$/ } @registeredRoommates )
|| ( @registeredGuests && grep { /^$devName$/ } @registeredGuests ) )
{
readingsBeginUpdate($hash);
return
if ( !$dev->{CHANGED} ); # Some previous notify deleted the array.
foreach my $change ( @{ $dev->{CHANGED} } ) {
readingsBeginUpdate($hash);
Log3 $hash, 5,
"RESIDENTS " . $hashName . ": processing change $change";
foreach my $change ( @{ $dev->{CHANGED} } ) {
# state changed
if ( $change !~ /:/
|| $change =~ /wayhome:/
|| $change =~ /wakeup:/ )
{
Log3 $hash, 4,
"RESIDENTS "
. $hashName . ": "
. $devName
. ": notify about change to $change";
Log3 $hash, 5,
"RESIDENTS " . $hashName . ": processing change $change";
RESIDENTS_UpdateReadings($hash);
}
# state changed
if ( $change !~ /:/
|| $change =~ /wayhome:/
|| $change =~ /wakeup:/ )
{
Log3 $hash, 4,
"RESIDENTS "
. $hashName . ": "
. $devName
. ": notify about change to $change";
# activity
if ( $change !~ /:/ ) {
RESIDENTS_UpdateReadings($hash);
}
# get user realname
my $realnamesrc;
if ( $dev->{TYPE} eq "GUEST" ) {
$realnamesrc = (
defined( $attr{$devName}{rg_realname} )
&& $attr{$devName}{rg_realname} ne ""
? $attr{$devName}{rg_realname}
: "alias"
);
}
else {
$realnamesrc = (
defined( $attr{$devName}{rr_realname} )
&& $attr{$devName}{rr_realname} ne ""
? $attr{$devName}{rr_realname}
: "group"
);
}
# activity
if ( $change !~ /:/ ) {
my $realname = (
defined( $attr{$devName}{$realnamesrc} )
&& $attr{$devName}{$realnamesrc} ne ""
? $attr{$devName}{$realnamesrc}
: $devName
# get user realname
my $realnamesrc;
if ( $dev->{TYPE} eq "GUEST" ) {
$realnamesrc = (
defined( $attr{$devName}{rg_realname} )
&& $attr{$devName}{rg_realname} ne ""
? $attr{$devName}{rg_realname}
: "alias"
);
# update statistics
readingsBulkUpdate( $hash, "lastActivity",
ReadingsVal( $devName, "state", $change ) );
readingsBulkUpdate( $hash, "lastActivityBy", $realname );
readingsBulkUpdate( $hash, "lastActivityByDev", $devName );
}
else {
$realnamesrc = (
defined( $attr{$devName}{rr_realname} )
&& $attr{$devName}{rr_realname} ne ""
? $attr{$devName}{rr_realname}
: "group"
);
}
my $realname = (
defined( $attr{$devName}{$realnamesrc} )
&& $attr{$devName}{$realnamesrc} ne ""
? $attr{$devName}{$realnamesrc}
: $devName
);
# update statistics
readingsBulkUpdate( $hash, "lastActivity",
ReadingsVal( $devName, "state", $change ) );
readingsBulkUpdate( $hash, "lastActivityBy", $realname );
readingsBulkUpdate( $hash, "lastActivityByDev", $devName );
}
readingsEndUpdate( $hash, 1 );
}
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;
}
# if we have registered wakeup devices
if (@registeredWakeupdevs) {
# process sub-child notifies: *_wakeupDevice
foreach my $wakeupDev (@registeredWakeupdevs) {
# if this is a notification of a registered wakeup device
if ( $devName ~~ @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( $devName, $change );
RESIDENTStk_wakeupSet( $wakeupDev, $change )
if ( $change ne "off" );
}
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;
}
last;
}
}
}
@ -264,15 +266,17 @@ sub RESIDENTS_Notify($$) {
###################################
sub RESIDENTS_Set($@) {
my ( $hash, @a ) = @_;
my $name = $hash->{NAME};
my $state = ReadingsVal( $name, "state", "initialized" );
my $roommates = ( $hash->{ROOMMATES} ? $hash->{ROOMMATES} : "" );
my $guests = ( $hash->{GUESTS} ? $hash->{GUESTS} : "" );
my $name = $hash->{NAME};
my $state = ReadingsVal( $name, "state", "initialized" );
Log3 $name, 5, "RESIDENTS $name: called function RESIDENTS_Set()";
return "No Argument given" if ( !defined( $a[1] ) );
RESIDENTStk_findResidentSlaves($hash);
my $roommates = ( $hash->{ROOMMATES} ? $hash->{ROOMMATES} : "" );
my $guests = ( $hash->{GUESTS} ? $hash->{GUESTS} : "" );
# depending on current FHEMWEB instance's allowedCommands,
# restrict set commands if there is "set-user" in it
my $adminMode = 1;
@ -475,94 +479,6 @@ sub RESIDENTS_Set($@) {
}
}
# register
elsif ( $a[1] eq "register" ) {
if ( defined( $a[2] ) && $a[2] ne "" ) {
return "No such device " . $a[2]
if ( !defined( $defs{ $a[2] } ) );
# ROOMMATE
if ( $defs{ $a[2] }{TYPE} eq "ROOMMATE" ) {
Log3 $name, 4, "RESIDENTS $name: " . $a[2] . " registered";
# update readings
$roommates .= ( $roommates eq "" ? $a[2] : "," . $a[2] )
if ( $roommates !~ /$a[2]/ );
$hash->{ROOMMATES} = $roommates;
}
# GUEST
elsif ( $defs{ $a[2] }{TYPE} eq "GUEST" ) {
Log3 $name, 4, "RESIDENTS $name: " . $a[2] . " registered";
# update readings
$guests .= ( $guests eq "" ? $a[2] : "," . $a[2] )
if ( $guests !~ /$a[2]/ );
$hash->{GUESTS} = $guests;
}
# unsupported
else {
return "Device type is not supported.";
}
}
else {
return "No Argument given, choose one of ROOMMATE GUEST ";
}
}
# unregister
elsif ( $a[1] eq "unregister" ) {
if ( defined( $a[2] ) && $a[2] ne "" ) {
return "No such device " . $a[2]
if ( !defined( $defs{ $a[2] } ) );
# ROOMMATE
if ( $defs{ $a[2] }{TYPE} eq "ROOMMATE" ) {
Log3 $name, 4, "RESIDENTS $name: " . $a[2] . " unregistered";
# update readings
my $replace = "," . $a[2];
$roommates =~ s/$replace//g;
$replace = $a[2] . ",";
$roommates =~ s/^$replace//g;
$roommates =~ s/^$a[2]//g;
$hash->{ROOMMATES} = $roommates;
}
# GUEST
elsif ( $defs{ $a[2] }{TYPE} eq "GUEST" ) {
Log3 $name, 4, "RESIDENTS $name: " . $a[2] . " unregistered";
# update readings
my $replace = "," . $a[2];
$guests =~ s/$replace//g;
$replace = $a[2] . ",";
$guests =~ s/^$replace//g;
$guests =~ s/^$a[2]//g;
$hash->{GUESTS} = $guests;
}
# unsupported
else {
return "Device type is not supported.";
}
}
else {
return "No Argument given, choose one of ROOMMATE GUEST ";
}
readingsBeginUpdate($hash);
RESIDENTS_UpdateReadings($hash);
readingsEndUpdate( $hash, 1 );
}
# create
elsif ( $a[1] eq "create" ) {
if ( defined( $a[2] ) && $a[2] eq "wakeuptimer" ) {

View File

@ -32,8 +32,6 @@ use Time::Local;
use Data::Dumper;
require RESIDENTStk;
no if $] >= 5.017011, warnings => 'experimental';
sub GUEST_Set($@);
sub GUEST_Define($$);
sub GUEST_Notify($$);
@ -69,57 +67,14 @@ sub GUEST_Define($$) {
return $msg;
}
$hash->{TYPE} = "GUEST";
my $parents = ( defined( $a[2] ) ? $a[2] : "" );
# unregister at parent objects if we get modified
my @registeredResidentgroups;
my $modified = 0;
if ( defined( $hash->{RESIDENTGROUPS} ) && $hash->{RESIDENTGROUPS} ne "" ) {
$modified = 1;
@registeredResidentgroups =
split( /,/, $hash->{RESIDENTGROUPS} );
# unregister at parent objects
foreach my $parent (@registeredResidentgroups) {
if ( defined( $defs{$parent} )
&& $defs{$parent}{TYPE} eq "RESIDENTS" )
{
fhem("set $parent unregister $name");
Log3 $name, 4,
"GUEST $name: Unregistered at RESIDENTS device $parent";
}
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
RESIDENTStk_findResidentSlaves( $defs{$_} )
if ( defined( $defs{$_} ) );
}
}
# register at parent objects
$hash->{RESIDENTGROUPS} = "";
if ( $parents ne "" ) {
@registeredResidentgroups = split( /,/, $parents );
foreach my $parent (@registeredResidentgroups) {
if ( !defined( $defs{$parent} ) ) {
Log3 $name, 3,
"GUEST $name: Unable to register at RESIDENTS device $parent (not existing)";
next;
}
if ( $defs{$parent}{TYPE} ne "RESIDENTS" ) {
Log3 $name, 3,
"GUEST $name: Device $parent is not a RESIDENTS device (wrong type)";
next;
}
fhem("set $parent register $name");
$hash->{RESIDENTGROUPS} .= $parent . ",";
Log3 $name, 4,
"GUEST $name: Registered at RESIDENTS device $parent";
}
}
else {
$modified = 0;
}
# set reverse pointer
$modules{GUEST}{defptr}{$name} = \$hash;
@ -139,15 +94,15 @@ sub GUEST_Define($$) {
$attr{$name}{sortby} = "1";
$attr{$name}{webCmd} = "state";
$attr{$name}{room} = $attr{ $registeredResidentgroups[0] }{room}
if ( @registeredResidentgroups
&& exists( $attr{ $registeredResidentgroups[0] }{room} ) );
my $firstRgr = $hash->{RESIDENTGROUPS};
$firstRgr =~ s/,[\s\S]*$//gmi;
$attr{$name}{room} = $attr{$firstRgr}{room}
if ( exists( $attr{$firstRgr}{room} ) );
}
# trigger for modified objects
unless ( $modified == 0 ) {
readingsBulkUpdate( $hash, "state", ReadingsVal( $name, "state", "" ) );
}
readingsBulkUpdateIfChanged( $hash, "state",
ReadingsVal( $name, "state", "" ) );
readingsEndUpdate( $hash, 1 );
@ -176,18 +131,9 @@ sub GUEST_Undefine($$) {
RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
my @registeredResidentgroups =
split( /,/, $hash->{RESIDENTGROUPS} );
# unregister at parent objects
foreach my $parent (@registeredResidentgroups) {
if ( defined( $defs{$parent} )
&& $defs{$parent}{TYPE} eq "RESIDENTS" )
{
fhem("set $parent unregister $name");
Log3 $name, 4,
"GUEST $name: Unregistered at RESIDENTS device $parent";
}
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
RESIDENTStk_findResidentSlaves( $defs{$_} )
if ( defined( $defs{$_} ) );
}
}
@ -251,7 +197,7 @@ sub GUEST_Notify($$) {
if (@registeredWakeupdevs) {
# if this is a notification of a registered wakeup device
if ( $devName ~~ @registeredWakeupdevs ) {
if ( grep { /^$devName$/ } @registeredWakeupdevs ) {
# Some previous notify deleted the array.
return
@ -289,7 +235,7 @@ sub GUEST_Notify($$) {
}
# process PRESENCE
if ( @presenceDevices && $devName ~~ @presenceDevices ) {
if ( @presenceDevices && grep { /^$devName$/ } @presenceDevices ) {
my $counter = {
absent => 0,

View File

@ -32,8 +32,6 @@ use Time::Local;
use Data::Dumper;
require RESIDENTStk;
no if $] >= 5.017011, warnings => 'experimental';
sub ROOMMATE_Set($@);
sub ROOMMATE_Define($$);
sub ROOMMATE_Notify($$);
@ -70,57 +68,14 @@ sub ROOMMATE_Define($$) {
return $msg;
}
$hash->{TYPE} = "ROOMMATE";
my $parents = ( defined( $a[2] ) ? $a[2] : "" );
# unregister at parent objects if we get modified
my @registeredResidentgroups;
my $modified = 0;
if ( defined( $hash->{RESIDENTGROUPS} ) && $hash->{RESIDENTGROUPS} ne "" ) {
$modified = 1;
@registeredResidentgroups =
split( /,/, $hash->{RESIDENTGROUPS} );
# unregister at parent objects
foreach my $parent (@registeredResidentgroups) {
if ( defined( $defs{$parent} )
&& $defs{$parent}{TYPE} eq "RESIDENTS" )
{
fhem("set $parent unregister $name");
Log3 $name, 4,
"ROOMMATE $name: Unregistered at RESIDENTS device $parent";
}
$hash->{RESIDENTGROUPS} = defined( $a[2] ) ? $a[2] : "";
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
RESIDENTStk_findResidentSlaves( $defs{$_} )
if ( defined( $defs{$_} ) );
}
}
# register at parent objects
$hash->{RESIDENTGROUPS} = "";
if ( $parents ne "" ) {
@registeredResidentgroups = split( /,/, $parents );
foreach my $parent (@registeredResidentgroups) {
if ( !defined( $defs{$parent} ) ) {
Log3 $name, 3,
"ROOMMATE $name: Unable to register at RESIDENTS device $parent (not existing)";
next;
}
if ( $defs{$parent}{TYPE} ne "RESIDENTS" ) {
Log3 $name, 3,
"ROOMMATE $name: Device $parent is not a RESIDENTS device (wrong type)";
next;
}
fhem("set $parent register $name");
$hash->{RESIDENTGROUPS} .= $parent . ",";
Log3 $name, 4,
"ROOMMATE $name: Registered at RESIDENTS device $parent";
}
}
else {
$modified = 0;
}
# set reverse pointer
$modules{ROOMMATE}{defptr}{$name} = \$hash;
@ -140,15 +95,15 @@ sub ROOMMATE_Define($$) {
$attr{$name}{sortby} = "1";
$attr{$name}{webCmd} = "state";
$attr{$name}{room} = $attr{ $registeredResidentgroups[0] }{room}
if ( @registeredResidentgroups
&& exists( $attr{ $registeredResidentgroups[0] }{room} ) );
my $firstRgr = $hash->{RESIDENTGROUPS};
$firstRgr =~ s/,[\s\S]*$//gmi;
$attr{$name}{room} = $attr{$firstRgr}{room}
if ( exists( $attr{$firstRgr}{room} ) );
}
# trigger for modified objects
unless ( $modified == 0 ) {
readingsBulkUpdate( $hash, "state", ReadingsVal( $name, "state", "" ) );
}
readingsBulkUpdateIfChanged( $hash, "state",
ReadingsVal( $name, "state", "" ) );
readingsEndUpdate( $hash, 1 );
@ -181,18 +136,9 @@ sub ROOMMATE_Undefine($$) {
RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
my @registeredResidentgroups =
split( /,/, $hash->{RESIDENTGROUPS} );
# unregister at parent objects
foreach my $parent (@registeredResidentgroups) {
if ( defined( $defs{$parent} )
&& $defs{$parent}{TYPE} eq "RESIDENTS" )
{
fhem("set $parent unregister $name");
Log3 $name, 4,
"ROOMMATE $name: Unregistered at RESIDENTS device $parent";
}
foreach ( split( /,/, $hash->{RESIDENTGROUPS} ) ) {
RESIDENTStk_findResidentSlaves( $defs{$_} )
if ( defined( $defs{$_} ) );
}
}
@ -256,7 +202,7 @@ sub ROOMMATE_Notify($$) {
if (@registeredWakeupdevs) {
# if this is a notification of a registered wakeup device
if ( $devName ~~ @registeredWakeupdevs ) {
if ( grep { /^$devName$/ } @registeredWakeupdevs ) {
# Some previous notify deleted the array.
return
@ -294,7 +240,7 @@ sub ROOMMATE_Notify($$) {
}
# process PRESENCE
if ( @presenceDevices && $devName ~~ @presenceDevices ) {
if ( @presenceDevices && grep { /^$devName$/ } @presenceDevices ) {
my $counter = {
absent => 0,

View File

@ -1715,4 +1715,33 @@ sub RESIDENTStk_RemoveInternalTimer($$) {
}
}
sub RESIDENTStk_findResidentSlaves($) {
my ($hash) = @_;
return unless ( ref($hash) eq "HASH" && defined( $hash->{NAME} ) );
delete $hash->{ROOMMATES};
foreach ( devspec2array("TYPE=ROOMMATE") ) {
next
unless (
defined( $defs{$_}{RESIDENTGROUPS} )
&& grep { /^$hash->{NAME}$/ }
split( /,/, $defs{$_}{RESIDENTGROUPS} )
);
$hash->{ROOMMATES} .= "," if ( $hash->{ROOMMATES} );
$hash->{ROOMMATES} .= $_;
}
delete $hash->{GUESTS};
foreach ( devspec2array("TYPE=GUEST") ) {
next
unless (
defined( $defs{$_}{RESIDENTGROUPS} )
&& grep { /^$hash->{NAME}$/ }
split( /,/, $defs{$_}{RESIDENTGROUPS} )
);
$hash->{GUESTS} .= "," if ( $hash->{GUESTS} );
$hash->{GUESTS} .= $_;
}
}
1;