Vor einiger Zeit habe ich einmal ein 3-Kanal Thermometer im Supermarkt (vorne LI und hinten DL) für einfaches Geld gekauft. Meist liegen diese Gimmicks zum Schnökern im Mittelgang, an denen man nie so ohne Weiteres vorbei gehen kann. Dieses Teil verrichtet seinen Dienst seit zwei Jahren sehr zuverlässig. Es überträgt in einem Intervall von etwa 100 Sekunden drahtlos Temperatur und Luftfeuchte mit einer zufriedenstellenden Genauigkeit. Meine Frage nun: Kann man diese Datenübertragung irgendwie abgreifen und dekodieren?

Natürlich! Und zwar mit einem RTL-USB-Stick und einem Einplatinencomputer, wie z.B. ein Raspberry Pi.

 

Wie kommt man an solche Daten?

Auf der Verpackung des Thermometers sollte der Frequenzbereich der Übertragungsstrecke ersichtlich sein. In meinem Fall ist das 433 MHz. Ein Blick mit gqrx und einem angeschlossenen RTL-Stick am USB-Port meines Linux-Rechners zeigt eine Menge mehr oder weniger laute Signale in diesem Bereich, die dort senden dürfen, zum Leid jedes Funkamateurs. Das, was da als Störsignale empfangen wird, ist nichts anderes als Daten, die von eben solchen funkenden Außeneinheiten an ihre Basisstation senden. Auch Funk-Autoschlüssel senden noch überwiegend in diesem Frequenzbereich. 

Bevor ich mich nun aber auf die Entschlüsselung dieser Daten heran wage, haben sich andere bereits ihren Kopf zerbrochen und eine wundervolle kleine Software öffentlich bereit gestellt mit dem Namen rtl_433. Diese Software ist in der Lage schon mit den Standardeinstellungen alle diese “Störsignale” um 433,92 MHz herum mit einer Bandbreite von 250kHz zu empfangen, zu dekodieren und als Text auf dem Bildschirm auszugeben. Natürlich kann man das Programm mit entsprechenden Parametern konfigurieren. So ist u.a. auch die Ausgabe in eine Datei möglich, oder wie in meinem Fall im JSON-Format. Nodered kann ja ohne weiteres dieses Datenformat brauchbar umsetzen. Das will ich hier nutzen.

Bemerkenswert ist, dass über die Parameter des Programms auch andere ISM-Frequenzbereiche ausgelesen werden können, wie z.B. 868 MHz. Das rtl_433 kann sowohl unter verschiedenen Linux-Derivaten, als auch unter MacOS und Windows laufen. In meinem Fall läuft es auf meinem alten Raspberry Pi 2.

Ich beschreibe hier nicht die Installation oder Konfiguration von rtl_433, sondern den Weg, wie ich für (m)eine kleine Wetterstation diese Aussendungen zur Anzeige bringe:

Allgemein:

https://github.com/merbanan/rtl_433

Beschreibung zur Programmerstellung:

https://github.com/merbanan/rtl_433/blob/master/docs/BUILDING.md

Voraussetzung ist natürlich, dass der RTL-Stick funktionstüchtig am USB-Port hängt und keine andere Applikation darauf zugreift um den sog. claim error zu vermeiden.

Wenn man mal über mehrere Minuten oder Stunden dieses Programm laufen lässt, wird man erstaunt sein, was da so alles in der Nachbarschaft rumfunkt. Nach einigen Checks habe ich dann irgendwann auch meine Außeneinheit identifiziert und konnte sie dann mit Hilfe der Softwareparameter nach dem Hersteller filtern. Jedoch werden dann auch Daten eben des selben Herstellers aus meiner Umgebung dekodiert. Da scheinen wohl mehrere Haushalte sich eine solche Thermometer-Einheit im Supermarkt gekauft zu haben. Diese Angebote sind aber auch immer echt verlockend…

Sobald das Programm herunter geladen und kompiliert wurde kann man es aufrufen mit

rtl_433

Ohne weitere Parameter, werden nun alle Signale um 433,92 MHz empfangen und versucht zu dekodieren. Diese erscheinen prompt auf dem Bildschirm.

Mit dem Aufruf des Programms mit diesen Parametern, werden jeweils Daten im JSON-Format dekodiert:

rtl_433 -R 19 -F json

