Node-RED auf dem Raspberry

Eine Software, sie zu knechten, sie alle zu finden, … Das auf Node.js basierende Node-RED ist ideal um alle Geräte im Smart Home zentral zu sammeln, steuern, auszuwerten und miteinander zu verknüpfen. Dabei versteht es dank Erweiterungen gängige Standards wie MQTT und KNX, beschreibt MySQL und INFLUX Datenbanken, sendet per HTTP, TCP oder UDP und bindet bekannte Systeme etwas Loxone, Homematic, Hue, Sonoff usw direkt ein.

Installation

Dank einem offiziellen Script der Entwickler ist die Installation quasi selbsterklärend und je nach PI und Internetanbindung innerhalb von wenigen Minuten:

#Node Red Installation starten

bash <(curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)

Ein späteres Update gelingt über denselben Befehl und überschreibt die vorhandene Installation ohne unsere bisherige Arbeit zu zerstören. Ein vorheriges und generell regelmäßiges Backup ist natürlich dennoch empfehlenswert.

Node-RED starten

Nach erfolgreicher Installation können wir Node-RED testweise direkt aus der Konsole starten:

#Testweise starten
node-red-start

#Abbrechen mit CTRL-C

Für eine dauerhafte Nutzung und einen automatischen Start beim Booten aktiveren wir es als Service.

#1. Service dauerhaft anschalten
sudo systemctl enable nodered.service

#2. Service starten 
sudo service nodered start

Oberfläche

Für alles Weitere verlassen wir das Terminal und wechseln in den Browser. Unter der Server-IP und Port 1880 erscheint das noch sehr leere grafische Interface. Jetzt beginnt die eigentliche Arbeit …

#Im Browser eingeben
http://<deine-pi-ip-adresse>:1880

Backup

Um unsere kostbare Arbeit vor einem Datenverlust zu schützen, sollten die Flows regelmäßig auf einem externen Datenträger gesichert werden.

  • Der einfache Weg: Im Menu Exportieren -> alles Flows auswählen und in einer Textdatei speichern.
  • Manuelles komplettes Backup: Alle Dateien im verstecken Anwendungsverzeichnis /home/pi/.node-red packen und kopieren
  • Do it like a pro: Das Backup lässt sich natürlich auch selbst über Node-RED steuern, etwa für automatische Uploads in die Cloud

Xiaomi Mi Flora und Node Red – Pflanzen überwachen mit dem Raspberry

Genug Licht, Wasser und ab und an etwas Dünger, das macht unsere Pflanzen froh. Ob alles passt, verrät uns der Mi Flora von Xiaomi. Der kleine Bluetooth-Sensor wird normalerweise direkt mit der passenden App auf dem Smartphone gekoppelt, kann jedoch auch in den Raspberry funken.

Voraussetzungen

  • Ein Raspberry mit Bluetooth, etwas ein Model 3B, 4 oder auch Zero W. Installiertes Raspberry Pi OS (Buster oder neuer)
  • Xiaomi Mi Flora oder „Nachbauten“, ab ca. 12 Euro im Asiashop

Bluetooth Adresse finden

Zunächst überprüfen wir ob Bluetooth im Raspberry funktioniert und der Mi Flora entdeckt wird. Die gefundene Adresse benötigen wir später um die Daten auszulesen.

#Bluetooth Umgebungsscan
sudo hcitool lescan

#Scan abbrechen mit CTRL-C

#Beispielausgabe
LE Scan ...
31:D3:AF:2D:59:F0 (unknown)
51:32:37:CC:82:EE Flower Care

Neben vermutlich einigen „Unbekannten“ Geräten sollte in der Liste auch ein „Flower Care“ und damit unser Xiaomi Device auftauchen.

Einbindung per Node Red

Ist bereits Node Red installiert, ist die Einrichtung schnell erledigt. Die passende Node ist node-red-contrib-xiaomi-devices und wird einfach über die „Palette“ installiert.

Node installieren

Der einfache Flow

