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

98_DOIF.pm: Documentation on Perl mode moved to the FHEM Wiki

git-svn-id: https://svn.fhem.de/fhem/trunk@25386 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
Damian 2021-12-28 22:19:25 +00:00
parent 634025a84e
commit cb81d436ba

View File

@ -6336,7 +6336,7 @@ Dieses Verhalten ist sinnvoll, um zu verhindern, dass zyklisch sendende Sensoren
Das Verhalten des Moduls im FHEM-Modus kann durch diverse Attribute verändert werden. Im FHEM-Modus wird maximal nur ein Zweig pro Ereignis- oder Zeit-Trigger ausgeführt, es gibt nur einen Wait-Timer.<br>
<br>
<a name="DOIF_Einfache_Anwendungsbeispiele"></a>
<u>Einfache Anwendungsbeispiele (vgl. <a href="#DOIF_Einfache_Anwendungsbeispiele_Perl">Anwendungsbeispiele im Perl-Modus</a>):</u><ol>
<u>Einfache Anwendungsbeispiele</u><ol>
<br>
Fernbedienung (Ereignissteuerung)<br>
<br>
@ -7373,8 +7373,6 @@ Beispiel:<br>
<br>
<code>attr my_doif wait 1:[mydummy:state]*3:rand(600)+100,Attr("mydevice","myattr","")</code><br>
<br>
Im Perl-Modus werden Verzögerungen mit Hilfe der Funktion <a href="#DOIF_set_Exec">set_Exec</a> realisiert.<br>
<br>
</li><li><a name="DOIF_timerWithWait"></a>
<b>Verzögerungen von Timern</b>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht">back</a><br>
<br>
@ -7539,7 +7537,6 @@ attr di_shuttersdown waitdel 2<br>
attr di_shuttersdown do always</code><br>
<br>
"di_shuttersdown" kann nicht mit dem vorherigen Anwendungsbeispiel "di_shuttersup" innerhalb eines DOIF-Moduls kombiniert werden, da in beiden Fällen die gleiche Bedingung vorkommt.<br>
<a href="#DOIF_Einknopf_Fernbedienung">siehe auch Einknopf-Fernbedienung im Perl-Modus</a><br>
<br>
Die Attribute <code>wait</code> und <code>waitdel</code> 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.<br>
<br>
@ -7924,7 +7921,6 @@ attr di_on_for_timer do resetwait<br>
attr di_on_for_timer wait 0,30</code><br>
<br>
Hiermit wird das Licht bei Bewegung eingeschaltet. Dabei wird, solange es brennt, bei jeder Bewegung die Ausschaltzeit neu auf 30 Sekunden gesetzt, "set light on" wird dabei nicht unnötig wiederholt.<br>
<a href="#DOIF_Treppenhauslicht mit Bewegungsmelder">siehe auch Treppenhauslicht mit Bewegungsmelder im Perl-Modus</a><br>
<br>
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.<br>
<br>
@ -8325,412 +8321,7 @@ Hier passiert das nicht mehr, da die ursprünglichen Zustände cmd_1 und cmd_2 j
<a name="DOIF_Perl_Modus"></a>
<b>Perl Modus</b><br>
<br>
Der Perl-Modus ist sowohl für einfache, als auch für komplexere Automatisierungsabläufe geeignet. Der Anwender hat mehr Einfluss auf den Ablauf der Steuerung als im FHEM-Modus.
Die Abläufe lassen sich, wie in höheren Programmiersprachen üblich, strukturiert programmieren. Mit Hilfe von Templates können generalisiert DOIFs definiert werden.
Zum Zeitpunkt der Definition werden alle DOIF-spezifischen Angaben in Perl übersetzt, zum Zeitpunkt der Ausführung wird nur noch Perl ausgeführt, dadurch wird maximale Performance gewährleistet.<br>
<br>
Syntax Perl-Modus:<br>
<br>
<ol><code>define &lt;name&gt; DOIF &lt;Template-Definitionen (optional)&gt; &lt;DOIF-Blöcke&gt;</code></ol><br>
Syntax Template-Definition:<br>
<br>
<code>DEF TPL_&lt;Template-Name&gt;(&ltDOIF-Block-Definition mit Platzhaltern: $1,$2,...&gt;)</code><br>
<br>
<u><a href="https://forum.fhem.de/index.php/topic,111266.msg1054775.html#msg1054775">Anwendungsbeispiel zu DOIF-Templates</a></u><br>
<br>
Syntax DOIF-Block:<br>
<br>
<code>&lt;Blockname (optional)&gt; {&lt;Perlcode mit Ereignis-/Zeittriggern in eckigen Klammern&gt;}</code><br>
<br>
Ein DOIF-Block wird ausgeführt, wenn dieser bedingt durch <a href="#DOIF_Operanden">Ereignis- und Zeittrigger in eckigen Klammern</a> innerhalb des Blocks, getriggert wird.
Es wird die vollständige Perl-Syntax unterstützt. Es können beliebig viele Blöcke innerhalb eines DOIF-Devices definiert werden. Sie werden unabhängig voneinander durch passende Trigger ausgeführt. Der Name eines Blocks ist optional.<br>
<br>
Der Status des Moduls wird nicht vom Modul gesetzt, er kann vom Anwender mit Hilfe der Funktion <code>set_State</code> verändert werden, siehe <a href="#DOIF_Spezifische_Perl-Funktionen_im_Perl-Modus">spezifische Perl-Funktionen im Perl-Modus</a>.
FHEM-Befehle werden durch den Aufruf der Perlfunktion <code>fhem("...")</code> ausgeführt. Für den häufig genutzten fhem-Befehl <b>set</b> wurde eine kompatible Perlfunktion namens <b>fhem_set</b> definiert.
Sie ist performanter und sollte bevorzugt verwendet werden, da das Parsen nach dem FHEM set-Befehl entfällt.<br>
<br>
Der Benutzer kann mit der Funktion <code>set_Exec</code> beliebig viele eigene Timer definieren, die unabhängig voneinander gesetzt und ausgewertet werden können, siehe <a href="#DOIF_Spezifische_Perl-Funktionen_im_Perl-Modus">Spezifische Perl-Funktionen im Perl-Modus</a>.<br>
<br>
Definitionen im FHEM-Modus mit do-Attribut der Form:<br>
<br>
<ol><code>DOIF (&lt;Bedingung mit Trigger&gt;) (&lt;FHEM-Befehle&gt;) DOELSE (&lt;FHEM-Befehle&gt;)</code><br></ol>
<br>
lassen sich wie folgt in Perl-Modus übertragen:<br>
<br>
<ol><code>DOIF {if (&lt;Bedingung mit Trigger&gt;) {fhem"&lt;FHEM-Befehle&gt;"} else {fhem"&lt;FHEM-Befehle&gt;"}}</code><br></ol>
<br>
Die Bedingungen des FHEM-Modus können ohne Änderungen in Perl-Modus übernommen werden.<br>
<br>
<a name="DOIF_Einfache_Anwendungsbeispiele_Perl"></a>
<u>Einfache Anwendungsbeispiele (vgl. <a href="#DOIF_Einfache_Anwendungsbeispiele">Anwendungsbeispiele im FHEM-Modus</a>):</u>
<ol>
<br>
<code>define di_rc_tv DOIF {if ([remotecontol:"on"]) {fhem_set"tv on"} else {fhem_set"tv off"}}</code><br>
<br>
<code>define di_clock_radio DOIF {if ([06:30|Mo Di Mi] or [08:30|Do Fr Sa So]) {fhem_set"radio on"}} {if ([08:00|Mo Di Mi] or [09:30|Do Fr Sa So]) {fhem_set"radio off"}}</code><br>
<br>
<code>define di_lamp DOIF {if ([06:00-09:00] and [sensor:brightness] < 40) {fhem_set"lamp:FILTER=STATE!=on on"} else {fhem_set"lamp:FILTER=STATE!=off off"}}</code><br>
<br>
</ol>
Bemerkung: Im Gegensatz zum FHEM-Modus arbeitet der Perl-Modus ohne Auswertung des eigenen Status (Zustandsauswertung),
daher muss der Anwender selbst darauf achten, wiederholende Ausführungen zu vermeiden (im oberen Beispiel z.B. mit FILTER-Option). Elegant lässt sich das Problem der wiederholenden Ausführung bei zyklisch sendenden Sensoren mit Hilfe des Attributes <a href="#DOIF_DOIF_Readings">DOIF_Readings</a> lösen.<br>
<br>
Es können beliebig viele Ereignisblöcke definiert werden, die unabhängig von einander durch einen oder mehrere Trigger ausgewertet und zur Ausführung führen können:<br>
<br>
<code>DOIF<br>
{ if (&lt;Bedingung mit Triggern&gt;) ... }<br>
{ if (&lt;Bedingung mit Triggern&gt;) ... }<br>
...</code><br>
<br>
Einzelne Ereignis-/Zeittrigger, die nicht logisch mit anderen Bedingungen oder Triggern ausgewertet werden müssen, können auch ohne if-Anweisung angegeben werden, z. B.:<br>
<br>
<code>DOIF<br>
{["lamp:on"];...}<br>
{[08:00];...}<br>
...</code><br>
<br>
Ereignis-/Zeittrigger sind intern Perlfunktionen, daher können sie an beliebiger Stelle im Perlcode angegeben werden, wo Perlfunktionen vorkommen dürfen, z. B.:<br>
<br>
<code>DOIF {Log 1,"state of lamp: ".[lamp:state]}</code><br>
<br>
<code>DOIF {fhem_set("lamp ".[remote:state])}</code><br>
<br>
Es sind beliebige Hierarchietiefen möglich:<br>
<br>
<code>DOIF<br>
{ if (&lt;Bedingung&gt;) {<br>
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&lt;Bedingung&gt;)&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(&lt;Bedingung mit Triggern&gt;...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;&nbsp;&nbsp;}<br>
&nbsp;&nbsp;}<br>
}</code><br>
<br>
Bemerkung: Innerhalb eines Ereignisblocks muss mindestens ein Trigger definiert werden, damit der gesamte Block beim passenden Trigger ausgeführt wird.<br>
<br>
<a name="DOIF_Inhaltsuebersicht_Perl-Modus"></a>
<b>Inhaltsübersicht Perl-Modus</b><br>
<ul><br>
<a href="#DOIF_Eigene_Funktionen">Eigene Funktionen - subs-Block</a><br>
<a href="#DOIF_Eigene_Funktionen_mit_Parametern">Eigene Funktionen mit Parametern</a><br>
<a href="#DOIF_Eigener_Namensraum">Eigener_Namensraum</a><br>
<a href="#DOIF_Spezifische_Perl-Funktionen_im_Perl-Modus">Spezifische Perl-Funktionen im Perl-Modus:</a>&nbsp;
<a href="#DOIF_fhem_set">fhem_set</a>&nbsp;
<a href="#DOIF_set_Event">set_Event</a>&nbsp;
<a href="#DOIF_set_State">set_State</a>&nbsp;
<a href="#DOIF_get_State">get_State</a>&nbsp;
<a href="#DOIF_set_Reading">set_Reading</a>&nbsp;
<a href="#DOIF_get_Reading">get_Reading</a>&nbsp;
<a href="#DOIF_set_Reading_Update">set_Reading_Update</a><br>
<a href="#DOIF_Ausführungstimer">Ausführungstimer:</a>&nbsp;
<a href="#DOIF_set_Exec">set_Exec</a>&nbsp;
<a href="#DOIF_get_Exec">get_Exec</a>&nbsp;
<a href="#DOIF_del_Exec">del_Exec</a><br>
<a href="#DOIF_init-Block">Initialisierung - init-Block</a><br>
<a href="#DOIF_Device-Variablen">Device-Variablen</a><br>
<a href="#DOIF_Blockierende_Funktionsaufrufe">Blockierende Funktionsaufrufe</a><br>
<a href="#DOIF_Attribute_Perl_Modus">Attribute im Perl-Modus</a><br>
<a href="#DOIF_set_Perl_Modus">set-Befehle im Perl-Modus</a><br>
<a href="#DOIF_Anwendungsbeispiele_im_Perlmodus">Anwendungsbeispiele im Perl-Modus</a><br>
</ul>
<a name="DOIF_Eigene_Funktionen"></a><br>
<u>Eigene Funktionen</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
Ein besonderer Block ist der Block namens <b>subs</b>. In diesem Block werden Perlfunktionen definiert, die innerhalb des DOIFs genutzt werden.
Um eine möglichst hohe Kompatibilität zu Perl sicherzustellen, wird keine DOIF-Syntax in eckigen Klammern unterstützt, insb. gibt es keine Trigger, die den Block ausführen können.<br>
<br>
Beispiel:<br>
<br><code>
DOIF
subs { ## Definition von Perlfunktionen lamp_on und lamp_off<br>
&nbsp; sub lamp_on {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fhem_set("lamp&nbsp;on");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_State("on");<br>
&nbsp;&nbsp;}<br>
&nbsp;&nbsp;sub&nbsp;lamp_off&nbsp;{<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fhem_set("lamp&nbsp;off");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_State("off");<br>
&nbsp;&nbsp;}<br>
}<br>
{[06:00];lamp_on()}&nbsp;&nbsp;## Um 06:00 Uhr wird die Funktion lamp_on aufgerufen<br>
{[08:00];lamp_off()} ## Um 08:00 Uhr wird die Funktion lamp_off aufgerufen<br>
</code><br>
<a name="DOIF_Eigene_Funktionen_mit_Parametern"></a><br>
<u>Eigene Funktionen mit Parametern</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
Unter Verwendung von Funktionsparamerter lassen sich Definitionen oft vereinfachen, das obige Beispiel lässt sich mit Hilfe nur einer Funktion kürzer wie folgt definieren:<br>
<br><code>
DOIF
subs { ## Definition der Perlfunktion lamp<br>
&nbsp; sub lamp {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my ($state)=@_;&nbsp;&nbsp# Variable $state mit dem Parameter belegen<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fhem_set("lamp&nbsp;$state");<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_State($state);<br>
&nbsp;&nbsp;}<br>
}<br>
{[06:00];lamp("on")}&nbsp;&nbsp;## Um 06:00 Uhr wird die Funktion lamp mit Parameter "on" aufgerufen<br>
{[08:00];lamp("off")} ## Um 08:00 Uhr wird die Funktion lamp mit dem Parameter "off" aufgerufen<br>
</code><br>
<a name="DOIF_Eigener_Namensraum"></a><br>
<u>Eigener Namensraum</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
Der Namensraum im Perl-Modus ist gekapselt. Selbstdefinierte Funktionen im DOIF-Device können nicht bereits existierende Perlfunktionen in FHEM (Namensraum main) überschreiben.
Funktionen aus dem Namensraum main müssen mit vorangestellem Doppelpunkt angegeben werden: <code>::&lt;perlfunction&gt;</code><br>
<br>
Eigene Perlfunktionen, die in myutils ausgelagert sind, befinden sich ebenfalls im Namensraum main. Wenn sie ausschließich in DOIF-Devices benutzt werden sollen, so kann am Anfang vor deren Definition in myutils "package DOIF;" angegeben werden.
In diesen Fall sind auch diese Funktion im DOIF-Device bekannt - sie können dann ohne vorangestellten Doppelpunkt genutzt werden.<br>
<br>
Folgende FHEM-Perlfunktionen wurden ebenfalls im DOIF-Namensraum definiert, sie können, wie gewohnt ohne Doppelpunkt genutzt werden:<br>
<br>
<code><b>fhem, Log, Log3, InternVal, InternalNum, OldReadingsVal, OldReadingsNum, OldReadingsTimestamp, ReadingsVal, ReadingsNum, ReadingsTimestamp, ReadingsAge, Value, OldValue, OldTimestamp, AttrVal, AttrNum</code></b><br>
<a name="DOIF_Spezifische_Perl-Funktionen_im_Perl-Modus"></a><br>
<u>Spezifische Perl-Funktionen im Perl-Modus</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<a name="DOIF_fhem_set"></a><br>
FHEM set-Befehl ausführen: <code><b>fhem_set(&lt;content&gt;)</code></b>, mit &lt;content&gt; Übergabeparameter des FHEM set-Befehls<br>
<br>
Beispiel: Lampe ausschalten:<br>
<br>
<code>fhem_set("lamp off");</code><br>
<br>
entspricht:<br>
<br>
<code>fhem("set lamp off");</code><br>
<br>
Der Aufruf der fhem_set-Funktion ist performater, da das Parsen nach dem set-Befehl im Gegensatz zum Aufruf mit der Funktion <code>fhem</code> entfällt.<br>
<a name="DOIF_set_Event"></a><br>
Ein beliebiges FHEM-Event absetzen: <code><b>set_Event(&lt;Event&gt;)</code></b><br>
<br>
Beispiel: Setze das Event "on":<br>
<br>
<code>set_Event("on");</code><br>
<a name="DOIF_set_State"></a><br>
Status setzen: <code><b>set_State(&lt;value&gt;,&lt;trigger&gt;)</code></b>, mit &lt;trigger&gt;: 0 ohne Trigger, 1 mit Trigger, &lt;trigger&gt; ist optional, default ist 1<br>
<br>
Beispiel: Status des eignen DOIF-Device auf "on" setzen:<br>
<br>
<code>set_State("on");</code><br>
<a name="DOIF_get_State"></a><br>
Status des eigenen DOIF-Devices holen: <code><b>get_State()</code></b><br>
<br>
Beispiel: Schalte lampe mit dem eigenen Status:<br>
<br>
<code>fhem_set("lamp ".get_State());</code><br>
<a name="DOIF_set_Reading"></a><br>
Reading des eigenen DOIF-Devices schreiben: <code><b>set_Reading(&lt;readingName&gt;,&lt;value&gt;,&lt;trigger&gt;)</code></b>, mit &lt;trigger&gt;: 0 ohne Trigger, 1 mit Trigger, &lt;trigger&gt; ist optional, default ist 0<br>
<br>
<code>set_Reading("weather","cold");</code><br>
<a name="DOIF_get_Reading"></a><br>
Reading des eigenen DOIF-Devices holen: <code><b>get_Reading(&lt;readingName&gt;)</code></b><br>
<br>
Beispiel: Schalte Lampe mit dem Inhalt des eigenen Readings "dim":<br>
<br>
<code>fhem_set("lamp ".get_Reading("dim"));</code><br>
<a name="DOIF_set_Reading_Update"></a><br>
Setzen mehrerer Readings des eigenen DOIF-Devices in einem Eventblock:<br>
<br>
<code><b>set_Reading_Begin()</code></b><br>
<code><b>set_Reading_Update(&lt;readingName&gt;,&lt;value&gt;,&lt;change&gt;)</code></b>, &lt;change&gt; ist optional<br>
<code><b>set_Reading_End(&lt;trigger&gt;)</code></b>, mit &lt;trigger&gt;: 0 ohne Trigger, 1 mit Trigger, &lt;trigger&gt;<br>
<br>
Die obigen Funktionen entsprechen den FHEM-Perlfunktionen: <code>readingsBegin, readingsBulkUpdate, readingsEndUpdate</code>.<br>
<br>
Beispiel:<br>
<br>
Die Readings "temperature" und "humidity" sollen in einem Eventblock mit dem zuvor belegten Inhalt der Variablen $temp bzw. $hum belegt werden.<br>
<br>
<code>set_Reading_Begin;</code><br>
<code>set_Reading_Update("temperature",$temp);</code><br>
<code>set_Reading_Update("humidity",$hum);</code><br>
<code>set_Reading_End(1);</code><br>
<a name="DOIF_Ausführungstimer"></a><br>
<u>Ausführungstimer</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
Mit Hilfe von Ausführungstimern können Perl-Anweisungen verzögert ein- oder mehrmalig ausgeführt werden. Im Gegensatz zum FHEM-Modus können beliebig viele Timer gleichzeitig genutzt werden.
Ein Ausführungstimer wird mit einem Timer-Namen eindeutig definiert. Über den Timer-Namen kann die Restlaufzeit abgefragt werden, ebenfalls kann er vor seinem Ablauf gelöscht werden.<br>
<a name="DOIF_set_Exec"></a><br>
Timer setzen: <code><b>set_Exec(&lt;timerName&gt;, &lt;seconds&gt;, &lt;perlCode&gt;, &lt;paramRef&gt;, &lt;condition&gt)</code></b><br>
<br>
<b>&lt;timerName&gt;</b>: beliebige Angabe, sie spezifiziert eindeutig einen Timer<br>
<b>&lt;seconds&gt;</b>: Verzögerungszeit, sie wird per eval-Perlbefehl ausgewertet und kann daher Perlcode zur Bestimmung der Verzögerungszeit beinhalten<br>
<b>&lt;perlCode&gt;</b>: Perl-Anweisung, die nach Ablauf der Verzögerungszeit per eval-Perlbefehl ausgeführt wird<br>
<b>&lt;paramRef&gt;</b>: wird unter &lt;perlCode&gt; eine Perlfunktion angegeben, so kann optional hier eine Referenz auf den Übergabeparameter der Perlfunktion angegeben werden<br>
<b>&lt;condition&gt;</b>: optionale Bedingung zur Wiederholung der Perl-Ausführung. Sie wird per eval-Perlbefehl vor dem Setzen des Timers und vor der Ausführung der Perl-Anweisung auf wahr geprüft.
Bei falsch wird die Wiederholung der Ausführungskette beendet. Wird &lt;condition&gt; nicht angegeben, so erfolgt keine Wiederholung der Perl-Anweisung.<br>
<br>
Wird set_Exec mit dem gleichen &lt;timerName&gt; vor seinem Ablauf erneut aufgerufen, so wird der laufender Timer gelöscht und neugesetzt.<br>
<a name="DOIF_get_Exec"></a><br>
Timer holen: <code><b>get_Exec(&lt;timerName&gt;)</code></b>, Returnwert: 0, wenn Timer abgelaufen oder nicht gesetzt ist, sonst Anzahl der Sekunden bis zum Ablauf des Timers<br>
<a name="DOIF_del_Exec"></a><br>
Laufenden Timer löschen: <code><b>del_Exec(&lt;timerName&gt;)</code></b><br>
<br>
<u>Anwendungsbeispiele für einmalige verzögerte Ausführung</u><br>
<br>
Funktion namens "lamp" mit dem Übergabeparameter "on" 30 Sekunden verzögert aufrufen:<br>
<br>
<code>set_Exec("lamp_timer",30,'lamp("on")');</code><br>
<br>
Lampe verzögert um 30 Sekunden ausschalten:<br>
<br>
<code>set_Exec("off_timer",30,'fhem_set("lamp off")');</code><br>
<br>
Das Event "off" 30 Sekunden verzögert auslösen:<br>
<br>
<code>set_Exec("Event_timer",30,'set_Event("off")');</code><br>
<br>
Funktion namens "check_shutters" wird mit einer Referenz auf ein zuvor definiertes Array namens "shutters" um 5 Sekunden verzögert ausgeführt:<br>
<br>
<code>set_Exec("check_timer",5,"check_shutters",\@shutters);</code><br>
<br>
<u>Anwendungsbeispiele mit bedingter Wiederholung einer Ausführung</u><br>
<br>
Wenn Alarm ausgelöst wird, soll eine Benachrichtigung gesendet werden und alle 60 Sekunden wiederholt werden, solange Alarmanlage auf "on" steht.<br>
<br>
<code>defmod di_alarm DOIF {["alarm:on"];;fhem("send myphone alarm!");;set_Exec("timer",60,'fhem("send myphone alarm!")','ReadingsVal("alarm","state","on") eq "on"')}</code><br>
<br>
Wenn Taster auslöst, Lampe auf on schalten und noch zwei mal im Abstand von einer Sekunde wiederholt auf on schalten.<br>
<br>
<code>defmod di_lamp_on DOIF {["button:on"];;fhem_set"lamp on";;set_Exec("timer",1,'fhem_set("lamp on")','$count < 2')}</code><br>
<br>
alternativ:<br>
<br>
<code>defmod di_lamp_on DOIF {["button:on"];;set_Exec("timer",'$count == 0 ? 0 : 1','fhem_set("lamp on")','$count < 2')}</code><br>
<br>
$count ist eine interne Variable, die beginnend mit 0 nach jedem Durchlauf um eins erhöht wird.<br>
<br>
Wenn Fenster geöffnet wird, dann soll eine Benachrichtigung erfolgen, dabei soll die Benachrichtigung bis zu 10 mal jeweils um weitere 60 Sekunden verzögert werden: erste Benachrichtigung nach 5 Minuten,
zweite Benachrichtigung nach weiteren 6 Minuten, dritte Benachrichtigung nach weiteren 7 Minuten usw.<br>
<br>
<code>defmod di_window DOIF {if ([window:state] eq "open") {\<br>
&nbsp;&nbsp;set_Exec("timer",'300+$count*60','fhem("echo speak window open")','$count < 9')\<br>
} else {\<br>
&nbsp;&nbsp;del_Exec("timer")\<br>
}\<br>
}</code><br>
<br>
Pumpe alle zwei Stunden im Abstand von fünf Minuten 3 mal einschalten, beim ersten mal für 60 Sekunden, beim zweiten mal für 80 Sekunden und beim dritten mal für 100 Sekunden.<br>
<br>
<code>defmod di_pump DOIF {[08:00-20:00,+[2]:00];;set_Exec("timer",300,'fhem_set("pump on-for-timer ".60+$count*20)','$count < 3')}</code><br>
<br>
Hochdimmen beim Tastendruck im Sekundentakt.<br>
<br>
<code>defmod di_dimm DOIF {["button:on"];;@{$_pct}=(10,35,65,80,90,100);;set_Exec("timer",1,'fhem_set"lamp pct ".$_pct[$count]','$count < 6')}</code><br>
<br>
$_pct ist hier ein Array mit Helligkeitswerten, auf das innerhalb des Devices zu jedem Zeitpunkt zugegriffen werden kann.<br>
<br>
<a name="DOIF_init-Block"></a><br>
<u>init-Block</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
Wird ein Ereignisblock mit dem Namen <b>init</b> benannt, so wird dieser Block beim Systemstart ausgeführt. Er bietet sich insb. an, um Device-Variablen des Moduls vorzubelegen.<br>
<a name="DOIF_Device-Variablen"></a><br>
<u>Device-Variablen</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
Device-Variablen sind sogenannte Instanzvariablen, die global innerhalb eines DOIF-Devices genutzt werden können. Deren Inhalt bleibt von Trigger zu Trigger während der Laufzeit des System erhalten. Sie beginnen mit <b>$_</b> und müssen nicht deklariert werden.
Wenn sie nicht vorbelegt werden, gelten sie als nicht definiert. Das lässt sich abfragen mit:<br>
<br>
<code>if (defined $_...) ...</code><br>
<br>
Instanzvariablen überleben nicht den Neustart, sie können jedoch z.B. im init-Block, der beim Systemstart ausgewertet wird, aus Readings vorbelegt werden.<br>
<br>
Bsp. Vorbelgung einer Instanzvariablen beim Systemstart mit dem Status des Moduls:<br>
<br>
<code>init {$_status=get_State()}</code><br>
<br>
Instanzvariablen lassen sich indizieren, z. B.:<br>
<br>
<code>my $i=0;<br>
$_betrag{$i}=100;</code><br>
<br>
Ebenso funktionieren hash-Variablen z. B.: <br>
<code>$_betrag{heute}=100;</code><br>
<a name="DOIF_Blockierende_Funktionsaufrufe"></a><br>
<u>Blockierende Funktionsaufrufe (blocking calls)</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
DOIF verwaltet blockierende Funktionsaufrufe, d.h. die in diesem Zusammenhang gestarteten FHEM-Instanzen werden gel&ouml;scht, beim Herunterfahren (shutdown), Wiedereinlesen der Konfiguration (rereadcfg) &Auml;nderung der Konfiguration (modify) und Deaktivieren des Ger&auml;tes (disabled).<br>
<br>
Die Handhabung von blockierenden Funktionsaufrufen ist im FHEMwiki erkl&auml;rt, s. <a href="https://wiki.fhem.de/wiki/Blocking_Call">Blocking Call</a>.<br>
<br>
Der von der Funktion BlockingCall zur&uuml;ckgegebene Datensatz ist unterhalb von <b>$_blockingcalls</b> abzulegen, z.B.<br>
<br>
<code>$_blockingcalls{&lt;blocking call name&gt;} = ::BlockingCall(&lt;blocking function&gt;, &lt;argument&gt;, &lt;finish function&gt;, &lt;timeout&gt;, &lt;abort function&gt;, &lt;abort argument&gt;) unless(defined($_blockingcalls{&lt;blocking call name&gt;}));</code><br>
<br>
F&uuml;r unterschiedliche blockierende Funktionen ist jeweils ein eigener Name (&lt;blocking call name&gt;) unterhalb von $_blockingcalls anzulegen.<br>
<br>
Wenn <i>&lt;blocking function&gt;</i>, <i>&lt;finish function&gt;</i> und <i>&lt;abort function&gt;</i> im Package DOIF definiert werden, dann ist dem Funktionsnamen <i>DOIF::</i> voranzustellen, im Aufruf der Funktion BlockingCall, z.B. <code>DOIF::&lt;blocking function&gt;</code> <br>
<br>
<b>$_blockingcalls</b> ist eine f&uuml;r DOIF reservierte Variable und darf nur in der beschriebener Weise verwendet werden.<br>
<a name="DOIF_Attribute_Perl_Modus"></a><br>
<u>Nutzbare Attribute im Perl-Modus</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<br>
<ul>
<a href="#DOIF_addStateEvent">addStateEvent</a> &nbsp;
<a href="#DOIF_checkReadingEvent">checkReadingEvent</a> &nbsp;
<a href="#DOIF_DOIF_Readings">DOIF_Readings</a> &nbsp;
<a href="#DOIF_disable">disable</a> &nbsp;
<a href="#DOIF_event_Readings">event_Readings</a> &nbsp;
<a href="#DOIF_notexist">notexist</a> &nbsp;
<a href="#DOIF_setList__readingList">readingList</a> &nbsp;
<a href="#DOIF_setList__readingList">setList</a> &nbsp;
<a href="#DOIF_uiTable">uiTable</a> &nbsp;
<a href="#DOIF_uiState">uiState</a> &nbsp;
<a href="#DOIF_weekdays">weekdays</a> &nbsp;
<br><a href="#readingFnAttributes">readingFnAttributes</a> &nbsp;
</ul>
<br>
<a name="DOIF_set_Perl_Modus"></a><br>
<u>set-Befehle im Perlmodus</u>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<dl>
<dt><code><b> set </b>&lt;name&gt;<b> disable</b></code></dt>
<dd>blockiert die Befehlsausf&uuml;hrung</dd>
<br>
<dt><code><b> set </b>&lt;name&gt;<b> enable</b></code></dt>
<dd>aktiviert die Befehlsausf&uuml;hrung</dd>
<br>
<dt><code><b> set </b>&lt;name&gt;<b> &lt;Blockname&gt;</b></code></dt>
<dd>führt den entsprechenden DOIF-Block aus</dd>
</dl>
<a name="DOIF_Anwendungsbeispiele_im_Perlmodus"></a><br>
<b>Anwendungsbeispiele im Perlmodus:</b>&nbsp;&nbsp;&nbsp;<a href="#DOIF_Inhaltsuebersicht_Perl-Modus">back</a><br>
<a name="DOIF_Treppenhauslicht mit Bewegungsmelder"></a><br>
<u>Treppenhauslicht mit Bewegungsmelder</u><br>
<br><code>
defmod&nbsp;di_light&nbsp;DOIF&nbsp;{\<br>
&nbsp;&nbsp;if&nbsp;(["FS:motion"])&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;bei&nbsp;Bewegung\<br>
&nbsp;&nbsp;&nbsp;&nbsp;fhem_set("lamp&nbsp;on")&nbsp;if&nbsp;([?lamp]&nbsp;ne&nbsp;"on");;&nbsp;&nbsp;#&nbsp;Lampe&nbsp;einschalten,&nbsp;wenn&nbsp;sie&nbsp;nicht&nbsp;an&nbsp;ist\<br>
&nbsp;&nbsp;&nbsp;&nbsp;set_Exec("off",30,'fhem_set("lamp&nbsp;off")');;&nbsp;#&nbsp;Timer&nbsp;namens&nbsp;"off"&nbsp;für&nbsp;das&nbsp;Ausschalten&nbsp;der&nbsp;Lampe&nbsp;auf&nbsp;30&nbsp;Sekunden&nbsp;setzen&nbsp;bzw.&nbsp;verlängern\<br>
&nbsp;&nbsp;}\<br>
}<br>
</code>
<a name="DOIF_Einknopf_Fernbedienung"></a><br>
<u>Einknopf-Fernbedienung</u><br>
<br>
Anforderung: Wenn eine Taste innerhalb von zwei Sekunden zwei mal betätig wird, soll der Rollladen nach oben, bei einem Tastendruck nach unten.<br>
<br>
<code>
defmod&nbsp;di_shutter&nbsp;DOIF&nbsp;{\<br>
&nbsp;&nbsp;if&nbsp;(["FS:^on$"]&nbsp;and&nbsp;!get_Exec("shutter")){&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;wenn&nbsp;Taste&nbsp;betätigt&nbsp;wird&nbsp;und&nbsp;kein&nbsp;Timer&nbsp;läuft\<br>
&nbsp;&nbsp;&nbsp;&nbsp;set_Exec("shutter",2,'fhem_set("shutter&nbsp;down")');;#Timer&nbsp;zum&nbsp;shutter&nbsp;down&nbsp;auf&nbsp;zwei&nbsp;Sekunden&nbsp;setzen\<br>
&nbsp;&nbsp;}&nbsp;else&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;wenn&nbsp;Timer&nbsp;läuft,&nbsp;d.h.&nbsp;ein&nbsp;weitere&nbsp;Tastendruck&nbsp;innerhalb&nbsp;von&nbsp;zwei&nbsp;Sekunden\<br>
&nbsp;&nbsp;&nbsp;&nbsp;del_Exec("shutter");;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;Timer&nbsp;löschen\<br>
&nbsp;&nbsp;&nbsp;&nbsp;fhem_set("shutter&nbsp;up");;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;Rollladen&nbsp;hoch\<br>
&nbsp;&nbsp;}\<br>
}<br>
</code>
<br>
<u>Aktion auslösen, wenn innerhalb einer bestimmten Zeitspanne ein Ereignis x mal eintritt</u><br>
<br>
Im folgenden Beispiel wird die Nutzung von Device-Variablen demonstriert.<br>
<br>
<code>
defmod&nbsp;di_count&nbsp;DOIF&nbsp;{\<br>
&nbsp;&nbsp;if&nbsp;(["FS:on"]&nbsp;and&nbsp;!get_Exec("counter"))&nbsp;{&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;wenn&nbsp;Ereignis&nbsp;(hier&nbsp;"FS:on")&nbsp;eintritt&nbsp;und&nbsp;kein&nbsp;Timer&nbsp;läuft\<br>
&nbsp;&nbsp;&nbsp;&nbsp;$_count=1;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;setze&nbsp;count-Variable&nbsp;auf&nbsp;1\<br>
&nbsp;&nbsp;&nbsp;&nbsp;set_Exec("counter",3600,'Log&nbsp;(3,"count:&nbsp;$_count&nbsp;action")&nbsp;if&nbsp;($_count&nbsp;>&nbsp;10)');;&nbsp;#&nbsp;setze&nbsp;Timer&nbsp;auf&nbsp;eine&nbsp;Stunde&nbsp;zum&nbsp;Protokollieren&nbsp;der&nbsp;Anzahl&nbsp;der&nbsp;Ereignisse,&nbsp;wenn&nbsp;sie&nbsp;über&nbsp;10&nbsp;ist\<br>
&nbsp;&nbsp;}&nbsp;else&nbsp;{\<br>
&nbsp;&nbsp;&nbsp;&nbsp;$_count++;;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;wenn&nbsp;Timer&nbsp;bereits&nbsp;läuft&nbsp;zähle&nbsp;Ereignis\<br>
&nbsp;&nbsp;}\<br>
}<br>
</code>
<u><a href="https://wiki.fhem.de/wiki/DOIF/Perl-Modus">Dokumentation zum DOIF-Perl-Modus</a></u><br>
</ul>
=end html_DE
=cut