wobei 19 das Datenformat des Herstellers “Nexus TH” festlegt. Der Filter wird mit -R 19 gesetzt. Der Parameter -F json definiert das Ausgabeformat. Das Ergebnis daraus wird eben alle ca. 100 sek. aktualisiert:

{"time" : "2020-06-08 16:09:47", "model" : "Nexus-TH", "id" : 138, "channel" : 3, "battery_ok" : 1, "temperature_C" : 20.200, "humidity" : 47}
{"time" : "2020-06-08 16:16:22", "model" : "Nexus-TH", "id" : 138, "channel" : 3, "battery_ok" : 1, "temperature_C" : 20.000, "humidity" : 47}
{"time" : "2020-06-08 16:25:35", "model" : "Nexus-TH", "id" : 138, "channel" : 3, "battery_ok" : 1, "temperature_C" : 19.900, "humidity" : 48}
..
{"time" : "2020-06-08 16:34:48", "model" : "Nexus-TH", "id" : 138, "channel" : 3, "battery_ok" : 1, "temperature_C" : 19.800, "humidity" : 48}

Man erkennt also in diesen Datensätzen einige Daten, die man nun weiter benutzen kann.

  1. “time”: Die Uhrzeit des Datensatzes
  2. “model”. Das Hersteller-Modell (“Nexus-TH”)
  3. “id”: eine eindeutige ID, mit der genau dieses Gerät identifiziert werden kann (138 = meins!). Die Nexus-Geräte der Nachbarn haben jeweils eine andere ID
    Nach einem Neustart einer solchen Außeneinheit kann sich die ID auch ändern, z.B. nach Batteriewechsel.
  4. “channel”: der eingestellte Kanal der Außeneinheit (3)
  5. “battery_ok”: einen Batteriestatus (1) – ob sich der Status auf 0 ändert, wenn die Batterie mal nicht mehr ok ist, bleibt abzuwarten
  6. “temperature_C”: die aktuelle Temperatur am Sensor in Grad Celsius (20.200)
  7. “humidity”: die aktuelle relative Luftfeuchte am Sensor in Prozent (47)

 

Wie kommen die Daten nun ins Nodered?

Versenden der Daten an einen Zwischenspeicher

Da ich keine Dateien auf die Speicherkarte schreiben wollte, sende ich diese Daten (publish) an einen MQTT-Broker, von dem ich sie dann wieder abhole (subscribe). Das kommt dem späteren Einsatz in der Relaisstation auf dem Ravensberg ebenfalls zu gute. Natürlich muss dazu auf dem Raspberry noch der Mosquitto-Client installiert werden, wenn nicht schon geschehen.

Installation Mosquitto:

https://tutorials-raspberrypi.de/datenaustausch-raspberry-pi-mqtt-broker-client/

oder auch so:

sudo apt install mosquitto mosquitto-clients

Jetzt sende ich mit diesem Befehl die Daten kontinuierlich an meinen Broker:

rtl_433 -R 19 -F json | mosquitto_pub -h <broker-ip> -t <Verzeichnis auf dem Broker-Server> -l 

wobei

  • <broker-ip> entweder die IP-Adresse des Broker-Servers oder auch der DNS-Name ist.
  • <Verzeichnis auf dem Broker-Server> das Ablage-Verzeichnis beschreibt.
  • der letzte Parameter -l ein kleines L enthält.

Der obige Befehl blockiert natürlich nun eine Konsole. Wenn man mit dem Raspberry remote mit ssh verbunden ist und man die Verbindung trennt, wird das Programm natürlich auch beendet. Um dem vorzubeugen, erzeuge ich beim Start des Raspberry eine virtuelle Sitzung mit dem Programm screen. Sofern es auf dem Raspberry nicht vorhanden ist, kann es einfach nachinstalliert werden:

sudo apt install screen

Zudem habe ich eine bash-Datei erstellt, um die komplette Prozedur zu starten. Diese liegt im Standard-Verzeichnis /home/pi/monitor-rtl_433.sh und hat diesen Inhalt:

#!/bin/bash

if pgrep -f "rtl_433 -R 19"
then 
    echo "rtl_433 läuft"
