2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-03 23:06:37 +00:00

20_GUEST: add language helper; new attribute rg_lang

git-svn-id: https://svn.fhem.de/fhem/trunk@13616 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
jpawlowski 2017-03-05 18:36:46 +00:00
parent 9422e55356
commit 165a42d969

View File

@ -35,6 +35,7 @@ require RESIDENTStk;
sub GUEST_Set($@);
sub GUEST_Define($$);
sub GUEST_Notify($$);
sub GUEST_Attr(@);
sub GUEST_Undefine($$);
###################################
@ -46,9 +47,10 @@ sub GUEST_Initialize($) {
$hash->{SetFn} = "GUEST_Set";
$hash->{DefFn} = "GUEST_Define";
$hash->{NotifyFn} = "GUEST_Notify";
$hash->{AttrFn} = "GUEST_Attr";
$hash->{UndefFn} = "GUEST_Undefine";
$hash->{AttrList} =
"rg_locationHome rg_locationWayhome rg_locationUnderway rg_autoGoneAfter: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 "
"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 "
. $readingFnAttributes;
}
@ -82,6 +84,8 @@ sub GUEST_Define($$) {
# set default settings on first define
if ( $init_done && !defined( $hash->{OLDDEF} ) ) {
GUEST_Attr( "init", $name, "rg_lang" );
my $aliasname = $name;
$aliasname =~ s/^rg_//;
$attr{$name}{alias} = $aliasname;
@ -123,12 +127,86 @@ sub GUEST_Define($$) {
return undef;
}
###################################
sub GUEST_Attr(@) {
my ( $cmd, $name, $attribute, $value ) = @_;
my $hash = $defs{$name};
my $prefix = "rg_";
return unless ($init_done);
Log3 $name, 5, "GUEST $name: called function GUEST_Attr()";
if ( $attribute eq "disable" ) {
if ( $value and $value == 1 ) {
$hash->{STATE} = "disabled";
GUEST_StopInternalTimers($hash);
}
elsif ( $cmd eq "del" or !$value ) {
evalStateFormat($hash);
GUEST_StartInternalTimers( $hash, 1 );
}
}
elsif ( $attribute eq $prefix . "autoGoneAfter" ) {
if ($value) {
GUEST_AutoGone($hash);
}
elsif ( !$value ) {
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
}
}
elsif ( $attribute eq $prefix . "noDuration" ) {
if ($value) {
delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
}
elsif ( !$value ) {
GUEST_DurationTimer($hash);
}
}
elsif ( $attribute eq $prefix . "lang" ) {
my $lang =
$cmd eq "set" ? uc($value) : AttrVal( "global", "language", "EN" );
# for initial define, ensure fallback to EN
$lang = "EN"
if ( $cmd eq "init" && $lang !~ /^EN|DE$/i );
if ( $lang eq "DE" ) {
$attr{$name}{devStateIcon} =
'.*anwesend:user_available:absent .*abwesend:user_away:home .*keiner:control_building_empty:home .*bettfertig:scene_toilet:asleep .*schläft:scene_sleeping:awoken .*aufgestanden:scene_sleeping_alternat:home .*:user_unknown:home';
$attr{$name}{eventMap} =
"home:anwesend absent:abwesend none:keiner gotosleep:bettfertig asleep:schläft awoken:aufgestanden";
$attr{$name}{widgetOverride} =
"state:anwesend,bettfertig,abwesend,keiner";
}
elsif ( $lang eq "EN" ) {
$attr{$name}{devStateIcon} =
'.*home:user_available:absent .*absent:user_away:home .*none:control_building_empty:home .*gotosleep:scene_toilet:asleep .*asleep:scene_sleeping:awoken .*awoken:scene_sleeping_alternat:home .*:user_unknown:home';
delete $attr{$name}{eventMap}
if ( defined( $attr{$name}{eventMap} ) );
delete $attr{$name}{widgetOverride}
if ( defined( $attr{$name}{widgetOverride} ) );
}
else {
return "Unsupported language $lang";
}
evalStateFormat($hash);
}
return if ( IsDisabled($name) );
return;
}
###################################
sub GUEST_Undefine($$) {
my ( $hash, $name ) = @_;
RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
GUEST_StopInternalTimers($hash);
if ( defined( $hash->{RESIDENTGROUPS} ) ) {
my $old = $hash->{RESIDENTGROUPS};
@ -150,6 +228,7 @@ 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"
@ -282,6 +361,8 @@ sub GUEST_Set($@) {
my $location = ReadingsVal( $name, "location", "undefined" );
my $silent = 0;
return if ( IsDisabled($name) );
Log3 $name, 5, "GUEST $name: called function GUEST_Set()";
return "No Argument given" if ( !defined( $a[1] ) );
@ -652,6 +733,7 @@ sub GUEST_Set($@) {
GUEST_AutoGone($hash);
}
elsif ( $state eq "absent" ) {
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
}
}
@ -884,20 +966,19 @@ sub GUEST_Set($@) {
###################################
sub GUEST_AutoGone($;$) {
my ( $mHash, @a ) = @_;
my $hash = ( $mHash->{HASH} ) ? $mHash->{HASH} : $mHash;
my $name = $hash->{NAME};
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();
my $timeout = (
defined( $attr{$name}{rg_autoGoneAfter} )
? $attr{$name}{rg_autoGoneAfter}
: "16"
);
( $date, $time ) = split( ' ', $hash->{READINGS}{state}{TIME} );
( $y, $m, $d ) = split( '-', $date );
@ -906,13 +987,14 @@ sub GUEST_AutoGone($;$) {
$timestamp = timelocal( $sec, $min, $hour, $d, $m, $y );
$timeDiff = $timestampNow - $timestamp;
if ( $timeDiff >= $timeout * 3600 ) {
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 + $timeout * 3600;
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 );
@ -934,74 +1016,71 @@ sub GUEST_DurationTimer($;$) {
my $durPresence = "0";
my $durAbsence = "0";
my $durSleep = "0";
my $noDuration = AttrVal( $hash->{NAME}, "rg_noDuration", 0 );
delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
if ( !defined( $attr{$name}{rg_noDuration} )
|| $attr{$name}{rg_noDuration} == 0 )
return if ( IsDisabled($name) || $noDuration );
# presence timer
if ( ReadingsVal( $name, "presence", "absent" ) eq "present"
&& ReadingsVal( $name, "lastArrival", "-" ) ne "-" )
{
# 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 );
readingsBulkUpdate( $hash, "durTimerPresence_cr", $durPresence_cr )
if ( ReadingsVal( $name, "durTimerPresence_cr", "" ) ne
$durPresence_cr );
readingsBulkUpdate( $hash, "durTimerPresence", $durPresence_hr )
if (
ReadingsVal( $name, "durTimerPresence", "" ) ne $durPresence_hr );
readingsBulkUpdate( $hash, "durTimerAbsence_cr", $durAbsence_cr )
if (
ReadingsVal( $name, "durTimerAbsence_cr", "" ) ne $durAbsence_cr );
readingsBulkUpdate( $hash, "durTimerAbsence", $durAbsence_hr )
if ( ReadingsVal( $name, "durTimerAbsence", "" ) ne $durAbsence_hr );
readingsBulkUpdate( $hash, "durTimerSleep_cr", $durSleep_cr )
if ( ReadingsVal( $name, "durTimerSleep_cr", "" ) ne $durSleep_cr );
readingsBulkUpdate( $hash, "durTimerSleep", $durSleep_hr )
if ( ReadingsVal( $name, "durTimerSleep", "" ) ne $durSleep_hr );
readingsEndUpdate( $hash, 1 ) if ( !$silent );
$durPresence =
$timestampNow -
time_str2num( ReadingsVal( $name, "lastArrival", "" ) );
}
RESIDENTStk_InternalTimer( "DurationTimer", $timestampNow + 60,
# 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 );
readingsBulkUpdate( $hash, "durTimerPresence_cr", $durPresence_cr )
if ( ReadingsVal( $name, "durTimerPresence_cr", "" ) ne $durPresence_cr );
readingsBulkUpdate( $hash, "durTimerPresence", $durPresence_hr )
if ( ReadingsVal( $name, "durTimerPresence", "" ) ne $durPresence_hr );
readingsBulkUpdate( $hash, "durTimerAbsence_cr", $durAbsence_cr )
if ( ReadingsVal( $name, "durTimerAbsence_cr", "" ) ne $durAbsence_cr );
readingsBulkUpdate( $hash, "durTimerAbsence", $durAbsence_hr )
if ( ReadingsVal( $name, "durTimerAbsence", "" ) ne $durAbsence_hr );
readingsBulkUpdate( $hash, "durTimerSleep_cr", $durSleep_cr )
if ( ReadingsVal( $name, "durTimerSleep_cr", "" ) ne $durSleep_cr );
readingsBulkUpdate( $hash, "durTimerSleep", $durSleep_hr )
if ( ReadingsVal( $name, "durTimerSleep", "" ) ne $durSleep_hr );
readingsEndUpdate( $hash, 1 ) if ( !$silent );
$hash->{DURATIONTIMER} = $timestampNow + 60;
RESIDENTStk_InternalTimer( "DurationTimer", $hash->{DURATIONTIMER},
"GUEST_DurationTimer", $hash, 1 )
if ( $state ne "none" );
@ -1203,6 +1282,17 @@ sub GUEST_StartInternalTimers($$) {
GUEST_DurationTimer($hash);
}
###################################
sub GUEST_StopInternalTimers($) {
my ($hash) = @_;
delete $hash->{AUTOGONE} if ( $hash->{AUTOGONE} );
delete $hash->{DURATIONTIMER} if ( $hash->{DURATIONTIMER} );
RESIDENTStk_RemoveInternalTimer( "AutoGone", $hash );
RESIDENTStk_RemoveInternalTimer( "DurationTimer", $hash );
}
1;
=pod
@ -1358,6 +1448,9 @@ sub GUEST_StartInternalTimers($$) {
<li>
<b>rg_geofenceUUIDs</b> - comma separated list of device UUIDs updating their location via <a href="#GEOFANCY">GEOFANCY</a>. Avoids necessity for additional notify/DOIF/watchdog devices and can make GEOFANCY attribute <i>devAlias</i> obsolete. (using more than one UUID/device might not be a good idea as location my leap)
</li>
<li>
<b>rg_lang</b> - overwrite global language setting; helps to set device attributes to translate FHEMWEB display text
</li>
<li>
<b>rg_locationHome</b> - locations matching these will be treated as being at home; first entry reflects default value to be used with state correlation; separate entries by space; defaults to 'home'
</li>
@ -1380,7 +1473,7 @@ sub GUEST_StartInternalTimers($$) {
<b>rg_moods</b> - list of moods to be shown in FHEMWEB; separate entries by comma only and do NOT use spaces
</li>
<li>
<b>rg_noDuration</b> - may be used to disable duration timer calculation (see readings durTimer*)
<b>rg_noDuration</b> - may be used to disable continuous, non-event driven duration timer calculation (see readings durTimer*)
</li>
<li>
<b>rg_passPresenceTo</b> - synchronize presence state with other GUEST or GUEST devices; separte devices by space
@ -1655,6 +1748,9 @@ sub GUEST_StartInternalTimers($$) {
<li>
<b>rg_geofenceUUIDs</b> - Mit Komma getrennte Liste von Ger&auml;te UUIDs, die ihren Standort &uuml;ber <a href="#GEOFANCY">GEOFANCY</a> aktualisieren. Vermeidet zus&auml;tzliche notify/DOIF/watchdog Ger&auml;te und kann als Ersatz f&uuml;r das GEOFANCY attribute <i>devAlias</i> dienen. (hier ehr als eine UUID/Device zu hinterlegen ist eher keine gute Idee da die Lokation dann wom&ouml;glich anf&auml;ngt zu springen)
</li>
<li>
<b>rg_lang</b> - &uuml;berschreibt globale Spracheinstellung; hilft beim setzen von Device Attributen, um FHEMWEB Anzeigetext zu &uuml;bersetzen
</li>
<li>
<b>rg_locationHome</b> - hiermit &uuml;bereinstimmende Lokationen werden als zu Hause gewertet; der erste Eintrag wird f&uuml;r das Zusammenspiel bei Status&auml;nderungen benutzt; mehrere Eintr&auml;ge durch Leerzeichen trennen; Standard ist 'home'
</li>
@ -1677,7 +1773,7 @@ sub GUEST_StartInternalTimers($$) {
<b>rg_moods</b> - Liste von Stimmungen, wie sie in FHEMWEB angezeigt werden sollen; mehrere Eintr&auml;ge nur durch Komma trennen und KEINE Leerzeichen verwenden
</li>
<li>
<b>rg_noDuration</b> - deaktiviert die Berechnung der Zeitspannen (siehe Readings durTimer*)
<b>rg_noDuration</b> - deaktiviert die kontinuierliche, nicht Event-basierte Berechnung der Zeitspannen (siehe Readings durTimer*)
</li>
<li>
<b>rg_passPresenceTo</b> - synchronisiere die Anwesenheit mit anderen GUEST oder ROOMMATE Devices; mehrere Devices durch Leerzeichen trennen