From 3a3c7852216ecec98fcf5adfbb649b4c935ebaf7 Mon Sep 17 00:00:00 2001 From: Damian <> Date: Sat, 11 Feb 2017 16:57:02 +0000 Subject: [PATCH] 98_DOIF.pm: set cmd_, checkReadingEvent default for indirect timers, not replace Reading or Device in command branch if not exist git-svn-id: https://svn.fhem.de/fhem/trunk@13391 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/FHEM/98_DOIF.pm | 97 +++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/fhem/FHEM/98_DOIF.pm b/fhem/FHEM/98_DOIF.pm index 6b59d65bc..fdca307fb 100644 --- a/fhem/FHEM/98_DOIF.pm +++ b/fhem/FHEM/98_DOIF.pm @@ -562,11 +562,9 @@ sub ReplaceReadingEvalDoIf($$$) my ($block,$err,$device,$reading,$internal)=ReplaceReadingDoIf($element); return ($block,$err) if ($err); if ($eval) { - #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})); - #} + return ("[".$element."]","") if(!$defs{$device}); + return ("[".$element."]","") if (defined ($reading) and !defined($defs{$device}{READINGS}{$reading})); + return ("[".$element."]","") if (defined ($internal) and !defined($defs{$device}{$internal})); my $ret = eval $block; return($block." ",$@) if ($@); $block=$ret; @@ -632,10 +630,14 @@ sub ReplaceAllReadingsDoIf($$$$) return ($block,$err) if ($err); if ($block ne "") { if ($block =~ /^"([^"]*)"/){ - ($block,$err)=ReplaceEventDoIf($block); - return ($block,$err) if ($err); - AddRegexpTriggerDoIf($hash,$1,$condition); - $event=1; + if ($condition>=0) { + ($block,$err)=ReplaceEventDoIf($block); + return ($block,$err) if ($err); + AddRegexpTriggerDoIf($hash,$1,$condition); + $event=1; + } else { + $block="[".$block."]"; + } } else { if (substr($block,0,1) eq "?") { $block=substr($block,1); @@ -1172,7 +1174,7 @@ sub CheckiTimerDoIf($$$) my ($device,$itimer,$eventa)=@_; my $max = int(@{$eventa}); my $found; - return 1 if ($itimer =~ /\[$device\]/); + return 1 if ($itimer =~ /\[$device(\]|,.+\])/); for (my $j = 0; $j < $max; $j++) { if ($eventa->[$j] =~ "^(.+): ") { $found = ($itimer =~ /\[$device:$1(\]|:.+\]|,.+\])/); @@ -1393,9 +1395,10 @@ DOIF_Notify($$) } if (($hash->{itimer}{all}) and $hash->{itimer}{all} =~ / $dev->{NAME} /) { - for (my $j=0; $j<$hash->{helper}{last_timer};$j++) - { if (AttrVal($pn, "checkReadingEvent", 0) and CheckiTimerDoIf ($dev->{NAME},$hash->{time}{$j},$eventas) - or !AttrVal($pn, "checkReadingEvent", 0) and $hash->{time}{$j} =~ /\[$dev->{NAME}(\]|:.+\]|,.+\])/) { + for (my $j=0; $j<$hash->{helper}{last_timer};$j++) { + if (CheckiTimerDoIf ($dev->{NAME},$hash->{time}{$j},$eventas)) { + # { if (AttrVal($pn, "checkReadingEvent", 0) and CheckiTimerDoIf ($dev->{NAME},$hash->{time}{$j},$eventas) + # or !AttrVal($pn, "checkReadingEvent", 0) and $hash->{time}{$j} =~ /\[$dev->{NAME}(\]|:.+\]|,.+\])/) { DOIF_SetTimer($hash,"DOIF_TimerTrigger",$j); } } @@ -2006,12 +2009,25 @@ DOIF_Set($@) readingsSingleUpdate ($hash,"state",ReadingsVal($pn,"last_cmd",""),0) if (ReadingsVal($pn,"last_cmd","") ne ""); delete ($defs{$hash->{NAME}}{READINGS}{last_cmd}); readingsSingleUpdate ($hash,"mode","enable",1) + } elsif ($arg =~ /^cmd_(.*)/ ) { + if (ReadingsVal($pn,"mode","") ne "disabled") { + if ($hash->{helper}{sleeptimer} != -1) { + RemoveInternalTimer($hash); + readingsSingleUpdate ($hash, "wait_timer", "no timer",1); + $hash->{helper}{sleeptimer}=-1; + } + DOIF_cmd ($hash,$1-1,0,"set_cmd_".$1); + } } else { - - my $setList = AttrVal($pn, "setList", " "); $setList =~ s/\n/ /g; - return "unknown argument ? for $pn, choose one of disable:noArg initialize:noArg enable:noArg $setList" if($arg eq "?"); + my $cmdList; + my $max_cond=keys %{$hash->{condition}}; + $max_cond++ if (defined ($hash->{do}{$max_cond}{0}) or ($max_cond == 1 and !(AttrVal($pn,"do","") or AttrVal($pn,"repeatsame","")))); + for (my $i=0; $i <$max_cond;$i++) { + $cmdList.="cmd_".($i+1).":noArg "; + } + return "unknown argument ? for $pn, choose one of disable:noArg initialize:noArg enable:noArg $cmdList $setList" if($arg eq "?"); my @rl = split(" ", AttrVal($pn, "readingList", "")); my $doRet; eval { @@ -2023,11 +2039,8 @@ DOIF_Set($@) } }; return if($doRet); - - - return "unknown argument $arg for $pn, choose one of disable:noArg initialize:noArg enable:noArg $setList"; + return "unknown argument $arg for $pn, choose one of disable:noArg initialize:noArg enable:noArg cmd $setList"; } - return $ret; } @@ -2165,12 +2178,13 @@ Kombinierte Ereignis- und Zeitsteuerung: define di_lamp DOIF ([06:00-09:00 Triggerung durch selbst ausgelöste Events
Setzen der Timer mit Event
Zeitspanne eines Readings seit der letzten Änderung
- [Neu] Darstellungselement mit Eingabemöglichkeit im Frontend und Schaltfunktion
+ Darstellungselement mit Eingabemöglichkeit im Frontend und Schaltfunktion
Status des Moduls
Reine Statusanzeige ohne Ausführung von Befehlen
Anpassung des Status mit Hilfe des Attributes state
Vorbelegung des Status mit Initialisierung nach dem Neustart mit dem Attribut initialize
- Deaktivieren des Moduls
+ Deaktivieren des Moduls
+ Bedingungslose Ausführen von Befehlszweigen
Initialisieren des Moduls
Weitere Anwendungsbeispiele
Zu beachten
@@ -2375,11 +2389,6 @@ attr di_battery do always


