Python MQTT Einführungstutorial

21.02.2021

Tutorial

Mein Python MQTT Tutorial soll dir in ein paar Beispielen zeigen, wie du ganz leicht MQTT-Nachrichten mit Python senden und empfangen kannst. Die Grundlagen habe ich bereits in meiner MQTT Raspberry Pi Einführung vorgestellt. Diese Python MQTT Einführung soll dir jedoch darüber hinaus weitere Funktionen und Anwendungsbeispiele verdeutlichen.  

Inhaltsverzeichnis

  1. MQTT mit dem Raspberry Pi und dem ESP8266
  2. Was ist MQTT?
  3. Quality of Service Levels
  4. Python MQTT Bibliothek
  5. Kostenlose MQTT Broker
  6. MQTT Nachrichten empfangen
  7. MQTT Nachrichten versenden
  8. MQTT Last Will Nachricht konfigurieren
  9. Mit Nutzername und Password am Broker anmelden

Weitere MQTT Tutorials

Ich habe bereits zwei weitere MQTT-Tutorials hier veröffentlicht. Eines für den Raspberry Pi und eines für den NodeMCU ESP8266. Dort gehe ich auf bereits auf ein paar der Punkte ein, die ich in diesem Guide erkläre. Sieh dir die beiden Tutorials auf jeden Fall an, wenn du den Raspberry Pi oder ESP8266 mit MQTT in dein Smarthome integrieren möchtest!

MQTT Grundlagen

Bevor mit der Programmierung des Tutorials begonnen wird, möchte ich die Grundlagen des MQTT-Standards erklären.

Was ist MQTT?

Bei MQTT handelt es sich um ein Publish-Subscribe-Messaging-Protokoll. Beim Publish-Subscribe-Modell gibt es Themen, die abonniert (subscribe) und auf denen Daten veröffentlicht (publish) werden können. Teilnehmer, die ein Thema abonniert haben, erhalten alle Daten, die auf diesem Kanal veröffentlicht werden. In der Mitte des Netzwerks befindet sich ein Broker, der als Server agiert und der die gesamte Kommunikation aller Teilnehmer verwaltet. Das Publish-Subscribe-Modell eignet sich vor allem für Anwendungen im Bereich Internet of Things, da dort sehr viele Daten gesammelt und mit anderen Geräten geteilt werden. Durch die Einteilung in einzelne Themen-Kanäle können die Daten gezielter verteilt werden. Im Smarthome wird beispielsweise für jeden Raum ein Kanal angelegt und in diesem Kanal ein Unterkanal für jedes Gerät. Ein Bewegungsmelder im Wohnzimmer würde dann seine Daten auf dem Kanal "Wohnzimmer/Bewegung" veröffentlichen. Die Lampen im Wohnzimmer können dann auf neue Daten in diesem Kanal reagieren und zum Beispiel das Licht einschalten, wenn der Bewegungsmelder eine neue Bewegung meldet. Zusätzlich zu den normalen Nachrichten, gibt es auch sogenannte Last Will Messages, die automatisch versendet werden können, wenn die Verbindung eines Geräts unerwartet getrennt wird. Im Smarthome kann so zum Beispiel eine Nachricht gesendet werden, wenn der Akku eines Sensors leer ist.

MQTT Quality of Service (QoS)

Der MQTT-Standard verfügt über drei unterschiedliche "Qualitätsstufen" (Quality of Service oder QoS). Sie geben an, wie zuverlässig die Zustellung der Nachrichten ist. Die verfügbaren QoS-Levels:
  • Nachricht kommt höchstens einmal an (0)
  • Nachricht kommt mindestens einmal an (1)
  • Nachricht kommt genau einmal an (2)

QoS Level 0: Nachricht kommt höchstens einmal an

Das unterste Quality of Service Level im MQTT-Standard garantiert nicht, dass die Nachrichten auch ankommen. Vielmehr wird eine Nachricht gesendet und nicht geprüft, ob die Nachricht auch ankommt. Geht die Nachricht aufgrund von Verbindungsabbrüchen oder sonstigen technischen Problemen verloren, wird sie nicht erneut gesendet.
Beim QoS Level 0 wird nur eine einzige Nachricht versendet. Beim QoS Level 0 wird nur eine einzige Nachricht versendet.
Das QoS-Level 0 eignet sich also im Smarthome in den meisten Fällen nicht für den produktiven Einsatz, da nicht sichergestellt ist, dass die Nachrichten auch ankommen. Dabei könnten beispielsweise Sensorwerte verloren gehen oder Geräte nicht auf Schaltbefehle reagieren.

QoS Level 1: Nachricht kommt mindestens einmal an

