Daten vom RevPi über MQTT senden

Wir möchten euch hier ein Beispielprogramm zeigen, mit dem ihr beliebige Werte vom RevPi über MQTT versenden könnt. Das vorgestellte Programm läuft sowohl als „Stand-alone“ oder kann in ein bestehendes Python Programm importiert werden.

Wichtig sind folgende Voraussetzungen:
Auf dem Revolution Pi ist python3-revpimodio2 und paho-mqtt installiert.

# RevPiModIO2 über das Kunbus Repository installieren
pi@RevPi0000:~ $ sudo apt-get install python3-revpimodio2

# paho-mqtt über pip3 installieren, da es nicht in den Repositories ist
pi@RevPi0000:~ $ sudo pip3 install paho-mqtt
Downloading/unpacking paho-mqtt
 Downloading paho-mqtt-1.3.1.tar.gz (80kB): 80kB downloaded
 Running setup.py (path:/tmp/pip-build-t3xxgmr2/paho-mqtt/setup.py) egg_info for package paho-mqtt
 
Installing collected packages: paho-mqtt
 Running setup.py install for paho-mqtt
 
Successfully installed paho-mqtt
Cleaning up...
Das MQTT Programm
#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# Version 0.1.0
# (c) Sven Sager, License: GPLv3
#
"""Klasse fuer das Senden von Sensordaten ueber MQTT."""
import logging
import revpimodio2
from paho.mqtt.client import Client
from ssl import CERT_NONE
from threading import Event, Thread

logger = logging.getLogger()

# !!! Nur zum TESTEN, auf INFO belassen, sonst WARNING !!!
logging.basicConfig(level=logging.INFO)
# logging.basicConfig(level=logging.WARNING)


class RevPiMqtt(Thread):

    """Sendet Sensordaten ueber MQTT."""

    def __init__(
            self, io_list, basetopic, host, port=1883, tls=False,
            user=None, password=None):
        """Init RevPiMqtt class.

        @param io_list Liste mit IO Namen, die gesendet werden sollen
        @param basetopic MQTT Basistopic
        @param host MQTT Broker IP
        @param user MQTT Username
        @param password MQTT Passwort
        @param port MQTT Port
        @param tls Wenn True, wird verschluesselt verbunden

        """
        super().__init__()
        self._evt_exit = Event()
        self._mqtt_connected = False
        self._rpi = revpimodio2.RevPiModIO(monitoring=True)
        self._interval = 10

        # Parameter übernehmen
        self.io_list = io_list
        self.basetopic = basetopic
        self.host = host
        self.user = user
        self.password = password
        self.port = port
        self.tls = tls

        # Prüfen ob alle IOs auf dem Pi sind
        for io in self.io_list:
            if io not in self._rpi.io:
                raise ValueError("io name nicht in piCtory")

    def run(self):
        """Uebertragung der Daten im Thread."""

        # MQTT Client erzeugen
        mqtt = Client(client_id="ilc01")
        if self.user is not None:
            mqtt.username_pw_set(self.user, self.password)
        if self.tls:
            mqtt.tls_set(cert_reqs=CERT_NONE)
            mqtt.tls_insecure_set(True)

        # Mainloop
        while not self._evt_exit.is_set():

            # Erstes Verbinden zu MQTT
            if not self._mqtt_connected:
                try:
                    mqtt.connect(self.host, self.port, 60)
                    self._mqtt_connected = True
                except:
                    # Bei fehlerhaften Versucht 15 Sekunden warten
                    logger.error("Keine Verbindung zu MQTT Broker")
                    self._evt_exit.wait(15)
            else:

                # Daten vom RevPi lesen
                self._rpi.readprocimg()

                # Daten der IOs per publish senden
                for ioname in self.io_list:
                    # MQTT Topic an den gesendet wird
                    topic = "{}/{}".format(self.basetopic, ioname)

                    # Zahlenwert der gesendet wird
                    value = int(self._rpi.io[ioname].value)

                    # MQTT Paket senden
                    mqtt.publish(topic, value)
                    logger.info("Daten geschrieben {}: {}".format(
                        topic, value
                    ))

            # Warten bis zur nächsten Übertragung
            self._evt_exit.wait(self._interval)

        # MQTT trennen
        mqtt.disconnect()

    def stop(self, signum=None, sigframe=None):
        """Beendet den Mainloop."""
        self._evt_exit.set()