else
    echo "rtl_433 läuft nicht"
    if pgrep -f "mosquitto_pub -h <mqtt-Server-Adresse> -t <Ablageort im Server> -l"
    then
        killall -s 9 mosquitto_pub
        killall -s 9 mosquitto_pub
        killall -s 9 mosquitto_pub
        sleep 2
    fi
    echo "Starte rtl_433..."
    rtl_433 -R 19 -F json | mosquitto_pub -h <mqtt-Server-Adresse> -t <Ablageort im Server> -l
fi

Diese Datei sollte nun noch ausführbar gemacht werden mit

chmod +x /home/pi/monitor-rtl_433.sh

 

In der Datei /etc/rc.local vor der Zeile mit exit 0 diese Zeile eintragen:

screen -dmS rtl433 bash /home/pi/monitor-rtl_433.sh

Damit startet der Empfang über den RTL-USB-Stick und die Datenübertragung direkt mit dem Neustart des Raspberry Pi.

 

 

Vorbereiten des Nodered zur Abholung und Darstellung der Daten

Nodered holt nun über einen MQTT-Node die Daten ab. Diese werden aufbereitet und zur Anzeige gebracht.

 

Der Workflow sieht in diesem Falle dann so aus:

 

Der Node mqtt:

In der input-Sektion des Nodered fügt man den mqtt in node hinzu. Bitte nicht verwechseln mit dem mqtt out node in der output-Sektion.
1. Server: Hinzufügen eines neuen mqtt-Brokers. Das ist die Adresse (URL oder IP) des Broker-Servers
  Auf einigen Plattformen im Internet ist es notwendig auch ein Benutzer-Login einzutragen
2. Topic: Die Daten werden in einer Ordner-Struktur dort abgelegt. Diesen Ordner gibt man hier ein
3. Done: Wenn fertig

 

Der Node json:

Den json node findet man in der function-Sektion. Hier meine Einstellungen:

 

Der Node Filter:

Den switch node findet man in der functions-Sektion. Ich benutze ihn als Filter, um die ID meines Außenfühlers zu filtern. In den rohen Textnachrichten ist der Sensor mit der ID 138 versehen. Somit setze ich die Property auf msg.payload.id und füge den ersten gefilterten Ausgang == 138 ein. Sollte es ein anderer Wert sein, werden weitere Nachrichten an den Ausgang mit der Einstellung “otherwise” geleitet. Da ich diesen Ausgang zunächst nicht bearbeite, laufen also anders lautende Meldungen als mit der ID 138 ins nichts.

 

Der Funktions-Node “outdoor_string”:

In (m)einer kleinen Wetterstation habe ich zu Beginn des Flow 1 einen function Node zur Deklaration von globalen Variablen hinzugefügt. Auf diese Variablen habe ich somit nun in allen Nodes und in allen Flows Zugriff auf die Werte.
In den ersten beiden Zeilen speichere ich die aktuellen Temperatur- und Luftfeuchte-Werte in die dafür vorgesehenen Variablen ab.
Das folgende If..then..else-Konstrukt setzt die globale Variable als Text in Abhängigkeit der Nachricht battery_ok
Danach wird ein String zusammengesetzt, der in einem Text input-Node mit dem Namen Außenfühler auf dem Dashboard ausgegeben werden kann.

global.set("outdoor_temperature",msg.payload.temperature_C);
global.set("outdoor_humidity",msg.payload.humidity);

if (msg.payload.battery_ok == 1){
global.set("outdoor_battery",'OK');
}
else {
global.set("outdoor_battery",'LOW');
}

msg.payload = msg.payload.time + ' | T: ' + global.get("outdoor_temperature") + ' °C | H: ' + global.get("outdoor_humidity") + ' % | B: ' + global.get("outdoor_battery");

return msg;

 

Das Ergebnis auf dem Dashboard

Außenfühler: 2020-06-09 13:41:27 | T: 16.4 °C | H: 69 % | B: OK

Fein, nicht wahr? Nicht grad spektakulär das Ergebnis, aber es ist eine Grundlage für die weitere Datenverarbeitung (Speichern in eine Datenbank, Mittelwerte, Darstellung) in bestimmten Abhängigkeiten von anderen Werten.

 

Ableitend daraus kann man z.B. auch den Taupunkt und den Hitze-Index (zumindest bei Temperaturen über 20°C) berechnen. Informationen dazu habe ich hier in der Rubrik “Physik und Chemie” gefunden.

v

Kommentar verfassen

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.