Zum Versenden der eingelesenen Sensordaten zu Temperatur, Luftfeuchtigkeit und Co2-Wert wird ein MQTT-Client verwendet. In unserem Projekt wird dies durch die Python Bibliothek Paho-Python umgesetzt. Dazu können große Teile des Beispielcodes von Herrn Schulmeister übernommen werden. Lediglich die Adresse des Brokers, die Namen der zu verwendenden Topics, sowie ein Benutzername und ein Kennwort für den Zugriff auf den Broker müssen geändert, bzw. gesetzt werden.

Da der Broker von HiveMQ unter der Adresse broker.hivemq.com zwar einfach aufzurufen ist, aber auch öffentlich zugänglich haben wir uns dazu entschieden einen privaten Broker zu nutzen. Dabei sind wir auf das BASIC Paket der HiveMQ Cloud aufmerksam geworden, welches einen kostenlosen, privaten Broker zur Verfügung stellt. Die mit der kostenlosen Version einhergehenden Einschränkungen sind dabei für unser Projekt kaum ein Hindernis.

Meldet man sich bei dem Broker an, bietet sich die Möglichkeit, ein neues Cluster mit einer eigenen URL zu erstellen und dieses zu verwalten. Es können unterschiedliche Nutzernamen und zugehörige Kennwörter erstellt werden.

Beim erstellen eines Clusters kann auch gewählt werden, ob es durch Amazon Webservices oder durch die Microsoft Azure Cloud gehostet werden soll. Außerdem bietet HiveMQ im Cluster einen leicht verständlichen Getting-Started Guide an, dem man bei der Einbindung folgen kann.

Ein einfaches Testprogramm welches an eine Topic des Brokers sendet, sowie das Gegenstück, welches die Daten empfängt waren mit Hilfe des Guides schnell aufgesetzt:
sowohl der Sender:

import paho.mqtt.client as mqtt
import time

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected successfully")
    else:
        print("Connect returned result code: " + str(rc))

# create the client
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

# enable TLS
client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS)

# set username and password
client.username_pw_set("XXXXXXX", "XXXXXXXX")

# connect to HiveMQ Cloud on port 8883
client.connect("XXXXXXXXXXXXXXXXXXX.s1.eu.hivemq.cloud", 8883)

count = 0
while 1:
    count= count+1
    client.publish("XXXX/XXXX/XXX", "" + str(count) + "te Nachricht")
    time.sleep(2)

# Blocking call that processes network traffic, dispatches callbacks and handles reconnecting.
client.loop_forever()

Als auch der Empfänger:

import paho.mqtt.client as mqtt

# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, rc):
    if rc == 0:
        print("Connected successfully")
    else:
        print("Connect returned result code: " + str(rc))

# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
    print("Received message: " + msg.payload.decode("utf-8"))

# create the client
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

# enable TLS
client.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS)

# set username and password
client.username_pw_set("XXXXXXXXXX", "XXXXXXXXXXXXX")

#connect to the broker and subscribe to a topic 
client.connect("XXXXXXXXXXXXXXXXXXXXX.s1.eu.hivemq.cloud", 8883)
client.subscribe("XXXX/XXXX/XXX")

client.loop_forever()

Bei der Einbindung in den Programmcode auf dem Pi kam es jedoch zu kurzzeitigen Schwierigkeiten: Es konnte keine Verbindung zum Broker hergestellt werden.
Wie sich dann herausgestellt hat, ist es notwendig den MQTT-Client so zu konfigurieren, dass er eine verschlüsselt Verbindung zulässt. Dies ist über folgenden Befehl möglich, welcher im Testcode bereits verwendet wurde, in der Vorlage zu diesem Zeitpunkt jedoch noch nicht eingebunden war:

self._mqtt.tls_set(tls_version=mqtt.ssl.PROTOCOL_TLS)

Weitere Informationen dazu sind auch im Blogbeitrag von Herrn Schulmeister nachzulesen. Der dort veröffentlichte Commit, welcher eine Abfrage, ob TLS verwendet werden soll mitbringt, konnte jedoch zum aktuellen Zeitpunkt noch nicht erfolgreich in unseren Code eingebunden werden. So ist die Verbindung mit TLS bei uns hardcodiert aktiviert.
Sollte es noch gelingen den Code so anzupassen, dass es funktioniert, wird hier im Blog (als Edit oder Comment) ein Update erfolgen.

