From 311125b99a0e56ceedc0852d73859f3850c5b41a Mon Sep 17 00:00:00 2001 From: dietmar63 Date: Thu, 14 Feb 2013 19:54:52 +0000 Subject: [PATCH] Bugfixing when switching at defined times - many switches implementing definition of day in format "So-Mi,Fr or "Su-We,Fr" git-svn-id: svn://svn.code.sf.net/p/fhem/code/trunk@2727 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/98_Heating_Control.pm | 186 ++++++++++++++++++++------------ 1 file changed, 117 insertions(+), 69 deletions(-) diff --git a/fhem/FHEM/98_Heating_Control.pm b/fhem/FHEM/98_Heating_Control.pm index 1061d4f92..5ab26981a 100644 --- a/fhem/FHEM/98_Heating_Control.pm +++ b/fhem/FHEM/98_Heating_Control.pm @@ -40,7 +40,7 @@ Heating_Control_Initialize($) $hash->{DefFn} = "Heating_Control_Define"; $hash->{UndefFn} = "Heating_Control_Undef"; $hash->{GetFn} = "Heating_Control_Get"; - $hash->{AttrList}= "loglevel:0,1,2,3,4,5 disable:0,1 ". + $hash->{AttrList}= "disable:0,1 loglevel:0,1,2,3,4,5 ". $readingFnAttributes; } @@ -69,6 +69,8 @@ sub Heating_Control_Define($$) { my ($hash, $def) = @_; + + RemoveInternalTimer($hash); my @a = split("[ \t]+", $def); return "Usage: define Heating_Control " @@ -129,25 +131,55 @@ Heating_Control_Define($$) $temp = $st[2]; } - # nur noch die Einzelteile per regExp testen - return "invalid daylist in $name <$daylist> - please use 123... | Sa,So,..." - if(!($daylist =~ m/^(\d){1,7}$/g || $daylist =~ m/^((sa|so|mo|di|mi|do|fr)(,|$)){1,7}$/g )); + my %dayNumber=(); + my %hdays=(); + my $daysRegExp = "(mo|di|mi|do|fr|sa|so|tu|we|th|su)"; - # Sa, So ... in den Index übersetzen - my $idx = 1; - foreach my $day ("mo","di","mi","do","fr","sa","so") { - $daylist =~ s/$day/$idx/g; - $idx++; + #wday 01 02 03 04 05 06 00 + my $idx = 1; # 07 !!! + foreach my $day ("mo","di","mi","do","fr","sa","so") { + $dayNumber{$day} = $idx; $idx++; + } + $idx = 1; + foreach my $day ("mo","tu","we","th","fr","sa","su") { + $dayNumber{$day} = $idx; $idx++; } - # Kommas entfernen - $daylist =~ s/,//g; - @days = split("", $daylist); + #Aufzählung 1234 ... + if ( $daylist =~ m/^(\d){0,7}$/g) { + + @days = split("", $daylist); + @hdays{@days}=1; + + # Aufzählung Sa,So,... | Mo-Di,Do,Fr-Mo + } elsif ($daylist =~ m/^($daysRegExp(,|-|$)){0,7}$/g ) { + + my $oldDay, my $oldDel; + for (;length($daylist);) { + my $day = substr($daylist,0,2,""); + my $del = substr($daylist,0,1,""); + my @subDays; + if ($oldDel eq "-" ){ + # von bis Angabe: Mo-Di + my $low = $dayNumber{$oldDay}; + my $high = $dayNumber{$day}; + if ($low <= $high) { + @subDays = ($low .. $high); + } else { + @subDays = (1 .. $high, $low .. 7); + } + @hdays{@subDays}=1; + } else { + #einzelner Tag: Sa + $hdays{$dayNumber{$day}} = 1; + } + $oldDay = $day; + $oldDel = $del; + } + } else{ + return "invalid daylist in $name <$daylist> 123... | Sa,So,... | Mo-Di,Do,Fr-Mo | Su-Th,We" + } - # doppelte Tage entfernen - my %hdays=(); - @hdays{@days}=1; - #korrekt die Tage sortieren @days = sort(SortNumber keys %hdays); return "invalid time in $name <$time> HH:MM" @@ -158,7 +190,14 @@ Heating_Control_Define($$) for (my $d=0; $d<@days; $d++) { #Log 3, "Switchingtime: $switchingtimes[$i] : $days[$d] -> $time -> $temp "; $hash->{helper}{SWITCHINGTIME}{$days[$d]}{$time} = $temp; - $hash->{"PROFILE ".($days[$d]).": ".$Wochentage[$days[$d]-1]} .= sprintf("%s: %.1f°C, ", $time, $temp); + } + } + + # Profile sortiert aufbauen + for (my $d=1; $d<=7; $d++) { + foreach my $st (sort (keys %{ $hash->{helper}{SWITCHINGTIME}{$d} })) { + my $temp = $hash->{helper}{SWITCHINGTIME}{$d}{$st}; + $hash->{"PROFILE ".($d).": ".$Wochentage[$d-1]} .= sprintf("%s: %.1f°C, ", $st, $temp); } } @@ -194,42 +233,50 @@ sub Heating_Control_Update($) { my ($hash) = @_; - my $now = time(); + my $now = time() + 5; # garantiert > als die eingestellte Schlatzeit my $next = 0; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now); - my $AktDesiredTemp = ReadingsVal($hash->{DEVICE}, $hash->{helper}{DESIRED_TEMP_READING}, 0); - my $newDesTemperature = $AktDesiredTemp; #default# + my $AktDesiredTemp = ReadingsVal($hash->{DEVICE}, $hash->{helper}{DESIRED_TEMP_READING}, 0); + my $newDesTemperature = $AktDesiredTemp; #default# my $nextDesTemperature = 0; my $nextSwitch = 0; - my $nowSwitch = 0; + my $nowSwitch = 0; + + my $loglevel = GetLogLevel ($hash->{NAME}, 5); + # $loglevel = 3; $wday=7 if($wday==0); - my @days = ($wday..7, 1..$wday-1); + my @days = ($wday..7, 1..$wday); + + Log $loglevel, "Begin##################>$hash->{NAME}"; + Log $loglevel, "wday------------>$wday"; for (my $d=0; $d<@days; $d++) { - #über jeden Tag + Log $loglevel, "d------------>$d--->nextSwitch:$nextSwitch"; + #ber jeden Tag last if ($nextSwitch > 0); + Log $loglevel, "days[$d]------------>$days[$d]"; foreach my $st (sort (keys %{ $hash->{helper}{SWITCHINGTIME}{$days[$d]} })) { - #berechnen, des Schaltpunktes - my $secondsToSwitch = 3600*(int(substr($st,0,2)) - $hour) + - 60*(int(substr($st,3,2)) - $min ) - $sec; - # Tagesdiff dazurechnen - if($wday <= int($days[$d])) { - $secondsToSwitch += 3600*24*(int($days[$d])-$wday) - } else { - $secondsToSwitch += 3600*24*(7-$wday+int($days[$d])) - } + Log $loglevel, "st------------>$st"; + # Tagediff + Sekunden des Tages addieren + my $secondsToSwitch = $d*24*3600 + + 3600*(int(substr($st,0,2)) - $hour) + + 60*(int(substr($st,3,2)) - $min ) - $sec; + Log $loglevel, "secondsToSwitch------------>$secondsToSwitch"; + Log $loglevel, "wday-days[d]----------->$wday $days[$d]"; - $next = time()+$secondsToSwitch; - #Log 3, "Jetzt:".strftime('%d.%m.%Y %H:%M:%S',localtime($now))." -> Next: ".strftime('%d.%m.%Y %H:%M:%S',localtime($next))." -> Temp: $hash->{helper}{SWITCHINGTIME}{$days[$d]}{$st}"; + $next = $now+$secondsToSwitch; - if ($now > $next) { + Log $loglevel, "Jetzt:".strftime('%d.%m.%Y %H:%M:%S',localtime($now))." -> Next: ".strftime('%d.%m.%Y %H:%M:%S',localtime($next))." -> Temp: $hash->{helper}{SWITCHINGTIME}{$days[$d]}{$st}"; + if ($now >= $next) { $newDesTemperature = $hash->{helper}{SWITCHINGTIME}{$days[$d]}{$st}; - #Log 3, "temperature------------>$newDesTemperature"; + Log $loglevel, "newDestemperature------------>$newDesTemperature"; $nowSwitch = $now; + Log $loglevel, "nowSwitch------------>$nowSwitch--->" .strftime('%d.%m.%Y %H:%M:%S',localtime($nowSwitch)); } else { $nextSwitch = $next; + Log $loglevel, "nextSwitch------------>$nextSwitch--->".strftime('%d.%m.%Y %H:%M:%S',localtime($nextSwitch)); $nextDesTemperature = $hash->{helper}{SWITCHINGTIME}{$days[$d]}{$st}; last; } @@ -243,7 +290,9 @@ Heating_Control_Update($) my $name = $hash->{NAME}; my $command; - #Log 3, "NowSwitch: ".strftime('%d.%m.%Y %H:%M:%S',localtime($nowSwitch))." ; AktDesiredTemp: $AktDesiredTemp ; newDesTemperature: $newDesTemperature"; + Log $loglevel, "NowSwitch: ".strftime('%d.%m.%Y %H:%M:%S',localtime($nowSwitch))." ; AktDesiredTemp: $AktDesiredTemp ; newDesTemperature: $newDesTemperature"; + Log $loglevel, "NextSwitch=".strftime('%d.%m.%Y %H:%M:%S',localtime($nextSwitch)); + if ($nowSwitch gt "" && $AktDesiredTemp != $newDesTemperature) { if (defined $hash->{helper}{CONDITION}) { $command = '{ fhem("set @ '.$hash->{helper}{DESIRED_TEMP_READING}.' %") if' . $hash->{helper}{CONDITION} . '}'; @@ -258,18 +307,17 @@ Heating_Control_Update($) $command =~ s/@/$hash->{DEVICE}/g; $command =~ s/%/$newDesTemperature/g; $command = SemicolonEscape($command); - my $ret = AnalyzeCommandChain(undef, $command); + Log $loglevel, "command-$hash->{NAME}----------->$command"; + my $ret = AnalyzeCommandChain(undef, $command); Log GetLogLevel($name,3), $ret if($ret); } - #Log 3, "nextSwitch=".strftime('%d.%m.%Y %H:%M:%S',localtime($nextSwitch)); - InternalTimer($nextSwitch, "Heating_Control_Update", $hash, 0); readingsBeginUpdate($hash); - readingsBulkUpdate($hash, "nextUpdate", strftime("%d.%m.%Y %H:%M:%S",localtime($nextSwitch))); - readingsBulkUpdate($hash, "nextValue", $nextDesTemperature . "°C"); - readingsBulkUpdate($hash, "state", strftime("%d.%m.%Y %H:%M:%S",localtime($nextSwitch)). ": " . $nextDesTemperature."°C"); - readingsEndUpdate($hash, defined($hash->{LOCAL} ? 0 : 1)); + readingsBulkUpdate ($hash, "nextUpdate", strftime("%d.%m.%Y %H:%M:%S",localtime($nextSwitch))); + readingsBulkUpdate ($hash, "nextValue", $nextDesTemperature . "°C"); + readingsBulkUpdate ($hash, "state", $newDesTemperature . "°C"); + readingsEndUpdate ($hash, defined($hash->{LOCAL} ? 0 : 1)); return 1; } @@ -299,7 +347,7 @@ sub SortNumber {

