99 myUtils anlegen: Unterschied zwischen den Versionen
Krikan (Diskussion | Beiträge) (FHEM(R)) |
Drhirn (Diskussion | Beiträge) K (veraltete "source"-Angaben in "syntaxhighlight" geändert) |
||
(27 dazwischenliegende Versionen von 6 Benutzern werden nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
Die Speicherung von Perl-Code unmittelbar in [[Eventhandler|Eventhandlern]], [[Timehandler|Timehandlern]] oder anderen Geräten in der [[Konfiguration]], in denen Perl-Ausdrücke angegeben werden können, wird mit wachsender Zahl von Geräten und Logiken eventuell unübersichtlich. Um z.B. Doppelungen zu vermeiden und Logikbausteine zentral vorzuhalten, kann man eine oder mehrere eigene Programmdateien erzeugen, in der diese als kleine Programme gesammelt und dann aus entsprechenden Geräten aufgerufen werden können. | |||
== Eine neue Programmdatei erzeugen == | == Eine neue Programmdatei erzeugen == | ||
FHEM enthält | FHEM enthält eine Vorlage ''myUtilsTemplate.pm'', die zur Erzeugung von Programmdateien genutzt werden sollte; nachfolgend soll beispielhaft eine Datei namens ''99_myUtils.pm'' verwendet werden. | ||
Vorgehensweise: | Vorgehensweise: | ||
* FHEM-Menüpunkt {{Taste|Edit files}} anklicken | * FHEM-Menüpunkt {{Taste|Edit files}} anklicken | ||
* Weblink 'myUtilsTemplate.pm' anklicken | * Weblink ''myUtilsTemplate.pm'' anklicken | ||
* Im Textfeld hinter 'Save as' den Dateinamen '99_myUtils.pm' für die Programmdatei eintragen | * Im Textfeld hinter ''Save as'' den Dateinamen ''99_myUtils.pm'' für die Programmdatei eintragen | ||
: Hinweis: Wenn ein anderer Dateiname angegeben wird, muss der Name Initialize-Routine entsprechend angepasst werden (siehe nachfolgende Erläuterung zur Grundstruktur unter Nr. 3) | : Hinweis: Wenn ein anderer Dateiname angegeben wird, muss der Name Initialize-Routine entsprechend angepasst werden (siehe nachfolgende Erläuterung zur Grundstruktur unter Nr. 3) | ||
* {{Taste|Save as}} anklicken | * {{Taste|Save as}} anklicken | ||
Nun ist die eigene Programmdatei '99_myUtils.pm' mit der notwendigen Grundstruktur unter dem Menüpunkt 'Edit files' zur Bearbeitung mit dem [[ | Nun ist die eigene Programmdatei ''99_myUtils.pm'' mit der notwendigen Grundstruktur unter dem Menüpunkt ''Edit files'' zur Bearbeitung mit dem [[codemirror|Integrierter Editor]] zu finden. Für eine einfache und fehlerminimierende Bearbeitung sollten die [[Konfiguration#Syntaxhervorhebung|Syntaxhervorhebungs-, Befehlsauswahl- und Befehlsvervollständigungsfunktionen]] im Integrierten Editor eingeschaltet sein. | ||
{{Randnotiz|RNTyp=g|RNText=Nutzt man {{Link2CmdRef|Lang=en|Anker=configDB|Label=configDB}}, können (bzw. sollten) die eigenen Programmdateien in die Datenbank importiert werden, statt unmittelbar im Dateisystem gespeichert zu bleiben. Sie können dann weiter über {{Taste|Edit files}} bearbeitet werden, stehen dann aber z.B. bei einem Umzug oder Neuaufsetzen des Systems direkt wieder zur Verfügung.}} | |||
Die Programmdateien können zwar auch mit einem [[Konfiguration#Externer Editor|externen Editor]] bearbeitet werden, diese Vorgehensweise wird jedoch nicht empfohlen, da dies insbesondere Einsteigern das debugging erschwert. | |||
Eine ‚leere‘ Programmdatei muss grundsätzlich folgenden Grundstruktur besitzen: | Eine ‚leere‘ Programmdatei muss grundsätzlich folgenden Grundstruktur besitzen: | ||
< | <syntaxhighlight lang="perl"> | ||
package main; | package main; | ||
use strict; | use strict; | ||
use warnings; | use warnings; | ||
sub | sub | ||
myUtils_Initialize($$) | myUtils_Initialize($$) | ||
Zeile 25: | Zeile 26: | ||
} | } | ||
1; | 1; | ||
</ | </syntaxhighlight> | ||
Folgende Dinge sind für | Folgende Dinge sind für eigene Programmdateien besonders zu beachten: | ||
# Der Dateiname muss mit 99_ beginnen. FHEM lädt beim Start alle Programmdateien mit dem prefix 99_. Andere Programmdateien werden erst dann geladen, wenn sie durch eine define-Anweisung in der [[Konfiguration]] angefordert werden. So wird z.B. 10_FS20.pm erst geladen, wenn beim Einlesen der Konfiguration das erste define für ein FS20-device abgearbeitet wird. Da Ihre eigene Programmsammlung wahrscheinlich kein neues Gerät mit einem zugehörigen define-Befehl implementiert, würde sie also nie geladen, wenn ihr Name nicht mit 99_ beginnt. | # Der Dateiname muss mit 99_ beginnen. FHEM lädt beim Start alle Programmdateien mit dem prefix 99_. Andere Programmdateien werden erst dann geladen, wenn sie durch eine define-Anweisung in der [[Konfiguration]] angefordert werden. So wird z.B. 10_FS20.pm erst geladen, wenn beim Einlesen der Konfiguration das erste define für ein FS20-device abgearbeitet wird. Da Ihre eigene Programmsammlung wahrscheinlich kein neues Gerät mit einem zugehörigen define-Befehl implementiert, würde sie also nie geladen, wenn ihr Name nicht mit 99_ beginnt. | ||
# Damit die neue Datei bei 'Edit files' angezeigt wird, muss sie mit | # Damit die neue Datei bei ''Edit files'' angezeigt wird, muss sie mit ''.pm'' enden und den Bestandteil ''Utils'' enthalten. Also zum Beispiel ''99_meineUtils.pm'' oder ''99_myUtils_Homematic.pm''. | ||
# Der Name der Programmdatei muss mit dem Namen der Initialize-Routine übereinstimmen. Wenn Sie Ihr Programm also 99_Werkzeugkasten.pm nennen, muss die im code dargestellte initialize-Routine sub Werkzeugkasten_Initialize heißen. | # Der Name der Programmdatei muss mit dem Namen der Initialize-Routine übereinstimmen. Wenn Sie Ihr Programm also 99_Werkzeugkasten.pm nennen, muss die im code dargestellte initialize-Routine sub Werkzeugkasten_Initialize heißen. | ||
# Die Zeile <code> 1; </code> muss immer die letzte Programmzeile sein. Wenn Sie also eigene Routinen in Ihre Programmsammlung einfügen, tragen Sie diese zwischen dem Ende der Initialize-Routine und der abschließenden Zeile <code> 1; </code> ein. | # Die Zeile <code> 1; </code> muss immer die letzte Programmzeile sein. Wenn Sie also eigene Routinen in Ihre Programmsammlung einfügen, tragen Sie diese zwischen dem Ende der Initialize-Routine und der abschließenden Zeile <code> 1; </code> ein. | ||
Zeile 38: | Zeile 39: | ||
Das gesamte Programm sieht dann folgendermaßen aus: | Das gesamte Programm sieht dann folgendermaßen aus: | ||
< | <syntaxhighlight lang="perl"> | ||
package main; | package main; | ||
use strict; | use strict; | ||
use warnings; | use warnings; | ||
sub | sub | ||
myUtils_Initialize($$) | myUtils_Initialize($$) | ||
Zeile 66: | Zeile 67: | ||
} | } | ||
} | } | ||
1;</ | 1;</syntaxhighlight> | ||
Der Aufruf erfolgt dann z.B. so: | Der Aufruf erfolgt dann z.B. so: | ||
<pre>#fhem.cfg | <pre>#fhem.cfg | ||
define lampe_untoggle notify lampe {Untoggle( | define lampe_untoggle notify lampe {Untoggle("$NAME")}</pre> | ||
Der Aufruf aus einem notify (oder at) erfolgt als Perl-code, muss also in geschweiften Klammern stehen. Der Aufruf erfolgt durch Angabe des Namens der Routine (Untoggle) unter Angabe der zu übergebenden Parameter (hier "$NAME"). | Der Aufruf aus einem notify (oder at) erfolgt als Perl-code, muss also in geschweiften Klammern stehen. Der Aufruf erfolgt durch Angabe des Namens der Routine (Untoggle) unter Angabe der zu übergebenden Parameter (hier "$NAME"). | ||
Im Programm wurde die Routine Untoggle mit '''einem''' Parameter definiert ( Untoggle($) , die Anzahl der $-Zeichen bestimmt die Anzahl der zu übergebenden Parameter). Der Wert des übergebenen Parameters wird in der ersten Programmzeile in die Variable $obj übernommen (my ($obj) = @_; ). | Im Programm wurde die Routine Untoggle mit '''einem''' Parameter definiert ( Untoggle($) , die Anzahl der $-Zeichen bestimmt die Anzahl der zu übergebenden Parameter). Der Wert des übergebenen Parameters wird in der ersten Programmzeile in die Variable $obj übernommen (my ($obj) = @_; ). | ||
Zeile 78: | Zeile 79: | ||
In der Definition der Routine geben Sie außerdem an, wieviele Parameter übergeben werden sollen, für 2 Parameter z.B. so: | In der Definition der Routine geben Sie außerdem an, wieviele Parameter übergeben werden sollen, für 2 Parameter z.B. so: | ||
< | <syntaxhighlight lang="perl">define test at *09:00 { wakeup($we, "Schlafzimmerlampe") }</syntaxhighlight> | ||
Die Deklaration der Routine in Ihrer Programmdatei muss dann so beginnen: | Die Deklaration der Routine in Ihrer Programmdatei muss dann so beginnen: | ||
< | <syntaxhighlight lang="perl">#Nur am Wochenende eingeschaltet | ||
sub wakeup($$) { | sub wakeup($$) { | ||
my ($wochenende, $device) = @_; | my ($wochenende, $device) = @_; | ||
Zeile 90: | Zeile 91: | ||
fhem( "set $device off" ); | fhem( "set $device off" ); | ||
} | } | ||
}</ | }</syntaxhighlight> | ||
Durch die Anzahl der $-Zeichen in der Routinen-Deklaration wird also die Anzahl der Parameter festgelegt. In der ersten Programmzeile Ihrer Routine übernehmen Sie dann die übergebenen Parameterwerte in lokale Variablen. Wie beim Routinen-Aufruf muss auch hierbei die Anzahl der Parameter mit der Routinen-Deklaration (also Anzahl der $-Zeichen) übereinstimmen. | Durch die Anzahl der $-Zeichen in der Routinen-Deklaration wird also die Anzahl der Parameter festgelegt. In der ersten Programmzeile Ihrer Routine übernehmen Sie dann die übergebenen Parameterwerte in lokale Variablen. Wie beim Routinen-Aufruf muss auch hierbei die Anzahl der Parameter mit der Routinen-Deklaration (also Anzahl der $-Zeichen) übereinstimmen<ref>Mehr zu diesen sog. prototypes ist z.B. [https://perldoc.perl.org/perlsub.html#Prototypes hier] nachzulesen; auch [[fhem.pl]] beginnt mit einer Liste der prototyes der darin enthaltenen Funktionen. Da diese Funktionen auch innerhalb der myUtils verwendet werden können, empfiehlt es sich, zunächst dort nachzusehen, ob eventuell bereits hilfreiche Funktionen für das zu lösende Problem vorhanden sind.</ref>. | ||
=== Routinen ohne Parameter === | === Routinen ohne Parameter === | ||
Auch Routinen ohne Parameter sind natürlich möglich. Definition und Aufruf sehen dann folgendermassen aus: | Auch Routinen ohne Parameter sind natürlich möglich. Definition und Aufruf sehen dann folgendermassen aus: | ||
< | <syntaxhighlight lang="perl">sub parameterlos() { | ||
... | ... | ||
}</ | }</syntaxhighlight> | ||
{ parameterlos() } | { parameterlos() } | ||
Zeile 110: | Zeile 111: | ||
Bei der nicht empfohlenen Bearbeitung der Programmdatei mit einem '''externen Editor''' muss FHEM manuell angewiesen werden, die Programmdatei mit den Änderungen zu laden. Also bearbeiten Sie Ihr Programm, speichern die Programmdatei, und weisen FHEM dann explizit an, die Programmdatei erneut zu laden. Der Befehl dazu, der in das Befehls-Eingabefeld eingegeben wird, lautet: <code>reload 99_myUtils.pm</code> | Bei der nicht empfohlenen Bearbeitung der Programmdatei mit einem '''externen Editor''' muss FHEM manuell angewiesen werden, die Programmdatei mit den Änderungen zu laden. Also bearbeiten Sie Ihr Programm, speichern die Programmdatei, und weisen FHEM dann explizit an, die Programmdatei erneut zu laden. Der Befehl dazu, der in das Befehls-Eingabefeld eingegeben wird, lautet: <code>reload 99_myUtils.pm</code> | ||
Treten beim Laden (Syntax)fehler auf, werden diese am Bildschirm wie auch im Log angezeigt. Da der Ladevorgang fehlgeschlagen ist, stehen Ihre eigenen Routinen nun nicht zur Verfügung (bzw. in der zuletzt erfolgreich geladenen Version). | Treten beim Laden (Syntax)fehler auf, werden diese am Bildschirm wie auch im Log angezeigt. Da der Ladevorgang fehlgeschlagen ist, stehen Ihre eigenen Routinen nun nicht zur Verfügung (bzw. in der zuletzt erfolgreich geladenen Version). Es empfiehlt sich daher bei der Entwicklung neuer Code-Teile v.a. für "Einsteiger", diese zunächst in einer separaten myUtils-Datei zu entwickeln und erst dann in die für den "produktiven Betrieb" genutzten myUtils-Dateien zu übernehmen, wenn sie als funktional getestet anzusehen sind. | ||
== Eigene Programmdatei dokumentieren == | == Eigene Programmdatei dokumentieren == | ||
In der lokalen Commandref kann man die eigenen Routinen auch dokumentieren. | In der lokalen Commandref kann man die eigenen Routinen auch dokumentieren. | ||
Dazu muss am Ende der 99_myUtils folgender Codeblock eingefügt werden | Dazu muss am Ende der 99_myUtils folgender Codeblock eingefügt werden | ||
< | <syntaxhighlight lang="perl"> | ||
=pod | =pod | ||
=begin html | =begin html | ||
<a | <a id="myUtils"></a> | ||
<h3>myUtils</h3> | <h3>myUtils</h3> | ||
<ul> | <ul> | ||
Zeile 133: | Zeile 134: | ||
=begin html_DE | =begin html_DE | ||
<a | <a id="myUtils"></a> | ||
<h3>myUtils</h3> | <h3>myUtils</h3> | ||
=end html_DE | =end html_DE | ||
=cut | =cut | ||
</ | </syntaxhighlight> | ||
Der a Tag stellt einen Verweis dar, der h3 Tag kennzeichnet die Überschrift. Beide Tags müssen sein, ansonsten kann FHEM die Doku nicht in die commandref einbinden. Der Abschnitt für die deutsche Doku kann komplett fehlen. Die Beschreibungen der einzelnen Routinen werden mit ul Tags geklammert und eventuell mit ul Tags weiter untergliedert. Dabei entsteht ein eingerückter Text. Beispiele können mit dem code Tag formatiert werden. | Der a Tag stellt einen Verweis dar, der h3 Tag kennzeichnet die Überschrift. Beide Tags müssen sein, ansonsten kann FHEM die Doku nicht in die commandref einbinden. Der Abschnitt für die deutsche Doku kann komplett fehlen. Die Beschreibungen der einzelnen Routinen werden mit ul Tags geklammert und eventuell mit ul Tags weiter untergliedert. Dabei entsteht ein eingerückter Text. Beispiele können mit dem code Tag formatiert werden. | ||
Mit diesem Befehl kann die Erzeugung des Commandrefeintrages initiiert und getestet werden: | Mit diesem Befehl kann die Erzeugung des Commandrefeintrages initiiert und getestet werden: | ||
< | <syntaxhighlight lang="perl">{system("/usr/bin/perl ./contrib/commandref_join.pl")}</syntaxhighlight> | ||
Für eine schnelle Überprüfung des Commandrefeintrages können Sie auch <syntaxhighlight lang="perl">help myUtils</syntaxhighlight> (bzw. statt myUtils den Namen Ihrer Utils-Datei) eingeben. | |||
Weiterführende Hinweise sind in den [[Guidelines zur Dokumentation]] zu finden. | |||
== Weitere Informationen == | |||
=== Globale Ablage von Daten === | |||
Um Daten zentral zwischenzuspeichern, kann man | |||
* die Funktionen ''[[DevelopmentModuleAPI#setKeyValue|setKeyValue()]]'' bzw. ''getKeyValue()'' nutzen, um die Daten im Dateisystem abzulegen; | |||
* in den globalen Hash ''%data schreiben'', wie in diesem {{Link2Forum|Topic=63737|LinkText=Forumsbeitrag}} erläutert. | |||
=== Vertiefende Informationen === | |||
Weiterführende Hinweise, z.B. wie aus einer Sammlung kleiner Tools ggf. ein eigenes Modul entstehen kann, sind der [[DevelopmentModuleIntro]] zu entnehmen. Dort sind v.a. auch einige häufig benötigte Funktionen aus fhem.pl dokumentiert. | |||
== Links == | == Links == | ||
* Eine Zusammenstellung wichtiger Funktionen ist in den Perl specials der {{Link2CmdRef|Anker=perl|Label=commandref}} enthalten. | |||
* Eine weitere Sammlung hilfreicher "Helferlein" samt Hilfe enthält [https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/99_Utils.pm 99_Utils.pm]. | |||
* Hilfsfunktionen für Farboperationen: [[Color]]. | |||
* [[Zeitangaben, rechnen mit|Wiki-Beitrag zum Rechnen mit Zeitangaben]] | |||
* [[Gleitende Mittelwerte berechnen und loggen]] | |||
* Beispiele für Geräteüberwachungen: [[EBUS#Mithilfe von FHEM|EBUS]], [[Netzwerkgeräte:_Verfügbarkeit_prüfen#Erweiterung 99 myUtils|Netzwerkgeräte]], {{Link2Forum|Topic=51267|Message=935071|LinkText=Nextion-Display bei Inaktivität zurücksetzen}}, {{Link2Forum|Topic=97173|Message=917347|LinkText=devStateIcon für das Modul ''monitoring''}} | |||
* [[Batterieüberwachung#Alternativ per Skript|Batterieüberwachung]] | |||
* Routine zum [[E-Mail_senden#Raspberry Pi|E-Mail senden]] aus FHEM heraus | |||
* [[E-Mail per notify nach Zeitablauf erneut senden|Beispiel]], wie ggf. an mehreren Stellen relevante Variablen zentral zur Verfügung gestellt werden können. | |||
* [[Plot-Abriss_vermeiden#Implementierung|Plot-Abrisse vermeiden]] | |||
* Formatierungsanweisungen auslagern: [[ReadingsGroup#Enigma_Receiver|ReadingsGroup]], [[Spritpreismonitor#Farbliche_Hervorhebung|Spritpreismonitor]], [[EBUS-MQTT2#myUtils-Code|Balkenanzeige]] (hier: für EBUS) | |||
* Befehle an ein Netzwerkgerät senden: [[Listenlive#Der Code|Listenlive]] | |||
* [[HM-Dis-WM55_Funk_Statusanzeige#99_myUtils|Homematic-Display]] mit Informationen versorgen | |||
* {{Link2Forum|Topic=34363|Message=266811|LinkText=Zeit- und Datumsvariablen $hour, $wday, $month, ... in 99_myUtils.pm verfügbar machen}} | * {{Link2Forum|Topic=34363|Message=266811|LinkText=Zeit- und Datumsvariablen $hour, $wday, $month, ... in 99_myUtils.pm verfügbar machen}} | ||
* {{Link2Forum|Topic=36504|Message=287778|LinkText=Globale und flexible Fenster- und Türüberwachung}} | |||
* {{Link2Forum|Topic=87895|Message=803439|LinkText=57_CALENDAR.pm - events mit deviceNames nutzen}} | |||
* {{Link2Forum|Topic=96959|Message=901268|LinkText=Konstanten für das Rechnen mit Zeiten}} | |||
* {{Link2Forum|Topic=97430|Message=906576|LinkText=devStateIcon-Code für Homematic-Thermostate}} | |||
* {{Link2Forum|Topic=86073|Message=836537|LinkText=php-Script aufrufen und Rückgabewert in einen dummy schreiben}} (hier: Viessmann Heizung)) | |||
* {{Link2Forum|Topic=84831|Message=771485|LinkText=Windchill und Hitzeindex berechnen}} | |||
* {{Link2Forum|Topic=84016|Message=762888|LinkText=Countdown Timer}} | |||
<references /> | |||
[[Kategorie:Code Snippets]] | [[Kategorie:Code Snippets]] | ||
[[Kategorie:HOWTOS]] | [[Kategorie:HOWTOS]] | ||
[[Kategorie:Perl]] |
Aktuelle Version vom 9. November 2023, 11:45 Uhr
Die Speicherung von Perl-Code unmittelbar in Eventhandlern, Timehandlern oder anderen Geräten in der Konfiguration, in denen Perl-Ausdrücke angegeben werden können, wird mit wachsender Zahl von Geräten und Logiken eventuell unübersichtlich. Um z.B. Doppelungen zu vermeiden und Logikbausteine zentral vorzuhalten, kann man eine oder mehrere eigene Programmdateien erzeugen, in der diese als kleine Programme gesammelt und dann aus entsprechenden Geräten aufgerufen werden können.
Eine neue Programmdatei erzeugen
FHEM enthält eine Vorlage myUtilsTemplate.pm, die zur Erzeugung von Programmdateien genutzt werden sollte; nachfolgend soll beispielhaft eine Datei namens 99_myUtils.pm verwendet werden. Vorgehensweise:
- FHEM-Menüpunkt Edit files anklicken
- Weblink myUtilsTemplate.pm anklicken
- Im Textfeld hinter Save as den Dateinamen 99_myUtils.pm für die Programmdatei eintragen
- Hinweis: Wenn ein anderer Dateiname angegeben wird, muss der Name Initialize-Routine entsprechend angepasst werden (siehe nachfolgende Erläuterung zur Grundstruktur unter Nr. 3)
- Save as anklicken
Nun ist die eigene Programmdatei 99_myUtils.pm mit der notwendigen Grundstruktur unter dem Menüpunkt Edit files zur Bearbeitung mit dem Integrierter Editor zu finden. Für eine einfache und fehlerminimierende Bearbeitung sollten die Syntaxhervorhebungs-, Befehlsauswahl- und Befehlsvervollständigungsfunktionen im Integrierten Editor eingeschaltet sein.
Die Programmdateien können zwar auch mit einem externen Editor bearbeitet werden, diese Vorgehensweise wird jedoch nicht empfohlen, da dies insbesondere Einsteigern das debugging erschwert.
Eine ‚leere‘ Programmdatei muss grundsätzlich folgenden Grundstruktur besitzen:
package main;
use strict;
use warnings;
sub
myUtils_Initialize($$)
{
my ($hash) = @_;
}
1;
Folgende Dinge sind für eigene Programmdateien besonders zu beachten:
- Der Dateiname muss mit 99_ beginnen. FHEM lädt beim Start alle Programmdateien mit dem prefix 99_. Andere Programmdateien werden erst dann geladen, wenn sie durch eine define-Anweisung in der Konfiguration angefordert werden. So wird z.B. 10_FS20.pm erst geladen, wenn beim Einlesen der Konfiguration das erste define für ein FS20-device abgearbeitet wird. Da Ihre eigene Programmsammlung wahrscheinlich kein neues Gerät mit einem zugehörigen define-Befehl implementiert, würde sie also nie geladen, wenn ihr Name nicht mit 99_ beginnt.
- Damit die neue Datei bei Edit files angezeigt wird, muss sie mit .pm enden und den Bestandteil Utils enthalten. Also zum Beispiel 99_meineUtils.pm oder 99_myUtils_Homematic.pm.
- Der Name der Programmdatei muss mit dem Namen der Initialize-Routine übereinstimmen. Wenn Sie Ihr Programm also 99_Werkzeugkasten.pm nennen, muss die im code dargestellte initialize-Routine sub Werkzeugkasten_Initialize heißen.
- Die Zeile
1;
muss immer die letzte Programmzeile sein. Wenn Sie also eigene Routinen in Ihre Programmsammlung einfügen, tragen Sie diese zwischen dem Ende der Initialize-Routine und der abschließenden Zeile1;
ein.
Eigene Routinen einfügen
Als Beispiel dient das Umsetzen von FS20 toggle-Events aus dem Artikel "FS20 Toggle Events auf On/Off umsetzen". Das gesamte Programm sieht dann folgendermaßen aus:
package main;
use strict;
use warnings;
sub
myUtils_Initialize($$)
{
my ($hash) = @_;
}
##########################################################
# Untoggle
# toggle-Vorgänge in den Status on/off umsetzen
sub Untoggle($) {
my ($obj) = @_;
if( Value($obj) eq "toggle" ){
if( OldValue($obj) eq "off" ) {
fhem( "setstate $obj on" );
}
else {
fhem( "setstate $obj off" );
}
}
else {
fhem( "setstate $obj ".Value($obj) );
}
}
1;
Der Aufruf erfolgt dann z.B. so:
#fhem.cfg define lampe_untoggle notify lampe {Untoggle("$NAME")}
Der Aufruf aus einem notify (oder at) erfolgt als Perl-code, muss also in geschweiften Klammern stehen. Der Aufruf erfolgt durch Angabe des Namens der Routine (Untoggle) unter Angabe der zu übergebenden Parameter (hier "$NAME"). Im Programm wurde die Routine Untoggle mit einem Parameter definiert ( Untoggle($) , die Anzahl der $-Zeichen bestimmt die Anzahl der zu übergebenden Parameter). Der Wert des übergebenen Parameters wird in der ersten Programmzeile in die Variable $obj übernommen (my ($obj) = @_; ). Der Aufruf erfolgt mit Untoggle(„$NAME“) . Der Platzhalter $NAME in fhem steht für den Namen des Geräts. Im o.g. Beispiel erfolgt der Aufruf also eigentlich mit Untoggle(„lampe“). Natürlich können beim Aufruf auch feste Werte ( „lampe1“ ) oder Variablen ( $hour ) übergeben werden.
Routinen mit mehreren Parametern
In der Definition der Routine geben Sie außerdem an, wieviele Parameter übergeben werden sollen, für 2 Parameter z.B. so:
define test at *09:00 { wakeup($we, "Schlafzimmerlampe") }
Die Deklaration der Routine in Ihrer Programmdatei muss dann so beginnen:
#Nur am Wochenende eingeschaltet
sub wakeup($$) {
my ($wochenende, $device) = @_;
if ($wochenende) {
fhem( "set $device on" );
}
else {
fhem( "set $device off" );
}
}
Durch die Anzahl der $-Zeichen in der Routinen-Deklaration wird also die Anzahl der Parameter festgelegt. In der ersten Programmzeile Ihrer Routine übernehmen Sie dann die übergebenen Parameterwerte in lokale Variablen. Wie beim Routinen-Aufruf muss auch hierbei die Anzahl der Parameter mit der Routinen-Deklaration (also Anzahl der $-Zeichen) übereinstimmen[1].
Routinen ohne Parameter
Auch Routinen ohne Parameter sind natürlich möglich. Definition und Aufruf sehen dann folgendermassen aus:
sub parameterlos() {
...
}
{ parameterlos() }
Eigene Programmdatei laden
Die Programmdatei wird beim FHEM-Start immer automatisch geladen.
Bei Änderungen an der Programmdatei bei laufendem FHEM ist bezüglich Neuladen ohne FHEM-Neustart zwischen den verschiedenen Bearbeitungsvarianten der Progammdatei zu unterscheiden.
Bei der Bearbeitung über den Integrierten Editor wird die Programmdatei beim Abspeichern automatisch mit den Änderungen neu geladen.
Bei der nicht empfohlenen Bearbeitung der Programmdatei mit einem externen Editor muss FHEM manuell angewiesen werden, die Programmdatei mit den Änderungen zu laden. Also bearbeiten Sie Ihr Programm, speichern die Programmdatei, und weisen FHEM dann explizit an, die Programmdatei erneut zu laden. Der Befehl dazu, der in das Befehls-Eingabefeld eingegeben wird, lautet: reload 99_myUtils.pm
Treten beim Laden (Syntax)fehler auf, werden diese am Bildschirm wie auch im Log angezeigt. Da der Ladevorgang fehlgeschlagen ist, stehen Ihre eigenen Routinen nun nicht zur Verfügung (bzw. in der zuletzt erfolgreich geladenen Version). Es empfiehlt sich daher bei der Entwicklung neuer Code-Teile v.a. für "Einsteiger", diese zunächst in einer separaten myUtils-Datei zu entwickeln und erst dann in die für den "produktiven Betrieb" genutzten myUtils-Dateien zu übernehmen, wenn sie als funktional getestet anzusehen sind.
Eigene Programmdatei dokumentieren
In der lokalen Commandref kann man die eigenen Routinen auch dokumentieren. Dazu muss am Ende der 99_myUtils folgender Codeblock eingefügt werden
=pod
=begin html
<a id="myUtils"></a>
<h3>myUtils</h3>
<ul>
<b>Name</b>
<br>
Text<br>
Examples:
<ul>
<code>Example Code </code><br>
</ul>
</ul>
=end html
=begin html_DE
<a id="myUtils"></a>
<h3>myUtils</h3>
=end html_DE
=cut
Der a Tag stellt einen Verweis dar, der h3 Tag kennzeichnet die Überschrift. Beide Tags müssen sein, ansonsten kann FHEM die Doku nicht in die commandref einbinden. Der Abschnitt für die deutsche Doku kann komplett fehlen. Die Beschreibungen der einzelnen Routinen werden mit ul Tags geklammert und eventuell mit ul Tags weiter untergliedert. Dabei entsteht ein eingerückter Text. Beispiele können mit dem code Tag formatiert werden.
Mit diesem Befehl kann die Erzeugung des Commandrefeintrages initiiert und getestet werden:
{system("/usr/bin/perl ./contrib/commandref_join.pl")}
Für eine schnelle Überprüfung des Commandrefeintrages können Sie auch
help myUtils
(bzw. statt myUtils den Namen Ihrer Utils-Datei) eingeben.
Weiterführende Hinweise sind in den Guidelines zur Dokumentation zu finden.
Weitere Informationen
Globale Ablage von Daten
Um Daten zentral zwischenzuspeichern, kann man
- die Funktionen setKeyValue() bzw. getKeyValue() nutzen, um die Daten im Dateisystem abzulegen;
- in den globalen Hash %data schreiben, wie in diesem Forumsbeitrag erläutert.
Vertiefende Informationen
Weiterführende Hinweise, z.B. wie aus einer Sammlung kleiner Tools ggf. ein eigenes Modul entstehen kann, sind der DevelopmentModuleIntro zu entnehmen. Dort sind v.a. auch einige häufig benötigte Funktionen aus fhem.pl dokumentiert.
Links
- Eine Zusammenstellung wichtiger Funktionen ist in den Perl specials der commandref enthalten.
- Eine weitere Sammlung hilfreicher "Helferlein" samt Hilfe enthält 99_Utils.pm.
- Hilfsfunktionen für Farboperationen: Color.
- Wiki-Beitrag zum Rechnen mit Zeitangaben
- Gleitende Mittelwerte berechnen und loggen
- Beispiele für Geräteüberwachungen: EBUS, Netzwerkgeräte, Nextion-Display bei Inaktivität zurücksetzen, devStateIcon für das Modul monitoring
- Batterieüberwachung
- Routine zum E-Mail senden aus FHEM heraus
- Beispiel, wie ggf. an mehreren Stellen relevante Variablen zentral zur Verfügung gestellt werden können.
- Plot-Abrisse vermeiden
- Formatierungsanweisungen auslagern: ReadingsGroup, Spritpreismonitor, Balkenanzeige (hier: für EBUS)
- Befehle an ein Netzwerkgerät senden: Listenlive
- Homematic-Display mit Informationen versorgen
- Zeit- und Datumsvariablen $hour, $wday, $month, ... in 99_myUtils.pm verfügbar machen
- Globale und flexible Fenster- und Türüberwachung
- 57_CALENDAR.pm - events mit deviceNames nutzen
- Konstanten für das Rechnen mit Zeiten
- devStateIcon-Code für Homematic-Thermostate
- php-Script aufrufen und Rückgabewert in einen dummy schreiben (hier: Viessmann Heizung))
- Windchill und Hitzeindex berechnen
- Countdown Timer
- ↑ Mehr zu diesen sog. prototypes ist z.B. hier nachzulesen; auch fhem.pl beginnt mit einer Liste der prototyes der darin enthaltenen Funktionen. Da diese Funktionen auch innerhalb der myUtils verwendet werden können, empfiehlt es sich, zunächst dort nachzusehen, ob eventuell bereits hilfreiche Funktionen für das zu lösende Problem vorhanden sind.