Aber auch so, wie es aktuell ist, ist es möglich Daten per MQTT zu senden und auch wieder zu empfangen. Im Folgenden ein Beispiel eines von unserem Raspberry Pi versendeten, und von oben genanntem Testempfänger empfangenen Datensatzes:

Received message: [{"_id": "1624283334375-0", "_device_uuid": "▮▮▮▮▮▮▮▮▮▮▮▮▮", "_device_type": "raspberrypi4-64", "_app_id": "1", "_app_name": "localapp", "temperatur": "27", "feuchtigkeit": "53", "co2_wert": "728"}]

Update:

Durch eine Änderung der Reihenfolge der Aufrufe konnte der Code von Herrn Schulmeister für unser Projekt lauffähig gemacht werden:

vorher:

self._mqtt = mqtt.Client()
        self._mqtt.on_connect = self._on_mqtt_connect
        self._mqtt.on_disconnect = self._on_mqtt_disconnect

        self._mqtt.connect(host=self._mqtt_config["host"], port=self._mqtt_config["port"], keepalive=self._mqtt_config["keepalive"])

        if self._mqtt_config["tls_ca_certs"] or self._mqtt_config["tls_certfile"] or self._mqtt_config["tls_keyfile"]:
            self._logger.info(
                "Setze TLS-Parameter für die MQTT-Verbindung: "
                "tls_ca_certs=%(tls_ca_certs)s, tls_certfile=%(tls_certfile)s, tls_keyfile=%(tls_keyfile)s" % self._mqtt_config
            )

            self._mqtt.tls_set(tls_version=ssl.PROTOCOL_TLS, ca_certs=self._mqtt_config["tls_ca_certs"], certfile=self._mqtt_config["tls_certfile"], keyfile=self._mqtt_config["tls_keyfile"])
        elif self._mqtt_config["tls_enable"]:
            self._logger.info("Aktiviere TLS/SSL-Verschlüsselung")
            self._mqtt.tls_set(tls_version=ssl.PROTOCOL_TLS)

        if self._mqtt_config["tls_insecure"]:
            self._logger.info("Erlaube unsichere TLS-Zertifikate für die Verbindung zum MQTT-Broker")
            self._mqtt.tls_insecure_set(True)

        if self._mqtt_config["username"] or self._mqtt_config["password"]:
            self._logger.info("Setze Benutzername und Passwort für den MQTT-Broker")
            self._mqtt.username_pw_set(username=self._mqtt_config["username"], password=self._mqtt_config["password"])

nachher:

        self._mqtt = mqtt.Client()
        self._mqtt.on_connect = self._on_mqtt_connect
        self._mqtt.on_disconnect = self._on_mqtt_disconnect


        if self._mqtt_config["username"] or self._mqtt_config["password"]:
            self._logger.info("Setze Benutzername und Passwort für den MQTT-Broker")
            self._mqtt.username_pw_set(username=self._mqtt_config["username"], password=self._mqtt_config["password"])

        if self._mqtt_config["tls_insecure"]:
            self._logger.info("Erlaube unsichere TLS-Zertifikate für die Verbindung zum MQTT-Broker")
            self._mqtt.tls_insecure_set(True)

        if self._mqtt_config["tls_ca_certs"] or self._mqtt_config["tls_certfile"] or self._mqtt_config["tls_keyfile"]:
            self._logger.info(
                "Setze TLS-Parameter für die MQTT-Verbindung: "
                "tls_ca_certs=%(tls_ca_certs)s, tls_certfile=%(tls_certfile)s, tls_keyfile=%(tls_keyfile)s" % self._mqtt_config
            )

            self._mqtt.tls_set(tls_version=ssl.PROTOCOL_TLS, ca_certs=self._mqtt_config["tls_ca_certs"], certfile=self._mqtt_config["tls_certfile"], keyfile=self._mqtt_config["tls_keyfile"])

        elif self._mqtt_config["tls_enable"]:
            self._logger.info("Aktiviere TLS/SSL-Verschlüsselung")
            self._mqtt.tls_set(tls_version=ssl.PROTOCOL_TLS)

        self._mqtt.connect(host=self._mqtt_config["host"], port=self._mqtt_config["port"], keepalive=self._mqtt_config["keepalive"])

außerdem musste in den Imports der Import „ssl“ hinzugefügt werden, oder statt ssl.PROTOCOL_TLS die version mqtt.ssl.PROTOCOL_TLS verwendet werden.

MQTT in Python und die Probleme mit der Verschlüsselung

Schreibe einen Kommentar