Eine aktuelle Übersicht aller Batterie-Stati entsteht gleichzeitig in den Readings des di_battery-DOIF-Moduls.

- - - - -
Allgemeine Ereignistrigger können ebenfalls so definiert werden, dass sie nicht nur wahr zum Triggerzeitpunkt und sonst nicht wahr sind, sondern Inhalte des Ereignisses zurückliefern. Initiiert wird dieses Verhalten durch die Angabe eines Default-Wertes.
@@ -2987,19 +2996,18 @@ Standardmäßig werden angegebene Readings ausgewertet, wenn irgend ein Event de Möchte man gezielt nur dann ein angegebenes Reading auswerten, wenn sich nur dieses ändert, so lässt sich das mit dem Attribut checkReadingEvent einschränken. Das ist insb. dann interessant, wenn ein Modul verschiedene Readings zu unterschiedlichen Zeitpunkten aktualisiert.

-Beispiele:
+Beispiel:

define di_lamp DOIF ([mytwilight:light] < 3) (set lamp on) DOELSEIF ([mytwilight:light] > 3) (set lamp off)
attr di_lamp checkReadingEvent 1


-Ebenso gilt die Einschränkung für indirekte Timer:
+Bei der Angabe von indirekten Timern wird grundsätzlich intern checkReadingEvent benutzt:

define di_lamp ([[mytwilight:ss_weather]]) (set lamp on)
-attr di_lamp do always
-attr di_lamp checkReadingEvent 1

+attr di_lamp do always

-Ohne checkReadingEvent, würde alle fünf Minuten die Einschaltzeit der Lampe neu gesetzt werden, da das twilight-Modul regelmäßig andere Reading wie z. B. das azimuth-Reading ändert und damit Events erzeugt. -Durch die Angabe des Attributes checkReadingEvent wird die Zeit nur dann neu gesetzt, wenn sich tatsächlich das Reading ss_weather ändert.
+Hier braucht das Attribut checkReadingEvent nicht explizit gesetzt werden. +Die Zeit wird nur dann neu gesetzt, wenn sich tatsächlich das Reading ss_weather ändert.

Eindeutige Statuserkennung   back
@@ -3152,6 +3160,26 @@ Mit set <DOIF-modul> initialize wird ein mit set <DO 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.

+ +Auführen von Befehlszweigen ohne Auswertung der Bedingung   back
+
+Mit set <DOIF-modul> cmd_<nr> lässt sich ein Befehlszweig (cmd_1, cmd_2, usw.) bedingunglos ausführen.
+
+Der Befehl hat folgende Eigenschaften:
+
+1) der set-Befehl übersteuert alle Attribute wie z. B. wait, do, usw.
+2) ein laufender Wait-Timer wird unterbrochen
+3) beim deaktivierten oder im Modus disable befindlichen Modul wird der set Befehl ignoriert
+
+Anwendungsbeispiel: Schaltbare Lampe über Fernbedienung und Webinterface
+
+ +define di_lamp DOIF ([FB:"on"]) (set lamp on) DOELSEIF ([FB:"off"]) (set lamp off)
+attr di_lamp cmdState on|off
+attr di_lamp devStateIcon on:on:cmd_2 initialized|off:off:cmd_1
+

+Mit der Definition des Attribut devStateIcon führt das Anklicken des on/off-Lampen-Icons zum Ausführen des set-Kommandos cmd_1 bzw. cmd_2 und damit zum Schalten der Lampe.
+
Weitere Anwendungsbeispiele   back

@@ -3392,6 +3420,9 @@ Hier passiert das nicht mehr, da die ursprünglichen Zustände cmd_1 und cmd_2 j
enable set <name> enable
aktiviert die Befehlsausführung, im Gegensatz zur obigen Initialisierung bleibt der letzte Zustand des Moduls erhalten
+
+
cmd_<nr> set <name> cmd_<nr>
+
führt ohne Auswertung der Bedingung den Befehlszweig mit der Nummer <nr> aus