ECMD: Unterschied zwischen den Versionen
GRZBRZ (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
K (<syntaxhighlight> - Verwendung an diversen Stellen korrigiert) |
||
(Eine dazwischenliegende Version von einem anderen Benutzer wird nicht angezeigt) | |||
Zeile 1: | Zeile 1: | ||
ECMD bedeutet "Ethersex Command"<ref>[http://www.ethersex.de/index.php/Main_Page_%28Deutsch%29 Ethersex.de]</ref> und ist laut FHEM-Dokumentation | ECMD bedeutet "Ethersex Command"<ref>[http://www.ethersex.de/index.php/Main_Page_%28Deutsch%29 Ethersex.de]</ref> und ist laut FHEM-Dokumentation | ||
:''Any physical device with request/response-like communication capabilities over a TCP connection''<ref>{{Link2CmdRef|Anker=ECMD|Label=FHEM Commandref}}</ref>, | |||
das heisst, irgendein physisches Gerät, welches request/response-artige Kommunikationsfähigkeiten aufweist, sei es über eine TCP-Verbindung (Netzwerk) oder eine serielle Schnittstelle. | |||
In FHEM sind enthalten: | In FHEM sind enthalten: | ||
Zeile 13: | Zeile 15: | ||
Siehe [[Radioaktivitätsmessung mit DIYGeigerCounter]] | Siehe [[Radioaktivitätsmessung mit DIYGeigerCounter]] | ||
=== DIY Sensor via HC-12 === | === Beispiel DIY Sensor via HC-12 === | ||
Ein BME280 Temperatur/Druck/Feuchte-Sensor liefert via eines HC-12 Pärchens seine Daten an der seriellen Schnittstelle eines RasPi ab. Der Sketch im Nano, an dem sowohl der BME280 als auch einer der HC-12 hängen, liefert alle 10 Minuten ein Datagramm ab und schickt seinen Wirt in den Tiefschlaf bis zum nächsten Datagramm, um mit den notwendigen Batterien über ein Jahr aushalten zu können. | Ein BME280 Temperatur/Druck/Feuchte-Sensor liefert via eines HC-12 Pärchens seine Daten an der seriellen Schnittstelle eines RasPi ab. Der Sketch im Nano, an dem sowohl der BME280 als auch einer der HC-12 hängen, liefert alle 10 Minuten ein Datagramm ab und schickt seinen Wirt in den Tiefschlaf bis zum nächsten Datagramm, um mit den notwendigen Batterien über ein Jahr aushalten zu können. | ||
Zeile 20: | Zeile 22: | ||
====== Klassendefinition ====== | ====== Klassendefinition ====== | ||
Daraus werden die notwendigen Definitionen für eine Klassendefinition abgeleitet. Die z.B. unter '/opt/fhem/BME280.classdef' abgelegte Datei erhält den Inhalt<syntaxhighlight | Daraus werden die notwendigen Definitionen für eine Klassendefinition abgeleitet. Die z.B. unter '/opt/fhem/BME280.classdef' abgelegte Datei erhält den Inhalt | ||
<syntaxhighlight lang="text"> | |||
params devId | params devId | ||
reading temperature match "%devId | reading temperature match "%devId[^\n]+\n" | ||
reading temperature postproc { /%devId | reading temperature postproc { /%devId[^T]+T([-+.,0-9]+).*/; $1 } | ||
reading airpressure match "%devId | reading airpressure match "%devId[^\n]+\n" | ||
reading airpressure postproc { /%devId | reading airpressure postproc { /%devId[^P]+P([-+.,0-9]+).*/; $1 } | ||
reading humidity match "%devId | reading humidity match "%devId[^\n]+\n" | ||
reading humidity postproc { /%devId | reading humidity postproc { /%devId[^H]+H([-+.,0-9]+).*/; $1 } | ||
state humidity | state humidity | ||
</syntaxhighlight>Die regex ist in allen Zeilen | </syntaxhighlight> | ||
Die regex für match ist in allen Zeilen gleich gestaltet. Alle Werte werden durch diese Vorgehensweise gleichzeitig und erst dann gelesen, wenn das gesamte Datagramm eingetroffen ist. Es ließe sich auch auf Teil-Strings abfragen, Konflikte bei mehreren Sensoren sind dann denkbar. | |||
Die letzte Zeile sorgt dafür, dass der state nur dann einen neuen Wert erhält, wenn (in diesem Fall) 'humidity' ein Update erfährt. Bei den gewählten regex trift das hier eigentlich für alle zu, aber da humidity der letzte übertragene Wert ist, ist die Wahl auf ihn gefallen. Außerdem steht nun nur ein Wert im state ohne einleitenden reading Namen, der wäre hier im Beispiel erwartungsgemäß 'humidity', was hier insofern irritiert, weil ja 3 Werte gelesen wurden und man sich unwillkürlich fragt, wo den die anderen geblieben sind. Zum state daher später unter Notify noch weiteres. | Die letzte Zeile sorgt dafür, dass der state nur dann einen neuen Wert erhält, wenn (in diesem Fall) 'humidity' ein Update erfährt. Bei den gewählten regex trift das hier eigentlich für alle zu, aber da humidity der letzte übertragene Wert ist, ist die Wahl auf ihn gefallen. Außerdem steht nun nur ein Wert im state ohne einleitenden reading Namen, der wäre hier im Beispiel erwartungsgemäß 'humidity', was hier insofern irritiert, weil ja 3 Werte gelesen wurden und man sich unwillkürlich fragt, wo den die anderen geblieben sind. Zum state daher später unter Notify noch weiteres. | ||
====== Schnittstelle ====== | ====== Schnittstelle ====== | ||
Sollte bereits eine ECMD Schnittstelle bestehen, kann nun die Definition hinzugefügt werden. Z.B. die ECMD Schnittstelle namens 'SerDevDef' erhält eine zusätzliche Klasse 'BME280' mit den Definitionen aus der vorher generierten Datei, Beispiel siehe oben.<syntaxhighlight> | Sollte bereits eine ECMD Schnittstelle bestehen, kann nun die Definition hinzugefügt werden. Z.B. die ECMD Schnittstelle namens 'SerDevDef' erhält eine zusätzliche Klasse 'BME280' mit den Definitionen aus der vorher generierten Datei, Beispiel siehe oben. | ||
<syntaxhighlight lang="text"> | |||
set SerDevDef classdef BME280 /opt/fhem/BME280.classdef | set SerDevDef classdef BME280 /opt/fhem/BME280.classdef | ||
</syntaxhighlight> | |||
</syntaxhighlight>Ist noch keine ECMD Schnittstelle definiert, wird diese erstellt und gleich mit passenden Attributen versehen.<syntaxhighlight> | Ist noch keine ECMD Schnittstelle definiert, wird diese erstellt und gleich mit passenden Attributen versehen. | ||
<syntaxhighlight lang="text"> | |||
define SerDevDef ECMD serial /dev/ttyS0@9600 | define SerDevDef ECMD serial /dev/ttyS0@9600 | ||
set SerDevDef classdef BME280 /opt/fhem/BME280.classdef | set SerDevDef classdef BME280 /opt/fhem/BME280.classdef | ||
attr SerDevDef partial 2 | attr SerDevDef partial 2 | ||
</syntaxhighlight> | |||
Die letzte Zeile ist für die serielle Schnittstelle gerade bei längeren Datagrammen ein Muss. Sie sorgt dafür, dass die kleineren Informationsbröckchen zu einer vollständigen Einheit werden. Kommt das nächste Päckchen innerhalb von (hier) 2 Sekunden, wird das neue Päckchen an die bereits gelesenen Daten angehängt, ansonsten startet eine neue Aufzeichnung beginnend mit dem Päckchen. | |||
Für den Start kann noch zur Erleichterung der Fehlersuche folgendes ergänzt werden | |||
<syntaxhighlight lang="text"> | |||
Für den Start kann noch zur Erleichterung der Fehlersuche folgendes ergänzt werden<syntaxhighlight> | |||
attr SerDevDef logTraffic 5 | attr SerDevDef logTraffic 5 | ||
attr SerDevDef verbose 5 | attr SerDevDef verbose 5 | ||
</syntaxhighlight>Rückstelllen dieser Attribute nicht vergessen, so ist's reichlich gesprächig und füllt schnell das Log !!! | </syntaxhighlight> | ||
Rückstelllen dieser Attribute nicht vergessen, so ist's reichlich gesprächig und füllt schnell das Log !!! | |||
====== Device ====== | ====== Device ====== | ||
Damit ist alles vorbereitet den ECMD Device zu erstellen.<syntaxhighlight> | Damit ist alles vorbereitet den ECMD Device zu erstellen. | ||
<syntaxhighlight lang="text"> | |||
define BME280_42356 ECMDDevice BME280 42356 | define BME280_42356 ECMDDevice BME280 42356 | ||
attr BME280_42356 alias Gartenhaus | attr BME280_42356 alias Gartenhaus | ||
Zeile 56: | Zeile 65: | ||
attr BME280_42356 IODev SerDevDef | attr BME280_42356 IODev SerDevDef | ||
attr BME280_42356 userReadings airpressure_sealevel:humidity:.* { sprintf("%.2f", ReadingsVal("BME280_42356","pressure",0)*1.023);; } | attr BME280_42356 userReadings airpressure_sealevel:humidity:.* { sprintf("%.2f", ReadingsVal("BME280_42356","pressure",0)*1.023);; } | ||
</syntaxhighlight>Der fragliche Sensor beginnt seine Datagramme immer mit '42356', das ist seine DevId, die über den Parameter 'devId' in der Klassendefinition (siehe oben) Eingang in die readings findet. Über 'BME280' wird die Klassendefinition festgelegt, über '42356' die devId. Sinnigerweise wird im Beispiel hier 'BME280_42356' als Devicename festgelegt, Systematik ist Trumpf. | </syntaxhighlight> | ||
Der fragliche Sensor beginnt seine Datagramme immer mit '42356', das ist seine DevId, die über den Parameter 'devId' in der Klassendefinition (siehe oben) Eingang in die readings findet. Über 'BME280' wird die Klassendefinition festgelegt, über '42356' die devId. Sinnigerweise wird im Beispiel hier 'BME280_42356' als Devicename festgelegt, Systematik ist Trumpf. | |||
Die letzte Zeile macht aus dem vom Sensor gemessenen Luftdruck noch den auf NormalNull Bezogenen. Nicht jeder wohnt direkt am Meer und kann auf diesen Schritt verzichten. Ansonsten weichen die Werte des Sensors immer von der Wettervorhersage ab, je höher der Sensor, um so markanter. Das Beispiel hier gilt für ca. 180m üNN. Die Erzeugung des Wertes für "airpressure_sealevel" ist übrigens an den Event "humidity geknüpft, sonst hat man im Event-Log in diesem Fall 3 Einträge, nämlich den beim Temperatur-, beim Druck- und beim Feuchte-Event (siehe auch beim folgenden Notify und dem linken Teil des Beispiel-Plots weiter unten). | Die letzte Zeile macht aus dem vom Sensor gemessenen Luftdruck noch den auf NormalNull Bezogenen. Nicht jeder wohnt direkt am Meer und kann auf diesen Schritt verzichten. Ansonsten weichen die Werte des Sensors immer von der Wettervorhersage ab, je höher der Sensor, um so markanter. Das Beispiel hier gilt für ca. 180m üNN. Die Erzeugung des Wertes für "airpressure_sealevel" ist übrigens an den Event "humidity geknüpft, sonst hat man im Event-Log in diesem Fall 3 Einträge, nämlich den beim Temperatur-, beim Druck- und beim Feuchte-Event (siehe auch beim folgenden Notify und dem linken Teil des Beispiel-Plots weiter unten). | ||
====== Notify ====== | ====== Notify ====== | ||
Da der state nach einer Übermittlung aufgrund der Festlegungen aus der Klassendefinition nun nur den Wert der Luftfeuchte enthält, ist es hilfreich ein 'notify' für eine gefälligere Darstellung zu definieren.<syntaxhighlight> | Da der state nach einer Übermittlung aufgrund der Festlegungen aus der Klassendefinition nun nur den Wert der Luftfeuchte enthält, ist es hilfreich ein 'notify' für eine gefälligere Darstellung zu definieren. | ||
<syntaxhighlight lang="text"> | |||
define ECMDDevState notify BME280_42356:humidity:.* { Log 1, "$NAME has new values";;sleep 1;;fhem "setstate BME280_42356"." T:".ReadingsVal("BME280_42356","temperature",0)." P:".ReadingsVal("BME280_42356","airpressure_sealevel",0)." H:".ReadingsVal("BME280_42356","humidity",0) } | define ECMDDevState notify BME280_42356:humidity:.* { Log 1, "$NAME has new values";;sleep 1;;fhem "setstate BME280_42356"." T:".ReadingsVal("BME280_42356","temperature",0)." P:".ReadingsVal("BME280_42356","airpressure_sealevel",0)." H:".ReadingsVal("BME280_42356","humidity",0) } | ||
</syntaxhighlight>Für die Übersicht zerlegt:<syntaxhighlight lang="perl" line | </syntaxhighlight> | ||
Für die Übersicht zerlegt: | |||
<syntaxhighlight lang="perl" line start=1> | |||
define ECMDDevState notify BME280_42356:humidity:.* | define ECMDDevState notify BME280_42356:humidity:.* | ||
{ | { | ||
Zeile 73: | Zeile 86: | ||
" H:".ReadingsVal("BME280_42356","humidity",0) | " H:".ReadingsVal("BME280_42356","humidity",0) | ||
} | } | ||
</syntaxhighlight> | |||
① 'ECMDDevState' wird immer dann benachrichtigt und ausgeführt, wenn der Device 'BME280_42356' ein reading 'humidity' mit einem beliebigen (.*) Wert hat. ③ Dies wird zunächst im Log vermerkt und ④ als nächstes ein wenig gewartet, damit eine Änderung des state auf jeden Fall nach dem Befüllen des state durch das humidity reading stattfindet und auch der Luftdruck fertig berechnet ist. Dann wird ⑤ der state mit einer Verkettung der gerade gelesenen bzw. berechneten Daten aller Werte ⑥,⑦,⑧ versorgt. | |||
====== Log HISTORY ====== | |||
Die Werte sammeln sich nun im Log. Dort haben die Werte ebenfalls eine Einheit, in diesem Fall "°C" für reading-Namen, die mit "temperature" beginnen und "%" für reading-Namen, die mit "humidity" beginnen. Andere Einheiten oder andere reading-Namen lassen sich entweder über ein Attribut in der Log-Definition | |||
<syntaxhighlight lang="perl"> | |||
attr myDbLog valueFn { | |||
if ($DEVICE eq "BME280_42356"){ | |||
if ($READING=~ m(^airpressure)){ | |||
$UNIT = "hPa"; | |||
} | |||
if ($READING=~ m(^pressure)){ | |||
$UNIT = "Pa"; | |||
} | |||
} | |||
} | |||
</syntaxhighlight> | |||
oder direkt im Device ergänzen bzw. beeinflussen. | |||
<syntaxhighlight lang="perl"> | |||
attr BME280_42356 DbLogValueFn { | |||
if ($READING=~ m(^airpressure)){ | |||
$UNIT = "hPa"; | |||
} | |||
if ($READING=~ m(^pressure)){ | |||
$UNIT = "Pa"; | |||
} | |||
} | |||
</syntaxhighlight> | |||
Damit lassen sich freilich auch ungewöhnliche Einheiten festlegen, Blutdruck wird z.B. in "mmHg" gemessen. | |||
====== Weiterführend ====== | ====== Weiterführend ====== | ||
Abschließend soll noch ein Plot der Messwerte gemacht werden, eine Kurve liest sich leichter. Als Erstes wird eine Datei z.B. '/opt/fhem/www/gplot/SVG_BME280_42356.gplot' mit folgendem Inhalt erstellt, der anzuzeigenden Linien und Beschriftungen des Plots beschreibt.<syntaxhighlight> | Abschließend soll noch ein Plot der Messwerte gemacht werden, eine Kurve liest sich leichter. Als Erstes wird eine Datei z.B. '/opt/fhem/www/gplot/SVG_BME280_42356.gplot' mit folgendem Inhalt erstellt, der anzuzeigenden Linien und Beschriftungen des Plots beschreibt. | ||
<syntaxhighlight lang="bash"> | |||
set terminal png transparent size <SIZE> crop | set terminal png transparent size <SIZE> crop | ||
set output '<OUT>.png' | set output '<OUT>.png' | ||
Zeile 92: | Zeile 133: | ||
"<IN>" using 1:2 axes x1y2 title 'Luftdruck' ls l1 lw 1 with lines,\ | "<IN>" using 1:2 axes x1y2 title 'Luftdruck' ls l1 lw 1 with lines,\ | ||
"<IN>" using 1:2 axes x1y1 title 'Feuchte' ls l2 lw 1 with lines | "<IN>" using 1:2 axes x1y1 title 'Feuchte' ls l2 lw 1 with lines | ||
</syntaxhighlight>Dabei wird der Luftdruck auf einen plausiblen Bereich eingegrenzt, Drücke außerhalb dieses Bereichs hat es noch nicht gegeben auf diesem Erdball. Der Wert der Feuchte wird dem zu erwartenden Temperaturbereich (-10 bis 40) angeglichen, das ergibt eine schönere Kurve (:$val=$val | </syntaxhighlight> | ||
Dabei wird der Luftdruck auf einen plausiblen Bereich eingegrenzt, Drücke außerhalb dieses Bereichs hat es noch nicht gegeben auf diesem Erdball (:$val=$val>1100?1100:$val<800?800:$val). Der Wert der Feuchte wird dem zu erwartenden Temperaturbereich (-10 bis 40) angeglichen, das ergibt eine schönere Kurve (:$val=$val/2-10). Eine Y-Achse für die Feuchte wäre ja die dritte Y-Achse, die haben wir also nicht. Also landet 100% Feuchte bei 40°C und 0% Feuchte bei -10°C. | |||
Dann wird der Plot definiert. In diesem Fall mit den Daten aus DbLog, für FileLog muss geringfügig angepaßt werden. Dann fehlten freilich auch die FileLog -Definitionen für 'BME280_42356'.<syntaxhighlight> | Dann wird der Plot definiert. In diesem Fall mit den Daten aus DbLog, für FileLog muss geringfügig angepaßt werden. Dann fehlten freilich auch die FileLog -Definitionen für 'BME280_42356'. | ||
<syntaxhighlight lang="text"> | |||
defmod SVG_BME280_42356 SVG myDbLog:SVG_BME280_42356:HISTORY | defmod SVG_BME280_42356 SVG myDbLog:SVG_BME280_42356:HISTORY | ||
</syntaxhighlight>Der Term 'SVG_BME280_42356' liest dabei die Definitionen aus der vorher angelegten Datei 'SVG_BME280_42356.gplot'. | </syntaxhighlight> | ||
Der Term 'SVG_BME280_42356' liest dabei die Definitionen aus der vorher angelegten Datei 'SVG_BME280_42356.gplot'. | |||
[[Datei:GHplotECMD.png|rahmenlos|1197x1197px]] | [[Datei:GHplotECMD.png|rahmenlos|1197x1197px]] |
Aktuelle Version vom 16. März 2021, 12:43 Uhr
ECMD bedeutet "Ethersex Command"[1] und ist laut FHEM-Dokumentation
- Any physical device with request/response-like communication capabilities over a TCP connection[2],
das heisst, irgendein physisches Gerät, welches request/response-artige Kommunikationsfähigkeiten aufweist, sei es über eine TCP-Verbindung (Netzwerk) oder eine serielle Schnittstelle.
In FHEM sind enthalten:
- Modul ECMD für die Bearbeitung physischer I/O-Schnittstellengeräte und
- Modul ECMDDevice für einzelne logische Geräte, deren Kommunikation über ein ECMD-Gerät läuft
Beispiele & Links
Links
Siehe Thread im FHEM-Forum
Siehe Radioaktivitätsmessung mit DIYGeigerCounter
Beispiel DIY Sensor via HC-12
Ein BME280 Temperatur/Druck/Feuchte-Sensor liefert via eines HC-12 Pärchens seine Daten an der seriellen Schnittstelle eines RasPi ab. Der Sketch im Nano, an dem sowohl der BME280 als auch einer der HC-12 hängen, liefert alle 10 Minuten ein Datagramm ab und schickt seinen Wirt in den Tiefschlaf bis zum nächsten Datagramm, um mit den notwendigen Batterien über ein Jahr aushalten zu können.
Das Datagramm hat die Form
DevId T-3.45°C P995.31hPa H63.27%RH\r\n
Klassendefinition
Daraus werden die notwendigen Definitionen für eine Klassendefinition abgeleitet. Die z.B. unter '/opt/fhem/BME280.classdef' abgelegte Datei erhält den Inhalt
params devId
reading temperature match "%devId[^\n]+\n"
reading temperature postproc { /%devId[^T]+T([-+.,0-9]+).*/; $1 }
reading airpressure match "%devId[^\n]+\n"
reading airpressure postproc { /%devId[^P]+P([-+.,0-9]+).*/; $1 }
reading humidity match "%devId[^\n]+\n"
reading humidity postproc { /%devId[^H]+H([-+.,0-9]+).*/; $1 }
state humidity
Die regex für match ist in allen Zeilen gleich gestaltet. Alle Werte werden durch diese Vorgehensweise gleichzeitig und erst dann gelesen, wenn das gesamte Datagramm eingetroffen ist. Es ließe sich auch auf Teil-Strings abfragen, Konflikte bei mehreren Sensoren sind dann denkbar.
Die letzte Zeile sorgt dafür, dass der state nur dann einen neuen Wert erhält, wenn (in diesem Fall) 'humidity' ein Update erfährt. Bei den gewählten regex trift das hier eigentlich für alle zu, aber da humidity der letzte übertragene Wert ist, ist die Wahl auf ihn gefallen. Außerdem steht nun nur ein Wert im state ohne einleitenden reading Namen, der wäre hier im Beispiel erwartungsgemäß 'humidity', was hier insofern irritiert, weil ja 3 Werte gelesen wurden und man sich unwillkürlich fragt, wo den die anderen geblieben sind. Zum state daher später unter Notify noch weiteres.
Schnittstelle
Sollte bereits eine ECMD Schnittstelle bestehen, kann nun die Definition hinzugefügt werden. Z.B. die ECMD Schnittstelle namens 'SerDevDef' erhält eine zusätzliche Klasse 'BME280' mit den Definitionen aus der vorher generierten Datei, Beispiel siehe oben.
set SerDevDef classdef BME280 /opt/fhem/BME280.classdef
Ist noch keine ECMD Schnittstelle definiert, wird diese erstellt und gleich mit passenden Attributen versehen.
define SerDevDef ECMD serial /dev/ttyS0@9600
set SerDevDef classdef BME280 /opt/fhem/BME280.classdef
attr SerDevDef partial 2
Die letzte Zeile ist für die serielle Schnittstelle gerade bei längeren Datagrammen ein Muss. Sie sorgt dafür, dass die kleineren Informationsbröckchen zu einer vollständigen Einheit werden. Kommt das nächste Päckchen innerhalb von (hier) 2 Sekunden, wird das neue Päckchen an die bereits gelesenen Daten angehängt, ansonsten startet eine neue Aufzeichnung beginnend mit dem Päckchen.
Für den Start kann noch zur Erleichterung der Fehlersuche folgendes ergänzt werden
attr SerDevDef logTraffic 5
attr SerDevDef verbose 5
Rückstelllen dieser Attribute nicht vergessen, so ist's reichlich gesprächig und füllt schnell das Log !!!
Device
Damit ist alles vorbereitet den ECMD Device zu erstellen.
define BME280_42356 ECMDDevice BME280 42356
attr BME280_42356 alias Gartenhaus
attr BME280_42356 room Grundstück
attr BME280_42356 IODev SerDevDef
attr BME280_42356 userReadings airpressure_sealevel:humidity:.* { sprintf("%.2f", ReadingsVal("BME280_42356","pressure",0)*1.023);; }
Der fragliche Sensor beginnt seine Datagramme immer mit '42356', das ist seine DevId, die über den Parameter 'devId' in der Klassendefinition (siehe oben) Eingang in die readings findet. Über 'BME280' wird die Klassendefinition festgelegt, über '42356' die devId. Sinnigerweise wird im Beispiel hier 'BME280_42356' als Devicename festgelegt, Systematik ist Trumpf.
Die letzte Zeile macht aus dem vom Sensor gemessenen Luftdruck noch den auf NormalNull Bezogenen. Nicht jeder wohnt direkt am Meer und kann auf diesen Schritt verzichten. Ansonsten weichen die Werte des Sensors immer von der Wettervorhersage ab, je höher der Sensor, um so markanter. Das Beispiel hier gilt für ca. 180m üNN. Die Erzeugung des Wertes für "airpressure_sealevel" ist übrigens an den Event "humidity geknüpft, sonst hat man im Event-Log in diesem Fall 3 Einträge, nämlich den beim Temperatur-, beim Druck- und beim Feuchte-Event (siehe auch beim folgenden Notify und dem linken Teil des Beispiel-Plots weiter unten).
Notify
Da der state nach einer Übermittlung aufgrund der Festlegungen aus der Klassendefinition nun nur den Wert der Luftfeuchte enthält, ist es hilfreich ein 'notify' für eine gefälligere Darstellung zu definieren.
define ECMDDevState notify BME280_42356:humidity:.* { Log 1, "$NAME has new values";;sleep 1;;fhem "setstate BME280_42356"." T:".ReadingsVal("BME280_42356","temperature",0)." P:".ReadingsVal("BME280_42356","airpressure_sealevel",0)." H:".ReadingsVal("BME280_42356","humidity",0) }
Für die Übersicht zerlegt:
define ECMDDevState notify BME280_42356:humidity:.*
{
Log 1, "$NAME has new values";;
sleep 1;;
fhem "setstate BME280_42356".
" T:".ReadingsVal("BME280_42356","temperature",0).
" P:".ReadingsVal("BME280_42356","airpressure_sealevel",0).
" H:".ReadingsVal("BME280_42356","humidity",0)
}
① 'ECMDDevState' wird immer dann benachrichtigt und ausgeführt, wenn der Device 'BME280_42356' ein reading 'humidity' mit einem beliebigen (.*) Wert hat. ③ Dies wird zunächst im Log vermerkt und ④ als nächstes ein wenig gewartet, damit eine Änderung des state auf jeden Fall nach dem Befüllen des state durch das humidity reading stattfindet und auch der Luftdruck fertig berechnet ist. Dann wird ⑤ der state mit einer Verkettung der gerade gelesenen bzw. berechneten Daten aller Werte ⑥,⑦,⑧ versorgt.
Log HISTORY
Die Werte sammeln sich nun im Log. Dort haben die Werte ebenfalls eine Einheit, in diesem Fall "°C" für reading-Namen, die mit "temperature" beginnen und "%" für reading-Namen, die mit "humidity" beginnen. Andere Einheiten oder andere reading-Namen lassen sich entweder über ein Attribut in der Log-Definition
attr myDbLog valueFn {
if ($DEVICE eq "BME280_42356"){
if ($READING=~ m(^airpressure)){
$UNIT = "hPa";
}
if ($READING=~ m(^pressure)){
$UNIT = "Pa";
}
}
}
oder direkt im Device ergänzen bzw. beeinflussen.
attr BME280_42356 DbLogValueFn {
if ($READING=~ m(^airpressure)){
$UNIT = "hPa";
}
if ($READING=~ m(^pressure)){
$UNIT = "Pa";
}
}
Damit lassen sich freilich auch ungewöhnliche Einheiten festlegen, Blutdruck wird z.B. in "mmHg" gemessen.
Weiterführend
Abschließend soll noch ein Plot der Messwerte gemacht werden, eine Kurve liest sich leichter. Als Erstes wird eine Datei z.B. '/opt/fhem/www/gplot/SVG_BME280_42356.gplot' mit folgendem Inhalt erstellt, der anzuzeigenden Linien und Beschriftungen des Plots beschreibt.
set terminal png transparent size <SIZE> crop
set output '<OUT>.png'
set xdata time
set timefmt "%Y-%m-%d_%H:%M:%S"
set xlabel "Verlauf"
set title 'Wetter'
set ylabel "Temperatur"
set y2label "Luftdruck"
#myDbLog BME280_42356:temperature:0:
#myDbLog BME280_42356:airpressure_sealevel:0::$val=$val>1100?1100:$val<800?800:$val
#myDbLog BME280_42356:humidity:0::$val=$val/2-10
plot "<IN>" using 1:2 axes x1y1 title 'Temperatur' ls l0 lw 1 with lines,\
"<IN>" using 1:2 axes x1y2 title 'Luftdruck' ls l1 lw 1 with lines,\
"<IN>" using 1:2 axes x1y1 title 'Feuchte' ls l2 lw 1 with lines
Dabei wird der Luftdruck auf einen plausiblen Bereich eingegrenzt, Drücke außerhalb dieses Bereichs hat es noch nicht gegeben auf diesem Erdball (:$val=$val>1100?1100:$val<800?800:$val). Der Wert der Feuchte wird dem zu erwartenden Temperaturbereich (-10 bis 40) angeglichen, das ergibt eine schönere Kurve (:$val=$val/2-10). Eine Y-Achse für die Feuchte wäre ja die dritte Y-Achse, die haben wir also nicht. Also landet 100% Feuchte bei 40°C und 0% Feuchte bei -10°C.
Dann wird der Plot definiert. In diesem Fall mit den Daten aus DbLog, für FileLog muss geringfügig angepaßt werden. Dann fehlten freilich auch die FileLog -Definitionen für 'BME280_42356'.
defmod SVG_BME280_42356 SVG myDbLog:SVG_BME280_42356:HISTORY
Der Term 'SVG_BME280_42356' liest dabei die Definitionen aus der vorher angelegten Datei 'SVG_BME280_42356.gplot'.
FIN
Viel Spaß bei den eigenen Experimenten.