Node-RED Tutorial-Reihe - Part 4: Mit FHEM verbinden
In diesem Teil möchte ich endlich einmal Node-RED mit FHEM verknüpfen. Das Video lag bei mir jetzt schon einen Monat unfertig auf der Festplatte. Heute habe ich dann endlich das Ende aufgenommen und gezeigt, wie man diese beiden Systeme miteinander verknüpft. Ziel ist es, möglichst einfach und ohne tausende andere Geräte anlegen zu müssen, die Events der Geräte per MQTT zu übermitteln. Dazu schreiben wir uns ein kurzes Notify in FHEM, welches dann diesen Job automatisch für uns erledigt.
Was wird benötigt?
- Einen Raspberry Pi mit Raspbian (in diesem Fall Stretch, sollte mit älteren Versionen aber genauso klappen)
- Eine Node-RED-Installation
- Eine FHEM-Installation
Video
Befehle
sudo cpan install Net::MQTT::Constants
sudo cpan install Net::MQTT::Simple
Da diese Befehle bei mir unter Stretch gescheitert sind, habe ich diese Module “zu Fuß” installiert. Dazu muss man die einzelnen Archive entpacken und an die richtigen Stellen kopieren. Super einfach wenn man weiß wie es geht, daher erkläre ich es hier einmal kurz. Hoffentlich wird dies aber in Zukunft nicht mehr notwendig sein.
sudo -s
cd /root/.cpan/sources/authors/id/J/JU/JUERD/
tar -xzf Net-MQTT-Simple-1.21.tar.gz
cd Net-MQTT-Simple-1.21/lib/Net
perl -e "print qq(@INC)"
cp -a MQTT/ /usr/lib/arm-linux-gnueabihf/perl5/5.24/Net/
cd /usr/lib/arm-linux-gnueabihf/perl5/5.24/Net/
chown -R root:root MQTT/
exit
sudo -s
cd /root/.cpan/sources/authors/id/B/BE/BEANZ/
tar -xzf Net-MQTT-1.163170.tar.gz
cd Net-MQTT-1.163170/lib/
chown -R root:root .
rsync -av . /usr/lib/arm-linux-gnueabihf/perl5/5.24/
sudo cpan install Module::Pluggable
sudo -s
cd /root/.cpan/sources/authors/id/S/SI/SIMONW/
tar -xzf Module-Pluggable-5.2.tar.gz
cd Module-Pluggable-5.2/lib/
chown -R root:root .
rsync -av . /usr/lib/arm-linux-gnueabihf/perl5/5.24/
exit
shutdown restart
define Mosquitto mqtt 127.0.0.1:1883
define n_publish_mqtt notify .*:.* {}
set Mosquitto publish /test/bla 123
Danach muss auf dem global-Device noch das Attribut userAttr angepasst werden, und die beiden Werte für mqttRoom und mqttName hinzugefügt werden. Wie diese heißen ist natürlich total egal, da wir diese ja im Notify dann erst auswerten. Ich fand die Namen aber ganz passend, da sie auf jeden Fall gut erklären was passieren soll.
Wie die Topics in MQTT aufgebaut werden ist natürlich auch völlig egal. Ich habe mir einfach dieses Konstrukt überlegt, da ich es dann so wie in FHEM habe. Also erst den Raum, dann das Gerät und zum Schluss das Reading.
.*:.* {
my $mqttRoom = AttrVal($NAME, 'mqttRoom', '');
my $mqttName = AttrVal($NAME, 'mqttName', '');
if ($mqttRoom ne '' && $mqttName ne '') {
my $reading = "";
my $message = "";
if ($EVENT =~ qr/(.*?): (.*)/p) {
$reading = $1;
$message = $2;
} else {
$reading = "state";
$message = $EVENT;
}
my $topic = "/SmartHome/$mqttRoom/$mqttName/$reading";
fhem("set Mosquitto publish $topic $message");
}
}
Um eine Übersicht dafür zu bekommen, welche Geräte welche Namen haben, lege ich mir eine readingsGroup an. Diese enthält dann alle Geräte, welche mir automatisch Ihre Events per MQTT liefern. Denn dies sind ja schließlich alle, welche das Attribut mqttName und mqttRoom gesetzt haben.
Natürlich könnte man sich den extra Raum auch schenken, aber ich habe den Pfad gerne so detailliert wie möglich aufgelöst.
define mqttPublishList readingsGroup <Name>,<MQTT-Name>,<MQTT-Raum> .*:?mqttName,?mqttRoom
Erweiterung um Readings-Filter
Michael Lankes hat in der Facebook-Gruppe eine Erweiterung dieser Variante vorgestellt, in welcher er ein weiteres Attribut eingeführt hat, welches ebenfalls die Readings filtern kann. Im oben genannten Beispiel war es so, dass ALLE Änderungen als Event in MQTT aufgetaucht sind. Bei Geräten mit sehr vielen Readings (z.B. Wetter) hat das natürlich viel Last erzeugt, welche eigentlich nicht notwendig ist.
.*:.* {
my $mqttRoom = AttrVal($NAME, 'mqttRoom', '');
my $mqttName = AttrVal($NAME, 'mqttName', '');
my @mqttReadings = split(/,/, AttrVal($NAME, 'mqttReadings', ''));
if ($mqttRoom ne '' && $mqttName ne '') {
my $reading = "";
my $message = "";
if ($EVENT =~ qr/(.*?): (.*)/p) {
$reading = $1;
$message = $2;
} else {
$reading = "state";
$message = $EVENT;
}
if (grep(/^$reading/, @mqttReadings)) {
my $topic = "/SmartHome/$mqttRoom/$mqttName/$reading";
fhem("set Mosquitto publish $topic $message");
}
}
}