2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-02-01 13:29:26 +00:00

HOMESTATEtk: add homealone support

git-svn-id: https://svn.fhem.de/fhem/trunk@19386 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
jpawlowski 2019-05-14 16:47:14 +00:00
parent 5d33f71232
commit 2400deb9cc
6 changed files with 221 additions and 70 deletions

View File

@ -7,6 +7,7 @@ use Data::Dumper;
use Time::Local;
require RESIDENTStk;
our ( %RESIDENTStk_types, %RESIDENTStk_subTypes );
# initialize ##################################################################
sub RESIDENTS_Initialize($) {
@ -29,7 +30,7 @@ sub RESIDENTS_Initialize($) {
. "rgr_showAllStates:0,1 "
. "rgr_wakeupDevice "
. "rgr_homealoneInStatus:0,1 "
. "rgr_homealoneSubTypes:multiple-strict,pet,bird,pig,monkey,cat,dog,baby,toddler,minor,child,guest,domesticWorker,vacationer,teenager,senior "
. "rgr_homealoneSubTypes:multiple-strict,pet,bird,pig,monkey,cat,dog,baby,toddler,childcare,child,guest,domesticWorker,vacationer,teenager,senior "
. $readingFnAttributes;
return FHEM::Meta::InitMod( __FILE__, $hash );
@ -47,7 +48,7 @@ sub RESIDENTS_UpdateReadings (@) {
AttrVal(
$name,
"rgr_homealoneSubTypes",
"pet,bird,pig,monkey,cat,dog,baby,toddler,minor,child,guest,domesticWorker,vacationer,teenager,senior"
"pet,bird,pig,monkey,cat,dog,baby,toddler,childcare,child,guest,domesticWorker,vacationer,teenager,senior"
)
);
@ -456,7 +457,7 @@ sub RESIDENTS_UpdateReadings (@) {
my $SubType =
defined( $defs{$roommate}{SUBTYPE} )
? $defs{$roommate}{SUBTYPE}
: 'generic';
: 'adult';
$state_homealone = 0
unless ( grep m/^$SubType$/, @homealoneSubTypes );
@ -1297,13 +1298,16 @@ sub RESIDENTS_UpdateReadings (@) {
next unless $TYPE;
my $subtype = 'generic';
$subtype = InternalVal( $obj, 'SUBTYPE', 'pet' )
$subtype = InternalVal( $obj, 'SUBTYPE', 'generic' )
if ( $TYPE eq 'PET' );
$subtype = InternalVal( $obj, 'SUBTYPE', 'adult' )
if ( $TYPE eq 'ROOMMATE' );
$subtype = InternalVal( $obj, 'SUBTYPE', 'guest' )
$subtype = InternalVal( $obj, 'SUBTYPE', 'generic' )
if ( $TYPE eq 'GUEST' );
$subtype = $RESIDENTStk_types{en}{$TYPE}
if ( $subtype eq 'generic' );
my $importance = 99;
my (@index) = grep { $homealoneSubTypes[$_] eq $subtype }
0 .. scalar @homealoneSubTypes - 1;

View File

@ -26,7 +26,7 @@ sub GUEST_Initialize($) {
"disable:1,0 disabledForIntervals do_not_notify:1,0 "
. "rg_states:multiple-strict,home,gotosleep,asleep,awoken,absent,none "
. "subType:"
. join( ',', @{ $RESIDENTStk_subTypes{GUEST} } ) . " "
. join( ',', @{ $RESIDENTStk_subTypes{en}{GUEST} } ) . " "
. $readingFnAttributes;
foreach (@RESIDENTStk_attr) {

View File

@ -26,7 +26,7 @@ sub PET_Initialize($) {
"disable:1,0 disabledForIntervals do_not_notify:1,0 "
. "rp_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone "
. "subType:"
. join( ',', @{ $RESIDENTStk_subTypes{PET} } ) . " "
. join( ',', @{ $RESIDENTStk_subTypes{en}{PET} } ) . " "
. $readingFnAttributes;
foreach (@RESIDENTStk_attr) {

View File

@ -26,7 +26,7 @@ sub ROOMMATE_Initialize($) {
"disable:1,0 disabledForIntervals do_not_notify:1,0 "
. "rr_states:multiple-strict,home,gotosleep,asleep,awoken,absent,gone "
. "subType:"
. join( ',', @{ $RESIDENTStk_subTypes{ROOMMATE} } ) . " "
. join( ',', @{ $RESIDENTStk_subTypes{en}{ROOMMATE} } ) . " "
. $readingFnAttributes;
foreach (@RESIDENTStk_attr) {

View File

@ -4,9 +4,9 @@ package main;
use strict;
use warnings;
use Data::Dumper;
use Time::Local;
require RESIDENTStk;
our ( %RESIDENTStk_types, %RESIDENTStk_subTypes );
# module variables ############################################################
my %stateSecurity = (
@ -39,7 +39,7 @@ my %readingsMap = (
dst_long => 'calTodDST',
isholiday => 'calTodHoliday',
isly => 'calTodLeapyear',
iswe => 'calTodTodWeekend',
iswe => 'calTodWeekend',
mday => 'calTodMonthday',
mdayrem => 'calTodMonthdayRem',
monISO => 'calTodMonthN',
@ -124,7 +124,8 @@ sub HOMESTATEtk_Initialize($) {
" HolidayDevices:multiple,"
. join( ",", devspec2array( "TYPE=holiday" . $holidayFilter ) );
$hash->{AttrList} .= " ResidentsDevices:multiple,"
. join( ",", devspec2array("TYPE=RESIDENTS,TYPE=ROOMMATE,TYPE=GUEST") );
. join( ",",
devspec2array("TYPE=RESIDENTS,TYPE=ROOMMATE,TYPE=PET,TYPE=GUEST") );
}
# module Fn ####################################################################
@ -269,12 +270,12 @@ sub HOMESTATEtk_Define($$$) {
$attr{$name}{icon} = "control_building_control"
if ( $TYPE eq "HOMESTATE" );
$attr{$name}{icon} = "control_building_eg"
if ( $TYPE eq "SECTIONSTATE" );
if ( $TYPE eq "ZONESTATE" );
$attr{$name}{icon} = "floor"
if ( $TYPE eq "ROOMSTATE" );
# find HOMESTATE device
if ( $TYPE eq "ROOMSTATE" || $TYPE eq "SECTIONSTATE" ) {
if ( $TYPE eq "ROOMSTATE" || $TYPE eq "ZONESTATE" ) {
my @homestates = devspec2array("TYPE=HOMESTATE");
if ( scalar @homestates ) {
$attr{$name}{"HomestateDevices"} = $homestates[0];
@ -310,7 +311,7 @@ sub HOMESTATEtk_Define($$$) {
}
# find ROOMSTATE device
if ( $TYPE eq "SECTIONSTATE" ) {
if ( $TYPE eq "ZONESTATE" ) {
my @roomstates = devspec2array("TYPE=ROOMSTATE");
unless ( scalar @roomstates ) {
my $n = "Room";
@ -334,7 +335,8 @@ sub HOMESTATEtk_Define($$$) {
# find RESIDENTS device
if ( $TYPE eq "HOMESTATE" ) {
my @residents = devspec2array("TYPE=RESIDENTS,TYPE=ROOMMATE");
my @residents =
devspec2array("TYPE=RESIDENTS,TYPE=ROOMMATE,TYPE=PET");
if ( scalar @residents ) {
$attr{$name}{"ResidentsDevices"} = $residents[0];
$attr{$name}{room} = $attr{ $residents[0] }{room}
@ -696,8 +698,8 @@ sub HOMESTATEtk_Attr(@) {
unless ( $cmd eq "del"
|| $value =~ m/^[A-Za-z\d._]+(?:,[A-Za-z\d._]*)*$/ );
delete $hash->{SECTIONSTATES};
$hash->{SECTIONSTATES} = $value unless ( $cmd eq "del" );
delete $hash->{ZONESTATES};
$hash->{ZONESTATES} = $value unless ( $cmd eq "del" );
}
elsif ( $attribute eq "RoomstateDevices" ) {
@ -775,7 +777,7 @@ sub HOMESTATEtk_Attr(@) {
if ( !defined( $attr{$name}{group} )
|| $attr{$name}{group} eq "Home State" );
}
if ( $TYPE eq "SECTIONSTATE" ) {
if ( $TYPE eq "ZONESTATE" ) {
$attr{$name}{group} = "Bereichstatus"
if ( !defined( $attr{$name}{group} )
|| $attr{$name}{group} eq "Section State" );
@ -800,7 +802,7 @@ sub HOMESTATEtk_Attr(@) {
if ( !defined( $attr{$name}{group} )
|| $attr{$name}{group} eq "Zuhause Status" );
}
if ( $TYPE eq "SECTIONSTATE" ) {
if ( $TYPE eq "ZONESTATE" ) {
$attr{$name}{group} = "Section State"
if ( !defined( $attr{$name}{group} )
|| $attr{$name}{group} eq "Bereichstatus" );
@ -910,11 +912,11 @@ m/^((?:DELETE)?ATTR)\s+([A-Za-z\d._]+)\s+([A-Za-z\d_\.\-\/]+)(?:\s+(.*)\s*)?$/
return "" if ( IsDisabled($name) or IsDisabled($devName) );
# process events from RESIDENTS, ROOMMATE or GUEST devices
# process events from RESIDENTS, ROOMMATE, PET or GUEST devices
# only when they hit HOMESTATE devices
if ( $TYPE ne $devType
&& $devType =~
m/^HOMESTATE|SECTIONSTATE|ROOMSTATE|RESIDENTS|ROOMMATE|GUEST$/ )
m/^HOMESTATE|ZONESTATE|ROOMSTATE|RESIDENTS|ROOMMATE|PET|GUEST$/ )
{
my $events = deviceEvents( $dev, 1 );
@ -925,6 +927,7 @@ m/^((?:DELETE)?ATTR)\s+([A-Za-z\d._]+)\s+([A-Za-z\d_\.\-\/]+)(?:\s+(.*)\s*)?$/
# state changed
if ( $event !~ /^[a-zA-Z\d._]+:/
|| $event =~ /^homealoneType:/
|| $event =~ /^state:/
|| $event =~ /^presence:/
|| $event =~ /^mode:/
@ -973,31 +976,31 @@ sub HOMESTATEtk_findHomestateSlaves($;$) {
if ( $hash->{TYPE} eq "HOMESTATE" ) {
my @SECTIONSTATES;
foreach ( devspec2array("TYPE=SECTIONSTATE") ) {
my @ZONESTATES;
foreach ( devspec2array("TYPE=ZONESTATE") ) {
next
unless (
defined( $defs{$_}{SECTIONSTATES} )
defined( $defs{$_}{ZONESTATES} )
&& grep { $hash->{NAME} eq $_ }
split( /,/, $defs{$_}{SECTIONSTATES} )
split( /,/, $defs{$_}{ZONESTATES} )
);
push @SECTIONSTATES, $_;
push @ZONESTATES, $_;
}
if ( scalar @SECTIONSTATES ) {
$hash->{SECTIONSTATES} = join( ",", @SECTIONSTATES );
if ( scalar @ZONESTATES ) {
$hash->{ZONESTATES} = join( ",", @ZONESTATES );
}
elsif ( $hash->{SECTIONSTATES} ) {
delete $hash->{SECTIONSTATES};
elsif ( $hash->{ZONESTATES} ) {
delete $hash->{ZONESTATES};
}
if ( $hash->{SECTIONSTATES} ) {
if ( $hash->{ZONESTATES} ) {
$ret .= "," if ($ret);
$ret .= $hash->{SECTIONSTATES};
$ret .= $hash->{ZONESTATES};
}
}
if ( $hash->{TYPE} eq "HOMESTATE" || $hash->{TYPE} eq "SECTIONSTATE" ) {
if ( $hash->{TYPE} eq "HOMESTATE" || $hash->{TYPE} eq "ZONESTATE" ) {
my @ROOMSTATES;
foreach ( devspec2array("TYPE=ROOMSTATE") ) {
@ -1009,9 +1012,9 @@ sub HOMESTATEtk_findHomestateSlaves($;$) {
split( /,/, $defs{$_}{HOMESTATES} )
)
|| (
defined( $defs{$_}{SECTIONSTATES} )
defined( $defs{$_}{ZONESTATES} )
&& grep { $hash->{NAME} eq $_ }
split( /,/, $defs{$_}{SECTIONSTATES} )
split( /,/, $defs{$_}{ZONESTATES} )
)
);
push @ROOMSTATES, $_;
@ -1058,27 +1061,60 @@ sub HOMESTATEtk_devStateIcon($) {
my $langUc = uc($lang);
my @devStateIcon;
# mode
# homeAlone
my $i = 0;
foreach ( @{ $UConv::daytimes{en} } ) {
push @devStateIcon, "$_:$UConv::daytimes{icons}[$i++]:toggle";
foreach my $TYPE ( keys %{ $RESIDENTStk_subTypes{en} } ) {
$i = 0;
foreach my $subType ( @{ $RESIDENTStk_subTypes{en}{$TYPE} } ) {
$subType = $RESIDENTStk_types{en}{$TYPE}
if ( $subType eq 'generic' );
push @devStateIcon,
$subType . "_.+:"
. $RESIDENTStk_subTypes{icons}{$TYPE}[ $i++ ]
. ":toggle";
}
}
unless ( $lang eq "en" && defined( $UConv::daytimes{$lang} ) ) {
unless ( $lang ne "en" && defined( $RESIDENTStk_subTypes{$lang} ) ) {
foreach my $TYPE ( keys %{ $RESIDENTStk_subTypes{$lang} } ) {
$i = 0;
foreach my $subType ( @{ $RESIDENTStk_subTypes{en}{$TYPE} } ) {
if ( $subType eq 'generic' ) {
$subType = $RESIDENTStk_types{$lang}{$TYPE};
}
else {
$subType = $RESIDENTStk_subTypes{$lang}{$TYPE}[$i];
}
push @devStateIcon,
$subType . "_.+:"
. $RESIDENTStk_subTypes{icons}{$TYPE}[ $i++ ]
. ":toggle";
}
}
}
# mode
$i = 0;
foreach ( @{ $UConv::daytimes{en} } ) {
push @devStateIcon,
$_ . ":" . $UConv::daytimes{icons}[ $i++ ] . ":toggle";
}
if ( $lang ne "en" && defined( $UConv::daytimes{$lang} ) ) {
$i = 0;
foreach ( @{ $UConv::daytimes{$lang} } ) {
push @devStateIcon, "$_:$UConv::daytimes{icons}[$i++]:toggle";
push @devStateIcon,
$_ . ":" . $UConv::daytimes{icons}[ $i++ ] . ":toggle";
}
}
# security
$i = 0;
foreach ( @{ $stateSecurity{en} } ) {
push @devStateIcon, "$_:$stateSecurity{icons}[$i++]";
push @devStateIcon, $_ . ":" . $stateSecurity{icons}[ $i++ ];
}
unless ( $lang eq "en" && defined( $UConv::daytimes{$lang} ) ) {
if ( $lang ne "en" && defined( $UConv::daytimes{$lang} ) ) {
$i = 0;
foreach ( @{ $stateSecurity{$lang} } ) {
push @devStateIcon, "$_:$stateSecurity{icons}[$i++]";
push @devStateIcon, $_ . ":" . $stateSecurity{icons}[ $i++ ];
}
}
@ -1162,19 +1198,40 @@ sub HOMESTATEtk_UpdateReadings (@) {
my $state_awoken = 0;
my $state_absent = 0;
my $state_gone = 0;
my $wayhome = 0;
my $wayhomeDelayed = 0;
my $wakeup = 0;
foreach my $internal ( "RESIDENTS", "SECTIONSTATES", "ROOMSTATES" ) {
my $state_homealoneType;
my $state_homealoneSubtype;
my $wayhome = 0;
my $wayhomeDelayed = 0;
my $wakeup = 0;
foreach my $internal ( "RESIDENTS", "ZONESTATES", "ROOMSTATES" ) {
next unless ( $hash->{$internal} );
foreach my $presenceDev ( split( /,/, $hash->{$internal} ) ) {
my $state = ReadingsVal( $presenceDev, "state", "gone" );
$state_home++ if ( $state eq "home" );
$state_gotosleep++ if ( $state eq "gotosleep" );
$state_asleep++ if ( $state eq "asleep" );
$state_awoken++ if ( $state eq "awoken" );
$state_absent++ if ( $state eq "absent" );
$state_gone++ if ( $state eq "gone" || $state eq "none" );
$state_home++ if ( $state =~ /home$/ );
$state_gotosleep++ if ( $state =~ /gotosleep$/ );
$state_asleep++ if ( $state =~ /asleep$/ );
$state_awoken++ if ( $state =~ /awoken$/ );
$state_absent++ if ( $state =~ /absent$/ );
$state_gone++ if ( $state =~ /(?:gone|none)$/ );
my $homealoneType =
ReadingsVal( $presenceDev, "homealoneType", "-" );
my $homealoneSubtype =
ReadingsVal( $presenceDev, "homealoneSubtype", "-" );
if (
$homealoneType ne '-'
&& (
!$state_homealoneType
|| ( $state_homealoneType eq 'PET'
&& $homealoneType ne 'PET' )
)
)
{
$state_homealoneType = $homealoneType;
$state_homealoneSubtype = $homealoneSubtype;
}
my $wayhome = ReadingsVal( $presenceDev, "wayhome", 0 );
$wayhome++ if ($wayhome);
@ -1186,7 +1243,7 @@ sub HOMESTATEtk_UpdateReadings (@) {
}
$state_home = 1
unless ( $hash->{RESIDENTS}
|| $hash->{SECTIONSTATES}
|| $hash->{ZONESTATES}
|| $hash->{ROOMSTATES} );
# autoMode
@ -1229,21 +1286,40 @@ sub HOMESTATEtk_UpdateReadings (@) {
my $newsecurity;
# unsecured
if ( $state_home > 0 && $mode !~ /^night|midevening$/ ) {
if (
$state_home > 0
&& $mode !~ /^night|midevening$/
&& (
!$state_homealoneType
|| (
$state_homealoneType eq 'GUEST'
&& ( $state_homealoneSubtype eq 'guest'
|| $state_homealoneSubtype eq 'generic'
|| $state_homealoneSubtype eq 'domesticWorker'
|| $state_homealoneSubtype eq 'vacationer' )
)
)
)
{
$newsecurity = "unlocked";
}
# locked
elsif ($state_home > 0
|| $state_awoken > 0
|| $state_gotosleep > 0
|| $wakeup > 0 )
elsif (
( !$state_homealoneType || $state_homealoneType ne 'PET' )
&& ( $state_home > 0
|| $state_awoken > 0
|| $state_gotosleep > 0
|| $wakeup > 0 )
)
{
$newsecurity = "locked";
}
# night
elsif ( $state_asleep > 0 ) {
# night or pet at home
elsif ( $state_asleep > 0
|| ( $state_homealoneType && $state_homealoneType eq 'PET' ) )
{
$newsecurity = "protected";
}
@ -1277,7 +1353,7 @@ sub HOMESTATEtk_UpdateReadings (@) {
#
# state calculation:
# combine security and mode
# combine security, mode and homealone
#
my $newstate;
my $statesrc;
@ -1294,16 +1370,48 @@ sub HOMESTATEtk_UpdateReadings (@) {
$statesrc = "security";
}
# homealone
if ($state_homealoneType) {
my $hs;
if ( $state_homealoneSubtype eq 'generic'
|| $state_homealoneType eq 'PET' )
{
$hs = $RESIDENTStk_types{en}{$state_homealoneType};
}
else {
$hs = $state_homealoneSubtype;
}
$newstate = $hs . '_' . $newstate;
}
if ( $newstate ne $state ) {
readingsBulkUpdate( $hash, "lastState", $state ) if ( $state ne "" );
readingsBulkUpdate( $hash, "state", $newstate );
$state = $newstate;
readingsBulkUpdate( $hash, "state", $state );
unless ( $lang eq "en" ) {
my $stateL = ReadingsVal( $name, "state_$langUc", "" );
readingsBulkUpdate( $hash, "lastState_$langUc", $stateL )
if ( $stateL ne "" );
$stateL = ReadingsVal( $name, $statesrc . "_$langUc", "" );
if ($state_homealoneType) {
my $hs;
if ( $state_homealoneSubtype eq 'generic'
|| $state_homealoneType eq 'PET' )
{
$hs = $RESIDENTStk_types{$lang}{$state_homealoneType};
}
else {
$hs = $RESIDENTStk_subTypes{$lang}{$state_homealoneType}[
HOMESTATEtk_GetIndexFromArray( $state_homealoneSubtype,
$RESIDENTStk_subTypes{en}{$state_homealoneType} )
];
}
$stateL = $hs . '_' . $stateL;
}
readingsBulkUpdate( $hash, "state_$langUc", $stateL );
}
}
@ -1312,7 +1420,6 @@ sub HOMESTATEtk_UpdateReadings (@) {
1;
=pod
=encoding utf8

View File

@ -7,7 +7,7 @@ use Data::Dumper;
use Unit;
use FHEM::Meta;
our ( @RESIDENTStk_attr, %RESIDENTStk_subTypes );
our ( @RESIDENTStk_attr, %RESIDENTStk_types, %RESIDENTStk_subTypes );
# module variables ############################################################
@RESIDENTStk_attr = (
@ -31,10 +31,50 @@ our ( @RESIDENTStk_attr, %RESIDENTStk_subTypes );
"wakeupDevice",
);
%RESIDENTStk_types = (
en => {
ROOMMATE => 'roommate',
GUEST => 'guest',
PET => 'pet',
},
de => {
ROOMMATE => 'Bewohner',
GUEST => 'Gast',
PET => 'Haustier',
},
);
%RESIDENTStk_subTypes = (
ROOMMATE => [ 'baby', 'toddler', 'child', 'teenager', 'adult', 'senior' ],
GUEST => [ 'generic', 'minor', 'domesticWorker', 'vacationer' ],
PET => [ 'generic', 'bird', 'cat', 'dog', 'monkey', 'pig' ]
en => {
ROOMMATE =>
[ 'baby', 'toddler', 'child', 'teenager', 'adult', 'senior' ],
GUEST => [ 'generic', 'childcare', 'domesticWorker', 'vacationer' ],
PET => [ 'generic', 'bird', 'cat', 'dog', 'monkey', 'pig' ]
},
de => {
ROOMMATE => [
'Säugling', 'Kleinkind', 'Kind', 'Teenager',
'Erwachsener', 'Senior'
],
GUEST =>
[ 'generisch', 'Kinderbetreuung', 'Hausangestellter', 'Urlaubsgast' ],
PET => [ 'generisch', 'Vogel', 'Katze', 'Hund', 'Affe', 'Schwein' ]
},
icons => {
ROOMMATE => [
'scene_baby@orange', 'scene_childs_room@orange',
'scene_childs_room@orange', 'people_sensor@orange',
'people_sensor@green', 'people_sensor@orange'
],
GUEST => [
'scene_visit_guests@orange', 'scene_childs_room@orange',
'scene_cleaning@orange', 'scene_visit_guests@orange'
],
PET => [
'dog_silhouette@green', 'dog_silhouette@green',
'dog_silhouette@green', 'dog_silhouette@green',
'dog_silhouette@green', 'dog_silhouette@green'
]
},
);
## initialize #################################################################
@ -1126,8 +1166,8 @@ m/^([a-zA-Z\d._]+(:[A-Za-z\d_\.\-\/]+)?,?)([a-zA-Z\d._]+(:[A-Za-z\d_\.\-\/]+)?,?
return "invalid value $value"
unless (
$cmd eq "del"
|| defined( $RESIDENTStk_subTypes{$TYPE} ) && grep m/^$value$/,
@{ $RESIDENTStk_subTypes{$TYPE} }
|| defined( $RESIDENTStk_subTypes{en}{$TYPE} ) && grep m/^$value$/,
@{ $RESIDENTStk_subTypes{en}{$TYPE} }
);
if ( $cmd eq "del" ) {
$hash->{SUBTYPE} = 'generic'