if __name__ == "__main__":
    # Standalone
    import signal

    # Liste der IO Namen, die übertragen werden sollen
    # ---------- ANPASSEN ----------
    lst = [
        "door_corridor",
        "door_workshop",
        "temp_heater",
        "temp_outside"
    ]

    # Klasse instantiieren
    # ---------- ANPASSEN ----------
    root = RevPiMqtt(
        io_list=lst,
        basetopic="datensammlung/revpi01",
        host="192.168.50.156",
        user="revpi01",
        password="test"
    )

    # Signale verbinden auf stop Funktion
    signal.signal(signal.SIGINT, root.stop)
    signal.signal(signal.SIGTERM, root.stop)

    # Anwendung starten und auf Beenden warten
    root.start()
    root.join()

DOWNLOAD

Das Beispielprogramm kann direkt auf einen Revolution Pi übertragen werden. Es müssen lediglich die Namen der IOs lst = [] und natürlich die MQTT-Einstellungen (basetopic, host, user, password) am Ende der Datei auf eure Werte angepasst werden!

In bestehendes Programm integrieren

Wenn man bereits ein Python Steuerungsprogramm auf dem Revolution Pi per RevPiPyLoad ausführt, kann man die MQTT Datenübertragung auch in dieses integrieren.

Dafür muss man lediglich unsere Pythondatei revpitomqtt.py in das selbe Verzeichnis kopieren, in dem auch das Steuerungsprogramm liegt. Bei Verwendung von RevPiPyLoad einfach die Datei per RevPiPyControl hochladen.
In das Bestehende Programm importiert man sich das Modul (die Datei) und instantiiert es selber (alles aus dem unteren Abschnitt von revpitomqtt.py).

#!/usr/bin/python3
# -*- coding: utf-8 -*-
#
# (c) Sven Sager, License: GPLv3
#
import revpimodio2
import revpitomqtt

# MQTT Übertragung
lst = [
    "door_corridor",
    "door_workshop",
    "temp_heater",
    "temp_outside"
]
mqtt = revpitomqtt.RevPiMqtt(
    io_list=lst,
    basetopic="datensammlung/revpi01",
    host="192.168.50.156",
    user="revpi01",
    password="test"
)
mqtt.start()

# ---------- Altes Steuerungsprogramm auf RevPi ----------

def endefunktion():
    # Ist wichtig zum aufräumen und Beenden des MQTT-Systems
    mqtt.stop()


def eventfunktion(ioname, iovalue):
    # Kleines dummes Beispiel einer "Steuerung"
    print(ioname, iovalue)


# RevPiModIO vorbereiten
rpi = revpimodio2.RevPiModIO(autorefresh=True)
rpi.handlesignalend(endefunktion)

# IOs für die normale Steuerung registrieren
rpi.io.I_1.reg_event(eventfunktion)

# RevPi Eventüberwachung starten
rpi.mainloop()
Programm übertragen und ausführen

Wir übertragen, in unserem Fall, das Programm per RevPiPyControl auf unseren Revolution Pi. Dort wird es von RevPiPyLoad ausgeführt und überwacht.

Alternativ kann es natürlich auch anders auf den Revolution Pi erstellt und dort direkt ausgeführt werden.

Wenn das Programm gestartet ist, verbindet es sich zu unserem MQTT Broker und überträgt die Sensordaten. Auf dem MQTT Broker können wir wieder mit mosquitto_sub die Nachrichten überwachen:

pi@raspberrypi:~ $ mosquitto_sub -u systemreader -P test -t "#" -v
datensammlung/revpi01/door_corridor 0
datensammlung/revpi01/door_workshop 1
datensammlung/revpi01/temp_heater 225
datensammlung/revpi01/temp_outside 287
So geht es weiter

Nun empfangen wir die Daten per MQTT auf unserem Cloud-Server. Dieser soll die Daten nun speichern. Dies zeigen wir in dem nächsten Blogeintrag.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.