diff --git a/fhem/FHEM/HOMESTATEtk.pm b/fhem/FHEM/HOMESTATEtk.pm index d4645c79c..7cd799c78 100644 --- a/fhem/FHEM/HOMESTATEtk.pm +++ b/fhem/FHEM/HOMESTATEtk.pm @@ -139,6 +139,7 @@ sub HOMESTATEtk_InitializeDev($) { my $langUc = uc($lang); my @error; + delete $hash->{NEXT_EVENT}; RemoveInternalTimer($hash); no strict "refs"; @@ -254,6 +255,7 @@ sub HOMESTATEtk_Define($$$) { $hash->{MOD_INIT} = 1; $hash->{NOTIFYDEV} = "global"; + delete $hash->{NEXT_EVENT}; RemoveInternalTimer($hash); # set default settings on first define @@ -267,12 +269,12 @@ sub HOMESTATEtk_Define($$$) { $attr{$name}{icon} = "control_building_control" if ( $TYPE eq "HOMESTATE" ); $attr{$name}{icon} = "control_building_eg" - if ( $TYPE eq "FLOORSTATE" ); + if ( $TYPE eq "SECTIONSTATE" ); $attr{$name}{icon} = "floor" if ( $TYPE eq "ROOMSTATE" ); # find HOMESTATE device - if ( $TYPE eq "ROOMSTATE" || $TYPE eq "FLOORSTATE" ) { + if ( $TYPE eq "ROOMSTATE" || $TYPE eq "SECTIONSTATE" ) { my @homestates = devspec2array("TYPE=HOMESTATE"); if ( scalar @homestates ) { $attr{$name}{"HomestateDevices"} = $homestates[0]; @@ -308,7 +310,7 @@ sub HOMESTATEtk_Define($$$) { } # find ROOMSTATE device - if ( $TYPE eq "FLOORSTATE" ) { + if ( $TYPE eq "SECTIONSTATE" ) { my @roomstates = devspec2array("TYPE=ROOMSTATE"); unless ( scalar @roomstates ) { my $n = "Room"; @@ -359,12 +361,6 @@ sub HOMESTATEtk_Define($$$) { "Auto-created by $TYPE module for use with HOMESTATE Toolkit"; $attr{$name}{"ResidentsDevices"} = $n; $attr{$n}{room} = $attr{$name}{room}; - $attr{$name}{"Lang"} = $attr{ $residents[0] }{rgr_lang} - if ( $attr{ $residents[0] } - && $attr{ $residents[0] }{rgr_lang} ); - $attr{$name}{"Lang"} = $attr{ $residents[0] }{rr_lang} - if ( $attr{ $residents[0] } - && $attr{ $residents[0] }{rr_lang} ); HOMESTATEtk_Attr( "set", $name, "Lang", $attr{$name}{"Lang"} ) if $attr{$name}{"Lang"}; @@ -379,6 +375,7 @@ sub HOMESTATEtk_Define($$$) { sub HOMESTATEtk_Undefine($$) { my ( $hash, $name ) = @_; + delete $hash->{NEXT_EVENT}; RemoveInternalTimer($hash); return undef; } @@ -631,21 +628,24 @@ sub HOMESTATEtk_Get($$$) { return "invalid date format $date" unless ( !$date || $date =~ m/^\d{4}\-\d{2}-\d{2}$/ - || $date =~ m/^\d{2}-\d{2}$/ ); + || $date =~ m/^\d{2}-\d{2}$/ + || $date =~ m/^\d{10}$/ ); return "invalid time format $time" unless ( !$time || $time =~ m/^\d{2}:\d{2}(:\d{2})?$/ ); - my ( $sec, $min, $hour, $mday, $mon, $year ) = UConv::_time(); - $date = "$year-$date" if ( $date =~ m/^\d{2}-\d{2}$/ ); - $time .= ":00" if ( $time && $time =~ m/^\d{2}:\d{2}$/ ); + unless ( $date =~ m/^\d{10}$/ ) { + my ( $sec, $min, $hour, $mday, $mon, $year ) = UConv::_time(); + $date = "$year-$date" if ( $date =~ m/^\d{2}-\d{2}$/ ); + $time .= ":00" if ( $time && $time =~ m/^\d{2}:\d{2}$/ ); - $date .= $time ? " $time" : " 00:00:00"; + $date .= $time ? " $time" : " 00:00:00"; - # ( $year, $mon, $mday, $hour, $min, $sec ) = - # split( /[\s.:-]+/, $date ); - # $date = timelocal( $sec, $min, $hour, $mday, $mon - 1, $year ); - $date = time_str2num($date); + # ( $year, $mon, $mday, $hour, $min, $sec ) = + # split( /[\s.:-]+/, $date ); + # $date = timelocal( $sec, $min, $hour, $mday, $mon - 1, $year ); + $date = time_str2num($date); + } } #TODO timelocal? 03-26 results in wrong timestamp @@ -679,7 +679,7 @@ sub HOMESTATEtk_Attr(@) { my $security = ReadingsVal( $name, "security", "" ); return - "Device is currently $security and attributes cannot be changed at this state" +"Device is currently $security and attributes cannot be changed at this state" unless ( !$init_done || $security =~ m/^unlocked|locked$/ ); if ( $attribute eq "HomestateDevices" ) { @@ -696,8 +696,8 @@ sub HOMESTATEtk_Attr(@) { unless ( $cmd eq "del" || $value =~ m/^[A-Za-z\d._]+(?:,[A-Za-z\d._]*)*$/ ); - delete $hash->{FLOORSTATES}; - $hash->{FLOORSTATES} = $value unless ( $cmd eq "del" ); + delete $hash->{SECTIONSTATES}; + $hash->{SECTIONSTATES} = $value unless ( $cmd eq "del" ); } elsif ( $attribute eq "RoomstateDevices" ) { @@ -775,10 +775,10 @@ sub HOMESTATEtk_Attr(@) { if ( !defined( $attr{$name}{group} ) || $attr{$name}{group} eq "Home State" ); } - if ( $TYPE eq "FLOORSTATE" ) { - $attr{$name}{group} = "Flurstatus" + if ( $TYPE eq "SECTIONSTATE" ) { + $attr{$name}{group} = "Bereichstatus" if ( !defined( $attr{$name}{group} ) - || $attr{$name}{group} eq "Floor State" ); + || $attr{$name}{group} eq "Section State" ); } if ( $TYPE eq "ROOMSTATE" ) { $attr{$name}{group} = "Raumstatus" @@ -800,10 +800,10 @@ sub HOMESTATEtk_Attr(@) { if ( !defined( $attr{$name}{group} ) || $attr{$name}{group} eq "Zuhause Status" ); } - if ( $TYPE eq "FLOORSTATE" ) { - $attr{$name}{group} = "Floor State" + if ( $TYPE eq "SECTIONSTATE" ) { + $attr{$name}{group} = "Section State" if ( !defined( $attr{$name}{group} ) - || $attr{$name}{group} eq "Flurstatus" ); + || $attr{$name}{group} eq "Bereichstatus" ); } if ( $TYPE eq "ROOMSTATE" ) { $attr{$name}{group} = "Room State" @@ -891,10 +891,12 @@ m/^((?:DELETE)?ATTR)\s+([A-Za-z\d._]+)\s+([A-Za-z\d_\.\-\/]+)(?:\s+(.*)\s*)?$/ # when own attributes were changed if ( $d eq $name ) { if ( defined( &{'DoInitDev'} ) ) { + delete $hash->{NEXT_EVENT}; RemoveInternalTimer($hash); InternalTimer( gettimeofday() + 0.5, "DoInitDev", $hash ); } else { + delete $hash->{NEXT_EVENT}; RemoveInternalTimer($hash); InternalTimer( gettimeofday() + 0.5, "RESIDENTStk_DoInitDev", $hash ); @@ -912,7 +914,7 @@ m/^((?:DELETE)?ATTR)\s+([A-Za-z\d._]+)\s+([A-Za-z\d_\.\-\/]+)(?:\s+(.*)\s*)?$/ # only when they hit HOMESTATE devices if ( $TYPE ne $devType && $devType =~ - m/^HOMESTATE|FLOORSTATE|ROOMSTATE|RESIDENTS|ROOMMATE|GUEST$/ ) + m/^HOMESTATE|SECTIONSTATE|ROOMSTATE|RESIDENTS|ROOMMATE|GUEST$/ ) { my $events = deviceEvents( $dev, 1 ); @@ -971,31 +973,31 @@ sub HOMESTATEtk_findHomestateSlaves($;$) { if ( $hash->{TYPE} eq "HOMESTATE" ) { - my @FLOORSTATES; - foreach ( devspec2array("TYPE=FLOORSTATE") ) { + my @SECTIONSTATES; + foreach ( devspec2array("TYPE=SECTIONSTATE") ) { next unless ( - defined( $defs{$_}{FLOORSTATES} ) + defined( $defs{$_}{SECTIONSTATES} ) && grep { $hash->{NAME} eq $_ } - split( /,/, $defs{$_}{FLOORSTATES} ) + split( /,/, $defs{$_}{SECTIONSTATES} ) ); - push @FLOORSTATES, $_; + push @SECTIONSTATES, $_; } - if ( scalar @FLOORSTATES ) { - $hash->{FLOORSTATES} = join( ",", @FLOORSTATES ); + if ( scalar @SECTIONSTATES ) { + $hash->{SECTIONSTATES} = join( ",", @SECTIONSTATES ); } - elsif ( $hash->{FLOORSTATES} ) { - delete $hash->{FLOORSTATES}; + elsif ( $hash->{SECTIONSTATES} ) { + delete $hash->{SECTIONSTATES}; } - if ( $hash->{FLOORSTATES} ) { + if ( $hash->{SECTIONSTATES} ) { $ret .= "," if ($ret); - $ret .= $hash->{FLOORSTATES}; + $ret .= $hash->{SECTIONSTATES}; } } - if ( $hash->{TYPE} eq "HOMESTATE" || $hash->{TYPE} eq "FLOORSTATE" ) { + if ( $hash->{TYPE} eq "HOMESTATE" || $hash->{TYPE} eq "SECTIONSTATE" ) { my @ROOMSTATES; foreach ( devspec2array("TYPE=ROOMSTATE") ) { @@ -1007,9 +1009,9 @@ sub HOMESTATEtk_findHomestateSlaves($;$) { split( /,/, $defs{$_}{HOMESTATES} ) ) || ( - defined( $defs{$_}{FLOORSTATES} ) + defined( $defs{$_}{SECTIONSTATES} ) && grep { $hash->{NAME} eq $_ } - split( /,/, $defs{$_}{FLOORSTATES} ) + split( /,/, $defs{$_}{SECTIONSTATES} ) ) ); push @ROOMSTATES, $_; @@ -1163,7 +1165,7 @@ sub HOMESTATEtk_UpdateReadings (@) { my $wayhome = 0; my $wayhomeDelayed = 0; my $wakeup = 0; - foreach my $internal ( "RESIDENTS", "FLOORSTATES", "ROOMSTATES" ) { + foreach my $internal ( "RESIDENTS", "SECTIONSTATES", "ROOMSTATES" ) { next unless ( $hash->{$internal} ); foreach my $presenceDev ( split( /,/, $hash->{$internal} ) ) { my $state = ReadingsVal( $presenceDev, "state", "gone" ); @@ -1184,7 +1186,7 @@ sub HOMESTATEtk_UpdateReadings (@) { } $state_home = 1 unless ( $hash->{RESIDENTS} - || $hash->{FLOORSTATES} + || $hash->{SECTIONSTATES} || $hash->{ROOMSTATES} ); # autoMode diff --git a/fhem/FHEM/UConv.pm b/fhem/FHEM/UConv.pm index 4386cdbfe..45f80fc35 100644 --- a/fhem/FHEM/UConv.pm +++ b/fhem/FHEM/UConv.pm @@ -1131,19 +1131,18 @@ sub IsHoliday(;$) { # Get current stage of the daytime based on temporal hours # https://de.wikipedia.org/wiki/Temporale_Stunden sub GetDaytime(;$$$$) { - my ( $time, $totalTemporalHours, $lang, @srParams ) = @_; + my ( $time, $totalTemporalHours, $lang, $params ) = @_; $lang = ( $main::attr{global}{language} ? $main::attr{global}{language} : "EN" ) unless ($lang); - my $ret = ref($time) eq "HASH" ? $time : _time( $time, $lang, 1 ); + my $ret = ref($time) eq "HASH" ? $time : _time( $time, $lang, 1, $params ); return undef unless ( ref($ret) eq "HASH" ); $ret->{daytimeStages} = $totalTemporalHours && $totalTemporalHours =~ m/^\d+$/ ? $totalTemporalHours : 12; - $ret->{srParams} = $ret{srParams} ? $ret{srParams} : []; # TODO: consider srParams $ret->{sunrise} = main::sunrise_abs_dat( $ret->{time_t} ); @@ -1166,7 +1165,7 @@ sub GetDaytime(;$$$$) { $ret->{daytimeStage_float} = $ret->{daytimeRel_s} / $ret->{daytimeStageLn_s}; $ret->{daytimeStage} = - int( $ret->{daytimeRel_s} / $ret->{daytimeStageLn_s} + 1 ); + int( ( ( $ret->{daytimeRel_s} + 1 ) / $ret->{daytimeStageLn_s} ) + 1 ); $ret->{daytimeStage} = 0 if ( $ret->{daytimeStage} < 1 || $ret->{daytimeStage} > $ret->{daytimeStages} ); @@ -1178,11 +1177,15 @@ sub GetDaytime(;$$$$) { #$ret = GetSeasonSocial( $ret, $lang ); #TODO https://de.wikipedia.org/wiki/F%C3%BCnfte_Jahreszeit # change midnight event when season changes + $ret->{events}{ $ret->{midnight_t} }{VALUE} = 1 + if ( $ret->{seasonMeteoChng} && $ret->{seasonMeteoChng} == 1 ); $ret->{events}{ $ret->{midnight_t} }{DESC} .= ", Begin meteorological $ret->{seasonMeteo_long} season" if ( $ret->{seasonMeteoChng} && $ret->{seasonMeteoChng} == 1 ); + $ret->{events}{ $ret->{midnight_t} }{VALUE} = 2 + if ( $ret->{seasonAstroChng} && $ret->{seasonAstroChng} == 1 ); $ret->{events}{ $ret->{midnight_t} }{DESC} .= - ", Begin astrological $ret->{seasonAstro_long} season" + ", Begin astronomical $ret->{seasonAstro_long} season" if ( $ret->{seasonAstroChng} && $ret->{seasonAstroChng} == 1 ); # calculate daytime from daytimeStage, season and DST @@ -1204,7 +1207,7 @@ sub GetDaytime(;$$$$) { # when no relation was found unless ( defined( $ret->{daytime} ) || $ds > -1 ) { - # assume evening after sunset + # assume midevening after sunset if ( $ret->{time_s} >= $ret->{sunset_s} ) { $ret->{daytime} = 5; } @@ -1240,15 +1243,15 @@ sub GetDaytime(;$$$$) { # # Midnight + $ret->{events}{ $ret->{midnight_t} }{TYPE} = "dayshift"; $ret->{events}{ $ret->{midnight_t} }{TIME} = main::FmtDateTime( $ret->{midnight_t} ); $ret->{events}{ $ret->{midnight_t} }{DESC} = - "Begin night time and new calendar day"; - $ret->{events}{ $ret->{1}{midnight_t} }{TIME} = - main::FmtDateTime( $ret->{1}{midnight_t} ); - $ret->{events}{ $ret->{1}{midnight_t} }{TIME} =~ s/00:00:00/24:00:00/; + "Begin of night time and new calendar day"; + $ret->{events}{ $ret->{1}{midnight_t} }{TYPE} = "dayshift"; + $ret->{events}{ $ret->{1}{midnight_t} }{TIME} = $ret->{date} . " 24:00:00"; $ret->{events}{ $ret->{1}{midnight_t} }{DESC} = - "End calendar day and begin night time"; + "End of calendar day and begin night time"; # Holidays $ret->{events}{ $ret->{midnight_t} }{DESC} .= @@ -1262,15 +1265,16 @@ sub GetDaytime(;$$$$) { #FIXME TODO if ( $ret->{dstchange} && $ret->{dstchange} == 1 ) { my $t = $ret->{midnight_t} + 2 * 60 * 60; - $ret->{events}{$t}{TIME} = main::FmtDateTime($t); - $ret->{events}{$t}{DESC} = "Begin standard time (-1h)" + $ret->{events}{$t}{TYPE} = "dstshift"; + $ret->{events}{$t}{VALUE} = $ret->{isdst}; + $ret->{events}{$t}{TIME} = main::FmtDateTime($t); + $ret->{events}{$t}{DESC} = "Begin of standard time (-1h)" unless ( $ret->{isdst} ); - $ret->{events}{$t}{DESC} = "Begin daylight saving time (+1h)" + $ret->{events}{$t}{DESC} = "Begin of daylight saving time (+1h)" if ( $ret->{isdst} ); } # daytime stage event forecast for today - #TODO add daytime to desc when it changes my $i = 1; my $b = $ret->{sunrise_t}; while ( $i <= $ret->{daytimeStages} + 1 ) { @@ -1290,14 +1294,22 @@ sub GetDaytime(;$$$$) { my $t = int( $b + 0.5 ); $ret->{events}{$t}{TIME} = main::FmtDateTime($t); if ( $i == $ret->{daytimeStages} + 1 ) { - $ret->{events}{$t}{DESC} = "Begin midevening time"; + $ret->{events}{$t}{TYPE} = "daytime"; + $ret->{events}{$t}{VALUE} = "midevening"; + $ret->{events}{$t}{DESC} = + "End of daytime"; } else { - $ret->{events}{$t}{DESC} = "Begin daytime stage $i" + $ret->{events}{$t}{TYPE} = "daytimeStage"; + $ret->{events}{$t}{VALUE} = $i; + $ret->{events}{$t}{DESC} = "Begin of daytime stage $i" unless ($daytime); - $ret->{events}{$t}{DESC} = - "Begin $daytimes{en}[$daytime] time and daytime stage $i" - if ( defined($daytime) ); + if ( defined($daytime) ) { + $ret->{events}{$t}{TYPE} = "daytime"; + $ret->{events}{$t}{VALUE} = $daytimes{en}[$daytime]; + $ret->{events}{$t}{DESC} = + "Begin of $daytimes{en}[$daytime] time and daytime stage $i"; + } } $i++; $b += $ret->{daytimeStageLn_s}; @@ -1607,8 +1619,8 @@ sub _round($;$) { sub _time(;$$$); -sub _time(;$$$) { - my ( $time, $lang, $dayOffset ) = @_; +sub _time(;$$$$) { + my ( $time, $lang, $dayOffset, $params ) = @_; $dayOffset = 1 if ( !defined($dayOffset) || $dayOffset !~ /^-?\d+$/ ); $lang = ( $main::attr{global}{language} @@ -1622,6 +1634,7 @@ sub _time(;$$$) { my %ret; $ret{time_t} = $time if ($time); $ret{time_t} = time unless ($time); + $ret{params} = $params if ($params); my @t = localtime( $ret{time_t} ); (