diff --git a/FHEM/98_WeekdayTimer.pm b/FHEM/98_WeekdayTimer.pm index 8922895fa..86426ea82 100644 --- a/FHEM/98_WeekdayTimer.pm +++ b/FHEM/98_WeekdayTimer.pm @@ -186,6 +186,25 @@ sub WeekdayTimer_Define($$) { my $language = WeekdayTimer_Language ($hash, \@a); + $hash->{NAME} = $name; + $hash->{DEVICE} = $device; + + InternalTimer(time(), "WeekdayTimer_Start",$hash,0); + + return undef; +} + +sub WeekdayTimer_Start($) { + my ($hash) = @_; + my $name = $hash->{NAME}; + my @a = split("[ \t]+", $hash->{DEF}); + #my @a = split("[ \t]+", $def); + + #my $type = shift @a; + my $device = shift @a; + + my $language = WeekdayTimer_Language ($hash, \@a); + my $idx = 0; $hash->{dayNumber} = {map {$_ => $idx++} @{$hash->{shortDays}{$language}}}; $hash->{helper}{daysRegExp} = '(' . join ("|", @{$hash->{shortDays}{$language}}) . ")"; @@ -196,9 +215,6 @@ sub WeekdayTimer_Define($$) { WeekdayTimer_GlobalDaylistSpec ($hash, \@a); - $hash->{NAME} = $name; - $hash->{DEVICE} = $device; - my @switchingtimes = WeekdayTimer_gatherSwitchingTimes ($hash, \@a); my $conditionOrCommand = join (" ", @a); @@ -229,9 +245,10 @@ sub WeekdayTimer_Define($$) { $attr{$name}{commandTemplate} = 'set $NAME '. WeekdayTimer_isHeizung($hash) .' $EVENT' if (!defined $attr{$name}{commandTemplate}); - InternalTimer(time(), "$hash->{TYPE}_SetTimer", $hash, 0); + WeekdayTimer_SetTimerOfDay({ HASH => $hash}); + #WeekdayTimer_SetTimer($hash); - WeekdayTimer_SetTimerForMidnightUpdate( { HASH => $hash} ); + #WeekdayTimer_SetTimerForMidnightUpdate( { HASH => $hash} ); return undef; } @@ -243,9 +260,9 @@ sub WeekdayTimer_Profile($) { my %longDays = %{$hash->{longDays}}; delete $hash->{profil}; - my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime(time()); - my $now = time(); + my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($now); + # ---- Zeitpunkte den Tagen zuordnen ----------------------------------- my $idx = 0; foreach my $st (@{$hash->{SWITCHINGTIMES}}) { @@ -255,16 +272,12 @@ sub WeekdayTimer_Profile($) { foreach my $d (@{$tage}) { my @listeDerTage = ($d); - push (@listeDerTage, WeekdayTimer_getListeDerTage($d, $time)) if ($d>=7); + push (@listeDerTage, WeekdayTimer_getListeDerTage($hash, $d, $time)) if ($d>=7); map { my $day = $_; - my $dayOfEchteZeit = $day; - unless (AttrVal('global', 'holiday2we', '') =~ m,\bweekEnd\b,|| $day > 6 ) { - $dayOfEchteZeit = ($wday==0||$wday==6) ? 1 : $wday if ($day==8); # ggf. Montag $wday ~~ [0, 6] + my $dayOfEchteZeit = $day; $dayOfEchteZeit = ($wday>=1&&$wday<=5) ? 6 : $wday if ($day==7); # ggf. Samstag $wday ~~ [1..5] - } else { - $dayOfEchteZeit = $wday; - } + $dayOfEchteZeit = ($wday==0||$wday==6) ? 1 : $wday if ($day==8); # ggf. Montag $wday ~~ [0, 6] my $echtZeit = WeekdayTimer_EchteZeit($hash, $dayOfEchteZeit, $time); $hash->{profile} {$day}{$echtZeit} = $parameter; $hash->{profile_IDX}{$day}{$echtZeit} = $idx; @@ -302,9 +315,8 @@ sub WeekdayTimer_Profile($) { delete $hash->{profile}; } ################################################################################ -sub WeekdayTimer_getListeDerTage($$) { - my ($d, $time) = @_; - +sub WeekdayTimer_getListeDerTage($$$) { + my ($hash, $d, $time) = @_; my %hdays=(); unless (AttrVal('global', 'holiday2we', '') =~ m,\bweekEnd\b,) { @hdays{(0, 6)} = undef if ($d==7); # sa,so ( $we) @@ -312,41 +324,12 @@ sub WeekdayTimer_getListeDerTage($$) { } else { @hdays{(0..6)} = undef if ($d==8); # mo-fr (!$we) } - my $wday; - my $now = time(); - my ($sec,$min,$hour,$mday,$mon,$year,$nowWday,$yday,$isdst) = localtime($now); - - my @realativeWdays = (0..6); + my ($sec,$min,$hour,$mday,$mon,$year,$nowWday,$yday,$isdst) = localtime(time()); for (my $i=0;$i<=6;$i++) { - - my $relativeDay = $i-$nowWday; - #Log 3, "relativeDay------------>$relativeDay"; - my ($stunde, $minute, $sekunde) = split (":",$time); - - my $echteZeit = WeekdayTimer_zeitErmitteln ($now, $stunde, $minute, $sekunde, $relativeDay); - #Log 3, "echteZeit---$i---->>>$relativeDay<<<----->".FmtDateTime($echteZeit); - ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($echteZeit); - - my $noWeekEnd = 0; - my $ergebnis = 'none'; - if ($wday==$nowWday ){ - $ergebnis = "is_true" if IsWe(); - } elsif ( $wday==$nowWday+1) { - $ergebnis = "is_true" if IsWe("tomorrow"); - } else { - foreach my $h2we (split(',', AttrVal('global', 'holiday2we', ''))) { - if($h2we && ( $ergebnis eq 'none' || $h2we eq "noWeekEnd" ) && InternalVal($h2we, 'TYPE', '') eq "holiday" && !$noWeekEnd) { - $ergebnis = CommandGet(undef,$h2we . ' ' . sprintf("%02d-%02d",$mon+1,$mday)); - if ($ergebnis ne 'none' && $h2we eq "noWeekEnd") { - $ergebnis = 'none'; - $noWeekEnd = 1; - } - } - } - } - if ($ergebnis ne 'none') { - #Log 3, "ergebnis-------$i----->$ergebnis"; - $hdays{$i} = undef if ($d==7||AttrVal('global', 'holiday2we', '') =~ m,\bweekEnd\b,); # $we Tag aufnehmen + my $relativeDay = $i - $nowWday; + $relativeDay = $relativeDay + 7 if $relativeDay < 0 ; + if ($hash->{helper}{WEDAYS}{$relativeDay}) { + $hdays{$i} = undef if ($d==7);#||AttrVal('global', 'holiday2we', '') =~ m,\bweekEnd\b,); # $we Tag aufnehmen delete $hdays{$i} if ($d==8); # !$we Tag herausnehmen } } @@ -607,6 +590,45 @@ sub WeekdayTimer_SetTimerOfDay($) { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time()); my $secSinceMidnight = 3600*$hour + 60*$min + $sec; + my %wedays =(); + + my $iswe = IsWe(); + $wedays{(0)} = $iswe if $iswe; + $iswe = IsWe("tomorrow"); + $wedays{(1)} = $iswe if $iswe; + + for (my $i=2;$i<=6;$i++) { + my $noWeekEnd = 0; + my $ergebnis = 'none'; + my $izeit = time() + DAYSECONDS * $i; + my ($isec,$imin,$ihour,$imday,$imon,$iyear,$iwday,$iyday,$iisdst) = localtime($izeit); + + foreach my $h2we (split(',', AttrVal('global', 'holiday2we', ''))) { + if($h2we && ( $ergebnis eq 'none' || $h2we eq "noWeekEnd" ) && InternalVal($h2we, 'TYPE', '') eq "holiday" && !$noWeekEnd) { + $ergebnis = CommandGet(undef,$h2we . ' ' . sprintf("%02d-%02d",$imon+1,$imday)); + if ($ergebnis ne 'none' && $h2we eq "noWeekEnd") { + $ergebnis = 'none'; + $noWeekEnd = 1; + } + } + } + if ($ergebnis ne 'none') { + $wedays{$i} = $ergebnis ; + } else { + if (AttrVal('global', 'holiday2we', '') =~ m,\bweekEnd\b, && ($iwday == 0 || $iwday == 6)) { + delete $wedays{$i}; + } elsif ( $iwday == 0 || $iwday == 6) { + $wedays{$i} = 1 ; + } else { + delete $wedays{$i}; + } + } + } + $hash->{helper}{WEDAYS} = \%wedays; + + + + $hash->{SETTIMERATMIDNIGHT} = $myHash->{SETTIMERATMIDNIGHT}; WeekdayTimer_DeleteTimer($hash); WeekdayTimer_Profile ($hash); @@ -713,10 +735,12 @@ sub WeekdayTimer_delayedTimerInPast($) { return if (!defined($hash)); my $tim = time(); + my $tipIpHash = $modules{WeekdayTimer}{timerInThePast}; - + +####To be deactivated for new routine, might be wrong... foreach my $device ( keys %$tipIpHash ) { - foreach my $time ( sort keys %{$tipIpHash->{$device}} ) { + foreach my $time ( sort keys %{$tipIpHash->{$device}} ) { Log3 $hash, 4, "$device ".FmtDateTime($time)." ".($tim-$time)."s "; foreach my $para ( @{$tipIpHash->{$device}{$time}} ) { @@ -726,6 +750,12 @@ sub WeekdayTimer_delayedTimerInPast($) { } } } +############# end deactivation +#### new + + + +#### end new delete $modules{WeekdayTimer}{timerInThePast}; delete $modules{WeekdayTimer}{timerInThePastHash} } @@ -759,12 +789,25 @@ sub WeekdayTimer_searchAktNext($$) { $nextTime = WeekdayTimer_zeitErmitteln ($now, $stunde, $minute, $sekunde, $relativeDay); $nextPara = $hash->{helper}{SWITCHINGTIME}{$relWday}{$time}; - $nextIdx = $hash->{profile_IDX}{$relWday}{$time}; - $nextTag = $relWday; + #$nextIdx = $hash->{helper}{SWITCHINGTIME}{$relWday}{$time}; + $nextIdx = $hash->{profile_IDX}{$relWday}{$time}; + $nextTag = $relWday; #Log3 $hash, 3, $shortDays{$language}[$nextTag]." ".FmtDateTime($nextTime)." ".$nextPara." ".$nextIdx; - - if ($nextTime >= $now) { + my $ignore = 0; + my $wend = 0; + my $tage = $hash->{profil}{$nextIdx}{TAGE}[0]; + if ($wday==$relWday) { + $wend = $hash->{helper}{WEDAYS}{0}; + #$wend = IsWe(); + $ignore = (($tage == 7 && !$wend ) || ($tage == 8 && $wend )); + } elsif ( $wday==$relWday+1) { + $wend = $hash->{helper}{WEDAYS}{1}; + #$wend = IsWe("tomorrow"); + $ignore = (($tage == 7 && !$wend ) || ($tage == 8 && $wend )); + } + if (!$ignore && $nextTime >= $now ) { + #if ($nextTime >= $now ) { #Log3 $hash, 3, "oldIdx------------->$oldIdx"; #Log3 $hash, 3, "oldTime------------>".FmtDateTime($oldTime); #Log3 $hash, 3, "oldPara------------>$oldPara"; @@ -797,7 +840,6 @@ sub WeekdayTimer_Update($) { # Schaltparameter ermitteln my $tage = $hash->{profil}{$idx}{TAGE}; my $time = $hash->{profil}{$idx}{TIME}; - #my $newParam = WeekdayTimer_evalAndcleanupParam($hash,$time,$hash->{profil}{$idx}{PARA}, $isHeating ); my $newParam = $hash->{profil}{$idx}{PARA}; #Log3 $hash, 3, "[$name] $idx ". $time . " " . $newParam . " " . join("",@$tage); @@ -808,9 +850,13 @@ sub WeekdayTimer_Update($) { return; } - my $dieGanzeWoche = [7,8]; + my $dieGanzeWoche = $hash->{helper}{WEDAYS}{0} ? [7]:[8]; + #my $dieGanzeWoche = IsWe() ? [7]:[8] ; ## Test, Benennung ist dann irreführend... + #my $dieGanzeWoche = [7,8]; + my ($activeTimer, $activeTimerState); if (defined $myHash->{immerSchalten}) { + $activeTimer = WeekdayTimer_isAnActiveTimer ($hash, $dieGanzeWoche, $newParam); $activeTimerState = WeekdayTimer_isAnActiveTimer ($hash, $tage, $newParam); Log3 $hash, 4, "[$name] Update - past timer activated"; @@ -854,7 +900,6 @@ sub WeekdayTimer_isAnActiveTimer ($$$) { Log3 $hash, 5, "[$name] condition: $xPression"; my $ret = AnalyzeCommandChain(undef, $xPression); - #Log3 $hash, 3, "[$name] condition:>>>$ret<<< $xPression"; Log3 $hash, 5, "[$name] result of condition:$ret"; return $ret; } @@ -929,7 +974,9 @@ sub WeekdayTimer_FensterOffen ($$$) { Log3 $hash, 3, "[$name] switch of $hash->{DEVICE} delayed - delayedExecutionCond: '$verzoegerteAusfuehrungCond' is TRUE"; } if (defined($hash->{VERZOEGRUNG_IDX}) && $hash->{VERZOEGRUNG_IDX}!=$time) { - Log3 $hash, 3, "[$name] timer at $hash->{profil}{$hash->{VERZOEGRUNG_IDX}}{TIME} skiped by new timer at $hash->{profil}{$time}{TIME}"; + #Prüfen, ob der nächste Timer überhaupt für den aktuellen Tag relevant ist! + + Log3 $hash, 3, "[$name] timer at $hash->{profil}{$hash->{VERZOEGRUNG_IDX}}{TIME} skipped by new timer at $hash->{profil}{$time}{TIME}, delayedExecutionCond returned $verzoegerteAusfuehrung"; WeekdayTimer_RemoveInternalTimer($hash->{VERZOEGRUNG_IDX},$hash); } $hash->{VERZOEGRUNG_IDX} = $time; @@ -945,6 +992,7 @@ sub WeekdayTimer_FensterOffen ($$$) { "ZWave" => { "READING" => "state", "STATUS" => "(open)", "MODEL" => "r" }, "MAX" => { "READING" => "state", "STATUS" => "(open.*)", "MODEL" => "r" }, "dummy" => { "READING" => "state", "STATUS" => "(([Oo]pen|[Tt]ilt).*)", "MODEL" => "r" }, + "HMCCUDEV" => { "READING" => "state", "STATUS" => "(open|tilted)", "MODEL" => "r" }, "WeekdayTimer" => { "READING" => "delayedExecution","STATUS" => "^1\$", "MODEL" => "a" }, "Heating_Control" => { "READING" => "delayedExecution","STATUS" => "^1\$", "MODEL" => "a" } ); @@ -990,7 +1038,7 @@ sub WeekdayTimer_FensterOffen ($$$) { Log3 $hash, 3, "[$name] switch of $hash->{DEVICE} delayed - sensor '$fk' Reading/Attribute '$reading' is '$windowStatus'"; } if (defined($hash->{VERZOEGRUNG_IDX}) && $hash->{VERZOEGRUNG_IDX}!=$time) { - Log3 $hash, 3, "[$name] timer at $hash->{profil}{$hash->{VERZOEGRUNG_IDX}}{TIME} skiped by new timer at $hash->{profil}{$time}{TIME}"; + Log3 $hash, 3, "[$name] timer at $hash->{profil}{$hash->{VERZOEGRUNG_IDX}}{TIME} skipped by new timer at $hash->{profil}{$time}{TIME} while window contact returned open state"; WeekdayTimer_RemoveInternalTimer($hash->{VERZOEGRUNG_IDX},$hash); } $hash->{VERZOEGRUNG_IDX} = $time; @@ -1011,35 +1059,7 @@ sub WeekdayTimer_FensterOffen ($$$) { delete $hash->{VERZOEGRUNG_IDX} if defined($hash->{VERZOEGRUNG_IDX}); return 0; } -################################################################################ -sub WeekdayTimer_evalAndcleanupParam($$$$) { - my ($hash,$time,$param,$isHeating) = @_; - my $name = $hash->{DEVICE} ; - my $wdName = $hash->{NAME}; - - my $newParam = $param; - if ($param =~ m/^{.*}$/) { - - Log3 $hash, 4, "[$wdName] calculating dynamic param before all: ....... $newParam"; - - $newParam =~ s/\$NAME/$hash->{DEVICE}/g; - $newParam =~ s/\$TIME/$time/g; - Log3 $hash, 4, "[$wdName] calculating dynamic param after substitutions: $newParam"; - - $newParam = eval $newParam; - if ($@ || not defined $newParam) { - Log3 $hash, 1, "[$wdName] problem calculating dynamic param: ........... $param"; - Log3 $hash, 1, "[$wdName] $@"; - } else { - Log3 $hash, 4, "[$wdName] calculating dynamic param after eval: ........ $newParam"; - } - - }elsif($isHeating && $param =~ m/^\d{1,3}$/){ - $newParam = sprintf("%.1f", $param); - } - return $newParam; -} ################################################################################ sub WeekdayTimer_Device_Schalten($$$) { my ($hash, $newParam, $tage) = @_; @@ -1064,8 +1084,6 @@ sub WeekdayTimer_Device_Schalten($$$) { my $aktParam = ReadingsVal($hash->{DEVICE}, $setModifier, ""); $aktParam = sprintf("%.1f", $aktParam) if ($isHeating && $aktParam =~ m/^[0-9]{1,3}$/i); $newParam = sprintf("%.1f", $newParam) if ($isHeating && $newParam =~ m/^[0-9]{1,3}$/i); - # my $aktParam = WeekdayTimer_evalAndcleanupParam($hash,$dummy,ReadingsVal($hash->{DEVICE}, $setModifier, ""),$isHeating); - # newParam is already processed by evalAndcleanupParam() my $disabled = AttrVal($hash->{NAME}, "disable", 0); my $disabled_txt = $disabled ? " " : " not"; @@ -1399,3 +1417,4 @@ sub WeekdayTimer_SetAllParms(;$) { # {WeekdayTimer_SetAllParms()} =end :application/json;q=META.json =cut +