diff --git a/fhem/FHEM/98_DOIF.pm b/fhem/FHEM/98_DOIF.pm
index 3dcf6282a..bd133d51b 100644
--- a/fhem/FHEM/98_DOIF.pm
+++ b/fhem/FHEM/98_DOIF.pm
@@ -207,6 +207,22 @@ sub ReplaceReadingDoIf($)
}
}
+sub ReplaceReadingEvalDoIf($$)
+{
+ my ($element,$eval) = @_;
+ my ($block,$err,$device,$reading,$internal)=ReplaceReadingDoIf($element);
+ return ($block,$err) if ($err);
+ if ($eval) {
+ return ($device,"device does not exist: $device") if(!$defs{$device});
+ return ($block,"reading does not exist: $device:$reading") if (defined ($reading) and !defined($defs{$device}{READINGS}{$reading}));
+ return ($block,"internal does not exist: $device:$internal") if (defined ($internal) and !defined($defs{$device}{$internal}));
+ my $ret = eval $block;
+ return($block." ",$@) if ($@);
+ $block=$ret;
+ }
+ return ($block,"",$device,$reading,$internal);
+}
+
sub AddItemDoIf($$)
{
my ($items,$item)=@_;
@@ -244,25 +260,12 @@ sub ReplaceAllReadingsDoIf($$$$)
$block=substr($block,1);
$trigger=0;
}
- if ($condition >= 0) {
- ($timer,$err)=DOIF_CheckTimers($hash,$block,$condition,$trigger,\@timerarray);
- return($timer,$err) if ($err);
- if ($timer) {
- $cmd.=$beginning.$timer;
- $event=1 if ($trigger);
- next;
- }
- }
- if ($block =~ /:/ or ($block =~ /[a-z]/i and $block =~ /^[a-z0-9._]*$/i)) {
- ($block,$err,$device,$reading,$internal)=ReplaceReadingDoIf($block);
+ # if ($block =~ /^[0-9]+$/) {
+ # $block="[".$block."]";
+ # } elsif
+ if ($block =~ /^\??[a-z0-9._]*[a-z._]+[a-z0-9._]*($|:.+$)/i) {
+ ($block,$err,$device,$reading,$internal)=ReplaceReadingEvalDoIf($block,$eval);
return ($block,$err) if ($err);
- if ($eval) {
- return ($block,"reading does not exist: [$device:$reading]") if (defined ($reading) and !defined($defs{$device}{READINGS}{$reading}));
- return ($block,"internal does not exist: [$device:$internal]") if (defined ($internal) and !defined($defs{$device}{$internal}));
- my $ret = eval $block;
- return($block." ",$@) if ($@);
- $block=$ret;
- }
if ($trigger) {
if ($condition >= 0) {
$hash->{devices}{$condition} = AddItemDoIf($hash->{devices}{$condition},$device);
@@ -279,6 +282,13 @@ sub ReplaceAllReadingsDoIf($$$$)
$hash->{itimer}{all} = AddItemDoIf($hash->{itimer}{all},$device);
}
}
+ } elsif ($condition >= 0) {
+ ($timer,$err)=DOIF_CheckTimers($hash,$block,$condition,$trigger,\@timerarray);
+ return($timer,$err) if ($err);
+ if ($timer) {
+ $block=$timer;
+ $event=1 if ($trigger);
+ }
} else {
$block="[".$block."]";
}
@@ -377,66 +387,80 @@ DOIF_CheckTimers($$$$$)
my $block;
my $result;
my ($hash,$timer,$condition,$trigger,$timerarray)=@_;
- if ($timer =~ /^(\+)?((\{.*\})|(\[.*\])|([0-9][0-9](:[0-5][0-9]){1,2}))(\|[0-8]+$|-(\+)?(([0-9][0-9](:[0-5][0-9]){1,2})|({.*})|(\[.*\]))|$)(\|[0-8]+$|$)/) {
- while ($timer ne "") {
- if ($timer=~ /^\s*\{/) {
- ($beginning,$time,$err,$timer)=GetBlockDoIf($timer,'[\{\}]');
- return ($time,$err) if ($err);
- $time="{".$time."}";
- if ($timer =~ /^\s*\|/g) {
- $pos=pos($timer);
- $days=substr($timer,$pos);
- $timer="";
- }
- } elsif ($timer=~ /^\s*\[/) {
- ($beginning,$time,$err,$timer)=GetBlockDoIf($timer,'[\[\]]');
- return ($time,$err) if ($err);
- $time="[".$time."]";
- ($result,$err)=ReplaceAllReadingsDoIf($hash,$time,-3,0);
- return ($time,$err) if ($err);
- if ($timer =~ /^\s*\|/g) {
- $pos=pos($timer);
- $days=substr($timer,$pos);
- $timer="";
- }
- } elsif ($timer =~ /-/g) {
- $pos=pos($timer)-1;
- $time=substr($timer,0,$pos);
- $timer=substr($timer,$pos+1);
- } else {
- ($time,$days)=split(/\|/,$timer);
- $timer="";
- }
- $times[$i]=$time;
- $nrs[$i++]=$hash->{helper}{last_timer}++;
- $timer=substr($timer,pos($timer)) if ($timer =~ /^\s*\-/g);
- }
- $days = "" if (!defined ($days));
- for (my $j=0; $j<$i;$j++) {
- $nr=$nrs[$j];
- $time=$times[$j];
- $time .=":00" if ($time =~ m/^[0-9][0-9]:[0-5][0-9]$/);
- $hash->{timer}{$nr}=0;
- $hash->{time}{$nr}=$time;
- $hash->{timeCond}{$nr}=$condition;
- $hash->{days}{$nr}=$days if ($days ne "");
- ${$timerarray}[$nr]={hash=>$hash,nr=>$nr};
- if ($init_done) {
- $err=(DOIF_SetTimer("DOIF_TimerTrigger",\${$timerarray}[$nr]));
- return($hash->{time}{$nr},$err) if ($err);
- }
- $hash->{timers}{$condition}.=" $nr " if ($trigger);
- $hash->{timerfunc}{$nr}=\${$timerarray}[$nr];
- }
- if ($i == 2) {
- $block='DOIF_time($hash->{realtime}{'.$nrs[0].'},$hash->{realtime}{'.$nrs[1].'},$wday,$hms,"'.$days.'")';
+ $timer =~ s/\s//g;
+ while ($timer ne "") {
+ if ($timer=~ /^\s*\+\(/) {
+ ($beginning,$time,$err,$timer)=GetBlockDoIf($timer,'[\(\)]');
+ return ($time,$err) if ($err);
+ $time="+(".$time.")";
+ ($result,$err)=ReplaceAllReadingsDoIf($hash,$time,-3,0);
+ return ($time,$err) if ($err);
+ } elsif ($timer=~ /^\s*\(/) {
+ ($beginning,$time,$err,$timer)=GetBlockDoIf($timer,'[\(\)]');
+ return ($time,$err) if ($err);
+ $time="(".$time.")";
+ ($result,$err)=ReplaceAllReadingsDoIf($hash,$time,-3,0);
+ return ($time,$err) if ($err);
+ } elsif ($timer=~ /^\s*\{/) {
+ ($beginning,$time,$err,$timer)=GetBlockDoIf($timer,'[\{\}]');
+ return ($time,$err) if ($err);
+ $time="{".$time."}";
+ } elsif ($timer=~ /^\s*\+\[/) {
+ ($beginning,$time,$err,$timer)=GetBlockDoIf($timer,'[\[\]]');
+ return ($time,$err) if ($err);
+ $time="+[".$time."]";
+ ($result,$err)=ReplaceAllReadingsDoIf($hash,$time,-3,0);
+ return ($time,$err) if ($err);
+ } elsif ($timer=~ /^\s*\[/) {
+ ($beginning,$time,$err,$timer)=GetBlockDoIf($timer,'[\[\]]');
+ return ($time,$err) if ($err);
+ $time="[".$time."]";
+ ($result,$err)=ReplaceAllReadingsDoIf($hash,$time,-3,0);
+ return ($time,$err) if ($err);
+ } elsif ($timer =~ /-/g) {
+ $pos=pos($timer)-1;
+ $time=substr($timer,0,$pos);
+ $timer=substr($timer,$pos);
} else {
- $block='DOIF_time_once($hash->{timer}{'.$nrs[0].'},$wday,"'.$days.'")';
+ ($time,$days)=split(/\|/,$timer);
+ $timer="";
}
- return ($block,"");
+ $times[$i]=$time;
+ $nrs[$i++]=$hash->{helper}{last_timer}++;
+ if ($timer) {
+ if ($timer =~ /\-/g) {
+ $timer=substr($timer,pos($timer));
+ } elsif ($timer =~ /\|/g) {
+ $days=substr($timer,pos($timer));
+ $timer="";
+ } else {
+ return ($timer,"wrong time format");
+ }
+ }
+ }
+ $days = "" if (!defined ($days));
+ for (my $j=0; $j<$i;$j++) {
+ $nr=$nrs[$j];
+ $time=$times[$j];
+ $time .=":00" if ($time =~ m/^[0-9][0-9]:[0-5][0-9]$/);
+ $hash->{timer}{$nr}=0;
+ $hash->{time}{$nr}=$time;
+ $hash->{timeCond}{$nr}=$condition;
+ $hash->{days}{$nr}=$days if ($days ne "");
+ ${$timerarray}[$nr]={hash=>$hash,nr=>$nr};
+ if ($init_done) {
+ $err=(DOIF_SetTimer("DOIF_TimerTrigger",\${$timerarray}[$nr]));
+ return($hash->{time}{$nr},$err) if ($err);
+ }
+ $hash->{timers}{$condition}.=" $nr " if ($trigger);
+ $hash->{timerfunc}{$nr}=\${$timerarray}[$nr];
}
- delete ($hash->{helper}{modify});
- return("","");
+ if ($i == 2) {
+ $block='DOIF_time($hash->{realtime}{'.$nrs[0].'},$hash->{realtime}{'.$nrs[1].'},$wday,$hms,"'.$days.'")';
+ } else {
+ $block='DOIF_time_once($hash->{timer}{'.$nrs[0].'},$wday,"'.$days.'")';
+ }
+ return ($block,"");
}
sub
@@ -673,7 +697,7 @@ DOIF_Trigger ($$$)
}
}
if ($doelse) { #DOELSE
- if (defined ($hash->{do}{$max_cond}) or $max_cond == 1) { #DOELSE
+ if (defined ($hash->{do}{$max_cond}) or ($max_cond == 1 and !(AttrVal($pn,"do","") or AttrVal($pn,"repeatsame","")))) { #DOELSE
if (DOIF_SetSleepTimer($hash,$last_cond,$max_cond,$device,$timerNr)) {
DOIF_cmd ($hash,$max_cond,$event) ;
return 1;
@@ -704,7 +728,7 @@ DOIF_Notify($$)
DOIF_SetTimer("DOIF_TimerTrigger",$hash->{timerfunc}{$j});
}
}
- return undef;
+ # return undef;
}
if (($hash->{itimer}{all}) and $hash->{itimer}{all} =~ / $dev->{NAME} /) {
@@ -756,7 +780,7 @@ DOIF_Notify($$)
sub
DOIF_TimerTrigger ($)
{
-my ($timer)=@_;
+ my ($timer)=@_;
my $nr=${$timer}->{nr};
my $hash=${$timer}->{hash};
my $ret;
@@ -769,6 +793,141 @@ my ($timer)=@_;
return($ret);
}
+sub
+DOIF_DetTime($)
+{
+ my ($timeStr) = @_;
+ my $rel=0;
+ my $align;
+ my $hr=0;
+ my $err;
+ my $h=0;
+ my $m=0;
+ my $s=0;
+ my $fn;
+ if (substr($timeStr,0,1) eq "+") {
+ $timeStr=substr($timeStr,1);
+ $rel=1;
+ }
+ my ($now, $microseconds) = gettimeofday();
+ my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
+ if($timeStr =~ m/^\[([0-9]+)\]:([0-5][0-9])$/) {
+ $hr=$1;
+ $rel=0;
+ $align=$2;
+ } elsif ($timeStr =~ m/^:([0-5][0-9])$/) {
+ $align=$1;
+ } elsif ($timeStr =~ m/^([0-9]+)$/) {
+ $s=$1;
+ } else {
+ if ($timeStr =~ m/^\$hms$/) {
+ $timeStr = sprintf("%02d:%02d:%02d", $hour, $min, $sec);
+ } elsif ($timeStr =~ m/^\$hm$/) {
+ $timeStr = sprintf("%02d:%02d", $hour, $min);
+ }
+ ($err, $h, $m, $s, $fn) = GetTimeSpec($timeStr);
+ return $err if ($err);
+ }
+ if (defined ($align)) {
+ if ($rel) {
+ if ($align > 0) {
+ $m = (int($min/$align)+1)*$align;
+ if ($m>=60) {
+ $h = $hour+1;
+ $m = 0;
+ } else {
+ $h = $hour;
+ }
+ }
+ } else {
+ $m=$align;
+ if ($hr > 1) {
+ $h = (int($hour/$hr)+1)*$hr;
+ $h = 0 if ($h >=24);
+ } else {
+ if ($m <= $min) {
+ $h = $hour+1;
+ } else {
+ $h = $hour;
+ }
+ }
+ }
+ }
+ my $second = $h*3600+$m*60+$s;
+ if ($second == 0 and $rel) {
+ $err = "null is not allowed on a relative time";
+ }
+ return ($err, ($rel and !defined ($align)), $second);
+}
+
+sub
+DOIF_CalcTime($)
+{
+ my ($block)= @_;
+ my $tailBlock;
+ my $beginning;
+ my $err;
+ my $cmd="";
+ my $rel="";
+ my $relGlobal=0;
+ my $reading;
+ my $internal;
+ my $device;
+ my $pos;
+ my $ret;
+
+ if ($block =~ /^\s*\+/g) {
+ $relGlobal=1;
+ $pos=pos($block);
+ $block=substr($block,$pos);
+ }
+
+ if ($block =~ /^\s*\(/) {
+ ($beginning,$tailBlock,$err,$tailBlock)=GetBlockDoIf($block,'[\(\)]');
+ return ($tailBlock,$err) if ($err);
+ } else {
+ if ($block =~ /^\s*\[/) {
+ ($beginning,$block,$err,$tailBlock)=GetBlockDoIf($block,'[\[\]]');
+ return ($block,$err) if ($err);
+ ($block,$err,$device,$reading,$internal)=ReplaceReadingEvalDoIf($block,1);
+ return ($block,$err) if ($err);
+ }
+ ($err,$rel,$block)=DOIF_DetTime($block);
+ $rel=1 if ($relGlobal);
+ return ($block,$err,$rel);
+ }
+ $tailBlock=$block;
+ while ($tailBlock ne "") {
+ ($beginning,$block,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\[\]]');
+ return ($block,$err) if ($err);
+ if ($block ne "") {
+ if ($block =~ /^\??[a-z0-9._]*[a-z._]+[a-z0-9._]*($|:.+$)/i) {
+ ($block,$err,$device,$reading,$internal)=ReplaceReadingEvalDoIf($block,1);
+ return ($block,$err) if ($err);
+ }
+ ($err,$rel,$block)=DOIF_DetTime($block);
+ }
+ $cmd.=$beginning.$block;
+ }
+ $tailBlock=$cmd;
+ $cmd="";
+ while ($tailBlock ne "") {
+ ($beginning,$block,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\{\}]');
+ return ($block,$err) if ($err);
+ if ($block ne "") {
+ $ret = eval $block;
+ return($block." ",$@) if ($@);
+ $block=$ret;
+ ($err,$rel,$block)=DOIF_DetTime($block);
+ }
+ $cmd.=$beginning.$block;
+ }
+ $ret = eval $cmd;
+ return($cmd." ",$@) if ($@);
+ return ($ret,"null is not allowed on a relative time",$relGlobal) if ($ret == 0 and $relGlobal);
+ return ($ret,"",$relGlobal);
+}
+
sub
DOIF_SetTimer($$)
{
@@ -777,37 +936,20 @@ DOIF_SetTimer($$)
my $hash=${$timer}->{hash};
my $timeStr=$hash->{time}{$nr};
my $cond=$hash->{timeCond}{$nr};
- my $rel=0;
my $next_time;
- if (substr($timeStr,0,1) eq "+") {
- $timeStr=substr($timeStr,1);
- $rel=1;
- }
- if ($timeStr=~ /^\s*\[/) {
- my $err;
- ($timeStr,$err)=ReplaceAllReadingsDoIf($hash,$timeStr,-3,1);
- if ($err)
- {
+
+ my ($second,$err, $rel)=DOIF_CalcTime($timeStr);
+ if ($err)
+ {
readingsSingleUpdate ($hash,"timer_".($nr+1)."_c".($cond+1),"error: ".$err,0);
RemoveInternalTimer($timer);
$hash->{realtime}{$nr}="00:00:00";
return $err;
- }
}
- my ($err, $h, $m, $s, $fn) = GetTimeSpec($timeStr);
- if ($err)
- {
- readingsSingleUpdate ($hash,"timer_".($nr+1)."_c".($cond+1),"error: ".$err,0);
- RemoveInternalTimer($timer);
- $hash->{realtime}{$nr}="00:00:00";
- return $err;
- }
- return $err if($err);
- my $second = $h*3600+$m*60+$s;
- #my $now = time();
my ($now, $microseconds) = gettimeofday();
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($now);
my $isdst_now=$isdst;
+
my $sec_today = $hour*3600+$min*60+$sec;
my $midnight = $now-$sec_today;
if ($rel) {
@@ -815,7 +957,7 @@ DOIF_SetTimer($$)
} else {
$next_time = $midnight+$second;
}
- $next_time+=86400 if ($sec_today>=$second and !$rel);
+ $next_time+=86400 if ($second <= $sec_today and !$rel);
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($next_time);
if ($isdst_now != $isdst) {
if ($isdst_now == 1) {
@@ -1093,8 +1235,8 @@ Complex problems can be solved with this module, which would otherwise be solved
Logical queries are created in conditions using Perl operators.
These are combined with information from states, readings, internals of devices or times in square brackets.
-Arbitrary Perl functions can also be specified that are defined in FHEM.
-The module is triggered by time or by events information through the Devices specified in the condition.
+Arbitrary Perl functions can also be specified that are defined in FHEM.
+The module is triggered by time or by events information through the Devices specified in the condition.
If a condition is true, the associated FHEM- or Perl commands are executed.
Syntax:
@@ -1110,7 +1252,9 @@ The commands are always processed from left to right. There is only one command
+ it can be any FHEM commands and perl commands are executed
+ syntax checking at the time of definition are identified missing brackets
+ status is specified with [<devicename>], readings with [<devicename>:<readingname>] or internals with [<devicename>:&<internal>]
-+ time information on the condition: [HH:MM:SS] or [HH:MM] or [[<devicename>]] or [[<devicename>:<readingname>]] or [{<perl-function>}]
++ time information on the condition: [HH:MM:SS] or [HH:MM] or [<seconds>]
++ indirect time on the condition: [[<devicename>]] or [[<devicename>:<readingname>]] or [{<perl-function>}]
++ time calculation on the condition: [(<time calculation in Perl with time syntax specified above>)]
+ time intervals: [<begin>-<end>] for <begin> and <end>, the above time format can be selected.
+ relative times preceded by a plus sign [+<time>] or [+<begin>-+<end>] combined with Perl functions
+ weekday control: [<time>|012345678] or [<begin>-<end>|012345678] (0-6 corresponds to Sunday through Saturday) such as 7 for $we and 8 for !$we
@@ -1137,50 +1281,63 @@ Es vereinigt die Funktionalität eines notify-, at-, watchdog-Befehls in Kombina
Damit können insb. komplexere Problemstellungen innerhalb eines DOIF-Moduls gelöst werden, die sonst nur mit Hilfe einzelner Module an mehreren Stellen in FHEM vorgenommen werden müssten. Das führt zu übersichtlichen Lösungen und vereinfacht deren Pflege.
Logische Abfragen werden in Bedingungen mit Hilfe von Perl-Operatoren erstellt.
-Diese werden mit Angaben von Stati, Readings, Internals, Events von Devices oder Zeiten in eckigen Klammern kombiniert. Ebenso können beliebige Perl-Funktionen angegeben werden, die in FHEM definiert sind.
+Diese werden mit Angaben von Stati, Readings, Internals, Events von Devices oder Zeiten in eckigen Klammern kombiniert. Ebenso können beliebige Perl-Funktionen angegeben werden, die in FHEM definiert sind.
Getriggert wird das Modul durch Zeitangaben bzw. durch Ereignisse ausgelöst durch die in der Bedingung angegebenen Devices.
Wenn eine Bedingung wahr wird, so werden die dazugehörigen FHEM- bzw. Perl-Kommandos ausgeführt.
Syntax:
-define <name> DOIF (<Bedingung>) (<Befehle>) DOELSEIF (<Bedingung>) (<Befehle>) DOELSEIF ... DOELSE (<Befehle>)
+
define <name> DOIF (<Bedingung>) (<Befehle>) DOELSEIF (<Bedingung>) (<Befehle>) DOELSEIF ... DOELSE (<Befehle>)define di_rc_tv DOIF ([remotecontol] eq "on") (set tv on) DOELSE (set tv off)define di_clock_radio DOIF ([06:30]) (set radio on) DOELSEIF ([08:00]) (set radio off)define di_lamp DOIF ([06:00-09:00] and [sensor:brightness] < 40) (set lamp on) DOELSE (set lamp off)[<devicename>], Readings mit [<devicename>:<readingname>], Internals mit [<devicename>:&<internal>] oder Events mit [<devicename>:?<regexp>] angegeben[HH:MM:SS] oder [HH:MM] oder [[<devicename>]] oder [[<devicename>:<readingname>]] oder [{<perl-function>}][<begin>-<end>] für <begin> bzw. <end> kann das obige Zeitformat gewählt werden[+<time>] oder [+<begin>-+<end>] kombinierbar mit Perl-Funktionen s. o.[<time>|012345678] oder [<begin>-<end>|012345678] (0-6 entspricht Sonntag bis Samstag) sowie 7 für $we und 8 für !$we[?...]==, !=, <, <=, >, >= bei Zahlen und mit eq, ne, lt, le, gt, ge, =~ bei Zeichenketten angegeben.
+Vergleichende Abfragen werden, wie in Perl gewohnt, mit Operatoren ==, !=, <, <=, >, >= bei Zahlen und mit eq, ne, lt, le, gt, ge, =~, !~ bei Zeichenketten angegeben.
Logische Verknüpfungen sollten zwecks Übersichtlichkeit mit and bzw. or vorgenommen werden.
Selbstverständlich lassen sich auch alle anderen Perl-Operatoren verwenden, da die Auswertung der Bedingung vom Perl-Interpreter vorgenommen wird.
-Die Reihenfolge der Auswertung wird, wie in höheren Sprachen üblich, durch runde Klammern beeinflusst.[<devicename>], Readings mit [<devicename>:<readingname>],
+Internals mit [<devicename>:&<internal>] angegeben.define di_garage DOIF ([remotecontrol] eq "on") (set garage on) DOELSEIF ([remotecontrol] eq "off") (set garage off)define di_garage DOIF ([remotecontrol] eq "on") (set garage on) DOELSEIF ([remotecontrol] eq "off") (set garage off)attr di_garage do alwaysdefine di_heating DOIF ([sens:temperature] < 20) (set heating on)do always nicht sinnvoll, da das entsprechende Kommando hier: "set heating on" jedes mal ausgeführt wird,
+wenn der Temperatursensor in regelmäßigen Abständen eine Temperatur unter 20 Grad sendet.
+Ohne do always wird hier dagegen erst wieder "set heating on" ausgeführt, wenn der Zustand des Moduls gewechselt hat, also die Temperatur zwischendurch größer oder gleich 20 Grad war.=~ vorgenommen werden.=~, insb
[<devicename>:?<regexp>]...(set lamp on)... (set lamp1 on, set lamp2 off)...((set lamp1,lamp2 on),set switch on)... ({system ("wmail Peter is at home")}) ...({system ("wmail Peter is at home");;system ("wmail Marry is at home")})... ({system ("wmail Peter is at home")}, set lamp on)[HH:MM:SS] oder [HH:MM] oder [Zahl]define di_light DOIF ([08:00]) (set switch on,set lamp on) DOELSEIF ([10:00]) (set switch off,set lamp off)define di_light DOIF ([08:00]) ((set lamp1,lamp2 on),set switch on)define di_light DOIF ([08:00]) (set switch on) DOELSEIF ([10:00]) (set switch off)define di_light DOIF ([08:00] or [10:00] or [20:00]) (set switch on) DOELSEIF ([09:00] or [11:00] or [00:00]) (set switch off)define di_light DOIF ([3600]) (set lamp on)define di_save DOIF ([+01:00]) (save)
attr di_save do alwaysdefine di_save DOIF ([+3600]) (save)define di_gong DOIF ([:00])
+ ({system ("mplayer /opt/fhem/Sound/BigBen_00.mp3 -volume 90 −really−quiet &")})
+DOELSEIF ([:15])
+ ({system ("mplayer /opt/fhem/Sound/BigBen_15.mp3 -volume 90 −really−quiet &")})
+DOELSEIF ([:30])
+ ({system ("mplayer /opt/fhem/Sound/BigBen_30.mp3 -volume 90 −really−quiet &")})
+DOELSEIF ([:45])
+ ({system ("mplayer /opt/fhem/Sound/BigBen_45.mp3 -volume 90 −really−quiet &")})
+define di_gong DOIF ([+:15]) (set Gong_mp3 playTone 1)
+attr di_gong do alwaysdefine di_gong DOIF ([+[2]:05]) (set pump on-for-timer 300)
+attr di_gong do always[<time>|012345678] 0-8 entspricht: 0-Sonntag, 1-Montag, ... bis 6-Samstag sowie 7 für Wochende und Feiertage (entspricht $we) und 8 für Arbeitstage (entspricht !$we)define di_radio DOIF ([06:30|8] or [08:30|7]) (set radio on) DOELSEIF ([07:30|8] or [09:30|7]) (set radio off)[<begin>-<end>] für <begin> bzw. <end> wird das gleiche Zeitformat verwendet, wie bei einzelnen Zeitangaben.define di_radio DOIF ([08:00-10:00] or [20:00-22:00]) (set radio on) DOELSE (set radio off) define di_radio DOIF ([08:00-10:00|06]) (set radio on) DOELSE (set radio off) define di_radio DOIF ([08:00-10:00|0]) (set radio on) DOELSE (set radio off) define di_radio DOIF ([08:00-10:00|7]) (set radio on) DOELSE (set radio off) define di_radio DOIF ([08:00-10:00|8]) (set radio on) DOELSE (set radio off) define di_light DOIF ([22:00-07:00]) (set light on) DOELSE (set light off) time einstellbar sein:define time dummy
+set time 300
+define di_time DOIF ([+[time]])(save)define begin dummy
@@ -1313,6 +1538,47 @@ Indirekte Zeitangaben lassen sich mit Wochentagangaben kombinieren, z. B.:
define di_time DOIF ([[begin]-[end]|7]) (set radio on) DOELSE (set radio off)
+Zeitsteuerung mit Zeitberechnung
+
+Zeitberechnungen werden innerhalb der eckigen Klammern zusätzlich in runde Klammern gesetzt. Die berechneten Triggerzeiten können absolut oder relativ mit einem Pluszeichen vor den runden Klammern angegeben werden.
+Es können beliebige Ausdrücke der Form HH:MM und Angaben in Sekunden als ganze Zahl in Perl-Rechenoperationen kombiniert werden.
+Perlfunktionen, wie z. B. sunset(), die eine Zeitangabe in HH:MM liefern, werden in geschweifte Klammern gesetzt.
+Zeiten im Format HH:MM bzw. Stati oder Readings, die Zeitangaben in dieser Form beinhalten werden in eckige Klammern gesetzt.
+
+Anwendungsbeispiele:
+
+Lampe wird nach Sonnenuntergang zwischen 900 und 1500 (900+600) Sekunden zufällig zeitverzögert eingeschaltet. Ausgeschaltet wird die Lampe nach 23:00 Uhr um bis zu 600 Sekunden zufällig verzögert:
+
+define di_light DOIF ([({sunset()}+300+int(rand(600)))])
+ (set lamp on)
+DOELSEIF ([([23:00]+int(rand(600)))])
+ (set lamp off)
+
+Zeitberechnung können ebenfalls in Zeitintervallen genutzt werden.
+
+Licht soll eine Stunde vor gegebener Zeit eingeschaltet werden und eine Stunde danach wieder ausgehen:
+
+define Fixtime dummy
+set Fixtime 20:00
+
+define di_light DOIF ([([Fixtime]-[01:00]) - ([Fixtime]+[01:00])])
+ (set lampe on)
+DOELSE
+ (set lampe off)
+
+
+Hier das Gleiche wie oben, zusätzlich mit Zufallsverzögerung von 300 Sekunden und nur an Wochenenden:
+
+define di_light DOIF ([([Fixtime]-[01:00]-int(rand(300))) - ([Fixtime]+[01:00]+int(rand(300)))]|7])
+ (set lampe on)
+DOELSE
+ (set lampe off)
+
+
+Ein Änderung des Dummys Fixtime z. B. durch "set Fixtime ...", führt zur sofortiger Neuberechnung der Timer im DOIF-Modul.
+
+Für die Zeitberechnung wird der Perlinterpreter benutzt, daher sind für die Berechnung der Zeit keine Grenzen gesetzt.
+
Kombination von Ereignis- und Zeitsteuerung mit logischen Abfragen
Anwendungsbeispiel: Lampe soll ab 6:00 Uhr angehen, wenn es dunkel ist und wieder ausgehen, wenn es hell wird, spätestens aber um 9:00 Uhr:
@@ -1378,14 +1644,6 @@ Eine erneute Benachrichtigung wird erst wieder ausgelöst, wenn zwischendurch de
define di_shutters DOIF ([Sun] eq "on") (set shutters down) DOELSE (set shutters up)
attr di_shutters wait 1200:1200
-Anwendungsbeispiel: Rolladen nach Sonnenuntergang mit Zufallsverzögerung von 10 bis 20 Minuten herunterfahren:
-
-define di_shutters DOIF ([{sunset_abs()}]) (set shutters down, attr di_shutters wait {(600+int(rand(600)))})
-attr di_shutters do always
-attr di_shutters wait 600
-
-Hier wird der wait-timer per wait-Attribut für die nächste Ausführung per Zufall vorbereitet.
-
Anwendungsbeispiel: Beschattungssteuerung abhängig von der Temperatur. Der Rollladen soll runter von 11:00 Uhr bis Sonnenuntergang, wenn die Temperatur über 26 Grad ist. Temperaturschwankungen um 26 Grad werden mit Hilfe des wait-Attributes durch eine 15 minutige Verzögerung ausgeglichen.
define di_shutters DOIF ([sensor:temperature] > 26 and [11:00-{sunset_abs()}] (set shutters down) DOELSE (set shutters up)
@@ -1586,13 +1844,6 @@ attr di_light do always
müssen mit Attribut do always definiert werden, damit sie nicht nur einmal, sondern jedes mal (hier jeden Tag) ausgeführt werden.
-Bei der Angabe von zyklisch sendenden Sensoren (Temperatur, Feuchtigkeit, Helligkeit usw.) wie z. B.:
-
-define di_heating DOIF ([sens:temperature] < 20)(set heating on)
-
-ist die Nutzung des Attributes do always nicht sinnvoll, da das entsprechende Kommando hier: "set heating on" jedes mal ausgeführt wird,
-wenn der Temperatursensor in regelmäßigen Abständen eine Temperatur unter 20 Grad sendet.
-
Rekursionen vermeiden
Das Verändern des Status eines Devices z. B. durch set-Befehl, welches in der Bedingung bereits vorkommt, würde das Modul erneut triggern.