Das nächst-höhere Level besitzt bereits eine Prüfung, ob die gesendete Nachricht auch beim Empfänger angekommen ist. Dies geschieht durch eine Bestätigung des Empfängers, die an den Absender der Nachricht geschickt wird. Falls jedoch die Empfangsbestätigung verloren geht, sendet der Absender die Nachricht solange erneut, bis er eine Empfangsbestätigung empfängt.
Das QoS-Level 1 erhält bereits eine Empfangsbestätigung. Das QoS-Level 1 erhält bereits eine Empfangsbestätigung.
Dieses QoS-Level eignet sich beim Einsatz im Smarthome in den meisten Fällen für alle Schaltbefehle. Falls beispielsweise die Nachricht "Flur-Licht an" doppelt gesendet wird, geht das Licht an und die doppelte Nachricht ändert nichts daran. Lediglich bei Toggles (z.B. Licht umschalten) kann es zu Problemen führen, wenn eine Nachricht doppelt gesendet wird. Der erste Befehl schaltet hier das Gerät zum Beispiel an, während der zweite Befehl das Gerät sofort wieder ausschalten würde. Für das Loggen von Sensorwerten macht das QoS-Level 1 nur wenig Sinn, da Sensorwerte dann doppelt gespeichert werden könnten. Abhilfe schafft hier das QoS-Level 2.

QoS Level 2: Nachricht kommt genau einmal an

Ähnlich wie das QoS-Level 1 besitzt auch Level 2 eine Empfangsbestätigung - jedoch wird die Empfangsbestätigung ebenfalls bestätigt und die komplette Transaktion damit abgeschlossen. Geht eine der Bestätigungen dabei verloren, so wird die ursprüngliche Nachricht erneut gesendet, jedoch mit dem Hinweis, dass es sich um ein Duplikat handelt. Der Empfänger kann diese Nachricht dann ignorieren, wenn er sie beim ersten Versuch bereits empfangen hat und anschließend seine Empfangsbestätigung senden. Diese Prozedur wird so oft wiederholt, bis alle Empfangsbestätigungen empfangen wurden.
Das QoS-Level 2 erhält auch eine zweite Empfangsbestätigung, damit der Erhalt aller Nachrichten gewährleistet werden kann. Das QoS-Level 2 erhält auch eine zweite Empfangsbestätigung, damit der Erhalt aller Nachrichten gewährleistet werden kann.
Somit eignet sich das QoS-Level 2 also auch für Toggles oder den Versand von Sensorwerten, da Duplikate von Nachrichten entsprechend gekennzeichnet sind und so nicht zu doppelten Daten führen.

Welches Quality of Service Level soll ich verwenden?

Im Smarthome dürfte das QoS-Level 0 in nahezu keinem Anwendungsfall Sinn machen, da nicht garantiert werden kann, dass die Nachricht überhaupt ankommt. QoS-Level 1 hingegen reicht für alle Befehle aus, die einen festen Status setzen ("Gerät x an", "Heizung auf 25°C", "Lampe auf 100%"), jedoch weniger für das Loggen von Sensordaten oder Toggle-Befehle ("Lampe umschalten"), da das potenzielle doppelte Senden dieser Befehle den Status verfälscht. QoS-Level 2 eignet sich dagegen am besten für das Loggen von Sensorwerten und Toggle-Befehle, da sichergestellt ist, dass jede Nachricht genau einmal empfangen wird.

MQTT-Client für Python 2

Um den MQTT-Client für Python Version 2.x zu installieren, führst du die folgenden Befehle auf der Kommandozeile aus:
        
            
sudo apt-get install python-pip -y
sudo pip install paho-mqtt
        
    

MQTT-Client für Python 3

Falls du Python Version 3.x verwendet, führst du hingegen die folgenden Befehle auf der Kommandozeile aus:
        
            
sudo apt-get install python3-pip -y
sudo pip3 install paho-mqtt
        
    

Kostenlose MQTT Broker

Es gibt ein paar kostenlose und öffentliche MQTT-Broker, die du zum Testen von deinen Projekten benutzen kannst:
  • mqtt.eclipse.org
  • broker.hivemq.com
Da diese Broker jedoch für jeden öffentlich zugänglich sind, solltest du keine sensiblen Daten darüber versenden.

Für den produktiven Einsatz solltest du daher unbedingt einen eigenen MQTT-Broker verwenden. Ich habe hier bereits ein Tutorial veröffentlicht, dass dir erklärt, wie du einen Raspberry Pi als MQTT-Broker einsetzen kannst:

Raspberry Pi MQTT Tutorial 

MQTT Nachrichten mit Python empfangen

Das erste Skript, dass erstellt werden muss, ist das Empfänger-Skript. Es abonniert Nachrichten aus einer bestimmten Topic und gibt alle Nachrichten aus, die darauf veröffentlicht werden. Für dieses Tutorial benutze ich den öffentlichen MQTT-Broker von HiveMQT.[/vc_column_text]Für das Empfänger-Skript fügst du den folgenden Code in deine IDE ein und führst ihn aus:
        
            
# !/usr/bin/python
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt

TOPIC = "home/tutorial/PubSubDemo"
BROKER_ADDRESS = "broker.hivemq.com"
PORT = 1883

