MQTT & Python

Dans ce tutoriel j’ai essayé de simplifier au maximum la mise en œuvre de MQTT en Python. J’ai pour cela utilisé la librairie Paho MQTT pour Python mise à disposition par la Fondation Eclipse.

Comme je l’avais déjà fait pour Java, mon objectif est de réduire cet exemple au strict minimum: un programme qui envoie un message MQTT fixe (pahoTest001Producer.py), et un programme qui affiche les messages MQTT reçus (pahoTest001Consumer.py). Dans la terminologie MQTT on parle de publish et de subscribe. Une fois que l’on a compris les mécanismes de base, faire “mieux” n’est plus qu’une question d’algorithmique ☺

NB: Après quelques recherches sur le net j’étais tombé sur cet article dont je me suis largement inspiré pour le présent tutoriel: How to use MQTT in Python (Paho).

MQTT
MQTT

Quelques infos supplémentaires sur MQTT:


Installation de la bibliothèque Paho MQTT

Pour télécharger et installer la librairie Paho MQTT dans votre environnement Python nous allons utiliser l’outil pip3 de Python:

pip3 install paho-mqtt

Ce qui devrait vous donner un résultat du style:

login@host:dir$ pip3 install paho-mqtt
Collecting paho-mqtt
  Downloading paho-mqtt-1.6.1.tar.gz (99 kB)
     |████████████████████████████████| 99 kB 993 kB/s 
Building wheels for collected packages: paho-mqtt
  Building wheel for paho-mqtt (setup.py) ... done
  Created wheel for paho-mqtt: filename=paho_mqtt-1.6.1-py3-none-any.whl size=62114 sha256=b96320ee231c7ed052f07c704e22126b7aa4217a0b2f31185c705ab7dce73b80
  Stored in directory: /home/munier/.cache/pip/wheels/6a/48/01/c895c027e9b9367ec5470fbf371ee56e795a49ac6a19aa4c9f
Successfully built paho-mqtt
Installing collected packages: paho-mqtt
Successfully installed paho-mqtt-1.6.1

Envoi d’un message

Voici les principales étapes pour l’envoi d’un message MQTT:

  1. configuration du broker MQTT et génération du ID client unique

    import random
    from paho.mqtt import client as mqtt_client
    
    broker = 'test.mosquitto.org'
    port = 1883
    topic = "/foo"
    # generate client ID with pub prefix randomly
    client_id = f'python-mqtt-{random.randint(0, 1000)}'
    
  2. création du connecteur MQTT (client) et connection au broker MQTT

    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)
    
    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    
  3. création d’un message MQTT (payload = chaîne de caractères) puis publication sur le broker

    msg = "A single message from my computer"
    result = client.publish(topic, msg)
    # result: [0, 1]
    status = result[0]
    if status == 0:
        print(f"Send `{msg}` to topic `{topic}`")
    else:
        print(f"Failed to send message to topic {topic}")
    
Code source complet du script pahoTest001Producer.py

# python 3.6

import random
import time

from paho.mqtt import client as mqtt_client

# --------------------------------------------------

broker = 'test.mosquitto.org'
port = 1883
topic = "/foo"
# generate client ID with pub prefix randomly
client_id = f'python-mqtt-{random.randint(0, 1000)}'

# --------------------------------------------------

def connect_mqtt():
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client

# --------------------------------------------------

def publish(client):
    time.sleep(1)
    
    msg = "A single message from my computer"
    result = client.publish(topic, msg)
    # result: [0, 1]
    status = result[0]
    if status == 0:
        print(f"Send `{msg}` to topic `{topic}`")
    else:
        print(f"Failed to send message to topic {topic}")

# --------------------------------------------------

def run():
    client = connect_mqtt()
    client.loop_start()
    publish(client)

# --------------------------------------------------

if __name__ == '__main__':
    run()

# --------------------------------------------------


Réception d’un message

Voici les principales étapes pour la réception d’un message MQTT (NB: les 2 premières étapes sont strictement similaires à celles de la section précédente):

  1. configuration du broker MQTT et génération du ID client unique

    import random
    from paho.mqtt import client as mqtt_client
    
    broker = 'test.mosquitto.org'
    port = 1883
    topic = "/foo"
    # generate client ID with pub prefix randomly
    client_id = f'python-mqtt-{random.randint(0, 1000)}'
    
  2. création du connecteur MQTT (client) et connection au broker MQTT

    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)
    
    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    
  3. configuration du client pour définir l’action à exécuter (notion de callback) à réception d’un message; ici on appelera la fonction on_message(...)

    def on_message(client, userdata, msg):
        s = str(msg.payload.decode("utf-8"))
        print(f"Received `{s}` from `{msg.topic}` topic")
    
    client.on_message = on_message
    
  4. souscription du client au topic foo sur le broker MQTT; dès qu’un client publiera un message sur ce topic, le broker le diffusera à tous les autres clients qui y auront souscrit

    client.subscribe(topic)
    
Code source complet du script pahoTest001Consumer.py

# python3.6

import random

from paho.mqtt import client as mqtt_client

# --------------------------------------------------

broker = 'test.mosquitto.org'
port = 1883
topic = "/foo"
# generate client ID with pub prefix randomly
client_id = f'python-mqtt-{random.randint(0, 100)}'

# --------------------------------------------------

def connect_mqtt() -> mqtt_client:
    def on_connect(client, userdata, flags, rc):
        if rc == 0:
            print("Connected to MQTT Broker!")
        else:
            print("Failed to connect, return code %d\n", rc)

    client = mqtt_client.Client(client_id)
    client.on_connect = on_connect
    client.connect(broker, port)
    return client

# --------------------------------------------------

def subscribe(client: mqtt_client):
    def on_message(client, userdata, msg):
        s = str(msg.payload.decode("utf-8"))
        print(f"Received `{s}` from `{msg.topic}` topic")

    client.subscribe(topic)
    client.on_message = on_message

# --------------------------------------------------

def run():
    client = connect_mqtt()
    subscribe(client)
    client.loop_forever()

# --------------------------------------------------

if __name__ == '__main__':
    run()

# --------------------------------------------------


Exécution de cet exemple

  • Exécuter les 2 programmes dans 2 terminaux différents en démarrant le consumer en $1^{er}$ pour qu’il soit bien à l’écoute quand le producer enverra le message:
    python3 pahoTest001Consumer.py
    python3 pahoTest001Producer.py
    
Suivant