mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-22 14:16:42 +00:00
HOMESTATEtk: improved daytime calculation at switch point
git-svn-id: https://svn.fhem.de/fhem/trunk@14339 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
831d260f0e
commit
87e7da0a05
@ -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
|
||||
|
@ -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} );
|
||||
(
|
||||
|
Loading…
x
Reference in New Issue
Block a user