def on_message(client, userdata, message):
    msg = str(message.payload.decode("utf-8"))
    print("message received: ", msg)
    print("message topic: ", message.topic)

def on_connect(client, userdata, flags, rc):
    print("Connected to MQTT Broker: " + BROKER_ADDRESS)
    client.subscribe(TOPIC)

if __name__ == "__main__":
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message

    client.connect(BROKER_ADDRESS, PORT)

    client.loop_forever()
        
    
Der Code verbindet sich mit dem HiveMQ-Broker und abonniert das Topic "home/tutorial/PubSubDemo". Dann wartet er auf Nachrichten auf diesem Kanal und gibt alle aus.

MQTT Nachrichten mit Python verschicken

Als nächstes wird ein Skript erstellt, das eine Nachricht auf dem Topic "home/tutorial/PubSubDemo" mit dem QoS-Level 1 veröffentlicht. Füge einfach den folgenden Code ein und führe ihn aus (das erste Skript muss ebenfalls aktiv sein):
        
            
# !/usr/bin/python
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt

TOPIC = "home/tutorial/PubSubDemo"
BROKER_ADDRESS = "broker.hivemq.com"
PORT = 1883
QOS = 1

if __name__ == "__main__":
    client = mqtt.Client()

    client.connect(BROKER_ADDRESS, PORT)

    print("Connected to MQTT Broker: " + BROKER_ADDRESS)

    DATA = "{TEST_DATA}"

    client.publish(TOPIC, DATA, qos=QOS)

    client.loop()
        
    

Last Will Nachricht

Der MQTT-Standard ermöglicht es auch, andere Geräte zu benachrichtigen, wenn ein Gerät die Verbindung verliert. Dies ist möglich durch die sogenannte Last Will-Message (deutsch: Letzter Wille). Diese Nachricht kann vom Client gesetzt werden und wird dann vom Broker an alle Subscriber einer definierten Topic gesendet. Im Smarthome-Einsatz ließe sich damit etwa das Gateway benachrichtigen, dass ein Gerät die Verbindung verloren hat.

Last Will Nachricht senden

Im folgenden Beispiel zeige ich dir, wie du mit Python ganz einfach eine Last Will Message per MQTT versenden kannst.Als Empfänger wird wieder das Skript aus dem ersten Abschnitt dieses Tutorials verwendet. Die Last Will Nachricht wird dann auf dem entsprechenden Topic veröffentlicht.Der andere Client setzt auf der Topic "home/tutorial/PubSubDemo" als Last Will Message die Nachricht "Verbindung beendet!", verbindet sich dann mit dem Broker und veröffentlicht danach die Nachricht "Hello World!" auf der selben Topic. Als Quality of Service wird Level 1 verwendet, alle Nachrichten kommen also mindestens einmal beim Empfänger an. Verliert er die Verbindung, so veröffentlicht er also die Nachricht "Verbindung beendet!" auf dem Kanal "home/tutorial/PubSubDemo". Um dies zu simulieren, wird das Skript beendet, ohne die Verbindung zum Broker ordnungsgemäß zu beenden. Dies sorgt dafür, dass der Broker die Last Will Message auf dem entsprechenden Topic veröffentlicht.
        
            
# !/usr/bin/python
# -*- coding: utf-8 -*-

import paho.mqtt.client as mqtt

TOPIC = "home/tutorial/PubSubDemo"
BROKER_ADDRESS = "broker.hivemq.com"
PORT = 1883
QOS = 1

if __name__ == "__main__":
    client = mqtt.Client()

    LAST_WILL = "Verbindung beendet!"
    client.will_set(TOPIC, LAST_WILL, qos=QOS, retain=False)

    client.connect(BROKER_ADDRESS, PORT)
    print("Connected to MQTT Broker: " + BROKER_ADDRESS)

    DATA = "{TEST_DATA}"
    client.publish(TOPIC, DATA, qos=QOS)

    client.loop()
        
    
Um nun das Beispiel zu testen, startest du den Empfänger-Code und führst anschließend den Absender-Code aus. Der Empfänger sollte nun die Nachricht "Hello World!" erhalten und kurz darauf die Nachricht "Verbindung beendet!".
Die Ausgabe des Empfänger-Skripts sollte in etwa so aussehen. Die Ausgabe des Empfänger-Skripts sollte in etwa so aussehen.

Verbindung zu einem MQTT-Broker mit Zugangsdaten

Damit nicht jeder Zugang zu den veröffentlichten Nachrichten bekommt, ist es möglich, verschiedene Topics mit einem Nutzernamen und einem Passwort zu schützen. Um dich mit deinem Python-Skript an einem geschützten Broker anzumelden, kannst du einfach das folgende Code-Snippet verwenden und die entsprechenden Zugangsdaten einsetzen
        
            
client = mqtt.Client()
client.username_pw_set("my_username", "my_password")
        
    

Fazit

Ich hoffe, dass dir mein Python MQTT Tutorial einen guten Einblick in das MQTT-Protokoll geben konnte!