Notify: Unterschied zwischen den Versionen
(Beispiele von wuppi68 eingearbeitet, Debugging-Teil eingefügt) |
TomLee (Diskussion | Beiträge) K (→Syntax) |
||
(42 dazwischenliegende Versionen von 10 Benutzern werden nicht angezeigt) | |||
Zeile 8: | Zeile 8: | ||
|ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]]) | |ModOwner=rudolfkoenig ({{Link2FU|8|Forum}} / [[Benutzer Diskussion:Rudolfkoenig|Wiki]]) | ||
}} | }} | ||
== Einführung == | |||
{{Hinweis|Weitere grundlegende Informationen/Beispiele zu notify enthält [http://fhem.de/Heimautomatisierung-mit-fhem.pdf Heimautomatisierung mit FHEM]}} | {{Hinweis|Weitere grundlegende Informationen/Beispiele zu notify enthält [http://fhem.de/Heimautomatisierung-mit-fhem.pdf Heimautomatisierung mit FHEM]}} | ||
Das Hilfsmodul notify dient dazu [[Ereignis|Ereignisse]] über ein Suchmuster zu erkennen und bei einem Treffer eine Aktion auszulösen. Mit ''notify'' und anderen [[Eventhandler|Eventhandlern]] <ref>hierzu gehören u.a. auch [[DOIF]], [[THRESHOLD]] und [[watchdog]]</ref> ist es möglich, Logikfunktionen im FHEM abzubilden. | |||
Das Hilfsmodul | |||
'''Beispiele:''' | '''Beispiele:''' | ||
Zeile 38: | Zeile 35: | ||
Suchmuster/Regex kann man im Internet beispielsweise auf [http://regexpal.com/| http://regexpal.com/] testen. | Suchmuster/Regex kann man im Internet beispielsweise auf [http://regexpal.com/| http://regexpal.com/] testen. | ||
Es gibt seit Juli 2020 eine Perlfunktion notifyRegexpCheck zum Testen, wie FHEM über das Suchmuster "denkt" - siehe {{Link2Forum|Topic=111938|Message=1074202|LinkText=diesen Beitrag}} im Forum. | |||
{{Hinweis|Das '''Suchmuster''' wird notify-intern um das Zeichen ^ (beginnt mit) und das Zeichen $ (endet mit) ergänzt<ref>Der Eventhandler [[DOIF]] verwendet die in Perl übliche Syntax für reguläre Ausdrücke als DOIF-Suchmuster.</ref>. | |||
Deshalb darf das Suchmuster nicht mit einem üblichen [[Regulärer Ausdruck|'''Regulären Ausdruck''']], wie er in Perl<ref>https://perldoc.perl.org/perlre.html</ref> verwendet wird, gleichgesetzt werden, da die Ergänzung zu einem grundsätzlich unterschiedlichen Verhalten führt, siehe nachstehendes Beispiel.}} | |||
'''Beispiel für das unterschiedliche Verhalten von ''Suchmuster'' und ''regulären Ausdruck''''' | |||
Für einen '''regulären Audruck''' gilt: Wenn der reguläre Ausdruck ''lampe'' ist und das [[Ereignis]] ''tischlampe'' dann passen ''tischlampe'' und ''lampe'' zueinander. | |||
Für das '''Suchmuster''' gilt: Wenn das Suchmuster ''lampe'' ist und das [[Ereignis]] ''tischlampe'' dann passen ''tischlampe'' und ''lampe'' '''nicht''' zueinander, weil das Suchmuster zu ^lampe$ ergänzt wird und damit exakt nur auf ''lampe'' matcht (passt). | |||
'''Variablen Zuordnung zum Event''' | |||
'''Beispiel 1''' | |||
2020-01-21 22:40:39 HUEDevice VibrationTest1 battery: 88 | |||
{| class="wikitable" | |||
|- | |||
! !!$NAME !! colspan="2" |$EVENT | |||
|- | |||
| ||||$EVTPART0 ||$EVTPART1 | |||
|- | |||
|2020-01-21 22:40:39 HUEDevice|| VibrationTest1|| battery:|| 88 | |||
|} | |||
'''Beispiel 2''' | |||
2021-05-09 19:11:43 FB_CALLMONITOR cm_example external_name: Graf Herzog von und zu ... | |||
{| class="wikitable" | |||
|- | |||
! !!$NAME !! colspan="7" |$EVENT | |||
|- | |||
| ||||$EVTPART0 ||$EVTPART1 || $EVTPART2|| $EVTPART3 || $EVTPART4|| $EVTPART5|| ... | |||
|- | |||
|2021-05-09 19:11:43 FB_CALLMONITOR|| cm_example|| external_name:|| Graf|| Herzog|| von|| und|| zu|| ... | |||
|} | |||
'''Beispiel 3''' | |||
2023-04-29 16:53:04 dummy Demo closed | |||
{| class="wikitable" | |||
|- | |||
! !!$NAME !! colspan="1" |$EVENT | |||
|- | |||
| ||||$EVTPART0 | |||
|- | |||
|2023-04-29 16:53:04 dummy|| Demo|| closed | |||
|} | |||
== FHEMWEB- | == FHEMWEB-unterstütztes Anlegen eines notify == | ||
{{Hinweis|Die Erstellung eines notify und insbesondere die korrekte Angabe des Suchmusters (Regex) führt gerade bei Einsteigern immer wieder zu Schwierigkeiten. Zur Fehlerminimierung empfiehlt es sich zum einen, die [[Konfiguration]] nicht direkt zu bearbeiten, sondern die "Befehl-Eingabezeile", die "Objektdetails" oder den [[Import von Code Snippets|Import von RAW-Definitionen]] zur Bearbeitung zu nutzen.}} | {{Hinweis|Die Erstellung eines notify und insbesondere die korrekte Angabe des Suchmusters (Regex) führt gerade bei Einsteigern immer wieder zu Schwierigkeiten. Zur Fehlerminimierung empfiehlt es sich zum einen, die [[Konfiguration]] nicht direkt zu bearbeiten, sondern die "Befehl-Eingabezeile", die "Objektdetails" oder den [[Import von Code Snippets|Import von RAW-Definitionen]] zur Bearbeitung zu nutzen.}} | ||
Zeile 46: | Zeile 91: | ||
=== Regexp wizard === | === Regexp wizard === | ||
Zudem enthält FHEM einen Regexp wizard mit dem Regex anhand der in FHEM vorhandenen Devices und deren Events aus einer Auswahlbox selektiert werden können. Voraussetzungen sind: | Zudem enthält FHEM einen Regexp wizard mit dem Regex anhand der in FHEM vorhandenen Devices und deren Events aus einer Auswahlbox selektiert werden können. Voraussetzungen sind: | ||
* Aktivierung des Hilfsmoduls [[eventTypes]] (bei allen Neuinstallationen Standard) | * Aktivierung des Hilfsmoduls [[eventTypes]] (bei allen Neuinstallationen Standard) | ||
Zeile 72: | Zeile 115: | ||
== Mein notify geht nicht - wie kann ich mir selbst helfen: Debugging == | == Mein notify geht nicht - wie kann ich mir selbst helfen: Debugging == | ||
Funktioniert ein notify nicht wie gewünscht, kann es nur zwei Hauptursachen haben: | |||
* Entweder das Suchmuster paßt nicht zum gewünschten Auslöser (FHEM Device), und/oder | |||
* die Anweisung enthält einen Fehler. | |||
Sollte kein Fehler im Logfile auftauchen aber das notify ausgelöst werden, stimmt meist der Übertragungsweg zum Zieldevice nicht. | |||
Der STATE des notify zeigt normalerweise mit Datum/Uhrzeit die letzte Auslösung an. | |||
Beim Debuggen sollte man daher beide Elemente getrennt untersuchen. Hier ein Beispiel welches nicht wie gewünscht funktioniert: | |||
* | <syntaxhighlight lang="perl"> define n_test notify n_test:muster Ausführungsteil</syntaxhighlight> | ||
* die | Zum debuggen benötigen wir | ||
* den [[Event monitor]] | |||
* das [https://fhem.de/commandref.html#trigger trigger-Kommando] - kann man jederzeit verwenden um das Suchmuster als Event unabhängig vom Auslöser zu erzeugen. | |||
* die FHEM Kommandozeile | |||
* den [[DEF-Editor]] | |||
* eventuell einen Texteditor um Codeblöcke zwischen zu lagern und Notizen zu machen. | |||
Das Suchmuster im Beispiel notify triggert auf sich selbst, es soll auf jeden Event mit dem Inhalt '''muster''' ausgelöst werden, Beispiel: | |||
2018-07-14 14:31:03 notify n_test muster bild | |||
=== | === Suchmuster === | ||
Sollte das notify nicht funktionieren: | |||
* keine Reaktion wie gewünscht | |||
* keine Fehlermeldung in der Weboberfläche beim Anlegen, keine Fehlermeldung im Logfile | |||
* STATE ist unverändert auf active oder einem altem Datum/Uhrzeit | |||
liegt der Fehler mit Sicherheit im Suchmuster. Man hat die Chance das Suchmuster mit dem trigger Befehl zu erzeugen und zu schauen ob die Anweisung ausgeführt wird. Dabei ist zu beachten: Der erste ":" im Suchmuster ist zusätzlich zwischen Gerät und Event als Trennung. Jeder weiter : ist, wenn vorhanden, Bestandteil des Events! Siehe dazu den Abschnitt [https://fhem.de/commandref_DE.html#notify Hinweise in der commandref] | |||
*Im Beispiel: Event: n_test muster -> Suchmuster n_test:muster | |||
Um aus dem [[Event]] ein passendes Suchmuster zu erzeugen kann der [[Event monitor|Event-Monitor]] direkt verwendet werden. Man kann ein neues notify erzeugen oder ein Bestehendes modifizieren lassen. | |||
Unser Regex im Beispiel ist zu spezifisch, es triggert nur exakt auf '''muster'''. Dieser Trigger erzeugt den folgenden Eintrag im Eventmonitor, entspricht exakt dem Suchmuster und löst das notify aus: | |||
trigger n_test muster | |||
2018-07-13 11:52:08 notify n_test muster | |||
Das Suchmuster für unsere Anforderung muss in <code>n_test:muster.*</code> geändert werden, damit jeder Event der mit muster beginnt das notify auslöst. | |||
Der . im Regex steht für jedes beliebige Zeichen und der * für eine beliebige Anzahl des Zeichens davor: also beliebig viele beliebige Zeichen nach muster. | |||
Das Suchmuster wird häufig in ein komplizierteres Regex umgewandelt um im notify mehrere Aktionen zu starten. Das eigene Regex kann z.B. mit http://regexpal.com/ oder https://regex101.com/ getestet werden. | |||
Funktioniert der Auslöser, das notify tut aber noch nicht was es soll, müssen wir die Anweisung untersuchen. In unserem korrigierten Beispiel | |||
<syntaxhighlight lang="perl"> defmod n_test notify n_test:muster.* Ausführungsteil</syntaxhighlight> | |||
folgt beim Kommando <code>trigger n_test muster bild</code> ein Eintrag im Log: | |||
2018.07.13 11:47:57 3: n_test return value: Unknown command Ausführungsteil, try help. | |||
Das notify wurde zwar getriggert aber die Anweisung war nicht ausführbar. | |||
Ein richtiges Suchmuster und eine fehlerhafte Anweisung wird also normalerweise einen Fehlereintrag im Logfile erzeugen! | |||
=== Spezialfall: notify löst zwar aus - aber zu oft === | |||
In dem Fall ist das Suchmuster (regExp) zu unscharf oder das triggernde Gerät löst das Event zu oft aus. Das regExp sollte so genau wie möglich konstruiert werden, device:.* ist eine einfache aber oft keine gute Wahl! | |||
Im Device, welches den Event auslöst, kann mit den Attributen event-on-.* die Häufigkeit gesteuert werden. Insbesondere ist hier das regExp .* eine Art Standardwahl um aufeinanderfolgende gleichartige Events zu verhindern. | |||
:<code>attr device event-on-change-reading .*</code> | |||
'''Achtung''': durch falsche Angaben kann man Events ganz leicht völlig verhindern! | |||
Siehe auch [[event-on-change-reading]] | |||
=== Anweisung === | |||
Wird das notify getriggert oder will man ganz schnell mal ein notify testen, kann man die Anweisung durch folgenden Code ersetzen, man öffnet also einfach nur die DEF, kopiert den ursprünglichen Inhalt an einen sicheren Ort und ersetzt die Anweisung durch eine der beiden Zeilen. Die erste Zeile kann man auch einfach mal in der Kommandozeile testen: | |||
<syntaxhighlight lang="perl">{Log 1, "Das Notify n_test hat ausgeloest."} | |||
{Log 1, "Das Device $NAME hat ausgeloest, der Event sah so aus: $EVENT"}</syntaxhighlight> | |||
Wird das notify ausgelöst, muss anschließend im Logfile ein Eintrag zu finden sein: | |||
2018.07.13 10:28:57 1: Das Notify n_test hat ausgeloest, der Event sah so aus: muster | |||
Unsere Anweisung <code>Ausführungsteil</code> liefert in der Kommandozeile selbst einen Fehler: | |||
<code>Unknown command Ausführungsteil, try help.</code> | |||
Ein Versuch mit geschweiften Klammern <code>{Ausführungsteil}</code> liefert wieder einen Fehler: | |||
<code>Unrecognized character \xC3; marked by <-- HERE after {Ausf<-- HERE near column 6 at (eval 5977) line 1.</code> | |||
Diese Variante <code>{"Ausführungsteil"}</code> liefert den String Ausführungsteil ohne Fehler: Das notify arbeitet fehler- aber sinnfrei. | |||
Der fertige Code: | |||
defmod n_test notify n_test:muster.* {"Ausführungsteil"} | |||
Man kann die Anweisung, normalerweise so wie sie ist, in der FHEM Kommandozeile testen. Sind im Perl Code (in geschweiften Klammern) im DEF Editor Semikolon enthalten muss man diese für den Test in der Kommandozeile (oder Raw Def) verdoppeln. | |||
Laufzeitabhängige Variablen sind in der Kommandozeile meist nicht verfügbar, diese sollte man für den Test einfach durch passende Inhalte austauschen. So kann man die komfortable Variante (loggt den Namen und das komplette Event) nicht in der Kommandozeile ausführen. | |||
Funktioniert ein FHEM Befehl in der Kommandozeile nicht (z.B. Lampe geht nicht an) kann es im notify auch nicht funktionieren, dann muss die Fehlersuche an anderer Stelle fortgeführt werden. | |||
Komplexeren Code im Ausführungsteil sollte man beim Testen in Teilabschnitte aufteilen, von der Laufzeit abhängige Variable ($NAME, $EVENT, $EVTPART) durch Strings ("TestWort") ersetzen, die Teilabschnitte separat testen und anschließend schrittweise wieder komplettieren. | |||
== Beispiele == | == Beispiele == | ||
{{Hinweis|Für die nachfolgenden Beispiele wurden einige unterschiedliche Technologien verwendet. Sie können aber recht einfach auf alle anderen Systeme übertragen werden, dabei sollte ggf. darauf geachtet werden, dass sich Schaltbefehle und Events teilweise je nach konkret eingesetzter Technologie unterscheiden können. Dann ist ggf. eine Erweiterung, z.B. durch eine [[if-condition|if-Abfrage]] erforderlich.}} | |||
=== | === Schalter entprellen === | ||
Will man ein notify innerhalb eines bestimmten Zeitraumes nur einmal auslösen lassen, auch wenn er in diesem Zeitraum mehrfach getriggered werden sollte, so bietet sich das Attribut disabledAfterTrigger an, | |||
attr <notify_device> disabledAfterTrigger <Anzahl Sekunden> | |||
In dem Zeitraum wird dann nur einmal (beim ersten Mal) der Befehl ausgelöst, auch wenn mehrfach getriggered wurde. Der Zeitraum kann Bruchteile von Sekunden umfassen. | |||
=== Etwas schalten, wenn ein anderes Gerät geschaltet wird === | |||
==== Vorbedingungen ==== | |||
Dieses Beispiel verwendet eine einfache InterTechno-kompatible Funksteckdose für das Radio und einen HM-Aktor für das Licht: | |||
define RadioKueche | define RadioKueche IT 000000FFFF 0F F0 | ||
define LichtKueche | define LichtKueche CUL_HM 3A37D6 | ||
Beachte: beide kennen als Event bzw. Schaltbefehle ''on'' und ''off''. | |||
==== notify Befehl ==== | ==== notify Befehl ==== | ||
define LichtamRadioan notify LichtKueche set RadioKueche $EVENT | define LichtamRadioan notify LichtKueche set RadioKueche $EVENT | ||
oder alternativ: | oder alternativ: | ||
Zeile 125: | Zeile 217: | ||
* Wann ist ein Wechsel auf die Perl-Ebene erforderlich? | * Wann ist ein Wechsel auf die Perl-Ebene erforderlich? | ||
** einfache FHEM-Befehle sollten in der Regel direkt verwendet werden, dies ist ressourcenschonender. | ** einfache FHEM-Befehle sollten in der Regel direkt verwendet werden, dies ist ressourcenschonender. | ||
** Immer dann, wenn dies nicht möglich ist, weil z.B. komplexerer Code ausgeführt werden soll, (blockierende) Prozesse ausgelagert werden sollten oder Systembefehle ausgeführt werden, ist es günstiger, auf die Perl-Ebene zu wechseln <ref>In diesem {{Link2Forum|Topic=88398|Message=808685|LinkText=Forenbeitrag}} wird z.B. erläutert, wie man nichtblockierend externe | ** Immer dann, wenn dies nicht möglich ist, weil z.B. komplexerer Code ausgeführt werden soll, (blockierende) Prozesse ausgelagert werden sollten oder Systembefehle ausgeführt werden, ist es günstiger, auf die Perl-Ebene zu wechseln <ref>In diesem {{Link2Forum|Topic=88398|Message=808685|LinkText=Forenbeitrag}} wird z.B. erläutert, wie man nichtblockierend externe Scripte aufrufen kann, die dann ihre Ergebnisse wieder an FHEM übergeben.</ref>. | ||
=== Einschalten von mehreren Geräten/Lampen, wenn das Licht eingeschaltet wird === | === Einschalten von mehreren Geräten/Lampen, wenn das Licht eingeschaltet wird === | ||
Dieses Beispiel verwendet einen HM-Aktor für das Licht sowie zwei Milight-Birnen, die einzeln geschaltet werden sollen<ref>Dies ist ausdrücklich keine Empfehlung für diese Technologie und der Module</ref> in den Stehlampen: | |||
==== Vorbedingungen ==== | |||
FHEM: | FHEM: | ||
define LichtWZ | define LichtWZ CUL_HM 3A37D8 | ||
define | define Stehlampe1 MilightDevice RGBW Milight_Wohnzimmer 5 | ||
define | define Stehlampe2 MilightDevice RGBW Milight_Wohnzimmer 6 | ||
==== notify Befehl ==== | ==== notify Befehl ==== | ||
define SteckdoseWZein notify LichtWZ set Stehlampe1,Stehlampe2 $EVENT | |||
define SteckdoseWZein notify LichtWZ set | |||
oder ''in Perl'' | oder ''in Perl'' | ||
define SteckdoseWZein notify LichtWZ { fhem "set | define SteckdoseWZein notify LichtWZ { fhem "set Stehlampe1 $EVENT;;set Stehlampe2 $EVENT " } | ||
==== Erklärung ==== | ==== Erklärung ==== | ||
Wenn das LichtWZ eingeschaltet wird, dann werden auch die | Wenn das LichtWZ eingeschaltet wird, dann werden auch die Stehlampen (1 und 2) eingeschaltet. | ||
=== Einfache ODER Funktion === | === Einfache ODER Funktion === | ||
Zeile 153: | Zeile 243: | ||
FHEM: | FHEM: | ||
define Licht1 | define Licht1 CUL_HM 3A37D8 | ||
define Licht2 | define Licht2 CUL_HM 1B7EC3 | ||
define | define Stehlampe MilightDevice RGBW Milight_Wohnzimmer 7 | ||
==== notify Befehl ==== | ==== notify Befehl ==== | ||
define SteckdoseWZein notify (Licht1|Licht2) set | define SteckdoseWZein notify (Licht1|Licht2) set Stehlampe $EVENT | ||
oder | oder | ||
define SteckdoseWZein notify (Licht.) set | define SteckdoseWZein notify (Licht.) set Stehlampe $EVENT | ||
==== Erklärung ==== | ==== Erklärung ==== | ||
Zeile 171: | Zeile 261: | ||
=== Einfache UND Funktion === | === Einfache UND Funktion === | ||
Ob man dieses Konstrukt noch als einfach bezeichnen kann, wage ich mal zu | Ob man dieses Konstrukt noch als einfach bezeichnen kann, wage ich mal zu bezweifeln. In FHEM fehlen Loggingfunktionen, die man alle selber mit Perl Code erstellen kann (Danke an MAZ). | ||
Dadurch ist FHEM zwar mächtig, wird aber für viele sehr kompliziert. | Dadurch ist FHEM zwar mächtig, wird aber für viele sehr kompliziert. | ||
Zeile 182: | Zeile 272: | ||
FHEM: | FHEM: | ||
define R1ZU KNX 0/0/50 | define R1ZU KNX 0/0/50:dpt1.009 | ||
attr R1ZU dummy 1 | attr R1ZU dummy 1 | ||
define R2ZU KNX 0/0/51 | define R2ZU KNX 0/0/51:dpt1.009 | ||
attr R2ZU dummy 1 | attr R2ZU dummy 1 | ||
define R3ZU KNX 0/0/52 | define R3ZU KNX 0/0/52:dpt1.009 | ||
attr R3ZU dummy 1 | attr R3ZU dummy 1 | ||
define LEDalleRolloZu KNX 0/0/106 | define LEDalleRolloZu KNX 0/0/106:dpt1 | ||
Durch das | Durch das Attribut dummy werden keine Schaltfunktion angeboten. Es kann nur Werte anzeigen. | ||
==== notify Befehl ==== | ==== notify Befehl ==== | ||
define nt.allerolloszu notify (R1ZU|R2ZU|R3ZU) { | define nt.allerolloszu notify (R1ZU|R2ZU|R3ZU) {\ | ||
my $r1 = Value("R1ZU");; | my $r1 = Value("R1ZU");;\ | ||
my $r2 = Value("R2ZU");; | my $r2 = Value("R2ZU");;\ | ||
my $r3 = Value("R3ZU");; | my $r3 = Value("R3ZU");;\ | ||
if ($r1 eq "on" && $r2 eq "on" && $r3 eq "on") { | if ($r1 eq "on" && $r2 eq "on" && $r3 eq "on") {\ | ||
fhem "set LEDalleRolloZu on" | fhem("set LEDalleRolloZu on");;\ | ||
} else { | } else {\ | ||
fhem "set LEDalleRolloZu off" | fhem("set LEDalleRolloZu off");;\ | ||
} | }\ | ||
} | } | ||
Zeile 209: | Zeile 299: | ||
= Value("R1ZU");; ==> weist den Rückgabewert (on oder off) von R1ZU der Variable $r1 zu | = Value("R1ZU");; ==> weist den Rückgabewert (on oder off) von R1ZU der Variable $r1 zu | ||
Der doppelte ;; ist ein FHEM Thema. Eigentlich würde für Perl ein ; reichen. Aber FHEM nutzt selbst das ; und daher wird ein ;; benötigt. Mit den ersten drei my Zeilen werden die Rückgabewerte den | Der doppelte ;; ist ein FHEM Thema. Eigentlich würde für Perl ein ; reichen. Aber FHEM nutzt selbst das ; und daher wird ein ;; benötigt. Mit den ersten drei my Zeilen werden die Rückgabewerte den Variablen zugewiesen. | ||
Danach erfolgt ein normales "if then else" Konstrukt. Die Zeile »($r1 eq "on" && $r2 eq "on" && $r3 eq "on")« kann man so lesen: Wenn $r1 den Wert "on" und (&&) $r2 den Wert "on" und $r3 den Wert "on" dann schalte die LEDalleRolloZu ein {fhem("set LEDalleRolloZu on")} | Danach erfolgt ein normales "if then else" Konstrukt. Die Zeile »($r1 eq "on" && $r2 eq "on" && $r3 eq "on")« kann man so lesen: Wenn $r1 den Wert "on" und (&&) $r2 den Wert "on" und $r3 den Wert "on" dann schalte die LEDalleRolloZu ein {fhem("set LEDalleRolloZu on")} | ||
Zeile 229: | Zeile 319: | ||
:''Quelle: {{Link2Forum|Topic=17161|LinkText=FHEM Forum}}'' | :''Quelle: {{Link2Forum|Topic=17161|LinkText=FHEM Forum}}'' | ||
|} | |} | ||
=== Eine PV-Anlage (Solarstrom) zur Steuerung der Rollos nutzen (optional Zeit und Datums abhängig) === | === Eine PV-Anlage (Solarstrom) zur Steuerung der Rollos nutzen (optional Zeit und Datums abhängig) === | ||
Zeile 246: | Zeile 335: | ||
attr sv event-on-change-reading currentPower | attr sv event-on-change-reading currentPower | ||
define nt.sonnenlichtpersolar notify | define nt.sonnenlichtpersolar notify sv:currentPower.* { \ | ||
if ($EVTPART1 < 3000 ) { | if ($EVTPART1 < 3000 ) {\ | ||
fhem('set Flur1 Auf') | fhem('set Flur1 Auf')\ | ||
}else { | }else {\ | ||
if ($EVTPART1 > 5000 ) { | if ($EVTPART1 > 5000 ) {\ | ||
fhem('set Flur1 Ab') | fhem('set Flur1 Ab')\ | ||
} | } \ | ||
} | }\ | ||
} | } | ||
Optional 1: Zeitabhängig | Optional 1: Zeitabhängig (Code gehört in die DEF) | ||
<syntaxhighlight lang="perl"> | |||
sv:currentPower.* { | |||
my $hm = sprintf("%02d:%02d", $hour, $min); | my $hm = sprintf("%02d:%02d", $hour, $min); | ||
if ( $hm gt "09:30" & | if ( $hm gt "09:30" && $hm lt "17:00") { | ||
if ($EVTPART1 | if ($EVTPART1 < 5000 ) { | ||
fhem('set Flur1 Auf') | fhem('set Flur1 Auf') | ||
}else { | }else { | ||
if ($EVTPART1 | if ($EVTPART1 > 8000 ) { | ||
fhem('set Flur1 Ab') | fhem('set Flur1 Ab') | ||
} | } | ||
} | } | ||
} | } | ||
} | } | ||
</syntaxhighlight> | |||
Optional 2: Zeit und Datum | Optional 2: Zeit und Datum (Code gehört in die DEF) | ||
<syntaxhighlight lang="perl"> | |||
sv:currentPower.* { | |||
my $hm = sprintf("%02d:%02d", $hour, $min); | my $hm = sprintf("%02d:%02d", $hour, $min); | ||
if ($month >= 6 & | if ($month >= 6 && $month <= 9) { | ||
if ( $hm gt "09:30" & | if ( $hm gt "09:30" && $hm lt "17:00") { | ||
if ($EVTPART1 | if ($EVTPART1 < 5000 ) { | ||
fhem('set Flur1,RBUERO1,RBUERO2 Auf'); | fhem('set Flur1,RBUERO1,RBUERO2 Auf'); | ||
}else { | }else { | ||
if ($EVTPART1 | if ($EVTPART1 > 8000 ) { | ||
fhem('set Flur1,Flur2,RBUERO1,RBUERO2 Ab'); | fhem('set Flur1,Flur2,RBUERO1,RBUERO2 Ab'); | ||
} | } | ||
Zeile 287: | Zeile 376: | ||
} | } | ||
} | } | ||
</syntaxhighlight> | |||
==== Erklärung ==== | ==== Erklärung ==== | ||
* Das define wird in der Kommandozeile im Webbrowser eingegeben. | * Das define wird in der Kommandozeile im Webbrowser eingegeben. | ||
* | * Anschließend wird im Webbrowser die DEF bearbeitet, das erspart uns Probleme mit Perl | ||
* define sv SolarView ... <==== ist die Schnittstelle vom SolarView | * define sv SolarView ... <==== ist die Schnittstelle vom SolarView | ||
* define nt.sonnenlichtpersolar notify (sv:currentPower.*) { <==== hier wird ein notify angelegt, der auf das "define sv" Wert "currentPower.*" (.* ist irgendwas) reagiert | * define nt.sonnenlichtpersolar notify (sv:currentPower.*) { <==== hier wird ein notify angelegt, der auf das "define sv" Wert "currentPower.*" (.* ist irgendwas) reagiert | ||
Zeile 301: | Zeile 391: | ||
} | } | ||
} | } | ||
Diese if-Funktion wertet den Rückgabewert von currentPower aus. Hierbei muss man wissen, dass $EVTPART1 das | Diese if-Funktion wertet den Rückgabewert von currentPower aus. Hierbei muss man wissen, dass $EVTPART1 das Split-Ergebnis vom Rückgabewert ist | ||
Beispiel: Der Rückgabewert (wie im Beispiel) ist "currentPower: 6000". | Beispiel: Der Rückgabewert (wie im Beispiel) ist "currentPower: 6000". | ||
Zeile 312: | Zeile 402: | ||
'''Optional 1:''' Der Block "my $hm = sprintf("%02d:%02d", $hour, $min);" erzeugt die String-Variable $hm mit dem Inhalt $hour:$min. %02d begrenzt die Ausgabe auf zwei Stellen. | '''Optional 1:''' Der Block "my $hm = sprintf("%02d:%02d", $hour, $min);" erzeugt die String-Variable $hm mit dem Inhalt $hour:$min. %02d begrenzt die Ausgabe auf zwei Stellen. | ||
Danach wird mit "if ( $hm gt "09:30" && $hm lt "17:00")" mit | Danach wird mit "if ( $hm gt "09:30" && $hm lt "17:00")" mit stringvergleichenden Operatoren geprüft, ob die Uhrzeit zwischen 9:30 und 17:00 liegt (lt = kleiner als; gt = größer als). Es wäre auch ein le und ge möglich: le = kleiner/gleich als, ge = größer/gleich als. | ||
'''Optional 2:'''if( $month >= 6 && $month <= 9) { | '''Optional 2:'''if( $month >= 6 && $month <= 9) { | ||
Zeile 327: | Zeile 417: | ||
==== notify Syntax ==== | ==== notify Syntax ==== | ||
FHEM: | FHEM: | ||
define statusFenster notify fensterKontakt(Oben|Unten):(open|closed) { | define statusFenster notify fensterKontakt(Oben|Unten):(open|closed) {\ | ||
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open') | if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open')\ | ||
{ fhem 'set Terrassentuer open' } | { fhem 'set Terrassentuer open' }\ | ||
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed') | if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed')\ | ||
{ fhem 'set Terrassentuer closed' } | { fhem 'set Terrassentuer closed' }\ | ||
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed') | if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed')\ | ||
{ fhem 'set Terrassentuer tilted' } | { fhem 'set Terrassentuer tilted' }\ | ||
if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open') | if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open')\ | ||
{ fhem 'set Terrassentuer undef' } | { fhem 'set Terrassentuer undef' }\ | ||
} | } | ||
Zeile 341: | Zeile 431: | ||
* Entsprechend zu $EVENT gibt es auch noch $NAME und $TYPE. $NAME und $TYPE enthalten den Namen bzw. Typ des Ereignis auslösenden Gerätes. | * Entsprechend zu $EVENT gibt es auch noch $NAME und $TYPE. $NAME und $TYPE enthalten den Namen bzw. Typ des Ereignis auslösenden Gerätes. | ||
* Wird der Perl-Code in einem <code>notify</code> immer länger, lagere den Code wegen der Übersichtlichkeit in eine eigene Programmdatei aus, wie in [[99_myUtils anlegen]] beschrieben. | * Wird der Perl-Code in einem <code>notify</code> immer länger, lagere den Code wegen der Übersichtlichkeit in eine eigene Programmdatei aus, wie in [[99_myUtils anlegen]] beschrieben. | ||
* Achtung! Wenn man das Skript für den notify-Befehl über mehrere Zeilen schreibt, muss man anscheinend darauf achten, dass keine | * Achtung! Wenn man das Skript für den notify-Befehl über mehrere Zeilen schreibt, muss man anscheinend darauf achten, dass keine abschließende Leerzeile mitgespeichert wird. Sonst wird der notify-Befehl ignoriert. | ||
* Dieser {{Link2Forum|Topic=38520|Message=307325}} enthält Vorschläge zur Vorgehensweise bei der Erstellung von komplexen ''notify'' Definitionen bzw. bei deren Fehlerbehebung. | * Dieser {{Link2Forum|Topic=38520|Message=307325}} enthält Vorschläge zur Vorgehensweise bei der Erstellung von komplexen ''notify'' Definitionen bzw. bei deren Fehlerbehebung. | ||
Zeile 347: | Zeile 437: | ||
* [[Escapen in Perlbefehlen]] | * [[Escapen in Perlbefehlen]] | ||
* [[Klammerebenen]] | * [[Klammerebenen]] | ||
* Forenbeitrag zum Thema {{Link2Forum|Topic=115414|LinkText=Optimierung des Suchmusters - NOTIFYDEV}} | |||
== Hinweise == | == Hinweise == |
Aktuelle Version vom 29. April 2023, 16:04 Uhr
notify | |
---|---|
Zweck / Funktion | |
Ausführung von Anweisung(en) als Reaktion auf Ereignisse | |
Allgemein | |
Typ | Hilfsmodul |
Details | |
Dokumentation | EN / DE |
Support (Forum) | Automatisierung |
Modulname | 91_notify.pm |
Ersteller | rudolfkoenig (Forum / Wiki) |
Wichtig: sofern vorhanden, gilt im Zweifel immer die (englische) Beschreibung in der commandref! |
Einführung
Das Hilfsmodul notify dient dazu Ereignisse über ein Suchmuster zu erkennen und bei einem Treffer eine Aktion auszulösen. Mit notify und anderen Eventhandlern [1] ist es möglich, Logikfunktionen im FHEM abzubilden.
Beispiele:
- Wird das Licht in der Küche eingeschaltet, soll FHEM dort auch das Radio einschalten.
- Bei Druck auf einen Taster soll die Umwälzpumpe für das Warmwasser eingeschaltet werden.
- Erweiterte Möglichkeiten: Aber nur, wenn das Radio aus ist bzw. die Temperatur im Rücklauf des Warmwassers unterhalb einer bestimmten Schwelle liegt[2].
Syntax
define <name> notify <Suchmuster> <command>
Das Suchmuster (häufig als Regexp = regular expression = regulärer Ausdruck bezeichnet) ist sehr wichtig: Es ist entweder der Name des auslösenden ("triggernden") Gerätes oder die Kombination aus Gerät und auslösendem Ereignis (Event) Gerätename:Event
. Die Events kann man dem Event-Monitor entnehmen. Wenn dort z.B. Rollo1
steht, dann reagiert notify auf Rollo1 on
und Rollo1 off
usw.
Wenn man mehrere Suchmuster kombinieren möchte, kann man diese in Klammer schreiben, als Trenner wird dann Pipe (|) genutzt: (Rollo1|Rollo2|Steckdose5)
.
Auch die Verwendung von Platzhaltern ist möglich:
Rollo.
→ das notify reagiert auf alles was mit Rollo und einem weiteren beliebigen Zeichen anfängt. Also auf Rollo1 wie auch auf RolloG, aber nicht auf Rollo_wischundwegRollo.*
→ notify reagiert auf alles das mit Rollo beginnt.*isch
→ auf alles das mit isch aufhört (Tisch, Fisch)Schalter(1|2|3)
→ hört auf Schalter1, Schalter2 und Schalter3dimmer:pct:.(100|7[6-9]|[89][0-9])
→ reagiert, wenn pct einen Wert über 75 annimmt.
Suchmuster/Regex kann man im Internet beispielsweise auf http://regexpal.com/ testen.
Es gibt seit Juli 2020 eine Perlfunktion notifyRegexpCheck zum Testen, wie FHEM über das Suchmuster "denkt" - siehe diesen Beitrag im Forum.
Beispiel für das unterschiedliche Verhalten von Suchmuster und regulären Ausdruck
Für einen regulären Audruck gilt: Wenn der reguläre Ausdruck lampe ist und das Ereignis tischlampe dann passen tischlampe und lampe zueinander.
Für das Suchmuster gilt: Wenn das Suchmuster lampe ist und das Ereignis tischlampe dann passen tischlampe und lampe nicht zueinander, weil das Suchmuster zu ^lampe$ ergänzt wird und damit exakt nur auf lampe matcht (passt).
Variablen Zuordnung zum Event
Beispiel 1
2020-01-21 22:40:39 HUEDevice VibrationTest1 battery: 88
$NAME | $EVENT | ||
---|---|---|---|
$EVTPART0 | $EVTPART1 | ||
2020-01-21 22:40:39 HUEDevice | VibrationTest1 | battery: | 88 |
Beispiel 2
2021-05-09 19:11:43 FB_CALLMONITOR cm_example external_name: Graf Herzog von und zu ...
$NAME | $EVENT | |||||||
---|---|---|---|---|---|---|---|---|
$EVTPART0 | $EVTPART1 | $EVTPART2 | $EVTPART3 | $EVTPART4 | $EVTPART5 | ... | ||
2021-05-09 19:11:43 FB_CALLMONITOR | cm_example | external_name: | Graf | Herzog | von | und | zu | ... |
Beispiel 3
2023-04-29 16:53:04 dummy Demo closed
$NAME | $EVENT | |
---|---|---|
$EVTPART0 | ||
2023-04-29 16:53:04 dummy | Demo | closed |
FHEMWEB-unterstütztes Anlegen eines notify
Event Monitor
Die komfortabelste Möglichkeit, die häufigsten Event-Handler zu erstellen, bietet der Event-Monitor. Die Vorgehensweis ist in dem zugehörigen Artikel dargestellt.
Regexp wizard
Zudem enthält FHEM einen Regexp wizard mit dem Regex anhand der in FHEM vorhandenen Devices und deren Events aus einer Auswahlbox selektiert werden können. Voraussetzungen sind:
- Aktivierung des Hilfsmoduls eventTypes (bei allen Neuinstallationen Standard)
- das gesuchte Ereignis (Event) ist nach Aktivierung des Hilfsmoduls bereits mindestens einmal eingetreten
Schrittweise Darstellung der Nutzung des Regexp wizard zur Anlage eines "notify":
In das Befehls-Eingabefeld eingeben und mit Enter bestätigen:
define ntest notify a b
Als Beispiel wird ein notify mit <name> "ntest" angelegt. "a" und "b" sind beliebige Platzhalter für <Suchmuster> und <Command>, die bei der weiteren Bearbeitung mit dem endgültigen Werten ersetzt werden. Der Regexp wizard öffnet sich:
Nun in der Auswahlbox das auslösende Event (Ereignis) auswählen; zunächst das Device und dann das gewünschte Regex. Hier soll das notify bei jeder Veränderung der Temperatur (temperature.*) des Device BTHR918N reagieren. Abschließend mit einem Mausklick auf set bestätigen. Wählt man mehrere Regex in dieser Weise aus, so wird das "notify" bei Eintritt jedes dieser Events ausgeführt:
Anschließend den Platzhalter "a" mit Klick auf den Link "removeRegexpPart" löschen:
Den Link "DEF" anklicken, damit sich der DEF-Editor öffnet:
Jetzt den auszuführenden Befehl im "DEF"-Bereich durch Überschreiben des Platzhalters "b" eintragen und mit Klick auf modify ntest abschließen:
Das fertige und sofort aktive "notify" sieht abschließend folgendermaßen aus:
Am Schluss das Speichern über Save config nicht vergessen.
Mein notify geht nicht - wie kann ich mir selbst helfen: Debugging
Funktioniert ein notify nicht wie gewünscht, kann es nur zwei Hauptursachen haben:
- Entweder das Suchmuster paßt nicht zum gewünschten Auslöser (FHEM Device), und/oder
- die Anweisung enthält einen Fehler.
Sollte kein Fehler im Logfile auftauchen aber das notify ausgelöst werden, stimmt meist der Übertragungsweg zum Zieldevice nicht. Der STATE des notify zeigt normalerweise mit Datum/Uhrzeit die letzte Auslösung an.
Beim Debuggen sollte man daher beide Elemente getrennt untersuchen. Hier ein Beispiel welches nicht wie gewünscht funktioniert:
define n_test notify n_test:muster Ausführungsteil
Zum debuggen benötigen wir
- den Event monitor
- das trigger-Kommando - kann man jederzeit verwenden um das Suchmuster als Event unabhängig vom Auslöser zu erzeugen.
- die FHEM Kommandozeile
- den DEF-Editor
- eventuell einen Texteditor um Codeblöcke zwischen zu lagern und Notizen zu machen.
Das Suchmuster im Beispiel notify triggert auf sich selbst, es soll auf jeden Event mit dem Inhalt muster ausgelöst werden, Beispiel:
2018-07-14 14:31:03 notify n_test muster bild
Suchmuster
Sollte das notify nicht funktionieren:
- keine Reaktion wie gewünscht
- keine Fehlermeldung in der Weboberfläche beim Anlegen, keine Fehlermeldung im Logfile
- STATE ist unverändert auf active oder einem altem Datum/Uhrzeit
liegt der Fehler mit Sicherheit im Suchmuster. Man hat die Chance das Suchmuster mit dem trigger Befehl zu erzeugen und zu schauen ob die Anweisung ausgeführt wird. Dabei ist zu beachten: Der erste ":" im Suchmuster ist zusätzlich zwischen Gerät und Event als Trennung. Jeder weiter : ist, wenn vorhanden, Bestandteil des Events! Siehe dazu den Abschnitt Hinweise in der commandref
- Im Beispiel: Event: n_test muster -> Suchmuster n_test:muster
Um aus dem Event ein passendes Suchmuster zu erzeugen kann der Event-Monitor direkt verwendet werden. Man kann ein neues notify erzeugen oder ein Bestehendes modifizieren lassen.
Unser Regex im Beispiel ist zu spezifisch, es triggert nur exakt auf muster. Dieser Trigger erzeugt den folgenden Eintrag im Eventmonitor, entspricht exakt dem Suchmuster und löst das notify aus:
trigger n_test muster 2018-07-13 11:52:08 notify n_test muster
Das Suchmuster für unsere Anforderung muss in n_test:muster.*
geändert werden, damit jeder Event der mit muster beginnt das notify auslöst.
Der . im Regex steht für jedes beliebige Zeichen und der * für eine beliebige Anzahl des Zeichens davor: also beliebig viele beliebige Zeichen nach muster.
Das Suchmuster wird häufig in ein komplizierteres Regex umgewandelt um im notify mehrere Aktionen zu starten. Das eigene Regex kann z.B. mit http://regexpal.com/ oder https://regex101.com/ getestet werden.
Funktioniert der Auslöser, das notify tut aber noch nicht was es soll, müssen wir die Anweisung untersuchen. In unserem korrigierten Beispiel
defmod n_test notify n_test:muster.* Ausführungsteil
folgt beim Kommando trigger n_test muster bild
ein Eintrag im Log:
2018.07.13 11:47:57 3: n_test return value: Unknown command Ausführungsteil, try help.
Das notify wurde zwar getriggert aber die Anweisung war nicht ausführbar.
Ein richtiges Suchmuster und eine fehlerhafte Anweisung wird also normalerweise einen Fehlereintrag im Logfile erzeugen!
Spezialfall: notify löst zwar aus - aber zu oft
In dem Fall ist das Suchmuster (regExp) zu unscharf oder das triggernde Gerät löst das Event zu oft aus. Das regExp sollte so genau wie möglich konstruiert werden, device:.* ist eine einfache aber oft keine gute Wahl!
Im Device, welches den Event auslöst, kann mit den Attributen event-on-.* die Häufigkeit gesteuert werden. Insbesondere ist hier das regExp .* eine Art Standardwahl um aufeinanderfolgende gleichartige Events zu verhindern.
attr device event-on-change-reading .*
Achtung: durch falsche Angaben kann man Events ganz leicht völlig verhindern!
Siehe auch event-on-change-reading
Anweisung
Wird das notify getriggert oder will man ganz schnell mal ein notify testen, kann man die Anweisung durch folgenden Code ersetzen, man öffnet also einfach nur die DEF, kopiert den ursprünglichen Inhalt an einen sicheren Ort und ersetzt die Anweisung durch eine der beiden Zeilen. Die erste Zeile kann man auch einfach mal in der Kommandozeile testen:
{Log 1, "Das Notify n_test hat ausgeloest."}
{Log 1, "Das Device $NAME hat ausgeloest, der Event sah so aus: $EVENT"}
Wird das notify ausgelöst, muss anschließend im Logfile ein Eintrag zu finden sein:
2018.07.13 10:28:57 1: Das Notify n_test hat ausgeloest, der Event sah so aus: muster
Unsere Anweisung Ausführungsteil
liefert in der Kommandozeile selbst einen Fehler:
Unknown command Ausführungsteil, try help.
Ein Versuch mit geschweiften Klammern {Ausführungsteil}
liefert wieder einen Fehler:
Unrecognized character \xC3; marked by <-- HERE after {Ausf<-- HERE near column 6 at (eval 5977) line 1.
Diese Variante {"Ausführungsteil"}
liefert den String Ausführungsteil ohne Fehler: Das notify arbeitet fehler- aber sinnfrei.
Der fertige Code:
defmod n_test notify n_test:muster.* {"Ausführungsteil"}
Man kann die Anweisung, normalerweise so wie sie ist, in der FHEM Kommandozeile testen. Sind im Perl Code (in geschweiften Klammern) im DEF Editor Semikolon enthalten muss man diese für den Test in der Kommandozeile (oder Raw Def) verdoppeln. Laufzeitabhängige Variablen sind in der Kommandozeile meist nicht verfügbar, diese sollte man für den Test einfach durch passende Inhalte austauschen. So kann man die komfortable Variante (loggt den Namen und das komplette Event) nicht in der Kommandozeile ausführen.
Funktioniert ein FHEM Befehl in der Kommandozeile nicht (z.B. Lampe geht nicht an) kann es im notify auch nicht funktionieren, dann muss die Fehlersuche an anderer Stelle fortgeführt werden.
Komplexeren Code im Ausführungsteil sollte man beim Testen in Teilabschnitte aufteilen, von der Laufzeit abhängige Variable ($NAME, $EVENT, $EVTPART) durch Strings ("TestWort") ersetzen, die Teilabschnitte separat testen und anschließend schrittweise wieder komplettieren.
Beispiele
Schalter entprellen
Will man ein notify innerhalb eines bestimmten Zeitraumes nur einmal auslösen lassen, auch wenn er in diesem Zeitraum mehrfach getriggered werden sollte, so bietet sich das Attribut disabledAfterTrigger an,
attr <notify_device> disabledAfterTrigger <Anzahl Sekunden>
In dem Zeitraum wird dann nur einmal (beim ersten Mal) der Befehl ausgelöst, auch wenn mehrfach getriggered wurde. Der Zeitraum kann Bruchteile von Sekunden umfassen.
Etwas schalten, wenn ein anderes Gerät geschaltet wird
Vorbedingungen
Dieses Beispiel verwendet eine einfache InterTechno-kompatible Funksteckdose für das Radio und einen HM-Aktor für das Licht:
define RadioKueche IT 000000FFFF 0F F0 define LichtKueche CUL_HM 3A37D6
Beachte: beide kennen als Event bzw. Schaltbefehle on und off.
notify Befehl
define LichtamRadioan notify LichtKueche set RadioKueche $EVENT
oder alternativ:
define LichtamRadioan notify LichtKueche { fhem "set RadioKueche $EVENT" }
Erklärung
- Der Name des notify "LichtamRadioan" kann frei gewählt werden, er dient nur dazu, das notify in FHEM eindeutig zu identifizieren.
- "$EVENT" ist ein Platzhalter für den Zustand vom Pattern. $EVENT enthält ein "off" wenn das LichtKueche aus- und ein "on" wenn das Licht eingeschaltet wird.
- "{ <perlcode> }" alles was zwischen {} steht ist Perl code. Perl kennt das Schlüsselwort fhem. Das Schlüsselwort FHEM dient dazu, FHEM Befehle auszuführen. Es wird also der FHEM Befehl "set RadioKueche on/off" ausgeführt. on oder off ist abhängig vom Pattern. Der eigentliche FHEM Befehl muss in " " stehen.
- Wann ist ein Wechsel auf die Perl-Ebene erforderlich?
- einfache FHEM-Befehle sollten in der Regel direkt verwendet werden, dies ist ressourcenschonender.
- Immer dann, wenn dies nicht möglich ist, weil z.B. komplexerer Code ausgeführt werden soll, (blockierende) Prozesse ausgelagert werden sollten oder Systembefehle ausgeführt werden, ist es günstiger, auf die Perl-Ebene zu wechseln [5].
Einschalten von mehreren Geräten/Lampen, wenn das Licht eingeschaltet wird
Dieses Beispiel verwendet einen HM-Aktor für das Licht sowie zwei Milight-Birnen, die einzeln geschaltet werden sollen[6] in den Stehlampen:
Vorbedingungen
FHEM:
define LichtWZ CUL_HM 3A37D8 define Stehlampe1 MilightDevice RGBW Milight_Wohnzimmer 5 define Stehlampe2 MilightDevice RGBW Milight_Wohnzimmer 6
notify Befehl
define SteckdoseWZein notify LichtWZ set Stehlampe1,Stehlampe2 $EVENT
oder in Perl
define SteckdoseWZein notify LichtWZ { fhem "set Stehlampe1 $EVENT;;set Stehlampe2 $EVENT " }
Erklärung
Wenn das LichtWZ eingeschaltet wird, dann werden auch die Stehlampen (1 und 2) eingeschaltet.
Einfache ODER Funktion
Eine einfache ODER Funktion kann sehr einfach realisiert werden
Vorbereitung
KNX:
- 3x GAs der abzufragende Werte (0/0/40 0/0/41 0/0/42)
FHEM:
define Licht1 CUL_HM 3A37D8 define Licht2 CUL_HM 1B7EC3 define Stehlampe MilightDevice RGBW Milight_Wohnzimmer 7
notify Befehl
define SteckdoseWZein notify (Licht1|Licht2) set Stehlampe $EVENT
oder
define SteckdoseWZein notify (Licht.) set Stehlampe $EVENT
Erklärung
Die Werte in der Klammer (wichtig ist das »|«) sind die Rückgabewerte. Alternativ kann in diesem Beispiel auch »Licht.« (zu beachten ist der Punkt) geschrieben werden. Der Punkt ist ein Platzhalter für (genau) ein beliebiges Zeichen.
Danach folgt der set Befehl. Wenn also das Licht1 oder Licht2 den Wert "on" hat, dann hat auch die Steckdose den Wert "on"
Alternative: structure
Einfache UND Funktion
Ob man dieses Konstrukt noch als einfach bezeichnen kann, wage ich mal zu bezweifeln. In FHEM fehlen Loggingfunktionen, die man alle selber mit Perl Code erstellen kann (Danke an MAZ). Dadurch ist FHEM zwar mächtig, wird aber für viele sehr kompliziert.
In diesem Beispiel soll - wenn drei Rollos geschlossen sind - am Taster eine LED eingeschaltet werden.
Vorbereitung
KNX:
- 3x GDs für die Rückgabewert Rollo geschlossen == 1 (0/0/50 0/0/51 0/0/52)
- GD LED am Lichtschalter (0/0/106)
FHEM:
define R1ZU KNX 0/0/50:dpt1.009 attr R1ZU dummy 1 define R2ZU KNX 0/0/51:dpt1.009 attr R2ZU dummy 1 define R3ZU KNX 0/0/52:dpt1.009 attr R3ZU dummy 1 define LEDalleRolloZu KNX 0/0/106:dpt1
Durch das Attribut dummy werden keine Schaltfunktion angeboten. Es kann nur Werte anzeigen.
notify Befehl
define nt.allerolloszu notify (R1ZU|R2ZU|R3ZU) {\ my $r1 = Value("R1ZU");;\ my $r2 = Value("R2ZU");;\ my $r3 = Value("R3ZU");;\ if ($r1 eq "on" && $r2 eq "on" && $r3 eq "on") {\ fhem("set LEDalleRolloZu on");;\ } else {\ fhem("set LEDalleRolloZu off");;\ }\ }
Erklärung
Es werden die drei Rückgabewerte R1ZU, R2ZU und R3ZU ausgewertet. Danach folgt Perl Code, deswegen beginnt das ganze mit einer { und endet mit }
my $r1 => Variable $r1 definieren = Value("R1ZU");; ==> weist den Rückgabewert (on oder off) von R1ZU der Variable $r1 zu
Der doppelte ;; ist ein FHEM Thema. Eigentlich würde für Perl ein ; reichen. Aber FHEM nutzt selbst das ; und daher wird ein ;; benötigt. Mit den ersten drei my Zeilen werden die Rückgabewerte den Variablen zugewiesen.
Danach erfolgt ein normales "if then else" Konstrukt. Die Zeile »($r1 eq "on" && $r2 eq "on" && $r3 eq "on")« kann man so lesen: Wenn $r1 den Wert "on" und (&&) $r2 den Wert "on" und $r3 den Wert "on" dann schalte die LEDalleRolloZu ein {fhem("set LEDalleRolloZu on")} ansonsten else schalte die LED aus. {fhem("set LEDalleRolloZu off")
Alternative: structure
Zeitverzögert schalten
Aufgabe: | Zeitverzögert schalten |
Beschreibung: | Mit einem Notify zeitverzögert eine Aktion auslösen. |
Vorbereitung: | Gerät "Lampe" ist definiert und es gibt eine Situation, die ein Ereignis "Fernbedienung:.*" generiert. |
Befehl: | define ntfy1 notify Fernbedienung:.* sleep 7.5;; set Lampe $EVENT
|
Erläuterungen: | Bei Eintreten eines Ereignisses "Fernbedienung*" wird nach einer Pause von siebeneinhalb Sekunden der Befehl <set Lampe ??> ausgeführt, wobei der eigentliche Befehl aus dem auslösenden Ereignis übernommen wird.
|
Eine PV-Anlage (Solarstrom) zur Steuerung der Rollos nutzen (optional Zeit und Datums abhängig)
Hier ein kleines Beispiel, wie man mit Hilfe einer PV-Anlage die Sonneneinstrahlung auf der Südseite ermittelt und dies zur Rolladensteuerung nutzt. Optional: Die Funktion soll allerdings nur zwischen 9:30 und 17:00 stattfinden. (zweites Beispiel) Optional: Die Funktion soll nur zwischen dem 6. und 9. Monat funktioneren. (drittes Beispiel)
Vorbereitung
PV Anlage mit SolarView abfragen. Per Hand ermitteln, ab wieviel erzeugtem Strom es sinnvoll ist die Rollos zu schließen.
notify Syntax
FHEM:
define sv SolarView solarview 15000 wr1 wr2 wr3 wr4 <----vier Wechselrichter attr sv event-on-change-reading currentPower
define nt.sonnenlichtpersolar notify sv:currentPower.* { \ if ($EVTPART1 < 3000 ) {\ fhem('set Flur1 Auf')\ }else {\ if ($EVTPART1 > 5000 ) {\ fhem('set Flur1 Ab')\ } \ }\ }
Optional 1: Zeitabhängig (Code gehört in die DEF)
sv:currentPower.* {
my $hm = sprintf("%02d:%02d", $hour, $min);
if ( $hm gt "09:30" && $hm lt "17:00") {
if ($EVTPART1 < 5000 ) {
fhem('set Flur1 Auf')
}else {
if ($EVTPART1 > 8000 ) {
fhem('set Flur1 Ab')
}
}
}
}
Optional 2: Zeit und Datum (Code gehört in die DEF)
sv:currentPower.* {
my $hm = sprintf("%02d:%02d", $hour, $min);
if ($month >= 6 && $month <= 9) {
if ( $hm gt "09:30" && $hm lt "17:00") {
if ($EVTPART1 < 5000 ) {
fhem('set Flur1,RBUERO1,RBUERO2 Auf');
}else {
if ($EVTPART1 > 8000 ) {
fhem('set Flur1,Flur2,RBUERO1,RBUERO2 Ab');
}
}
}
}
}
Erklärung
- Das define wird in der Kommandozeile im Webbrowser eingegeben.
- Anschließend wird im Webbrowser die DEF bearbeitet, das erspart uns Probleme mit Perl
- define sv SolarView ... <==== ist die Schnittstelle vom SolarView
- define nt.sonnenlichtpersolar notify (sv:currentPower.*) { <==== hier wird ein notify angelegt, der auf das "define sv" Wert "currentPower.*" (.* ist irgendwas) reagiert
if ($EVTPART1 < 3000 ) { fhem('set Flur1 Auf'); }else { if ($EVTPART1 > 5000 ) { fhem('set Flur1 Ab'); } } }
Diese if-Funktion wertet den Rückgabewert von currentPower aus. Hierbei muss man wissen, dass $EVTPART1 das Split-Ergebnis vom Rückgabewert ist
Beispiel: Der Rückgabewert (wie im Beispiel) ist "currentPower: 6000". Jetzt steht im "$EVTPART0 == currentPower:" und im "$EVTPART1 == 6000" Das bedeutet, dass man sich nicht selbst den richtigen split (Perl Befehl) Aufruf ausdenken muss, dies übernimmt vielmehr FHEM.
Ergebnis: Das Rollo wird abhängig von der erzeugten IST_Strommenge auf und zu gefahren. Damit dies nicht dauernd hin und her pendelt, wurde der Auf Wert sehr klein und den Ab Wert sehr groß gewählt.
Optional 1: Der Block "my $hm = sprintf("%02d:%02d", $hour, $min);" erzeugt die String-Variable $hm mit dem Inhalt $hour:$min. %02d begrenzt die Ausgabe auf zwei Stellen. Danach wird mit "if ( $hm gt "09:30" && $hm lt "17:00")" mit stringvergleichenden Operatoren geprüft, ob die Uhrzeit zwischen 9:30 und 17:00 liegt (lt = kleiner als; gt = größer als). Es wäre auch ein le und ge möglich: le = kleiner/gleich als, ge = größer/gleich als.
Optional 2:if( $month >= 6 && $month <= 9) {
Hier wird die numerische FHEM-Standard-Variable $month (Monat) auf größer/gleich bzw kleiner/gleich mit den binären Operatoren überprüft. Die Funktion arbeitet also nur zwischen dem 6. und dem 9. Monat und dann auch nur zwischen 9:31 und 16:59.
Status eines Kippfensters mit 2 Fensterkontakten abbilden
Vorbereitung
Es ist je ein Fensterkontakt der open oder closed meldet, oben und unten am Fenster angebracht. Die Namen der beiden FHEM-Devices sind fensterKontaktOben und fensterKontaktUnten.
notify Syntax
FHEM:
define statusFenster notify fensterKontakt(Oben|Unten):(open|closed) {\ if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open')\ { fhem 'set Terrassentuer open' }\ if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed')\ { fhem 'set Terrassentuer closed' }\ if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'open' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'closed')\ { fhem 'set Terrassentuer tilted' }\ if ( ReadingsVal('fensterKontaktOben', 'state', 'undef') eq 'closed' && ReadingsVal('fensterKontaktUnten', 'state', 'undef') eq 'open')\ { fhem 'set Terrassentuer undef' }\ }
Weitere Hinweise
- Entsprechend zu $EVENT gibt es auch noch $NAME und $TYPE. $NAME und $TYPE enthalten den Namen bzw. Typ des Ereignis auslösenden Gerätes.
- Wird der Perl-Code in einem
notify
immer länger, lagere den Code wegen der Übersichtlichkeit in eine eigene Programmdatei aus, wie in 99_myUtils anlegen beschrieben. - Achtung! Wenn man das Skript für den notify-Befehl über mehrere Zeilen schreibt, muss man anscheinend darauf achten, dass keine abschließende Leerzeile mitgespeichert wird. Sonst wird der notify-Befehl ignoriert.
- Dieser Beitrag enthält Vorschläge zur Vorgehensweise bei der Erstellung von komplexen notify Definitionen bzw. bei deren Fehlerbehebung.
Weiterführende Links
- Escapen in Perlbefehlen
- Klammerebenen
- Forenbeitrag zum Thema Optimierung des Suchmusters - NOTIFYDEV
Hinweise
- ↑ hierzu gehören u.a. auch DOIF, THRESHOLD und watchdog
- ↑ vgl. hierzu z.B. FILTER und if-condition
- ↑ Der Eventhandler DOIF verwendet die in Perl übliche Syntax für reguläre Ausdrücke als DOIF-Suchmuster.
- ↑ https://perldoc.perl.org/perlre.html
- ↑ In diesem Forenbeitrag wird z.B. erläutert, wie man nichtblockierend externe Scripte aufrufen kann, die dann ihre Ergebnisse wieder an FHEM übergeben.
- ↑ Dies ist ausdrücklich keine Empfehlung für diese Technologie und der Module