diff --git a/FHEM/98_DOIF.pm b/FHEM/98_DOIF.pm
index fe0e81470..d66c78ab4 100644
--- a/FHEM/98_DOIF.pm
+++ b/FHEM/98_DOIF.pm
@@ -35,7 +35,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 waitsame cmdpause";
+ $hash->{AttrList} = "disable:0,1 loglevel:0,1,2,3,4,5,6 wait do:always,resetwait cmdState state initialize repeatsame waitsame waitdel cmdpause";
}
@@ -77,6 +77,29 @@ GetBlockDoIf ($$)
}
}
+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 $ret = 0;
+ return 1 if ($NotifyExp eq "");
+ for (my $i = 0; $i < $max; $i++) {
+ my $s = $events->[$i];
+ $s = "" if(!defined($s));
+ my $found = ($s =~ m/$NotifyExp/);
+ return 1 if ($found);
+ #if(!$found && AttrVal($n, "eventMap", undef)) {
+ # my @res = ReplaceEventMap($n, [$n,$s], 0);
+ # shift @res;
+ # $s = join(" ", @res);
+ # $found = ("$n:$s" =~ m/^$re$/);
+ }
+ return 0;
+}
+
sub
InternalDoIf($$$)
{
@@ -151,10 +174,15 @@ sub ReplaceReadingDoIf($)
my $regExp="";
my ($name,$reading,$format)=split(":",$element);
my $internal="";
+ my $notifyExp="";
if ($name) {
#return ($name,"unknown Device") if(!$defs{$name});
if ($reading) {
- $internal = substr($reading,1) if (substr($reading,0,1) eq "\&");
+ if (substr($reading,0,1) eq "\?") {
+ $notifyExp=substr($reading,1);
+ return("EventDoIf('$name',".'$hash->{helper}{triggerDev},'.'$hash->{helper}{triggerEvents},'."'$notifyExp')","",$name,undef,undef);
+ }
+ $internal = substr($reading,1) if (substr($reading,0,1) eq "\&");
if ($format) {
if ($format eq "d") {
$regExp = '(-?\d+(\.\d+)?)';
@@ -243,6 +271,7 @@ sub ReplaceAllReadingsDoIf($$$$)
$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});
@@ -653,6 +682,7 @@ DOIF_Notify($$)
readingsSingleUpdate ($hash, "e_".$dev->{NAME}."_".$reading,$defs{$device}{READINGS}{$reading}{VAL},0) if ($item and $device eq $dev->{NAME} and $defs{$device}{READINGS}{$reading});
}
}
+
if ($hash->{internals}{all}) {
foreach my $item (split(/ /,$hash->{internals}{all})) {
($device,$internal)=(split(":",$item));
@@ -664,6 +694,14 @@ DOIF_Notify($$)
# 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);
+ }
+ }
$ret=DOIF_Trigger($hash,$dev->{NAME},-1);
}
if (($hash->{state}{device}) and $hash->{state}{device} =~ / $dev->{NAME} / and !$ret) {
@@ -739,14 +777,17 @@ DOIF_SetSleepTimer($$$$$)
{
my ($hash,$last_cond,$nr,$device,$timerNr)=@_;
my $pn = $hash->{NAME};
+ my $sleeptimer=$hash->{helper}{sleeptimer};
return 1 if ($timerNr == -2); #Sleeptrigger
- if ($hash->{helper}{sleeptimer} != -1 and ($hash->{helper}{sleeptimer} != $nr or AttrVal($pn,"do","") eq "resetwait")) {
+ my @waitdel=split(/:/,AttrVal($pn,"waitdel",""));
+ if ($sleeptimer != -1 and (($sleeptimer != $nr or AttrVal($pn,"do","") eq "resetwait") or ($sleeptimer == $nr and $waitdel[$sleeptimer]))) {
RemoveInternalTimer($hash);
#delete ($defs{$hash->{NAME}}{READINGS}{wait_timer});
readingsSingleUpdate ($hash, "wait_timer", "no timer",1);
$hash->{helper}{sleeptimer}=-1;
+ return 0 if ($sleeptimer == $nr and $waitdel[$sleeptimer]);
}
-
+
if ($timerNr >= 0) {#Timer
if ($last_cond != $nr or AttrVal($pn,"do","") eq "always" or AttrVal($pn,"repeatsame","")) {
return 1;
@@ -756,9 +797,15 @@ DOIF_SetSleepTimer($$$$$)
}
if ($hash->{helper}{sleeptimer} == -1 and ($last_cond != $nr or AttrVal($pn,"do","") eq "always" or AttrVal($pn,"do","") eq "resetwait" or AttrVal($pn,"repeatsame",""))) {
my @sleeptimer=split(/:/,AttrVal($pn,"wait",""));
- if ($sleeptimer[$nr]) {
+ my $sleeptime=0;
+ if ($waitdel[$nr]) {
+ $sleeptime = $waitdel[$nr];
+ } elsif ($sleeptimer[$nr]) {
+ $sleeptime=$sleeptimer[$nr]
+ }
+ if ($sleeptime) {
my ($seconds, $microseconds) = gettimeofday();
- my $next_time = $seconds+$sleeptimer[$nr];
+ my $next_time = $seconds+$sleeptime;
$hash->{helper}{sleeptimer}=$nr;
$hash->{helper}{sleepdevice}=$device;
my $cmd_nr=$nr+1;
@@ -829,6 +876,7 @@ CmdDoIf($$)
delete ($hash->{days});
delete ($hash->{readings});
delete ($hash->{internals});
+ delete ($hash->{trigger});
delete ($defs{$hash->{NAME}}{READINGS});
readingsSingleUpdate ($hash,"state","initialized",1);
}
@@ -937,6 +985,8 @@ DOIF_Attr(@)
readingsSingleUpdate ($hash,"cmd_nr","0",1);
} elsif($a[0] eq "del" && $a[2] eq "repeatsame") {
delete ($defs{$hash->{NAME}}{READINGS}{cmd_count});
+ } elsif($a[0] eq "del" && $a[2] eq "waitsame") {
+ delete ($defs{$hash->{NAME}}{READINGS}{waitsame});
}
return undef;
}
@@ -1027,7 +1077,7 @@ 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 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.
@@ -1041,8 +1091,8 @@ Die Angaben werden immer von links nach rechts abgearbeitet. Es wird immer nur e
[<devicename>]
, Readings mit [<devicename>:<readingname>]
und Internals mit [<devicename>:&<internal>]
angegeben[<devicename>]
, Readings mit [<devicename>:<readingname>]
, Internals mit [<devicename>:&<internal>]
oder Events mit [<devicename>:?<regexp>]
angegeben[HH:MM:SS]
oder [HH:MM]
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.=~
, insbesondere in Verbindung mit regulären Ausdrücken, können in der Perl-Dokumentation nachgeschlagen werden.define di_garage DOIF ([remotecontrol:?on]) (set garage on) DOELSEIF ([remotecontrol] eq "off") (set garage off)
attr <Modulname> wait <Sekunden für das erste Kommando>:<Sekunden für das zweite Kommando>:...
waitsame <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.define di_shutters DOIF ([Button])(set shutters up)
-attr di_shutters waitsame 2
-attr di_shutters do always
define di_shuttersup DOIF ([Button])(set shutters up)
+attr di_shuttersup waitsame 2
+attr di_shuttersup do always
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.define di_shuttersdown DOIF ([Button])(set shutters down)
+attr di_shuttersdown waitdel 2
+attr di_shuttersdown do always
wait
und waitdel
lassen sich für verschiedene Kommandos kombinieren. Falls das Attribut für ein Kommando nicht gesetzt werden soll, kann die entsprechende Sekundenzahl ausgelassen oder eine Null angegeben werden.wait
gelten, für cmd_2 waitdel
attr di_cmd wait 2:0
+attr di_cmd waitdel 0:2