2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-04-20 19:36:02 +00:00

new features added:

- added attribute windowSensor. Defines a list of window sensors to avoid swichting when a window is open. Supports sensors of type CUL_FHTTK
- the time parameter of switches can now be a Perlfuncion like sunrise_abs().
- a new optional Parameter can change the language of profiles: de, en fr are possible
- symbolic constants like eco on off on-for-timer now a Parameter can be added. For example on-for-timer:30. The colon ist replaced by space.



git-svn-id: https://svn.fhem.de/fhem/trunk@4118 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
dietmar63 2013-10-27 12:35:10 +00:00
parent c75eb852b2
commit 10d31cb047
2 changed files with 264 additions and 129 deletions

View File

@ -28,8 +28,7 @@ use warnings;
use POSIX; use POSIX;
##################################### #####################################
sub sub Heating_Control_Initialize($)
Heating_Control_Initialize($)
{ {
my ($hash) = @_; my ($hash) = @_;
@ -38,12 +37,11 @@ Heating_Control_Initialize($)
$hash->{UndefFn} = "Heating_Control_Undef"; $hash->{UndefFn} = "Heating_Control_Undef";
$hash->{GetFn} = "Heating_Control_Get"; $hash->{GetFn} = "Heating_Control_Get";
$hash->{UpdFn} = "Heating_Control_Update"; $hash->{UpdFn} = "Heating_Control_Update";
$hash->{AttrList}= "disable:0,1 ". $hash->{AttrList}= "disable:0,1 windowSensor ".
$readingFnAttributes; $readingFnAttributes;
} }
################################################################################
sub sub Heating_Control_Get($@)
Heating_Control_Get($@)
{ {
my ($hash, @a) = @_; my ($hash, @a) = @_;
return "argument is missing" if(int(@a) != 2); return "argument is missing" if(int(@a) != 2);
@ -60,39 +58,60 @@ Heating_Control_Get($@)
} }
return "$a[0] $reading => $value"; return "$a[0] $reading => $value";
} }
################################################################################
sub Heating_Control_Define($$)
sub
Heating_Control_Define($$)
{ {
my ($hash, $def) = @_; my ($hash, $def) = @_;
my %longDays = ( "de" => ["Sonntag", "Montag","Dienstag","Mittwoch", "Donnerstag","Freitag", "Samstag" ],
"en" => ["Sunday", "Monday","Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
"fr" => ["Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi","Samedi" ]);
my %shortDays = ( "de" => ["so","mo","di","mi","do","fr","sa"],
"en" => ["su","mo","tu","we","th","fr","sa"],
"fr" => ["di","lu","ma","me","je","ve","sa"]);
my @a = split("[ \t]+", $def); my @a = split("[ \t]+", $def);
return "Usage: define <name> $hash->{TYPE} <device> <switching times> <condition|command>" return "Usage: define <name> $hash->{TYPE} <device> <language> <switching times> <condition|command>"
if(@a < 4); if(@a < 4);
my $name = shift @a; my $name = shift @a;
my $type = shift @a; my $type = shift @a;
my $device = shift @a; my $device = shift @a;
my @switchingtimes; my @switchingtimes;
my $conditionOrCommand = ""; my $conditionOrCommand = "";
my @Wochentage_de = ("Sonntag", "Montag","Dienstag","Mittwoch", "Donnerstag","Freitag", "Samstag" ); # ggf. language optional Parameter
my @Wochentage_en = ("Sunday", "Monday","Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); my $language = shift @a;
my @Wochentage_fr = ("Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi","Samedi"); my $langRegExp = "(";
foreach my $l (keys(%shortDays)) {
$langRegExp .= $l . "|";
}
$langRegExp =~ s/\|$//g;
$langRegExp .= ")";
if ($language =~ m/^$langRegExp$/g) {
$hash->{LANGUAGE} = $language;
} else {
Log3 $hash, 3, "[$name] illegal language: $language, use one of $langRegExp" if (length() == 2);
unshift (@a,$language) if (length($language) != 2) ;
$hash->{LANGUAGE} = "de";
}
$language = $hash->{LANGUAGE};
# test if device is defined
return "invalid Device, given Device <$device> not found" if(!$defs{$device}); return "invalid Device, given Device <$device> not found" if(!$defs{$device});
#Altlasten bereinigen #Altlasten bereinigen
delete($hash->{TIME_AS_PERL}) if($hash->{TIME_AS_PERL});
delete($hash->{helper}{CONDITION}) if($hash->{helper}{CONDITION}); delete($hash->{helper}{CONDITION}) if($hash->{helper}{CONDITION});
delete($hash->{helper}{COMMAND}) if($hash->{helper}{COMMAND}); delete($hash->{helper}{COMMAND}) if($hash->{helper}{COMMAND});
delete($hash->{helper}{SWITCHINGTIMES}) if($hash->{helper}{SWITCHINGTIMES}); delete($hash->{helper}{SWITCHINGTIMES}) if($hash->{helper}{SWITCHINGTIMES});
delete($hash->{helper}{SWITCHINGTIME}) if($hash->{helper}{SWITCHINGTIME}); delete($hash->{helper}{SWITCHINGTIME}) if($hash->{helper}{SWITCHINGTIME});
for (my $w=0; $w<@Wochentage_de; $w++) { foreach my $l (keys(%shortDays)) {
delete($hash->{"PROFILE ".($w).": ".$Wochentage_de[$w]}) if($hash->{"PROFILE ".($w).": ".$Wochentage_de[$w]}); for (my $w=0; $w<7; $w++) {
delete($hash->{"PROFILE ".($w).": ".$Wochentage_en[$w]}) if($hash->{"PROFILE ".($w).": ".$Wochentage_en[$w]}); delete($hash->{"PROFILE ".($w).": ".$longDays{$l}[$w]}) if($hash->{"PROFILE ".($w).": ".$longDays{$l}[$w]});
delete($hash->{"PROFILE ".($w).": ".$Wochentage_fr[$w]}) if($hash->{"PROFILE ".($w).": ".$Wochentage_fr[$w]}); }
} }
for(my $i=0; $i<@a; $i++) { for(my $i=0; $i<@a; $i++) {
@ -107,6 +126,8 @@ Heating_Control_Define($$)
last; last;
} }
} }
# wenn keine switchintime angegeben ist, dann Fehler
Log3 $hash, 3, "no Switchingtime found in <$conditionOrCommand>, check first parameter" if (@switchingtimes == 0);
$hash->{NAME} = $name; $hash->{NAME} = $name;
$hash->{DEVICE} = $device; $hash->{DEVICE} = $device;
@ -118,30 +139,58 @@ Heating_Control_Define($$)
$hash->{helper}{COMMAND} = $conditionOrCommand; $hash->{helper}{COMMAND} = $conditionOrCommand;
} }
my $daysRegExp = "(mo|di|mi|do|fr|sa|so|tu|we|th|su|lu|ma|me|je|ve)"; # jetzt die switchingtimes und Tagesangaben verarbeiten.
my $daysRegExp_en = "(tu|we|th|su)"; Heating_Control_ParseSwitchingProfile($hash, \@switchingtimes, \$shortDays{$language});
my $daysRegExp_fr = "(lu|ma|me|je|ve)";
# Profile sortiert aufbauen
for (my $d=0; $d<=6; $d++) {
foreach my $st (sort (keys %{ $hash->{helper}{SWITCHINGTIME}{$d} })) {
my $para = $hash->{helper}{SWITCHINGTIME}{$d}{$st};
$hash->{"PROFILE ".($d).": ".$longDays{$language}[$d]} .= sprintf("%s %s, ", substr ($st,0,5), $para);
}
}
RemoveInternalTimer($hash);
my $now = time();
InternalTimer ($now+30, "$hash->{TYPE}_Update", $hash, 0);
if (defined($hash->{TIME_AS_PERL})) {
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
my $midnight = $now + 24*3600 -(3600*$hour + 60*$min + $sec) + 10*60;
InternalTimer ($midnight, "$hash->{TYPE}_UpdatePerlTime", $hash, 0);
}
readingsBeginUpdate ($hash);
readingsBulkUpdate ($hash, "nextUpdate", strftime("Heute, %H:%M:%S",localtime($now+30)));
readingsBulkUpdate ($hash, "nextValue", "???");
readingsBulkUpdate ($hash, "state", "waiting...");
readingsEndUpdate ($hash, defined($hash->{LOCAL} ? 0 : 1));
return undef;
}
################################################################################
sub Heating_Control_ParseSwitchingProfile($$$) {
my ($hash, $switchingtimes, $shortDays) = @_;
my $name = $hash->{NAME};
my $language = $hash->{LANGUAGE};
my %dayNumber=(); my %dayNumber=();
my $idx = 0; my $daysRegExp = "(";
foreach my $day ("so","mo","di","mi","do","fr","sa") { for(my $idx=0; $idx<7; $idx++) {
$dayNumber{$day} = $idx; $idx++; my $day = @{$$shortDays}[$idx];
} $dayNumber{$day} = $idx;
$idx = 0; $daysRegExp .= $day . "|";
foreach my $day ("su","mo","tu","we","th","fr","sa") {
$dayNumber{$day} = $idx; $idx++;
}
$idx = 0;
foreach my $day ("di","lu","ma","me","je","ve","sa") {
$dayNumber{$day} = $idx; $idx++;
} }
$daysRegExp =~ s/\|$//g;
$daysRegExp .= ")";
my (@st, @days, $daylist, $time, $para, $englisch, $french); my (@st, @days, $daylist, $time, $para);
for(my $i=0; $i<@switchingtimes; $i++) { for(my $i=0; $i<@{$switchingtimes}; $i++) {
@st = split(/\|/, $switchingtimes[$i]); @st = split(/\|/, @{$switchingtimes}[$i]);
if ( @st == 2) { if ( @st == 2) {
$daylist = "1234567"; #jeden Tag/woche ist vordefiniert $daylist = "1234567"; #jeden Tag/Woche ist vordefiniert
$time = $st[0]; $time = $st[0];
$para = $st[1]; $para = $st[1];
} elsif ( @st == 3) { } elsif ( @st == 3) {
@ -152,7 +201,8 @@ Heating_Control_Define($$)
my %hdays=(); my %hdays=();
#Aufzaehlung 1234 ... # Angaben der Tage verarbeiten
# Aufzaehlung 1234 ...
if ( $daylist =~ m/^(\d){0,7}$/g) { if ( $daylist =~ m/^(\d){0,7}$/g) {
$daylist =~ s/7/0/g; $daylist =~ s/7/0/g;
@ -166,8 +216,6 @@ Heating_Control_Define($$)
for (;length($daylist);) { for (;length($daylist);) {
my $day = substr($daylist,0,2,""); my $day = substr($daylist,0,2,"");
my $del = substr($daylist,0,1,""); my $del = substr($daylist,0,1,"");
$englisch = ($day =~ m/^($daysRegExp_en)$/g);
$french = ($day =~ m/^($daysRegExp_fr)$/g);
my @subDays; my @subDays;
if ($oldDel eq "-" ){ if ($oldDel eq "-" ){
# von bis Angabe: Mo-Di # von bis Angabe: Mo-Di
@ -176,7 +224,8 @@ Heating_Control_Define($$)
if ($low <= $high) { if ($low <= $high) {
@subDays = ($low .. $high); @subDays = ($low .. $high);
} else { } else {
@subDays = ($dayNumber{so} .. $high, $low .. $dayNumber{sa}); #@subDays = ($dayNumber{so} .. $high, $low .. $dayNumber{sa});
@subDays = ( 00 .. $high, $low .. 06);
} }
@hdays{@subDays}=1; @hdays{@subDays}=1;
} else { } else {
@ -192,72 +241,129 @@ Heating_Control_Define($$)
@days = sort(SortNumber keys %hdays); @days = sort(SortNumber keys %hdays);
return "invalid time in $name <$time> HH:MM" # Zeitangabe verarbeiten.
if(!($time =~ m/^[0-2][0-9]:[0-5][0-9]$/g)); if($time =~ m/^\{.*\}$/g) { # Perlausdruck {*}
$time = eval($time); # must deliver HH:MM[:SS]
$hash->{TIME_AS_PERL} = 1;
}
if ($time =~ m/^[0-2][0-9]:[0-5][0-9]$/g) { # HH:MM
$time .= ":00"; # HH:MM:SS erzeugen
} elsif ($time =~ m/^[0-2][0-9](:[0-5][0-9]){2,2}$/g) { # HH:MM:SS
; # ok.
} else {
Log3 $hash, 1, "[$name] invalid time in $name <$time> HH:MM[:SS]"
}
for (my $d=0; $d<@days; $d++) { for (my $d=0; $d<@days; $d++) {
#Log3 $hash, 3, "Switchingtime: $switchingtimes[$i] : $days[$d] -> $time -> $para "; Log3 $hash, 5, "[$name] Switchingtime: @{$switchingtimes}[$i] : $days[$d] -> $time -> $para ";
$hash->{helper}{SWITCHINGTIME}{$days[$d]}{$time} = $para; $hash->{helper}{SWITCHINGTIME}{$days[$d]}{$time} = $para;
} }
} }
my $rWochentage;
if ($englisch) {
$rWochentage = \@Wochentage_en;
} elsif ($french) {
$rWochentage = \@Wochentage_fr;
} else {
$rWochentage = \@Wochentage_de;
}
# Profile sortiert aufbauen
for (my $d=0; $d<=6; $d++) {
foreach my $st (sort (keys %{ $hash->{helper}{SWITCHINGTIME}{$d} })) {
my $para = $hash->{helper}{SWITCHINGTIME}{$d}{$st};
$hash->{"PROFILE ".($d).": ".$$rWochentage[$d]} .= sprintf("%s %s, ", $st, $para);
}
}
RemoveInternalTimer($hash);
my $now = time();
InternalTimer ($now+30, "$hash->{TYPE}_Update", $hash, 0);
readingsBeginUpdate ($hash);
readingsBulkUpdate ($hash, "nextUpdate", strftime("Heute, %H:%M:%S",localtime($now+30)));
readingsBulkUpdate ($hash, "nextValue", "???");
readingsBulkUpdate ($hash, "state", "waiting...");
readingsEndUpdate ($hash, defined($hash->{LOCAL} ? 0 : 1));
return undef;
} }
################################################################################
sub sub Heating_Control_Undef($$) {
Heating_Control_Undef($$)
{
my ($hash, $arg) = @_; my ($hash, $arg) = @_;
RemoveInternalTimer($hash); RemoveInternalTimer($hash);
delete $modules{$hash->{TYPE}}{defptr}{$hash->{NAME}}; delete $modules{$hash->{TYPE}}{defptr}{$hash->{NAME}};
return undef; return undef;
} }
################################################################################
sub sub Heating_Control_UpdatePerlTime($)
Heating_Control_Update($) {
my ($hash) = @_;
Heating_Control_Define($hash, $hash->{NAME} . " " . $hash->{TYPE} . " " . $hash->{DEF} );
}
################################################################################
sub Heating_Control_Update($)
{ {
my ($hash) = @_; my ($hash) = @_;
my $mod = "[".$hash->{NAME} ."] "; my $mod = "[".$hash->{NAME} ."] ";
my $name = $hash->{NAME};
my $now = time() + 5; # garantiert > als die eingestellte Schlatzeit my $now = time() + 5; # garantiert > als die eingestellte Schlatzeit
# Fenserkontakte abfragen - wenn einer im Status closed, dann Schaltung um 60 Sekunden verzögern
if (Heating_Control_FensterOffen($hash)) {
return;
}
# Schaltparameter ermitteln
my ($nowSwitch,$nextSwitch,$aktParam,$newParam,$nextParam)
= Heating_Control_akt_next_param($now, $hash);
# ggf. Device schalten
if ($nowSwitch gt "" && $aktParam ne $newParam ) {
Heating_Control_Device_Schalten($hash, $now, $nowSwitch, $newParam)
}
# Timer und Readings setzen.
InternalTimer ($nextSwitch, "$hash->{TYPE}_Update", $hash, 0);
my $active = 1;
if (defined $hash->{helper}{CONDITION}) {
$active = eval ($hash->{helper}{CONDITION});
}
readingsBeginUpdate($hash);
readingsBulkUpdate ($hash, "nextUpdate", strftime("%d.%m.%Y %H:%M:%S",localtime($nextSwitch)));
readingsBulkUpdate ($hash, "nextValue", $nextParam);
readingsBulkUpdate ($hash, "state", $active ? $newParam : "inactive" );
readingsEndUpdate ($hash, defined($hash->{LOCAL} ? 0 : 1));
return 1;
}
################################################################################
sub Heating_Control_FensterOffen ($) {
my ($hash) = @_;
my $mod = "[".$hash->{NAME} ."]";
my %contacts = ( "CUL_FHTTK" => { "READING" => "Window", "STATUS" => "Open" },
"HM" => { "READING" => "hmw", "STATUS" => "hmo" },
"MAX" => { "READING" => "maxw", "STATUS" => "maxs"});
my $fensterKontakte = AttrVal($hash->{NAME}, "windowSensor", "nF");
Log3 $hash, 5, "$mod list of windowsenors found: '$fensterKontakte'";
if ($fensterKontakte ne "nF" ) {
my @kontakte = split(/ /, $fensterKontakte);
foreach my $fk (@kontakte) {
if(!$defs{$fk}) {
Log3 $hash, 3, "$mod Window sensor <$fk> not found - check name.";
} else {
my $fk_hash = $defs{$fk};
my $fk_typ = $fk_hash->{TYPE};
if (!defined($contacts{$fk_typ})) {
Log3 $hash, 3, "$mod TYPE '$fk_typ' of $fk not yet supported, $fk ignored - inform maintainer";
} else {
my $reading = $contacts{$fk_typ}{READING};
my $status = $contacts{$fk_typ}{STATUS};
my $windowStatus = ReadingsVal($fk,$reading,"nF");
if ($windowStatus eq "nF") {
Log3 $hash, 3, "$mod READING '$reading' of $fk not found, $fk ignored - inform maintainer";
} else {
Log3 $hash, 5, "$mod windowsensor '$fk' Reading '$reading' is '$windowStatus'";
if ($windowStatus eq $status) {
Log3 $hash, 3, "$mod switch of $hash->{DEVICE} delayed - windowsensor '$fk' Reading '$reading' is '$windowStatus'";
InternalTimer (time()+60, "$hash->{TYPE}_Update", $hash, 0);
return 1
}
}
}
}
}
}
return 0;
}
################################################################################
sub Heating_Control_akt_next_param($$) {
my ($now, $hash) = @_;
my $mod = "[".$hash->{NAME} ."] ";
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now); my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
my $aktParam = ReadingsVal($hash->{DEVICE}, $hash->{helper}{DESIRED_TEMP_READING}, 0); my $aktParam = ReadingsVal($hash->{DEVICE}, $hash->{helper}{DESIRED_TEMP_READING}, 0);
$aktParam = sprintf("%.1f", $aktParam) if ($aktParam =~ m/^[0-9]{1,3}$/i); $aktParam = sprintf("%.1f", $aktParam) if ($aktParam =~ m/^[0-9]{1,3}$/i);
my $newParam = $aktParam; #default# my $newParam = $aktParam; #default#
my $nextParam = 0;
my $next = 0;
my $nextSwitch = 0;
my $nowSwitch = 0;
my ($nextParam, $next, $nextSwitch, $nowSwitch) = (0,0,0,0);
# aktuellen und nächsten Schaltzeitpunkt ermitteln.
my $startIdx; my $startIdx;
for (my $d=-1; $d>=-7; $d--) { for (my $d=-1; $d>=-7; $d--) {
my $wd = ($d+$wday) % 7; my $wd = ($d+$wday) % 7;
@ -273,7 +379,8 @@ Heating_Control_Update($)
foreach my $st (sort (keys %{ $hash->{helper}{SWITCHINGTIME}{$wd} })) { foreach my $st (sort (keys %{ $hash->{helper}{SWITCHINGTIME}{$wd} })) {
# Tagediff + Sekunden des Tages addieren # 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; my @t = split(/:/, $st); # HH MM SS
my $secondsToSwitch = $d*24*3600 + 3600*($t[0] - $hour) + 60*($t[1] - $min) + $t[2] - $sec;
my $next = $now + $secondsToSwitch; my $next = $now + $secondsToSwitch;
if ($secondsToSwitch<=10 && $secondsToSwitch>=-20) { if ($secondsToSwitch<=10 && $secondsToSwitch>=-20) {
@ -292,23 +399,24 @@ Heating_Control_Update($)
} }
} }
my $name = $hash->{NAME};
my $command;
#$nextSwitch += get_SummerTimeOffset($now, $nextSwitch); #$nextSwitch += get_SummerTimeOffset($now, $nextSwitch);
Log3 $hash, 4, $mod .strftime('%d.%m.%Y %H:%M:%S',localtime($nowSwitch))." ; AktDesiredTemp: $aktParam ; newDesTemperature: $newParam"; Log3 $hash, 4, $mod .strftime('%d.%m.%Y %H:%M:%S',localtime($nowSwitch))." ; aktParam: $aktParam ; newParam: $newParam";
Log3 $hash, 4, $mod .strftime('%d.%m.%Y %H:%M:%S',localtime($nextSwitch)); Log3 $hash, 4, $mod .strftime('%d.%m.%Y %H:%M:%S',localtime($nextSwitch));
return ($nowSwitch,$nextSwitch,$aktParam,$newParam,$nextParam);
}
################################################################################
sub Heating_Control_Device_Schalten($$$$) {
my ($hash, $now, $nowSwitch, $newParam) = @_;
my $command = "";
my $mod = "[".$hash->{NAME} ."] ";
#modifier des Zieldevices auswaehlen #modifier des Zieldevices auswaehlen
my %modifier = ("MAX" => "desiredTemperature", my %modifier = ("MAX"=>"desiredTemperature","FHT"=>"desired-temp","CUL_HM"=>"desired-temp","FS20"=>"");
"FHT" => "desired-temp",
"FS20" => "",
"CUL_HM" => "desired-temp");
$hash->{helper}{DESIRED_TEMP_READING} = ""; $hash->{helper}{DESIRED_TEMP_READING} = "";
$hash->{helper}{DESIRED_TEMP_READING} = $modifier{$defs{$hash->{DEVICE}}{TYPE}}; $hash->{helper}{DESIRED_TEMP_READING} = $modifier{$defs{$hash->{DEVICE}}{TYPE}};
if ($nowSwitch gt "" && $aktParam ne $newParam ) { #if ($nowSwitch gt "" && $aktParam ne $newParam ) {
if (defined $hash->{helper}{CONDITION}) { if (defined $hash->{helper}{CONDITION}) {
$command = '{ fhem("set @ '.$hash->{helper}{DESIRED_TEMP_READING}.' %") if' . $hash->{helper}{CONDITION} . '}'; $command = '{ fhem("set @ '.$hash->{helper}{DESIRED_TEMP_READING}.' %") if' . $hash->{helper}{CONDITION} . '}';
} elsif (defined $hash->{helper}{COMMAND}) { } elsif (defined $hash->{helper}{COMMAND}) {
@ -316,9 +424,11 @@ Heating_Control_Update($)
} else { } else {
$command = '{ fhem("set @ '.$hash->{helper}{DESIRED_TEMP_READING}.' %") }'; $command = '{ fhem("set @ '.$hash->{helper}{DESIRED_TEMP_READING}.' %") }';
} }
} #}
#Kommando ausführen
my $secondsSinceSwitch = $nowSwitch - $now; my $secondsSinceSwitch = $nowSwitch - $now;
# toDo besser eine Positivliste mit Geraeten, die geschaltet werden sollen
my %vergangenheitNichtSchalten = ("FS20" => 1); my %vergangenheitNichtSchalten = ("FS20" => 1);
if ($vergangenheitNichtSchalten{$defs{$hash->{DEVICE}}{TYPE}} && $secondsSinceSwitch < -60) { if ($vergangenheitNichtSchalten{$defs{$hash->{DEVICE}}{TYPE}} && $secondsSinceSwitch < -60) {
; ;
@ -333,24 +443,8 @@ Heating_Control_Update($)
Log3 ($hash, 3, $ret) if($ret); Log3 ($hash, 3, $ret) if($ret);
} }
} }
my $active = 1;
if (defined $hash->{helper}{CONDITION}) {
$active = eval ($hash->{helper}{CONDITION});
}
RemoveInternalTimer($hash);
InternalTimer($nextSwitch, "$hash->{TYPE}_Update", $hash, 0);
readingsBeginUpdate($hash);
readingsBulkUpdate ($hash, "nextUpdate", strftime("%d.%m.%Y %H:%M:%S",localtime($nextSwitch)));
readingsBulkUpdate ($hash, "nextValue", $nextParam);
readingsBulkUpdate ($hash, "state", $active ? $newParam : "inactive" );
readingsEndUpdate ($hash, defined($hash->{LOCAL} ? 0 : 1));
return 1;
} }
# ################################################################################
sub Heating_Control_SetAllTemps() { # {Heating_Control_SetAllTemps()} sub Heating_Control_SetAllTemps() { # {Heating_Control_SetAllTemps()}
foreach my $hc ( sort keys %{$modules{Heating_Control}{defptr}} ) { foreach my $hc ( sort keys %{$modules{Heating_Control}{defptr}} ) {
@ -367,7 +461,7 @@ sub Heating_Control_SetAllTemps() { # {Heating_Control_SetAllTemps()}
} }
Log3 undef, 3, "Heating_Control_SetAllTemps() done!"; Log3 undef, 3, "Heating_Control_SetAllTemps() done!";
} }
################################################################################
sub SortNumber { sub SortNumber {
if($a < $b) if($a < $b)
{ return -1; } { return -1; }
@ -390,7 +484,7 @@ sub SortNumber {
<a name="Heating_Controldefine"></a> <a name="Heating_Controldefine"></a>
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define &lt;name&gt; Heating_Control &lt;device&gt; &lt;profile&gt; &lt;command&gt;|&lt;condition&gt;</code> <code>define &lt;name&gt; Heating_Control &lt;device&gt; [&lt;language&gt;] &lt;profile&gt; &lt;command&gt;|&lt;condition&gt;</code>
<br><br> <br><br>
to set a weekly profile for &lt;device&gt;, eg. a heating sink.<br> to set a weekly profile for &lt;device&gt;, eg. a heating sink.<br>
@ -410,14 +504,20 @@ sub SortNumber {
The device to switch at the given time. The device to switch at the given time.
</ul> </ul>
<p> <p>
<ul><b>language</b><br>
Specifies the language used for definition and profiles.
de,en,fr are possible. The parameter is optional.
</ul>
<p>
<ul><b>profile</b><br> <ul><b>profile</b><br>
Define the weekly profile. All timings are separated by space. One switchingtime are defined Define the weekly profile. All timings are separated by space. One switchingtime are defined
by the following example: <br> by the following example: <br>
<ul><b>[&lt;weekdays&gt;|]&lt;time&gt;|&lt;parameter&gt;</b></ul><br> <ul><b>[&lt;weekdays&gt;|]&lt;time&gt;|&lt;parameter&gt;</b></ul><br>
<u>weekdays:</u> optional, if not set every day is using.<br> <u>weekdays:</u> optional, if not set every day is using.<br>
Otherwise you can define one day as number or as shortname.<br> Otherwise you can define one day as number or as shortname.<br>
<u>time:</u>define the time to switch, format: HH:MM(HH in 24 hour format)<br> <u>time:</u>define the time to switch, format: HH:MM:[SS](HH in 24 hour format) or a Perlfunction like {sunrise_abs()}<br>
<u>parameter:</u>the temperature to be set, using a float with mask 99.9 or a sybolic value like <b>eco</b> or <b>comfort</b> - whatever your thermostat understands<br> <u>parameter:</u>the temperature to be set, using a float with mask 99.9 or a sybolic value like <b>eco</b> or <b>comfort</b> - whatever your thermostat understands.
The symbolic value can be added an additional parameter: dayTemp:16 night-temp:15. See examples <br>
</ul> </ul>
<p> <p>
<ul><b>command</b><br> <ul><b>command</b><br>
@ -450,6 +550,12 @@ sub SortNumber {
<code>define HCW Heating_Control WZ_Heizung Sa-Su,We|08:00|21 (ReadingsVal("WeAreThere", "state", "no") eq "yes")</code><br> <code>define HCW Heating_Control WZ_Heizung Sa-Su,We|08:00|21 (ReadingsVal("WeAreThere", "state", "no") eq "yes")</code><br>
The temperature is only set if the dummy variable WeAreThere is "yes".<p> The temperature is only set if the dummy variable WeAreThere is "yes".<p>
<code>define HCW Heating_Control WZ_Heizung en Su-Fr|{sunrise_abs()}|21 Mo-Fr|{sunset_abs()}|16</code><br>
The device is switched at sunrise/sunset. Language: english.
<code>define HCW Heating_Control WZ_Heizung en Mo-Fr|{myFunction}|night-temp:18 Mo-Fr|{myFunction()}|dayTemp:16</code><br>
The is switched at time myFunction(). It is sent the Command "night-temp 18" and "dayTemp 16".
</ul> </ul>
</ul> </ul>
@ -466,7 +572,7 @@ sub SortNumber {
<li><a href="#event-on-update-reading">event-on-update-reading</a></li> <li><a href="#event-on-update-reading">event-on-update-reading</a></li>
<li><a href="#event-on-change-reading">event-on-change-reading</a></li> <li><a href="#event-on-change-reading">event-on-change-reading</a></li>
<li><a href="#stateFormat">stateFormat</a></li> <li><a href="#stateFormat">stateFormat</a></li>
</ul><br> <li>windowSensor<br>Defines a list of window sensors. When one of its window state readings is <b>open</b> the aktual switch is delayed.</li> </ul><br>
</ul> </ul>
=end html =end html
@ -480,7 +586,7 @@ sub SortNumber {
<a name="Heating_Controldefine"></a> <a name="Heating_Controldefine"></a>
<b>Define</b> <b>Define</b>
<ul> <ul>
<code>define &lt;name&gt; Heating_Control &lt;device&gt; &lt;profile&gt; &lt;command&gt;|&lt;condition&gt;</code> <code>define &lt;name&gt; Heating_Control &lt;device&gt; [&lt;language&gt;] &lt;profile&gt; &lt;command&gt;|&lt;condition&gt;</code>
<br><br> <br><br>
Bildet ein Wochenprofil f&uumlr ein &lt;device&gt;, zb. Heizk&oumlrper, ab.<br> Bildet ein Wochenprofil f&uumlr ein &lt;device&gt;, zb. Heizk&oumlrper, ab.<br>
@ -496,7 +602,12 @@ sub SortNumber {
<p> <p>
Folgende Parameter sind im Define definiert: Folgende Parameter sind im Define definiert:
<ul><b>device</b><br> <ul><b>device</b><br>
Das an den Schaltpunkten zu schaltende Device. Name des zu schaltenden Device.
</ul>
<p>
<ul><b>language</b><br>
Spezifiziert die Sprache für die Definition und die Anzeige der Profile in der Weboberfläche.
Zurzeit sind de,en,fr definiert. Der Parameter ist optional.
</ul> </ul>
<p> <p>
<ul><b>profile</b><br> <ul><b>profile</b><br>
@ -506,9 +617,10 @@ sub SortNumber {
<u>Wochentage:</u> optionale Angabe, falls nicht gesetzt wird der Schaltpunkt jeden Tag ausgef&uumlhrt. <u>Wochentage:</u> optionale Angabe, falls nicht gesetzt wird der Schaltpunkt jeden Tag ausgef&uumlhrt.
F&uumlr die Tage an denen dieser Schaltpunkt aktiv sein soll, ist jeder Tag mit seiner F&uumlr 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.<br> Tagesnummer (Mo=1, ..., So=7) oder Name des Tages (Mo, Di, ..., So) einzusetzen.<br>
<u>Uhrzeit:</u>Angabe der Uhrzeit an dem geschaltet werden soll, Format: HH:MM(HH im 24 Stunden format)<br> <u>Uhrzeit:</u>Angabe der Uhrzeit zu der geschaltet werden soll, Format: HH:MM:[SS](HH im 24 Stunden Format) oder eine Perlfunction wie {sunrise_abs()}<br>
<u>Parameter:</u>Angabe der zu setzenden Temperatur als Zahl mit Format 99.9 oder als symbolische Konstante <b>eco</b> <u>Parameter:</u>Angabe der zu setzenden Temperatur als Zahl mit Format 99.9 oder als symbolische Konstante <b>eco</b>
or <b>comfort</b> - was immer das Heizk&oumlrperthermostat versteht.<br> or <b>comfort</b> - was immer das Heizk&oumlrperthermostat versteht.
Symbolischen Werten kann ein zusätzlicher Parameter angehängt werden: dayTemp:16 night-temp:15. Unten folgen Beispiele<br><br>
</ul> </ul>
<p> <p>
<ul><b>command</b><br> <ul><b>command</b><br>
@ -532,7 +644,7 @@ sub SortNumber {
<p> <p>
<b>Beispiel:</b> <b>Beispiel:</b>
<ul> <ul>
<code>define HCB Heating_Control Bad_Heizung 12345|05:20|21 12345|05:25|comfort 17:20|21 17:25|eco</code><br> <code>define HCW Heating_Control Bad_Heizung 12345|05:20|21 12345|05:25|comfort 17:20|21 17:25|eco</code><br>
Mo-Fr wird die Temperatur um 05:20Uhr auf 21&deg;C, und um 05:25Uhr auf <b>comfort</b> gesetzt. Mo-Fr wird die Temperatur um 05:20Uhr auf 21&deg;C, und um 05:25Uhr auf <b>comfort</b> gesetzt.
Jeden Tag wird die Temperatur um 17:20Uhr auf 21&deg;C und 17:25Uhr auf <b>eco</b> gesetzt.<p> Jeden Tag wird die Temperatur um 17:20Uhr auf 21&deg;C und 17:25Uhr auf <b>eco</b> gesetzt.<p>
@ -542,6 +654,13 @@ sub SortNumber {
<code>define HCW Heating_Control WZ_Heizung Sa-So,Mi|08:00|21 (ReadingsVal("WeAreThere", "state", "no") eq "yes")</code><br> <code>define HCW Heating_Control WZ_Heizung Sa-So,Mi|08:00|21 (ReadingsVal("WeAreThere", "state", "no") eq "yes")</code><br>
Die zu setzende Temperatur wird nur gesetzt, falls die Dummy Variable WeAreThere = "yes" ist.<p> Die zu setzende Temperatur wird nur gesetzt, falls die Dummy Variable WeAreThere = "yes" ist.<p>
<code>define HCW Heating_Control WZ_Heizung en Su-Fr|{sunrise_abs()}|21 Mo-Fr|{sunset_abs()}|16</code><br>
Das Gerät wird bei Sonnenaufgang und Sonnenuntergang geschaltet. Sprache: Englisch.
<code>define HCW Heating_Control WZ_Heizung en Mo-Fr|{myFunction}|night-temp:18 Mo-Fr|{myFunction()}|dayTemp:16</code><br>
Das Gerät wird bei myFunction() geschaltet. Es wird das Kommando "night-temp 18" bzw. "dayTemp 16" gesendet.
<p>
</ul> </ul>
</ul> </ul>
@ -558,6 +677,7 @@ sub SortNumber {
<li><a href="#event-on-update-reading">event-on-update-reading</a></li> <li><a href="#event-on-update-reading">event-on-update-reading</a></li>
<li><a href="#event-on-change-reading">event-on-change-reading</a></li> <li><a href="#event-on-change-reading">event-on-change-reading</a></li>
<li><a href="#stateFormat">stateFormat</a></li> <li><a href="#stateFormat">stateFormat</a></li>
<li>windowSensor<br>Definiert eine Liste mit Fensterkontakten. Wenn das Reading window state eines Fensterkontakts <b>open</b> ist, wird der aktuelle Schaltvorgang verzögert.</li>
</ul><br> </ul><br>
</ul> </ul>

View File

@ -32,6 +32,11 @@ WeekdayTimer_Initialize($)
{ {
my ($hash) = @_; my ($hash) = @_;
if(!$modules{Heating_Control}{LOADED} && -f "$attr{global}{modpath}/FHEM/98_Heating_Control.pm") {
my $ret = CommandReload(undef, "98_Heating_Control");
Log3 undef, 1, $ret if($ret);
}
# Consumer # Consumer
$hash->{DefFn} = "WeekdayTimer_Define"; $hash->{DefFn} = "WeekdayTimer_Define";
$hash->{UndefFn} = "WeekdayTimer_Undef"; $hash->{UndefFn} = "WeekdayTimer_Undef";
@ -62,6 +67,14 @@ WeekdayTimer_Undef($$){
return Heating_Control_Undef($hash, $arg); return Heating_Control_Undef($hash, $arg);
} }
sub
WeekdayTimer_UpdatePerlTime($)
{
my ($hash) = @_;
Heating_Control_Define($hash, $hash->{NAME} . " " . $hash->{TYPE} . " " . $hash->{DEF} );
}
sub sub
WeekdayTimer_Update($){ WeekdayTimer_Update($){
my ($hash) = @_; my ($hash) = @_;
@ -80,7 +93,9 @@ sub WeekdayTimer_SetAllTemps() { # {WeekdayTimer_SetAllTemps()}
} }
} }
WeekdayTimer_Update($hash); WeekdayTimer_Update($hash);
Log3 undef, 3, "WeekdayTimer_Update() for $hash->{NAME} done!";
} }
Log3 undef, 3, "WeekdayTimer_SetAllTemps() done!";
} }
1; 1;