to set a weekly profile for <device>, eg. a heating sink. You can define different switchingtimes for every day. - The new temperature is send to the <device> automaticly with set <device> desired-temp <temp> + The new temperature is sent to the <device> automaticly with set <device> desired-temp <temp> if the device is a heating thermostat (FHT8b, MAX). Have you defined a <condition> and this condition is false if the switchingtime has reached, no command will executed.
A other case is to define an own perl command with <command>. @@ -315,7 +363,7 @@ sub SortNumber {
    [<weekdays>|]<time>|<temperature>

weekdays: optional, if not set every day is using.
Otherwise you can define one day as number or as shortname.
- time:define the time to switch, format: HH24:MI
+ time:define the time to switch, format: HH:MM(HH in 24 hour format)
temperature:the temperature to set, using a Integer

@@ -340,15 +388,15 @@ sub SortNumber { Example:

    define HCB Heating_Control Bad_Heizung 12345|05:20|21 12345|05:25|12 17:20|21 17:25|12
    - Mo-Fr are setting the temperature at 05:20 to 21°C, and at 05:25 to 12°C. - Every day will be set the temperature at 17:20 to 21°C and 17:25 to 12°C.

    + Mo-Fr are setting the temperature at 05:20 to 21C, and at 05:25 to 12C. + Every day will be set the temperature at 17:20 to 21C and 17:25 to 12C.

    - define HCW Heating_Control WZ_Heizung 07:00|16 Mo,Die,Mi|16:00|18.5 20:00|12 - {fhem(“set dummy on”); fhem("set @ desired-temp %");}
    + define HCW Heating_Control WZ_Heizung 07:00|16 Mo,Di,Do-Fr|16:00|18.5 20:00|12 + {fhem("set dummy on"); fhem("set @ desired-temp %");}
    At the given times and weekdays only(!) the command will be executed.

    - define HCK Heating_Control KZ_Heizung 07:00|16 16:00|18.5 20:00|12 ($sunshine=0))
    - The temperature is only set if the variable is $sunhine=0.

    + define HCW Heating_Control WZ_Heizung Sa-So,Mi|08:00|21 (ReadingsVal("WeAreThere", "state", "no") eq "yes")
    + The temperature is only set if the dummy variable WeAreThere is "yes".

@@ -382,12 +430,12 @@ sub SortNumber { define <name> Heating_Control <device> <profile> <command>|<condition>

- Bildet ein Wochenprofil für ein <device>, zb. Heizkörper, ab. Es können für jeden Tag unterschiedliche - Schaltzeiten angegeben werden. Ist das <device> ein Heizkörperthermostat (zb. FHT8b, MAX) so wird die + Bildet ein Wochenprofil fr ein <device>, zb. Heizkrper, ab. Es knnen fr jeden Tag unterschiedliche + Schaltzeiten angegeben werden. Ist das <device> ein Heizkrperthermostat (zb. FHT8b, MAX) so wird die zu setzende Temperatur im <profile> automatisch mittels set <device> desired-temp <temp> dem Device mitgeteilt. Ist eine <condition> angegeben und ist zum Schaltpunkt der Ausdruck unwahr, - so wird dieser Schaltpunkt nicht ausgeführt.
- Alternativ zur Automatik kann stattdessen eigener Perl-Code im <command> ausgeführt werden. + so wird dieser Schaltpunkt nicht ausgefhrt.
+ Alternativ zur Automatik kann stattdessen eigener Perl-Code im <command> ausgefhrt werden.

Folgende Parameter sind im Define definiert:

    device
    @@ -398,10 +446,10 @@ sub SortNumber { Angabe des Wochenprofils. Die einzelnen Schaltzeiten sind durch Leerzeichen getrennt Die Angabe der Schaltzeiten ist nach folgendem Muster definiert:
      [<Wochentage>|]<Uhrzeit>|<Temperatur>

    - Wochentage: optionale Angabe, falls nicht gesetzt wird der Schaltpunkt jeden Tag ausgeführt. - Für die Tage an denen dieser Schaltpunkt aktiv sein soll, ist jeder Tag mit seiner - Tagesnummer (Mo=1, ..., So=7) oder Name des Tages (Mo, Die, ..., So) einzusetzen.
    - Uhrzeit:Angabe der Uhrzeit an dem geschaltet werden soll, Format: HH24:MI
    + Wochentage: optionale Angabe, falls nicht gesetzt wird der Schaltpunkt jeden Tag ausgefhrt. + Fr die Tage an denen dieser Schaltpunkt aktiv sein soll, ist jeder Tag mit seiner + Tagesnummer (Mo=1, ..., So=7) oder Name des Tages (Mo, Di, ..., So) einzusetzen.
    + Uhrzeit:Angabe der Uhrzeit an dem geschaltet werden soll, Format: HH:MM(HH im 24 Stunden format)
    Temperatur:Angabe der zu setzenden Temperatur als Zahl

@@ -409,7 +457,7 @@ sub SortNumber { Falls keine Condition in () angegeben wurde, so wird alles weitere als Command interpretiert. Perl-Code ist in {} zu setzen.
Wichtig: Falls ein Command definiert ist, so wird zu den definierten Schaltzeiten - nur(!) das Command ausgeführt. Falls ein desired-temp Befehl abgesetzt werde soll, + nur(!) das Command ausgefhrt. Falls ein desired-temp Befehl abgesetzt werde soll, so muss dies explizit angegeben werden.
Folgende Parameter werden ersetzt:

    @@ -420,22 +468,22 @@ sub SortNumber {

      condition
      Bei Angabe einer Condition ist diese in () zu setzen und mit validem Perl-Code zu versehen.
      - Der Rückgabedatentyp der condition muss boolean sein.
      + Der Rckgabedatentyp der condition muss boolean sein.
      Die Parameter @ und % werden interpretiert.

    Beispiel:

      define HCB Heating_Control Bad_Heizung 12345|05:20|21 12345|05:25|12 17:20|21 17:25|12
      - Mo-Fr wird die Temperatur um 05:20Uhr auf 21°C, und um 05:25Uhr auf 12°C gesetzt. - Jeden Tag wird die Temperatur um 17:20Uhr auf 21°C und 17:25Uhr auf 12°C gesetzt.

      + Mo-Fr wird die Temperatur um 05:20Uhr auf 21C, und um 05:25Uhr auf 12C gesetzt. + Jeden Tag wird die Temperatur um 17:20Uhr auf 21C und 17:25Uhr auf 12C gesetzt.

      - define HCW Heating_Control WZ_Heizung 07:00|16 Mo,Die,Mi|16:00|18.5 20:00|12 - {fhem(“set dummy on”); fhem("set @ desired-temp %");}
      - Zu den definierten Schaltzeiten wird nur(!) der in {} angegebene Perl-Code ausgeführt.

      + define HCW Heating_Control WZ_Heizung 07:00|16 Mo,Di,Mi|16:00|18.5 20:00|12 + {fhem("set dummy on"); fhem("set @ desired-temp %");}
      + Zu den definierten Schaltzeiten wird nur(!) der in {} angegebene Perl-Code ausgefhrt.

      - define HCK Heating_Control KZ_Heizung 07:00|16 16:00|18.5 20:00|12 ($sunshine=0))
      - Die zu setzendeTemperatur wird nur gesetzt, falls die globale Variable $sunhine=0 ist.

      + define HCW Heating_Control WZ_Heizung Sa-So,Mi|08:00|21 (ReadingsVal("WeAreThere", "state", "no") eq "yes")
      + Die zu setzende Temperatur wird nur gesetzt, falls die Dummy Variable WeAreThere = "yes" ist.