diff --git a/FHEM/98_DOIF.pm b/FHEM/98_DOIF.pm
index 7aaac7e20..ff6c6f713 100644
--- a/FHEM/98_DOIF.pm
+++ b/FHEM/98_DOIF.pm
@@ -55,6 +55,7 @@ DOIF_delAll($)
delete ($hash->{readings});
delete ($hash->{internals});
delete ($hash->{trigger});
+ delete ($hash->{regexp});
delete ($defs{$hash->{NAME}}{READINGS});
}
@@ -68,7 +69,7 @@ DOIF_Initialize($)
$hash->{UndefFn} = "DOIF_Undef";
$hash->{AttrFn} = "DOIF_Attr";
$hash->{NotifyFn} = "DOIF_Notify";
- $hash->{AttrList} = "disable:0,1 loglevel:0,1,2,3,4,5,6 wait do:always,resetwait cmdState state initialize repeatsame repeatcmd waitsame waitdel cmdpause timerWithWait ".$readingFnAttributes;
+ $hash->{AttrList} = "disable:0,1 loglevel:0,1,2,3,4,5,6 wait do:always,resetwait cmdState state initialize repeatsame repeatcmd waitsame waitdel cmdpause timerWithWait notexist ".$readingFnAttributes;
}
@@ -109,21 +110,55 @@ GetBlockDoIf ($$)
return ($cmd,"","","");
}
}
+sub
+EventCheckDoif($$$$)
+{
+ my ($n,$dev,$eventa,$NotifyExp)=@_;
+ my $found=0;
+ my $s;
+ return 0 if ($dev ne $n);
+ return 0 if(!$eventa);
+ my $max = int(@{$eventa});
+ my $ret = 0;
+ if ($NotifyExp eq "") {
+ return 1 ;
+ }
+ for (my $i = 0; $i < $max; $i++) {
+ $s = $eventa->[$i];
+ $s = "" if(!defined($s));
+ $found = ($s =~ m/$NotifyExp/);
+ if ($found) {
+ return 1;
+ }
+ }
+ return 0;
+}
sub
EventDoIf($$$$)
{
- my ($n,$dev,$events,$NotifyExp)=@_;
- return 0 if ($dev ne $n);
- return 0 if(!$events); # Some previous notify deleted the array.
- my $max = int(@{$events});
+ my ($n,$hash,$NotifyExp,$check)=@_;
+ my $dev=$hash->{helper}{triggerDev};
+ my $eventa=$hash->{helper}{triggerEvents};
+ if ($check) {
+ return 0 if ($dev ne $n);
+ } else {
+ return 0 if ($n and $dev !~ /$n/);
+ }
+ return 0 if(!$eventa);
+ my $max = int(@{$eventa});
my $ret = 0;
- return 1 if ($NotifyExp eq "");
+ if ($NotifyExp eq "") {
+ return 1 ;
+ }
for (my $i = 0; $i < $max; $i++) {
- my $s = $events->[$i];
+ my $s = $eventa->[$i];
$s = "" if(!defined($s));
my $found = ($s =~ m/$NotifyExp/);
- return 1 if ($found);
+ if ($found) {
+ $hash->{helper}{event}=$s;
+ return 1;
+ }
#if(!$found && AttrVal($n, "eventMap", undef)) {
# my @res = ReplaceEventMap($n, [$n,$s], 0);
# shift @res;
@@ -134,18 +169,20 @@ EventDoIf($$$$)
}
sub
-InternalDoIf($$$)
-{
- my ($name,$internal,$regExp)=@_;
+InternalDoIf($$$$)
+{
+ my ($name,$internal,$regExp,$default)=@_;
my $r="";
my $element;
- $r=$defs{$name}{$internal};
- if ($regExp) {
- $element = ($r =~ /$regExp/) ? $1 : "";
- } else {
- $element=$r;
- }
- return($element);
+ return ($default =~ /"(.*)"/) ? $1 : $default if (!defined $defs{$name});
+ return ($default =~ /"(.*)"/) ? $1 : $default if (!defined $defs{$name}{$internal});
+ $r=$defs{$name}{$internal};
+ if ($regExp) {
+ $element = ($r =~ /$regExp/) ? $1 : "";
+ } else {
+ $element=$r;
+ }
+ return($element);
}
sub
@@ -157,11 +194,13 @@ ReadingSecDoIf($$)
}
sub
-ReadingValDoIf($$$)
+ReadingValDoIf($$$$)
{
- my ($name,$reading,$regExp)=@_;
+ my ($name,$reading,$regExp,$default)=@_;
my $r;
my $element;
+ return ($default =~ /"(.*)"/) ? $1 : $default if (!defined $defs{$name});
+ return ($default =~ /"(.*)"/) ? $1 : $default if (!defined $defs{$name}{READINGS}{$reading}{VAL});
$r=$defs{$name}{READINGS}{$reading}{VAL};
$r="" if (!defined($r));
if ($regExp) {
@@ -173,15 +212,21 @@ ReadingValDoIf($$$)
}
sub
-EvalAllDoIf($)
+EvalAllDoIf($$)
{
- my ($tailBlock)= @_;
+ my ($hash,$tailBlock)= @_;
my $eval="";
my $beginning;
my $err;
my $cmd="";
my $ret="";
-
+ my $eventa=$hash->{helper}{triggerEvents};
+ my $device=$hash->{helper}{triggerDev};
+ my $event=$hash->{helper}{event};
+ my $events="";
+ if ($eventa) {
+ $events=join(",",@{$eventa});
+ }
while ($tailBlock ne "") {
($beginning,$eval,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\{\}]');
return ($eval,$err) if ($err);
@@ -210,12 +255,14 @@ sub ReplaceReadingDoIf($)
my $internal="";
my $notifyExp="";
if ($name) {
- #return ($name,"unknown Device") if(!$defs{$name});
if ($reading) {
if (substr($reading,0,1) eq "\?") {
$notifyExp=substr($reading,1);
- return("EventDoIf('$name',".'$hash->{helper}{triggerDev},'.'$hash->{helper}{triggerEvents},'."'$notifyExp')","",$name,undef,undef);
- }
+ return("EventDoIf('$name',".'$hash,'."'$notifyExp',1)","",$name,undef,undef);
+ } elsif ($reading =~ /^"(.*)"$/g) {
+ $notifyExp=$1;
+ return("EventDoIf('$name',".'$hash,'."'$notifyExp',1)","",$name,undef,undef);
+ }
$internal = substr($reading,1) if (substr($reading,0,1) eq "\&");
if ($format) {
if ($format eq "d") {
@@ -231,25 +278,27 @@ sub ReplaceReadingDoIf($)
}
}
if ($internal) {
- return("InternalDoIf('$name','$internal','$regExp')","",$name,undef,$internal);
+ return("InternalDoIf('$name','$internal','$regExp',".'AttrVal($hash->{NAME},'."'notexist',undef))","",$name,undef,$internal);
} else {
- return("ReadingValDoIf('$name','$reading','$regExp')","",$name,$reading,undef);
+ return("ReadingValDoIf('$name','$reading','$regExp',".'AttrVal($hash->{NAME},'."'notexist',undef))","",$name,$reading,undef);
}
} else {
- return("InternalDoIf('$name','STATE','$regExp')","",$name,undef,'STATE');
+ return("InternalDoIf('$name','STATE','$regExp',".'AttrVal($hash->{NAME},'."'notexist',undef))","",$name,undef,'STATE');
}
}
}
-sub ReplaceReadingEvalDoIf($$)
+sub ReplaceReadingEvalDoIf($$$)
{
- my ($element,$eval) = @_;
+ my ($hash,$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}));
+ if (!AttrVal($hash->{NAME},'notexist',undef)) {
+ 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;
@@ -267,7 +316,28 @@ sub AddItemDoIf($$)
}
return $items;
}
-
+
+sub AddRegexpTriggerDoIf($$$)
+{
+ my ($hash,$regexp,$condition)= @_;
+ my $max_regexp=keys %{$hash->{regexp}{$condition}};
+ for (my $i=0; $i<$max_regexp;$i++)
+ {
+ if ($hash->{regexp}{$condition}{$i} eq $regexp) {
+ return;
+ }
+ }
+ $hash->{regexp}{$condition}{$max_regexp}=$regexp;
+ $max_regexp=keys %{$hash->{regexp}{all}};
+ for (my $i=0; $i<$max_regexp;$i++)
+ {
+ if ($hash->{regexp}{all}{$i} eq $regexp) {
+ return;
+ }
+ }
+ $hash->{regexp}{all}{$max_regexp}=$regexp;
+}
+
sub ReplaceAllReadingsDoIf($$$$)
{
my ($hash,$tailBlock,$condition,$eval)= @_;
@@ -285,46 +355,66 @@ sub ReplaceAllReadingsDoIf($$$$)
my $reading;
my $internal;
my $trigger=1;
+ my $nameExp;
+ my $notifyExp;
+
while ($tailBlock ne "") {
$trigger=1;
($beginning,$block,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\[\]]');
return ($block,$err) if ($err);
if ($block ne "") {
- if (substr($block,0,1) eq "?") {
- $block=substr($block,1);
- $trigger=0;
- }
- # 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 ($trigger) {
+ if ($block =~ /^\"(.*)\"$/){
+ my $exp=$1;
+ if ($exp =~ /([^\:]*):(.*)/) {
+ $nameExp=$1;
+ $notifyExp=$2;
+ } else {
+ $nameExp=$exp;
+ }
+ #my ($nameExp,$notifyExp)=split (":",$1);
+ if ($condition >= 0) {
+ $nameExp="" if (!$nameExp);
+ $notifyExp="" if (!$notifyExp);
+ $block="EventDoIf('$nameExp',".'$hash,'."'$notifyExp',0)";
+ AddRegexpTriggerDoIf($hash,$exp,$condition);
+ $event=1;
+ }
+ } else {
+ if (substr($block,0,1) eq "?") {
+ $block=substr($block,1);
+ $trigger=0;
+ }
+ $trigger=0 if (substr($block,0,1) eq "\$");
+ if ($block =~ /^\$?[a-z0-9._]*[a-z._]+[a-z0-9._]*($|:.+$)/i) {
+ ($block,$err,$device,$reading,$internal)=ReplaceReadingEvalDoIf($hash,$block,$eval);
+ return ($block,$err) if ($err);
if ($condition >= 0) {
- $hash->{devices}{$condition} = AddItemDoIf($hash->{devices}{$condition},$device);
- $hash->{devices}{all} = AddItemDoIf($hash->{devices}{all},$device);
+ if ($trigger) {
+ $hash->{devices}{$condition} = AddItemDoIf($hash->{devices}{$condition},$device);
+ $hash->{devices}{all} = AddItemDoIf($hash->{devices}{all},$device);
+ $event=1;
+ }
$hash->{readings}{$condition} = AddItemDoIf($hash->{readings}{$condition},"$device:$reading") if (defined ($reading));
$hash->{internals}{$condition} = AddItemDoIf($hash->{internals}{$condition},"$device:$internal") if (defined ($internal));
$hash->{readings}{all} = AddItemDoIf($hash->{readings}{all},"$device:$reading") if (defined ($reading));
$hash->{internals}{all} = AddItemDoIf($hash->{internals}{all},"$device:$internal") if (defined ($internal));
$hash->{trigger}{all} = AddItemDoIf($hash->{trigger}{all},"$device") if (!defined ($internal) and !defined($reading));
- $event=1;
+
} elsif ($condition == -2) {
$hash->{state}{device} = AddItemDoIf($hash->{state}{device},$device) if ($device ne $hash->{NAME});
} elsif ($condition == -3) {
$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."]";
}
- } 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."]";
}
}
$cmd.=$beginning.$block;
@@ -345,7 +435,13 @@ ParseCommandsDoIf($$$)
my $last_error="";
my $ifcmd;
my $ret;
-
+ my $eventa=$hash->{helper}{triggerEvents};
+ my $device=$hash->{helper}{triggerDev};
+ my $event=$hash->{helper}{event};
+ my $events="";
+ if ($eventa) {
+ $events=join(",",@{$eventa});
+ }
while ($tailBlock ne "") {
if ($tailBlock=~ /^\s*\{/) { # perl block
($beginning,$currentBlock,$err,$tailBlock)=GetBlockDoIf($tailBlock,'[\{\}]');
@@ -354,7 +450,7 @@ ParseCommandsDoIf($$$)
($currentBlock,$err)=ReplaceAllReadingsDoIf($hash,$currentBlock,-1,$eval);
return ($currentBlock,$err) if ($err);
if ($eval) {
- ($currentBlock,$err)=EvalAllDoIf($currentBlock);
+ ($currentBlock,$err)=EvalAllDoIf($hash,$currentBlock);
return ($currentBlock,$err) if ($err);
}
}
@@ -390,7 +486,7 @@ ParseCommandsDoIf($$$)
($currentBlock,$err)=ReplaceAllReadingsDoIf($hash,$currentBlock,-1,$eval);
return ($currentBlock,$err) if ($err);
if ($eval) {
- ($currentBlock,$err)=EvalAllDoIf($currentBlock);
+ ($currentBlock,$err)=EvalAllDoIf($hash, $currentBlock);
return ($currentBlock,$err) if ($err);
}
}
@@ -510,7 +606,7 @@ DOIF_time($$$$$$)
($days,$err)=ReplaceAllReadingsDoIf($hash,$days,-1,1);
if ($err) {
my $errmsg="error in days: $err";
- Log3 ($hash->{NAME},2 , "$hash->{NAME}: $errmsg");
+ #Log3 ($hash->{NAME},2 , "$hash->{NAME}: $errmsg");
readingsSingleUpdate ($hash, "error", $errmsg,1);
return 0;
}
@@ -542,7 +638,7 @@ DOIF_time_once($$$$)
($days,$err)=ReplaceAllReadingsDoIf($hash,$days,-1,1);
if ($err) {
my $errmsg="error in days: $err";
- Log3 ($hash->{NAME},2 , "$hash->{NAME}: $errmsg");
+ #Log3 ($hash->{NAME},2 , "$hash->{NAME}: $errmsg");
readingsSingleUpdate ($hash, "error", $errmsg,1);
return 0;
}
@@ -605,7 +701,7 @@ DOIF_SetState($$$$$)
Log3 $pn,2 , "$pn: error in state: $err" if ($err);
$state=$err;
} else {
- ($state,$err)=EvalAllDoIf($state);
+ ($state,$err)=EvalAllDoIf($hash, $state);
if ($err) {
Log3 $pn,2 , "$pn: error in state: $err" if ($err);
$state=$err;
@@ -641,26 +737,58 @@ DOIF_CheckCond($$)
my ($sec,$min,$hour,$mday,$month,$year,$wday,$yday,$isdst) = localtime($seconds);
my $hms = sprintf("%02d:%02d:%02d", $hour, $min, $sec);
my $hm = sprintf("%02d:%02d", $hour, $min);
- my $device;
+ my $dev;
my $reading;
my $internal;
my $we=DOIF_we($wday);
-
+ my $eventa=$hash->{helper}{triggerEvents};
+ my $device=$hash->{helper}{triggerDev};
+ my $event=$hash->{helper}{event};
+ my $events="";
+ if ($eventa) {
+ $events=join(",",@{$eventa});
+ }
$month++;
$year+=1900;
if (defined ($hash->{readings}{$condition})) {
foreach my $devReading (split(/ /,$hash->{readings}{$condition})) {
- ($device,$reading)=(split(":",$devReading));
- return (0,"reading does not exist: [$device:$reading]") if ($devReading and !defined($defs{$device}{READINGS}{$reading}));
+ $devReading=~ s/\$DEVICE/$hash->{helper}{triggerDev}/g if ($devReading);
+ if (!AttrVal($hash->{NAME},'notexist',undef)) {
+ ($dev,$reading)=(split(":",$devReading));
+ return (-1,"device does not exist: [$dev:$reading]") if ($devReading and !defined ($defs{$dev}));
+ return (-1,"reading does not exist: [$dev:$reading]") if ($devReading and !defined($defs{$dev}{READINGS}{$reading}{VAL}));
+ }
}
}
if (defined ($hash->{internals}{$condition})) {
foreach my $devInternal (split(/ /,$hash->{internals}{$condition})) {
- ($device,$internal)=(split(":",$devInternal));
- return (0,"internal does not exist: [$device:$internal]") if ($devInternal and !defined($defs{$device}{$internal}));
+ $devInternal=~ s/\$DEVICE/$hash->{helper}{triggerDev}/g if ($devInternal);
+ if (!AttrVal($hash->{NAME},'notexist',undef)) {
+ ($dev,$internal)=(split(":",$devInternal));
+ return (-1,"device does not exist: [$dev:$internal]") if ($devInternal and !defined ($defs{$dev}));
+ return (-1,"internal does not exist: [$dev:$internal]") if ($devInternal and !defined($defs{$dev}{$internal}));
+ }
}
}
- my $ret = eval $hash->{condition}{$condition};
+ my $cmd=$hash->{condition}{$condition};
+ if ($cmd) {
+ my $eventa=$hash->{helper}{triggerEvents};
+ my $events="";
+ if ($eventa) {
+ $events=join(",",@{$eventa});
+ }
+ $cmd =~ s/\$DEVICE/$hash->{helper}{triggerDev}/g;
+ $cmd =~ s/\$EVENTS/$events/g;
+ $cmd =~ s/\$EVENT/$hash->{helper}{event}/g;
+ #my $idx = 0;
+ #my $evt;
+ #foreach my $part (split(" ", $hash->{helper}{event})) {
+ # $evt='\$EVTPART'.$idx;
+ # $cmd =~ s/$evt/$part/g;
+ # $idx++;
+ #}
+ }
+ my $ret = eval $cmd;
if($@){
$err = "perl error in condition: $hash->{condition}{$condition}: $@";
$ret = 0;
@@ -726,10 +854,28 @@ DOIF_cmd ($$$$)
}
if ($hash->{do}{$nr}{$subnr}) {
$hash->{helper}{cur_cmd_nr}="cmd_".($nr+1)."_".($subnr+1);
- ($cmd,$err)=ParseCommandsDoIf($hash,$hash->{do}{$nr}{$subnr},1);
+ $cmd=$hash->{do}{$nr}{$subnr};
+
+ my $eventa=$hash->{helper}{triggerEvents};
+ my $events="";
+ if ($eventa) {
+ $events=join(",",@{$eventa});
+ }
+ $cmd =~ s/\$DEVICE/$hash->{helper}{triggerDev}/g;
+ $cmd =~ s/\$EVENTS/$events/g;
+ $cmd =~ s/\$EVENT/$hash->{helper}{event}/g;
+ #my $idx = 0;
+ #my $evt;
+ #foreach my $part (split(" ", $hash->{helper}{event})) {
+ # $evt='\$EVTPART'.$idx;
+ # $cmd =~ s/$evt/$part/g;
+ # $idx++;
+ #}
+ #readingsSingleUpdate ($hash, "Event",$hash->{helper}{event},0);
+ ($cmd,$err)=ParseCommandsDoIf($hash,$cmd,1);
}
DOIF_SetState ($hash,$nr,$subnr,$event,$err);
- delete $hash->{helper}{cur_cmd_nr};
+ delete $hash->{helper}{cur_cmd_nr};
if (defined $hash->{do}{$nr}{++$subnr}) {
my $last_cond=ReadingsVal($pn,"cmd_nr",0)-1;
if (DOIF_SetSleepTimer($hash,$last_cond,$nr,$subnr,$event,-1,undef)) {
@@ -743,9 +889,60 @@ DOIF_cmd ($$$$)
}
}
}
+ #delete $hash->{helper}{cur_cmd_nr};
return undef;
}
-
+sub CheckRegexpDoIf($$$$)
+{
+ my ($hash,$name,$eventa,$condition)=@_;
+ my $cond=($condition == -1) ? "all" : $condition;
+ my $max_regexp=keys %{$hash->{regexp}{$cond}};
+ my $c;
+ my $nameExp;
+ my $notifyExp;
+
+ for (my $i=0; $i<$max_regexp;$i++)
+ {
+ if ($hash->{regexp}{$cond}{$i} =~ /([^\:]*):(.*)/) {
+ $nameExp=$1;
+ $notifyExp=$2;
+ } else {
+ $nameExp=$hash->{regexp}{$cond}{$i};
+ }
+ $nameExp="" if (!$nameExp);
+ $notifyExp="" if (!$notifyExp);
+ if ($nameExp eq "" or $name =~ /$nameExp/) {
+ #my $eventa = $hash->{helper}{triggerEvents};
+ my $events="";
+ if ($eventa) {
+ $events=join(",",@{$eventa});
+ }
+ if ($notifyExp eq "") {
+ if ($cond ne "all") {
+ $c=$cond+1;
+ readingsSingleUpdate ($hash, "machted_event_c".$c."_".($i+1),"$events",0);
+ }
+ return 1;
+ }
+ my $max = int(@{$eventa});
+ my $s;
+ my $found;
+ for (my $j = 0; $j < $max; $j++) {
+ $s = $eventa->[$j];
+ $s = "" if(!defined($s));
+ $found = ($s =~ m/$notifyExp/);
+ if ($found) {
+ if ($cond ne "all") {
+ $c=$cond+1;
+ readingsSingleUpdate ($hash, "machted_event_c".$c."_".($i+1),$s,0);
+ }
+ return 1
+ }
+ }
+ }
+ }
+ return 0;
+}
sub
DOIF_Trigger ($$$)
@@ -764,17 +961,22 @@ DOIF_Trigger ($$$)
next if ($hash->{timers}{$i} !~ / $timerNr /);
$event="timer_".($timerNr+1);
} else { #event
- next if (!defined ($hash->{devices}{$i}));
- next if ($hash->{devices}{$i} !~ / $device /);
+ if (!CheckRegexpDoIf($hash, $device, $hash->{helper}{triggerEvents}, $i)) {
+ next if (!defined ($hash->{devices}{$i}));
+ next if ($hash->{devices}{$i} !~ / $device /);
+ }
$event="$device";
}
if (($ret,$err)=DOIF_CheckCond($hash,$i)) {
if ($err) {
- Log3 $hash->{Name},2,"$hash->{NAME}: $err";
+ #Log3 $hash->{Name},2,"$hash->{NAME}: $err" if ($ret != -1);
readingsSingleUpdate ($hash, "error", $err,1);
return undef;
}
if ($ret) {
+ $hash->{helper}{timerevents}=$hash->{helper}{triggerEvents};
+ $hash->{helper}{timerevent}=$hash->{helper}{event};
+ $hash->{helper}{timerdev}=$hash->{helper}{triggerDev};
if (DOIF_SetSleepTimer($hash,$last_cond,$i,0,$device,$timerNr,undef)) {
DOIF_cmd ($hash,$i,0,$event);
return 1;
@@ -788,6 +990,9 @@ DOIF_Trigger ($$$)
}
if ($doelse) { #DOELSE
if (defined ($hash->{do}{$max_cond}{0}) or ($max_cond == 1 and !(AttrVal($pn,"do","") or AttrVal($pn,"repeatsame","")))) { #DOELSE
+ $hash->{helper}{timerevents}=$hash->{helper}{triggerEvents};
+ $hash->{helper}{timerevent}=$hash->{helper}{event};
+ $hash->{helper}{timerdev}=$hash->{helper}{triggerDev};
if (DOIF_SetSleepTimer($hash,$last_cond,$max_cond,0,$device,$timerNr,undef)) {
DOIF_cmd ($hash,$max_cond,0,$event) ;
return 1;
@@ -797,6 +1002,7 @@ DOIF_Trigger ($$$)
return undef;
}
+
sub
DOIF_Notify($$)
{
@@ -809,8 +1015,9 @@ DOIF_Notify($$)
my $internal;
my $ret;
my $err;
-
- if ($dev->{NAME} eq "global" and ((EventDoIf("global","global",deviceEvents($dev, AttrVal("global", "addStateEvent", 0)),"INITIALIZED")) or EventDoIf("global","global",deviceEvents($dev, AttrVal("global", "addStateEvent", 0)),"REREADCFG")))
+ my $eventa;
+ $eventa = deviceEvents($dev, AttrVal($dev->{NAME}, "addStateEvent", 0));
+ if ($dev->{NAME} eq "global" and (EventCheckDoif($dev->{NAME},"global",$eventa,"INITIALIZED") or EventCheckDoif($dev->{NAME},"global",$eventa,"REREADCFG")))
{
$hash->{helper}{globalinit}=1;
if ($hash->{helper}{last_timer} > 0){
@@ -829,16 +1036,15 @@ DOIF_Notify($$)
}
}
}
-
- return "" if (!$hash->{devices}{all} and !$hash->{state}{device});
- return "" if (!$hash->{helper}{globalinit});
return "" if (ReadingsVal($pn,"mode","") eq "disabled");
-
- if (($hash->{devices}{all}) and $hash->{devices}{all} =~ / $dev->{NAME} /) {
+ return "" if (!$hash->{helper}{globalinit});
+ return "" if (defined $hash->{helper}{cur_cmd_nr});
+ return "" if (!$hash->{devices}{all} and !$hash->{state}{device} and !$hash->{regexp}{all});
+
+ if ((($hash->{devices}{all}) and $hash->{devices}{all} =~ / $dev->{NAME} /) or CheckRegexpDoIf($hash,$dev->{NAME},$eventa,-1)){
readingsSingleUpdate ($hash, "Device",$dev->{NAME},0);
#my $events = deviceEvents($dev, AttrVal($dev->{NAME}, "addStateEvent", 0));
#readingsSingleUpdate ($hash, "Event","@{$events}",0);
-
if ($hash->{readings}{all}) {
foreach my $item (split(/ /,$hash->{readings}{all})) {
($device,$reading)=(split(":",$item));
@@ -852,22 +1058,20 @@ DOIF_Notify($$)
readingsSingleUpdate ($hash, "e_".$dev->{NAME}."_".$internal,$defs{$device}{$internal},0) if ($item and $device eq $dev->{NAME} and defined ($defs{$device}{$internal}));
}
}
- #my ($seconds, $microseconds) = gettimeofday();
- #if ($hash->{helper}{last_event_time}) {
- # return undef if (($seconds-$hash->{helper}{last_event_time}) < AttrVal($pn,"eventpause",0));
- #}
- #$hash->{helper}{last_event_time}=$seconds;
if ($hash->{trigger}{all}) {
foreach my $item (split(/ /,$hash->{trigger}{all})) {
- my $events = deviceEvents($dev, AttrVal($dev->{NAME}, "addStateEvent", 0));
- $hash->{helper}{triggerEvents}=$events;
- $hash->{helper}{triggerDev}=$dev->{NAME};
- readingsSingleUpdate ($hash, "e_".$dev->{NAME}."_events","@{$events}",0);
+ readingsSingleUpdate ($hash, "e_".$dev->{NAME}."_events",join(",",@{$eventa}),0);
}
}
+ $hash->{helper}{triggerEvents}=$eventa;
+ $hash->{helper}{triggerDev}=$dev->{NAME};
+ $hash->{helper}{event}=join(",",@{$eventa});
$ret=DOIF_Trigger($hash,$dev->{NAME},-1);
}
if (($hash->{state}{device}) and $hash->{state}{device} =~ / $dev->{NAME} / and !$ret) {
+ $hash->{helper}{triggerEvents}=$eventa;
+ $hash->{helper}{triggerDev}=$dev->{NAME};
+ $hash->{helper}{event}=join(",",@{$eventa});
DOIF_SetState($hash,"",0,"","");
}
return undef;
@@ -881,9 +1085,15 @@ DOIF_TimerTrigger ($)
my $hash=${$timer}->{hash};
my $pn = $hash->{NAME};
my $ret;
+ my @triggerEvents;
# if (!AttrVal($hash->{NAME},"disable","")) {
if (ReadingsVal($pn,"mode","") ne "disabled") {
$hash->{timer}{$nr}=1;
+ my $timer_nr=$nr+1;
+ @triggerEvents=("timer_$timer_nr");
+ $hash->{helper}{triggerEvents}=\@triggerEvents;
+ $hash->{helper}{triggerDev}="";
+ $hash->{helper}{event}="timer_$timer_nr";
$ret=DOIF_Trigger ($hash,"",$nr);
$hash->{timer}{$nr}=0;
}
@@ -960,9 +1170,9 @@ DOIF_DetTime($)
}
sub
-DOIF_CalcTime($)
+DOIF_CalcTime($$)
{
- my ($block)= @_;
+ my ($hash,$block)= @_;
my $tailBlock;
my $beginning;
my $err;
@@ -990,7 +1200,7 @@ DOIF_CalcTime($)
if ($block =~ /^\[/) {
($beginning,$block,$err,$tailBlock)=GetBlockDoIf($block,'[\[\]]');
return ($block,$err) if ($err);
- ($block,$err,$device,$reading,$internal)=ReplaceReadingEvalDoIf($block,1);
+ ($block,$err,$device,$reading,$internal)=ReplaceReadingEvalDoIf($hash,$block,1);
return ($block,$err) if ($err);
}
($err,$rel,$block)=DOIF_DetTime($block);
@@ -1003,7 +1213,7 @@ DOIF_CalcTime($)
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);
+ ($block,$err,$device,$reading,$internal)=ReplaceReadingEvalDoIf($hash,$block,1);
return ($block,$err) if ($err);
}
($err,$rel,$block)=DOIF_DetTime($block);
@@ -1039,7 +1249,7 @@ DOIF_SetTimer($$)
my $cond=$hash->{timeCond}{$nr};
my $next_time;
- my ($second,$err, $rel)=DOIF_CalcTime($timeStr);
+ my ($second,$err, $rel)=DOIF_CalcTime($hash,$timeStr);
if ($err)
{
readingsSingleUpdate ($hash,"timer_".($nr+1)."_c".($cond+1),"error: ".$err,0);
@@ -1086,9 +1296,6 @@ DOIF_SetSleepTimer($$$$$$$)
{
my ($hash,$last_cond,$nr,$subnr,$device,$timerNr,$repeatcmd)=@_;
my $pn = $hash->{NAME};
- if (defined $hash->{helper}{cur_cmd_nr}) {
- return 0;
- }
my $sleeptimer=$hash->{helper}{sleeptimer};
my @waitdel=split(/:/,AttrVal($pn,"waitdel",""));
my @waitdelsubnr=split(/,/,defined $waitdel[$sleeptimer] ? $waitdel[$sleeptimer] : "");
@@ -1177,6 +1384,9 @@ DOIF_SleepTrigger ($)
$hash->{helper}{sleeptimer}=-1;
$hash->{helper}{sleepsubtimer}=-1;
my $pn = $hash->{NAME};
+ $hash->{helper}{triggerEvents}=$hash->{helper}{timerevents};
+ $hash->{helper}{event}=$hash->{helper}{timerevent};
+ $hash->{helper}{triggerDev}=$hash->{helper}{timerdev};
readingsSingleUpdate ($hash, "wait_timer", "no timer",1);
# if (!AttrVal($hash->{NAME},"disable","")) {
if (ReadingsVal($pn,"mode","") ne "disabled") {
@@ -1426,7 +1636,7 @@ The commands are always processed from left to right. There is only one command
+ definition of the status display with use of any readings or statuses
-Many examples with english identifiers - see german section.
+Many examples with english identifiers - see german section.
=end html
@@ -1435,10 +1645,10 @@ Many examples with english identifiers - see german section.
define di_clock_radio DOIF ([06:30]) (set r
Kombinierte Ereignis- und Zeitsteuerung: define di_lamp DOIF ([06:00-09:00] and [sensor:brightness] < 40) (set lamp on) DOELSE (set lamp off)
+
Inhaltsübersicht
Features
@@ -1484,6 +1695,7 @@ Kombinierte Ereignis- und Zeitsteuerung: define di_lamp DOIF ([06:00-09:00
Zeitintervalle, Readings und Stati ohne Trigger
Nutzung von Readings, Stati oder Internals im Ausführungsteil
Berechnungen im Ausführungsteil
+ Ersatzwert für nicht existierende Readings oder Stati
Filtern nach Zahlen
Verzögerungen
Verzögerungen von Timern
@@ -1502,8 +1714,12 @@ Kombinierte Ereignis- und Zeitsteuerung: define di_lamp DOIF ([06:00-09:00
Initialisieren des Moduls
Weitere Anwendungsbeispiele
Zu beachten
+ Kurzreferenz
+
+
+
DOIF spezifische Attribute
@@ -1513,6 +1729,7 @@ Kombinierte Ereignis- und Zeitsteuerung: define di_lamp DOIF ([06:00-09:00
do always
do resetwait
initialize
+ notexist
repeatcmd
repeatsame
state
@@ -1523,7 +1740,7 @@ Kombinierte Ereignis- und Zeitsteuerung: define di_lamp DOIF ([06:00-09:00
-Features
+Features back
+ Syntax angelehnt an Verzweigungen if - elseif - ... - elseif - else in höheren Sprachen
+ Bedingungen werden vom Perl-Interpreter ausgewertet, daher beliebige logische Abfragen möglich
@@ -1533,7 +1750,7 @@ Kombinierte Ereignis- und Zeitsteuerung: define di_lamp DOIF ([06:00-09:00
+ Der Ausführungsteil kann jeweils ausgelassen werden. Damit kann das Modul für reine Statusanzeige genutzt werden
-Lesbarkeit der Definitionen
+Lesbarkeit der Definitionen back
Da die Definitionen im Laufe der Zeit recht umfangreich werden können, sollten die gleichen Regeln, wie auch beim Programmieren in höheren Sprachen, beachtet werden.
Dazu zählen: das Einrücken von Befehlen, Zeilenumbrüche sowie das Kommentieren seiner Definition, damit man auch später noch die Funktionalität seines Moduls nachvollziehen kann.
@@ -1554,7 +1771,7 @@ DOELSE ## im sonst-Fall, also wenn einer der Schalter off ist
Im Folgenden wird die Funktionalität des Moduls im Einzelnen an vielen praktischen Beispielen erklärt.
-Ereignissteuerung
+Ereignissteuerung back
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.
@@ -1590,7 +1807,7 @@ Wenn das Attribut do always
nicht gesetzt ist, wird dagegen bei Def
Ohne diesen automatischen Zustandswechsel, wäre ansonsten die Definition nicht sinnvoll, da der Zustand "cmd_1" ohne do always
nur ein einziges Mal ausgeführt werden könnte.
-Teilausdrücke abfragen
+Teilausdrücke abfragen back
Abfragen nach Vorkommen eines Wortes innerhalb einer Zeichenkette können mit Hilfe des Perl-Operators =~
vorgenommen werden.
@@ -1602,24 +1819,62 @@ attr di_garage do always
=~
, insbesondere in Verbindung mit regulären Ausdrücken, können in der Perl-Dokumentation nachgeschlagen werden.[<devicename>:?<regexp>]
[<devicename>:"<regex>"]
define di_garage DOIF ([remotecontrol:?on]) (set garage on) DOELSEIF ([remotecontrol] eq "off") (set garage off)
define di_garage DOIF ([remotecontrol:"on"]) (set garage on) DOELSEIF ([remotecontrol:"off"]) (set garage off)
[<devicename>:?<regex>]
wird aus Kompatibilitätsgründen noch unterstützt, sollte aber nicht mehr benutzt werden.["<device regex>:<event regex>"]
define di_all_events DOIF ([""])({Log 3,"Events from device $DEVICE:$EVENTS"})
+attr di_all_events do always
+define Battery dummy
+
+define di_battery DOIF ([":battery: low"] and [?Battery:$DEVICE] ne "low")
+ ({DebianMail('yourname@gmail.com', 'FHEM - battery warning from device: $DEVICE'}, setreading Battery $DEVICE low)
+DOELSEIF ([":battery: ok"] and [?Battery:$DEVICE] ne "ok")
+ (setreading Battery $DEVICE ok)
+
+attr di_battery do always
+attr di_battery notexist "novalue"
+...(set lamp on)
... ({system ("wmail Peter is at home")}, set lamp on)
[HH:MM:SS]
oder [HH:MM]
oder [Zahl]
define di_light DOIF ([3600]) (set lamp on)
define di_save DOIF ([+3600]) (save)
[<begin>-<end>]
,
für <begin>
bzw. <end>
wird das gleiche Zeitformat verwendet,
@@ -1772,7 +2027,7 @@ Schalten mit Zeitfunktionen, hier: bei Sonnenaufgang und Sonnenuntergang:define di_light DOIF ([+{sunrise_rel(900,"06:00","08:00")}]) (set outdoorlight off) DOELSEIF ([+{sunset_rel(900,"17:00","21:00")}]) (set outdoorlight on)
define di_time DOIF ([[begin]-[end]|7]) (set radio on) DOELSE (set radio off)
define di_shutters DOIF ([sensor:brightness]>100 and [06:25-09:00|8] or [09:00|7]) (set shutters up) DOELSEIF ([sensor:brightness]<50) (set shutters down)
define di_pushmsg DOIF ([window] eq "open" and [alarm] eq "armed") (set Pushover msg 'alarm' 'open windows [window:LastDevice]' '' 2 'persistent' 30 3600)
define di_average DOIF ([08:00]) (set TH_Modul desired {([default:temperature]+[outdoor:temperature])/2})
attr di_average do always
notexist
bewerkstelligen. Der definierte Ersatzwert gilt für das gesamte Modul.attr <DOIF-module> notexist "<default value>"
define di_heating DOIF ([adjusting:actuator:d] < 10) (set heating off) DOELSE (set heating on)
attr <DOIF-modul> wait <Sekunden für Befehlsfolge des ersten DO-Falls>:<Sekunden für Befehlsfolge des zweiten DO-Falls>:...
+attr <DOIF-module> wait <Sekunden für Befehlsfolge des ersten DO-Falls>:<Sekunden für Befehlsfolge des zweiten DO-Falls>:...
define delay dummy
-set delay 400
-attr <DOIF-modul> wait 1:[delay]:rand(600)
attr <DOIF-module> wait 1:[delay]:rand(600)
(set lamp1 on, set lamp2 on)
, soll vor dem Schalten von lamp2
eine Verzögerung von einer Sekunde stattfinden.
Die Befehlsfolge muss zunächst mit Hilfe von Klammerblöcke aufgespaltet werden: (set lamp1 on)(set lamp2 on)
.
Nun kann mit dem wait-Attribut nicht nur für den Beginn der Sequenz, sondern für jeden Klammerblock eine Verzögerung, getrennt mit Komma, definieren werden,
- hier also: wait 0,1
. Damit wird lamp1
sofort, lamp2
nach einer Sekunden geschaltet.wait 0,1
. Damit wird lamp1
sofort, lamp2
nach einer Sekunde geschaltet. Die Verzögerungszeit bezieht sich immer auf den verherigen Befehl.DOIF (Bedingung1)
(set ...) ## erster Befehl der ersten Sequenz soll um eine Sekunde verzögert werden
(set ...) ## zweiter Befehl der ersten Sequenz soll um 2 Sekunden verzögert werden
-DOELSE (Bedingung2)
+DOELSEIF (Bedingung2)
(set ...) ## erster Befehl der zweiten Sequenz soll um 3 Sekunden verzögert werden
(set ...) ## zweiter Befehl der zweiten Sequenz soll um 0,5 Sekunden verzögert werden
-attr <DOIF-modul> wait 1,2:3,0.5
timerWithWait
auf Timer ausgeweitet werden.do always
wird ein Waittimer mit dem Attribut do resetwait
auch dann zurückgesetzt, wenn die gleiche Bedingung wiederholt wahr wird.define di_pump_circ DOIF ([05:00-22:00])(set pump on)(set pump off)
+define di_pump_circ DOIF ([05:00-22:00])(set pump on)(set pump off) DOELSE (set pump off)
attr di_pump_circ wait 0,300
attr di_pump_circ repeatcmd 3600
@@ -2042,12 +2304,12 @@ Zwischen 5:00 und 22:00 Uhr läuft die Zirkulationspumpe alle 60 Minuten jeweils
Anwendungsbeispiel: Anwesenheitssimulation
-define di_presence_simulation DOIF ([19:00-00:00])(set lamp on-for-timer {(int(rand(1800)+300))})
-attr di_presence_simulation repeatcmd rand(3600)+2100
+define di_presence_simulation DOIF ([19:00-00:00])(set lamp on-for-timer {(int(rand(1800)+300))}) DOELSE (set lamp off)
+attr di_presence_simulation repeatcmd rand(3600)+2200
-Zwangspause für das Ausführen eines Kommandos seit der letzten Zustandsänderung
+Zwangspause für das Ausführen eines Kommandos seit der letzten Zustandsänderung back
Mit dem Attribut cmdpause <Sekunden für cmd_1>:<Sekunden für cmd_2>:...
wird die Zeitspanne in Sekunden angegeben für eine Zwangspause seit der letzten Zustandsänderung.
In der angegebenen Zeitspanne wird ein Kommando nicht ausgeführt, auch wenn die dazugehörige Bedingung wahr wird.
@@ -2059,7 +2321,7 @@ attr di_frost cmdpause 3600
attr di_frost do always
repeatsame <maximale Anzahl von cmd_1>:<maximale Anzahl von cmd_2>:...
wird die maximale Anzahl hintereinander folgenden Ausführungen festgelegt.do always
bzw. do resetwait
gilt f
attr di_repeat do alwayswaitsame <Zeitspanne in Sekunden für cmd_1>:<Zeitspanne in Sekunden für das cmd_2>:...
wird ein Kommando erst dann ausgeführt, wenn innerhalb einer definierten Zeitspanne die entsprechende Bedingung zweimal hintereinander wahr wird.waitsame
nicht gelten soll, werden die entsprechenden Sekundenangaben ausgelassen oder auf Null gesetzt.repeatsame
-Attribut ist das Attribut waitdel
. Die Syntax mit Sekundenangaben pro Kommando entspricht der, des wait-Attributs. Im Gegensatz zum wait-Attribut, wird ein laufender Timer gelöscht, falls eine Bedingung wiederholt wahr wird.
Sekundenangaben können pro Kommando ausgelassen oder auf Null gesetzt werden.wait
und waitdel
lassen sich für versch
attr di_cmd waitdel 0:2[<Device>:<Reading>:sec]
in Sekunden seit der letzten Änderung bestimmt werdenstate
state
backattr di_average state Average of the two rooms is {(sprintf("%.1f",([room1:temperature]+[room2:temperature])/2))}
initialize
initialize
backdi_lamp
mit "initialized" vorbelegt werden. Das Reading cmd_nr
wird auf 0 gesetzt, damit wird ein Zustandswechsel provoziert, das Modul wird initialisiert - der nächste Trigger führt zum Ausführen eines Kommandos.set <DOIF-modul> disable
geschehen.
@@ -2187,14 +2449,14 @@ Hierbei bleiben alle Timer aktiv, sie werden aktualisiert - das Modul bleibt im
Das Modul braucht mehr Rechenzeit, als wenn es komplett über das Attribut deaktiviert wird. In beiden Fällen bleibt der Zustand nach dem Neustart erhalten, das Modul bleibt deaktiviert.set <DOIF-modul> initialize
wird ein mit set <DOIF-modul> disable
deaktiviertes Modul wieder aktiviert.
Das Kommando set <DOIF-modul> initialize
kann auch dazu genutzt werden ein aktives Modul zu initialisiert,
in diesem Falle wird der letzte Zustand des Moduls gelöscht, damit wird ein Zustandswechsel herbeigeführt, der nächste Trigger führt zur Ausführung.define di_on_for_timer ([detector:?motion])
+define di_on_for_timer ([detector:"motion"])
(set light on)
(set light off)
attr di_on_for_timer do resetwait
@@ -2220,7 +2482,7 @@ Hiermit wird das Licht bei Bewegung eingeschaltet. Dabei wird, solange es brennt
Die Beispiele stellen nur eine kleine Auswahl von möglichen Problemlösungen dar. Da sowohl in der Bedingung (hier ist die komplette Perl-Syntax möglich), als auch im Ausführungsteil, keine Einschränkungen gegeben sind, sind die Möglichkeiten zur Lösung eigener Probleme mit Hilfe des Moduls sehr vielfältig.
-Zu beachten
+Zu beachten back
In jeder Bedingung muss mindestens ein Trigger angegeben sein (Angaben in eckigen Klammern). Die entsprechenden DO-Fälle werden nur dann ausgewertet, wenn auch das entsprechende Event oder Zeit-Trigger ausgelöst wird.
@@ -2264,6 +2526,165 @@ Hier wird um 19:00 Uhr Lampe eingeschaltet, obwohl sie evtl. vorher schon durch
Hier passiert das nicht mehr, da die ursprünglichen Zustände cmd_1 und cmd_2 jetzt nur noch einen Zustand cmd_1 darstellen und dieser wird nicht wiederholt.
+
+
+Kurzreferenz back
+
+
+〈〉 kennzeichnet optionale Angaben
+
+
+Definition
+
+
+ -
define <name> DOIF 〈(<Bedingung>) 〈〈(〈<Befehle>〉)〉 〈〈〈DOELSEIF (<Bedingung>) 〈(〈<Befehle>〉)〉〉 ... 〉〈DOELSE 〈(〈<Befehle>〉)〉〉〉〉〉
+
+ - Befehlstrennzeichen ist das Komma
(<Befehl>, <Befehl>, ...)
+
+ - Befehlssequenzen werden in runde Klammern gesetzt
(<Befehlssequenz A>) (<Befehlssequenz B>) ...
+
+ - Enthält ein Befehl Kommata, ist er zusätzlich in runde Klammern einzuschliessen
(<Befehlsteil a>, <Befehlsteil b> ... )
+
+ - Perl-Befehle
{<Perl-Befehl>}
sind in geschweifte Klammern einzuschliessen
+
+ - Jede Berechnung
{(<Berechnung>)〈<Berechnung>〉}
in einem Befehl ist in geschweifte Klammern einzuschliessen und muss mit einer geöffneten runden Klammer beginnen.
+
+
+
+
+Operanden in der Bedingung und den Befehlen
+
+
+ - Stati
[<devicename>]
+
+
+ - Readings
[<devicename>:<readingname>]
+
+
+ - Internals
[<devicename>:&<internalname>]
+
+
+ - Filtern nach Zahlen:
[<devicename>:<readingname>:d]
, ... ; allgemein: [<devicename>:<readingname>:[<regex>]]
, ...
+
+ - Zeitspanne eines Readings seit der letzten Änderung
[<devicename>:<readingname>:sec]
+
+ - $DEVICE
+ - für den Gerätenamen
+
+ - $EVENT
+ - für das zugehörige Ereignis
+
+ - $EVENTS
+ - für alle zugehörigen Ereignisse eines Triggers
+
+ - <globale Variable>
+ - Variablen für Zeit- und Datumsangaben, siehe auch PERL Besonderheiten
+
+
+
+
+Operanden in der Bedingung
+
+
+ - Events
[<devicename>:"<regex für Events>"]
oder ["<regex für Devices>:<regex für Events>"]
+ - für
<regex>
gilt: ^<ist eindeutig>$
, ^<beginnt mit>
, <endet mit>$
, ""
entspricht ".*"
, siehe auch Reguläre Ausdrücke
+
+
+ - Zeitpunkte
[<time>]
+ - als
[HH:MM]
, [HH:MM:SS]
oder [Zahl]
in Sekunden nach Mitternacht
+
+ - Zeitintervalle
[<begin>-<end>]
+ - als
[HH:MM]
, [HH:MM:SS]
oder [Zahl]
in Sekunden nach Mitternacht
+
+ - indirekte Zeitangaben
[[<indirekte Zeit>]]
+ - als
[HH:MM]
, [HH:MM:SS]
oder [Zahl]
in Sekunden nach Mitternacht, <indirekte Zeit>
ist ein Stati, Reading oder Internal
+
+ - relative Zeitangaben
[+<time>]
+ - als
[HH:MM]
, [HH:MM:SS]
oder [Zahl]
in Sekunden
+
+ - ausgerichtete Zeitraster
[:MM]
+ - in Minuten zwischen 00 und 59
+
+ - rel. Zeitraster ausgerichtet
[+:MM]
+ - in Minuten zwischen 1 und 59
+
+ - rel. Zeitraster ausgerichtet alle X Stunden
[+[h]:MM]
+ - MM in Minuten zwischen 1 und 59, h in Stunden zwischen 2 und 23
+
+ - Wochentagsteuerung
[<time>|012345678]
, [<begin>-<end>]|012345678]
+ - Pipe, gefolgt von ein o. mehreren Ziffern. Bedeutung: 0 bis 6 für So. bis Sa., 7 für $we, Wochenende oder Feiertag, 8 für !$we, Werktags.
+
+ - berechnete Zeitangaben
[(<Berechnung, gibt Zeit in Sekunden zurück, im Sinne von time>)]
+ - Berechnungen sind mit runden Klammern einzuschliessen. Perlfunktionen, die HH:MM zurückgeben sind mit geschweiften Klammern einzuschliessen.
+
+ - Trigger verhindern
[?<devicename>]
, [?<devicename>:<readingname>]
, [?<devicename>:&<internalname>]
, [?<time specification>]
+ - Werden Stati, Readings, Internals und Zeitangaben in der Bedingung mit einem Fragezeichen eingeleitet, triggern sie nicht.
+
+ - $device, $event, $events
+ - Perl-Variablen mit der Bedeutung der Schlüsselworte $DEVICE, $EVENT, $EVENTS
+
+
+
+set-Befehl
+
+
+ - disable
set <name> disable
+ - blockiert die Befehlsausführung
+
+ - initialize
set <name> initialize
+ - initialisiert das DOIF und aktiviert die Befehlsausführung
+
+
+
+
+Spezifische Attribute
+
+
+ - Verzögerungen
attr <name> wait <timer_1_1>,<timer_1_2>,...:<timer_2_1>,<timer_2_2>,...:...
+ - Zeit in Sekunden als direkte Angabe, [<Reading>] oder {<Perlfunktion>}, ein Doppelpunkt trennt die Timer der Bedingungsweige, ein Komma die Timer der Befehlssequenzen eines Bedingungszweiges.
+
+ - Verzögerung von Timern
attr <name> timerWithWait
+ - erweitert
wait
auf Zeitangaben
+
+ - Befehlswiederholung zulassen
attr <name> do always
+ - wiederholt den Ausführungsteil, wenn die selbe Bedingung wiederholt wahr wird.
+
+ - Zurücksetzen des Waittimers bei Wiederholung
attr <name> do resetwait
+ - setzt den Waittimer zurück, wenn die selbe Bedingung wiederholt wahr wird.
+
+ - Befehle wiederholen
attr <name> repeatcmd <timer Bedingungszweig 1>:<timer Bedingungszweig 2>:...
+ - Zeit in Sekunden als direkte Angabe, [<Reading>] oder {<Perlfunktion>}, nach der Befehle wiederholt werden.
+
+ - Pause für Wiederholung
attr <name> cmdpause <Pause cmd_1>:<Pause cmd_2>:...
+ - Zeit in Sekunden als direkte Angabe, blockiert die Befehlsausführung während der Pause.
+
+ - Begrenzung von Wiederholungen
attr <name> repeatsame <maximale Anzahl von cmd_1>:<maximale Anzahl von cmd_2>:...
+ - begrenzt die maximale Anzahl unmittelbar folgender Befehlsausführungen.
+
+ - Warten auf Wiederholung
attr <name> waitsame <Wartezeit cmd_1>:<Wartezeit cmd_2>:...
+ - Wartezeit in Sekunden als direkte Angabe, für ein unmittelbar wiederholtes Zutreffen einer Bedingung.
+
+ - Löschen des Waittimers
attr <name> waitdel <timer_1_1>,<timer_1_2>,...:<timer_2_1>,<timer_2_2>,...:...
+ - Zeit in Sekunden als direkte Angabe, ein laufender Timer wird gelöscht und die Befehle nicht ausgeführt, falls eine Bedingung vor Ablauf des Timers wiederholt wahr wird.
+
+ - Gerätestatus ersetzen
attr <name> cmdState <Ersatz cmd_1>|<Ersatz cmd_2>|...
+ - ersetzt die Standartwerte des Gerätestatus, die Ersatzstati werden durch das Pipe Zeichen getrennt.
+
+ - dynamischer Status
attr <name> state <dynamischer Inhalt>
+ - Zum Erstellen von
<dynamischer Inhalt>
können die für Befehle verfügbaren Operanden verwendet werden.
+
+ - Ersatzwert für nicht existierende Readings oder Stati
attr <name> notexist "<Ersatzwert>"
+
+
+ - Status Initialisierung nach Neustart
attr <name> intialize <Status nach Neustart>
+
+
+ - Gerät vollständig deaktivieren
attr <name> disable <0|1>
+ - 1 deaktiviert das Modul vollständig, 0 aktiviert es.
+
+
+
+