Im neuen Baustein Xiaomi BLE müssen wir lediglich die Bluetooth Adresse eingeben und durch inject auslesen. Die verfügbaren Daten sehen wir nach einer erfolgreichen Verbindung im Debug Fenster.

Einfacher Flow für den Mi Flora Sensor
[{"id":"ee7913c3.bbd26","type":"Xiaomi BLE","z":"83c28990.49ea18","name":"","address":"C4:7C:8D:6A:9C:C7","scanningTimeout":60,"x":470,"y":240,"wires":[["dc4d7fc3.9f3d68"]]},{"id":"5ae25c26.766174","type":"inject","z":"83c28990.49ea18","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":220,"y":240,"wires":[["ee7913c3.bbd26"]]},{"id":"dc4d7fc3.9f3d68","type":"debug","z":"83c28990.49ea18","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":780,"y":240,"wires":[]}]

Der fortgeschrittene Flow

Die gewonnen Daten können wir nun regelmäßig per MQTT im Netzwerk verteilen, im Dashboard ausgeben, über Influx nach Grafana leiten …

[{"id":"ca093678.f26d7","type":"Xiaomi BLE","z":"3785f120.90cd96","name":"Mein Mi Flora","address":"C4:7C:8D:6A:9C:C7","scanningTimeout":"20","x":440,"y":780,"wires":[["34548b43.4f3f2c","81042299.84e26"]]},{"id":"34548b43.4f3f2c","type":"debug","z":"3785f120.90cd96","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":890,"y":780,"wires":[]},{"id":"6a17af57.b4c798","type":"inject","z":"3785f120.90cd96","name":"Abruf alle 10 Min","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"600","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":780,"wires":[["ca093678.f26d7"]]},{"id":"81042299.84e26","type":"split","z":"3785f120.90cd96","name":"","splt":"\\n","spltType":"str","arraySplt":1,"arraySpltType":"len","stream":false,"addname":"topic","x":420,"y":980,"wires":[["3353ba18.c0f926","a0bbcaeb.928498"]]},{"id":"7627408b.d36d08","type":"inject","z":"3785f120.90cd96","name":"Demo Daten","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"battery\":100,\"temperature\":22.4,\"light\":608,\"moisture\":20,\"conductivity\":149}","payloadType":"json","x":170,"y":980,"wires":[["81042299.84e26"]]},{"id":"c6ddc559.5b7c1","type":"mqtt out","z":"3785f120.90cd96","name":"","topic":"","qos":"","retain":"","broker":"","x":870,"y":980,"wires":[]},{"id":"3353ba18.c0f926","type":"function","z":"3785f120.90cd96","name":"MQTT Topic festlegen","func":"msg.topic = \"pflanzen/miflora/\" + msg.topic;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":980,"wires":[["c6ddc559.5b7c1"]]},{"id":"a0bbcaeb.928498","type":"switch","z":"3785f120.90cd96","name":"","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"battery","vt":"str"},{"t":"eq","v":"temperature","vt":"str"},{"t":"eq","v":"light","vt":"str"},{"t":"eq","v":"moisture","vt":"str"},{"t":"eq","v":"conductivity","vt":"str"}],"checkall":"true","repair":false,"outputs":5,"x":590,"y":1160,"wires":[["86d74f08.7093f8"],["ea29e549.1c8c4"],["2cc343f3.8a2df4"],["160a38fa.0e8c87"],["1c6fef43.1d71d9"]]},{"id":"86d74f08.7093f8","type":"ui_chart","z":"3785f120.90cd96","name":"","group":"7cbba92f.3b546","order":4,"width":0,"height":0,"label":"Batterie","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"48","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#b4ad2c","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":880,"y":1080,"wires":[[]]},{"id":"ea29e549.1c8c4","type":"ui_chart","z":"3785f120.90cd96","name":"","group":"7cbba92f.3b546","order":4,"width":0,"height":0,"label":"Temperatur","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"48","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#b44828","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":890,"y":1120,"wires":[[]]},{"id":"2cc343f3.8a2df4","type":"ui_chart","z":"3785f120.90cd96","name":"","group":"7cbba92f.3b546","order":4,"width":0,"height":0,"label":"Licht","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"48","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#f5aa9d","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":870,"y":1160,"wires":[[]]},{"id":"160a38fa.0e8c87","type":"ui_chart","z":"3785f120.90cd96","name":"","group":"7cbba92f.3b546","order":4,"width":0,"height":0,"label":"Feuchtigkeit","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"48","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#256cf5","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":890,"y":1200,"wires":[[]]},{"id":"1c6fef43.1d71d9","type":"ui_chart","z":"3785f120.90cd96","name":"","group":"7cbba92f.3b546","order":4,"width":0,"height":0,"label":"Leitfähigkeit","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":"48","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#256cf5","#64e850","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":890,"y":1240,"wires":[[]]},{"id":"183605e2.5b40ba","type":"comment","z":"3785f120.90cd96","name":"Dashboard Grafiken","info":"","x":630,"y":1080,"wires":[]},{"id":"ce098039.3f9be8","type":"comment","z":"3785f120.90cd96","name":"Daten zum MQTT Server","info":"","x":650,"y":900,"wires":[]},{"id":"7cbba92f.3b546","type":"ui_group","z":"","name":"Mi Flora Sensor","tab":"ad98b36d.a329b8","order":1,"disp":true,"width":"6","collapse":false},{"id":"ad98b36d.a329b8","type":"ui_tab","z":"","name":"Pflanzen","icon":"dashboard","disabled":false,"hidden":false}]

Mi Flora ohne Node Red

Um allein die Daten auszulesen und per MQTT zu verschicken ist die Installation von Node Red natürlich übertrieben. Ein paar Zeilen Python erledigen einen genau so guten Job und sparen wertvolle Ressourcen. Die passende Anleitung und das notwendige Script findet ihr zum Beispiel auf Github von Thom Dietrich oder dieser Quelle.

Bluetooth Fehler

Die Bluetooth-Verbindung auf dem Raspberry scheint leider nicht immer die stabilste zu sein. Fehler wie „Set scan parameters failed: Input/output error.“ beim Scannen mit den hcitool oder „Gerät konnte nicht gefunden werden“ hatte ich selbst leider schon öfters.

Eine möglich Lösung ist dabei ein Neustart der betreffenden Services:

sudo service bluetooth restart
sudo service dbus restart

Um uns die Arbeit zu erleichtern und sicher sein, überlassen wir den täglichen Restart einem Cronjob:

#Cronjobs verwalten, für einen Service müssen wir diese als Sudo ausführen
sudo crontab -e

#Diese Zeile im Editor hinzugefügt startet den Service jeden Tag um Mitternacht
0 0 * * *  /usr/sbin/service bluetooth restart >/dev/null 2>&1

Raspberry als Zeitserver

Ob Laptop, Webcam oder IoT Device, nahezu alle Geräte in einem Netzwerk synchronisieren ihre Systemzeit üblicherweise mit einem NTP-Server aus dem Internet. Möchten wir dies unterbinden oder benötigt dank nicht vorhandenem Internetzugang eine lokale Alternative, bietet der Raspberry eine einfache Lösung.

Installation

Der Zeitserver und Client für den PI ist äußerst schlank und schnell installiert. Anschließend bezieht das System automatisch die aktuelle Uhrzeit und stellt diese wiederum als Server für andere Geräte zur Verfügung.

#Den Dienst installieren
sudo apt-get install ntp ntpdate

Nach erfolgreicher Installation können wir für einen ersten Test einen Abgleich mit einem externen NTP-Server anfordern.

#Zeitabgleich mit den in der ntp.conf eingetragenen Servern (meistens debian.pool.ntp.org)
sudo ntpd -qg

#Zeitabgleich mit einem bestimmen NTP-Server, z.B. aus Deutschland
sudo ntpdate -u de.pool.ntp.org

#Mögliche Antwort nach wenigen Sekunden
11 Dec 09:35:47 ntpdate[27127]: adjust time server 185.242.112.53 offset -0.005542 sec

War das Update erfolgreich, können wir anschließend unsere lokalen Geräte mit dem eigenen Server synchronisieren.

Clients einrichten

Unser NTP-Server stellt seinen Dienst unter seiner IP und dem Port 123 (UDP) bereit. Bei den meisten Client-Geräten reicht jedoch die Eingabe der Adresse in das passende Feld („Zeitserver“ oder „NTP-Server“).

#Adresse des Zeitservers für Clienten
<ip-meines-pis>:<Port>

#Beispiel
192.168.0.1 oder 192.168.0.1:123

Weitere Einstellungen für den NTP-Server

Welche externen NTP-Server zur Synchronisation in Verwendung sind, verrät uns der Befehl

ntpq -pn

Möchten wir andere Server hinzufügen oder Einstellungen ändern, ist hierfür die ntp.conf zuständig.

#Config bearbeiten
sudo nano /etc/ntp.conf

Für den Standort Deutschland sind natürlich die deutschen NTP Server bestens geeignet.

server 0.de.pool.ntp.org
server 1.de.pool.ntp.org
server 2.de.pool.ntp.org
server 3.de.pool.ntp.org

Nach dem Speichern sorgt ein Restart des Services für die Übernahme der Änderungen

#Dienst neu starten
sudo /etc/init.d/ntp restart

Timesyncd

Neuere Versionen des Raspberry Pi OS halten die Systemzeit bereits per timesyncd aktuell. Wer möchte, kann diesen nach der Installation von ntp nun unnötigen Dienst auch abschalten – oder einfach zur Sicherheit parallel laufen lassen.

#Service stoppen
systemctl stop systemd-timesyncd

#Autostart deaktivieren
systemctl disable systemd-timesyncd

Raspberry mit statischer IP

Verwenden wir unseren PI als (FTP-, Web-, Smarthome, …) Server, sollte dieser möglichst immer unter der selben IP erreichbar sein. Falls der verwendete DHCP Server (z.B. Router des Internetanbieters) jedoch keine dauerhafte Zuweisung erlaubt, können wir dem PI natürlich auch manuell eine statische IP verpassen.

IP finden und setzen

1. Die aktuelle IP (falls bereits mit einem Netzwerk verbunden) erfahren wir mit dem Befehl hostname

hostname -I

#Beispielantwort
192.168.1.10

oder alternativ per

ip r | grep default

#Beispielantwort
default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.10 metric 202 

In diesem Fall ist die erste IP der verwendete DNS-Server, die zweite die des PIs und eth0 steht für die Anbindung per LAN Schnittstelle.

2. Bei einer Standardinstallation von Raspian OS läuft auf unserem PI bereits ein DHCP-Dienst über den sich die Zuweisung unsere Wunsch-IP vornehmen lässt.

#DHCP Status testen - es sollte eine Meldung wie "Active: active (running)" erscheinen
sudo service dhcpcd status

#DHCP Konfiguration editieren
sudo nano /etc/dhcpcd.conf

3. Scrolle bis an das Ende der Datei, bis ein auskommentiertes Beispiel für eine mögliche Konfiguration erscheint.

# Example static IP configuration:
#interface eth0
#static ip_address=192.168.0.10/24
#static ip6_address=fd51:42f8:caae:d92e::ff/64
#static routers=192.168.0.1
#static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1

Entsprechend dem Beispielschema fügen wir direkt darunter unsere eigenen Daten ein, wobei wir bei interface entweder eth0 für Ethernet (LAN) oder wlan0 für Wifi verwenden. Bei routers und domain_name_servers steht üblicherweise die selbe IP oder Du verwendest als DNS alternativ z.B. den Server von Google unter 8.8.8.8 oder 1.1.1.1 von Cloudflare.

#Generisches Beispiel
interface <eht0 oder wlan0>
static ip_address=<Deine gewünschte IP>/24
static routers=<IP des Routers>
static domain_name_servers=<DNS>
#Beispiel
interface eht0
static ip_address=192.168.0.10/24
static routers=192.168.0.1
static domain_name_servers=8.8.8.8

Wichtig ist natürlich eine IP zu verwenden die noch im Netzwerk frei ist! (kann zuvor mit PING überprüft werden)

Anschließend den Editor mit CTRL-X und dem bestätigen des Speicherns beenden (Y oder J) und den PI einmal neu starten.

sudo reboot

4. Nun beten, dass alles funktioniert hat und das Ergebnis am besten überprüfen.

hostname -I

Alternative ohne DHCP

Befindet sich im Netzwerk bereits ein anderer DHCP-Server, können wir uns diesen Dienst und damit ein paar unnötige Ressourcen auf unserem PI auch einsparen.

1. Hierzu stoppen und deaktivieren wir den Service dauerhaft

#Dienst stoppen
sudo service dhcpcd stop

#Autostart verbieten
sudo systemctl disable dhcpcd

2. Für die Zuweisung nutzen wir direkt die Konfigurationsdatei der Netzwerkgeräte

#Config öffen
sudo nano /etc/network/interfaces

und ergänzen den Inhalt um

#Meine statische Konfiguration:
auto eth0
allow-hotplug eth0
iface eth0 inet static
address <Deine gewünschte IP>
netmask 255.255.255.0
gateway <IP des Routers>
dns-nameservers <IP des gewünschten DNS>

Nach einem Neustart sollte der PI nun stets unter der vorgegeben IP erreichbar sein.

Ordnergrößen in Linux

Die Festplatte wird voller und voller, nur wo befinden sich all diese Dateien und welcher Ordner belegt wie viel Platz? Die Antwort verrät uns das systeminterne du – Disk Usage.

Größe eines bestimmen Ordners

sudo du -sh /var

#Ausgabe 
910M    /var

Durch den Parameter -s (summarize) wird die Größe des gesamten Ordnerns inklusive Unterordner bestimmt, während -h für eine verständliche (human-readable) Ausgabe sorgt.

Um den belegten Platz im aktuellen Ordner anzuzeigen setzen wir am Ende einfach einen Punkt. Die zusätzliche Eingabe von sudo ist eigentlich nur für systemweite Suchen oder Abfragen in geschützten Verzeichnissen notwendig.

sudo du -sh .

Um dem gesamten auf der Festplatte belegten Platz anzuzeigen

sudo du -hs / 

Unterordner

Ergänzen wir obigen Befehl um ein Slash-Sternchen erhalten wir die Größen aller Unterordner. Wer nochmals die Gesamtgröße sehen möchte, verwendet einfach -shc anstelle von nur -sh.

sudo du -sh /var/*

#Ausgabe
812K    /var/backups
143M    /var/cache
354M    /var/lib
4.0K    /var/local
0       /var/lock
415M    /var/log
4.0K    /var/mail
4.0K    /var/opt
0       /var/run
28K     /var/spool
20K     /var/tmp
256K    /var/www

Die größten Verzeichnisse finden

Um etwa die zehn größten Verzeichnisse zu finden, lässt sich die Ausgabe von du sortieren (sort -rh) und per head auf eine gewünschte Anzahl begrenzen. Eine jeweilige Pipe grenzt diese nachfolgenden Bearbeitungen vom eigentlichen du-Befehl ab.

sudo du -h /var/ | sort -rh | head -10

Dateien ausschließen

Möchtest du bestimmte Dateien von der Einberechnung ausschließen hilft der Zusatz –exclude weiter. Für alle ZIP-Dateien wäre dies etwa –exclude=“*.zip“.

sudo du -shc --exclude="*.zip" /var/*

Die wichtigsten Optionen im Überblick

-aPlatzbedarf aller Dateien anzeigen
-c Zeigt am Ende zusätzlich den summierte Platzbedarf der Suche
-h Formatiert die Zahlen anstelle von Kilobyte in besser lesbare Werte wie Megabyte oder Gigabyte
-sSummiert das Ergebnis auf einzelne Ordner
–excludeSchließt bestimmte Dateien aus
–timeEine zusätzliche Spalte mit dem Zeitpunkt der letzten Änderung

Alle weiteren Möglichkeiten findest du mit

du --help