Raspberry Pi

Tutoriel MQTT Raspberry Pi : publier, s'abonner et automatiser avec Python

Un tutoriel MQTT Raspberry Pi complet : créez un environnement virtuel Python, publiez la température du CPU et des mesures de capteurs, commandez une LED via MQTT, exécutez le script comme service et passez à TLS avec vos propres identifiants.

Carte Raspberry Pi reliée à une LED et à un capteur publiant des données vers un broker cloud dans un tutoriel MQTT Raspberry Pi
Essayez-le sur votre propre broker MQTTObtenez un broker MQTT privé et managé avec l’offre Free et partez d’exemples de code prêts à l’emploi.
Essayer gratuitement Exemples de code Aucune carte bancaire requise

Ce tutoriel MQTT Raspberry Pi vous mène d'une installation fraîche de Raspberry Pi OS à un programme Python qui publie des mesures de capteurs, écoute des commandes et commute une broche GPIO depuis n'importe où. Vous testerez tout sur le serveur MQTT public gratuit broker.connectmq.com, puis transférerez le même code vers un broker privé sécurisé par TLS grâce à quelques variables d'environnement. En chemin, vous apprendrez les patterns qui gardent un équipement IoT à base de Pi fiable pendant des mois, et pas seulement quelques minutes.

Ce que vous allez construire

À la fin de ce guide, votre Raspberry Pi exécutera un unique service Python qui fait quatre choses :

  1. Il se connecte à un broker MQTT et se reconnecte automatiquement après une coupure Wi-Fi ou un redémarrage.
  2. Il publie toutes les dix secondes un message de télémétrie JSON avec la température du CPU, la charge moyenne et, en option, un capteur d'ambiance.
  3. Il s'abonne à un topic de commande et commute une LED (ou un relais) sur la GPIO17.
  4. Il publie un statut en ligne/hors ligne retenu, en utilisant un Last Will MQTT pour que les autres clients sachent quand le Pi disparaît.

L'organisation des topics regroupe tout sous un préfixe unique, ce qui compte sur un broker public partagé :

Topic Sens Exemple de payload Retenu
connectmq/demo/<deviceId>/telemetry Le Pi publie {"cpu_temp":48.3,"load":0.21} Non
connectmq/demo/<deviceId>/led/set Le Pi s'abonne ON, OFF, TOGGLE Non
connectmq/demo/<deviceId>/led/state Le Pi publie ON ou OFF Oui
connectmq/demo/<deviceId>/status Le Pi publie + Last Will online ou offline Oui

Si des termes comme topic, retained message ou Last Will sont nouveaux pour vous, parcourez ce que fait un broker MQTT avant de commencer. En bref : le broker est un bureau de poste, votre Pi et votre ordinateur portable sont des clients, et les topics sont les adresses.

Prérequis

Ce tutoriel MQTT Raspberry Pi demande très peu de matériel :

  • N'importe quel Raspberry Pi avec réseau : Pi 3, Pi 4, Pi 5 ou Zero 2 W. Le code est identique sur tous.
  • Raspberry Pi OS Bookworm (la version Lite convient), avec SSH activé et un accès réseau.
  • Une LED avec une résistance de 330 ohms, ou un module relais, sur la GPIO17 (broche physique 11) et GND (broche 9). Sans elle, le code fonctionne quand même et se contente de journaliser les commandes.
  • En option : un capteur DHT22 ou DS18B20. Nous commençons avec la température intégrée du CPU, donc rien de plus n'est nécessaire.
  • Une seconde machine avec mosquitto_sub et mosquitto_pub pour les tests (installez mosquitto-clients sous Linux, ou utilisez Homebrew sous macOS).

Vous comparez les cartes avant d'acheter ? Notre comparatif Raspberry Pi vs ESP32 explique quand un vrai ordinateur Linux l'emporte sur un microcontrôleur, et quand c'est disproportionné.

Étape 1 : préparer Python sur le Raspberry Pi

Bookworm protège le Python du système : pip install en dehors d'un environnement virtuel échoue avec une erreur « externally managed environment ». C'est une bonne chose : un environnement virtuel garde les dépendances de votre projet isolées et reproductibles. Créez-en un dans un dossier de projet :

sudo apt update
sudo apt install -y python3-venv python3-lgpio mosquitto-clients
mkdir -p ~/pi-mqtt && cd ~/pi-mqtt
python3 -m venv --system-site-packages .venv
source .venv/bin/activate
pip install "paho-mqtt>=2.0" gpiozero

L'option --system-site-packages permet à l'environnement virtuel de voir le paquet lgpio installé par apt, que gpiozero utilise comme backend de broches sur les versions actuelles de Raspberry Pi OS (et qui est indispensable sur le Pi 5, où l'ancienne bibliothèque RPi.GPIO ne fonctionne pas). Consultez la documentation GPIO officielle de Raspberry Pi pour le brochage de votre modèle.

Vérifiez la version du client installée. Ce guide utilise l'API de callbacks de paho-mqtt 2.x, différente de celle des anciens tutoriels que vous pourriez trouver en ligne :

python -c "import paho.mqtt; print(paho.mqtt.__version__)"

Étape 2 : votre premier publish et subscribe

Avant d'écrire le programme complet, vérifiez que le chemin réseau fonctionne. Choisissez un identifiant d'équipement aléatoire pour que vos topics n'entrent pas en collision avec ceux des autres sur le broker public. Dans un terminal (sur votre portable ou sur le Pi), abonnez-vous :

mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-laptop-7f3a -v -t "connectmq/demo/pi-7f3a/#"

Dans un second terminal, publiez un message de test :

mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-pi-7f3a -t "connectmq/demo/pi-7f3a/hello" -m "hello from the pi"

L'abonné affiche immédiatement le topic et le message. Chaque client a besoin d'un client ID non vide et unique ; si deux clients partagent un ID, le broker déconnecte le plus ancien et vous observerez une boucle connexion-déconnexion déroutante. Le serveur MQTT public gratuit est lisible par quiconque devine votre topic : n'envoyez donc jamais de mots de passe, de données personnelles ni rien que vous ne publieriez pas publiquement.

Étape 3 : le client MQTT Python complet

Enregistrez ce qui suit sous ~/pi-mqtt/pi_mqtt.py. Il lit tous ses réglages depuis des variables d'environnement : le même fichier fonctionne donc aujourd'hui avec le broker public et plus tard avec un broker privé.

#!/usr/bin/env python3
"""Raspberry Pi MQTT client: telemetry, GPIO control and online status."""
import json
import os
import signal
import ssl
import threading
import time
import uuid

import paho.mqtt.client as mqtt

try:
    from gpiozero import LED
    led = LED(int(os.getenv("LED_PIN", "17")))
except Exception as exc:  # pas de GPIO (ex. tests sur un ordinateur portable)
    print(f"GPIO unavailable, running without LED: {exc}")
    led = None

HOST = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USE_TLS = os.getenv("MQTT_TLS", "0") == "1"
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
DEVICE_ID = os.getenv("DEVICE_ID", f"pi-{uuid.uuid4().hex[:6]}")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", DEVICE_ID)
PREFIX = os.getenv("TOPIC_PREFIX", f"connectmq/demo/{DEVICE_ID}")
INTERVAL = float(os.getenv("PUBLISH_INTERVAL", "10"))

T_TELEMETRY = f"{PREFIX}/telemetry"
T_LED_SET = f"{PREFIX}/led/set"
T_LED_STATE = f"{PREFIX}/led/state"
T_STATUS = f"{PREFIX}/status"

stop_event = threading.Event()


def read_cpu_temp() -> float:
    with open("/sys/class/thermal/thermal_zone0/temp") as f:
        return round(int(f.read().strip()) / 1000.0, 1)


def publish_led_state(client: mqtt.Client) -> None:
    state = "ON" if (led and led.is_lit) else "OFF"
    client.publish(T_LED_STATE, state, qos=1, retain=True)


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connect failed: {reason_code}")
        return
    print(f"Connected to {HOST}:{PORT} as {CLIENT_ID}")
    client.publish(T_STATUS, "online", qos=1, retain=True)
    client.subscribe(T_LED_SET, qos=1)
    publish_led_state(client)


def on_disconnect(client, userdata, disconnect_flags, reason_code, properties):
    print(f"Disconnected ({reason_code}), paho will retry automatically")


def on_message(client, userdata, msg):
    command = msg.payload.decode("utf-8", errors="ignore").strip().upper()
    print(f"Command on {msg.topic}: {command}")
    if led is None:
        return
    if command == "ON":
        led.on()
    elif command == "OFF":
        led.off()
    elif command == "TOGGLE":
        led.toggle()
    else:
        print("Unknown command, ignoring")
        return
    publish_led_state(client)


def build_client() -> mqtt.Client:
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
    if USERNAME:
        client.username_pw_set(USERNAME, PASSWORD)
    if USE_TLS:
        client.tls_set(cert_reqs=ssl.CERT_REQUIRED)
    client.will_set(T_STATUS, "offline", qos=1, retain=True)
    client.reconnect_delay_set(min_delay=1, max_delay=60)
    client.on_connect = on_connect
    client.on_disconnect = on_disconnect
    client.on_message = on_message
    return client


def main() -> None:
    client = build_client()
    client.connect_async(HOST, PORT, keepalive=30)
    client.loop_start()

    signal.signal(signal.SIGTERM, lambda *_: stop_event.set())
    signal.signal(signal.SIGINT, lambda *_: stop_event.set())

    while not stop_event.is_set():
        if client.is_connected():
            payload = {
                "cpu_temp": read_cpu_temp(),
                "load": round(os.getloadavg()[0], 2),
                "ts": int(time.time()),
            }
            client.publish(T_TELEMETRY, json.dumps(payload), qos=0)
        stop_event.wait(INTERVAL)

    client.publish(T_STATUS, "offline", qos=1, retain=True).wait_for_publish(2)
    client.loop_stop()
    client.disconnect()


if __name__ == "__main__":
    main()

Exécutez-le avec un identifiant d'équipement fixe pour savoir quels topics surveiller :

cd ~/pi-mqtt && source .venv/bin/activate
DEVICE_ID=pi-7f3a python pi_mqtt.py

Comment fonctionne le code

Quelques choix de conception méritent d'être compris, car c'est là que la plupart des projets Pi dérapent :

  • connect_async combiné à loop_start exécute la boucle réseau dans un thread en arrière-plan et laisse paho réessayer aussi la première connexion. Un simple connect() lève une exception et tue le script si le réseau n'est pas encore disponible, ce qui est fréquent juste après le démarrage.
  • Le Last Will (will_set) est stocké par le broker au moment de la connexion. Si le Pi perd l'alimentation, le broker publie offline à votre place après l'expiration du keepalive. Le chemin d'arrêt propre publie explicitement offline.
  • Les topics d'état retenus permettent à un tableau de bord qui se connecte plus tard de voir immédiatement l'état actuel de la LED et le statut en ligne, sans attendre le prochain changement.
  • S'abonner dans on_connect restaure l'abonnement après chaque reconnexion. S'abonner une seule fois après connect() est un bug classique qui interrompt silencieusement les commandes après le premier incident réseau.
  • QoS 1 pour les commandes et l'état, QoS 0 pour la télémétrie est un choix par défaut raisonnable. Perdre une mesure périodique est sans conséquence ; perdre une commande OFF ne l'est pas. Notre guide des niveaux de QoS MQTT détaille ces compromis.

Étape 4 : piloter les GPIO via MQTT

Le script étant en cours d'exécution, envoyez des commandes depuis votre portable :

mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-laptop-7f3a -q 1 -t "connectmq/demo/pi-7f3a/led/set" -m "ON"
mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-laptop-7f3a -q 1 -t "connectmq/demo/pi-7f3a/led/set" -m "TOGGLE"

La LED change d'état et la fenêtre de l'abonné affiche le nouvel état retenu sur led/state. Le même pattern pilote un relais pour une pompe, un ventilateur ou une gâche électrique ; remplacez simplement LED par gpiozero.OutputDevice et envisagez d'inverser la logique pour les cartes relais actives à l'état bas. Pour les boutons, la gradation PWM et les broches multiples, poursuivez avec le guide dédié GPIO du Raspberry Pi via MQTT, et pour le matériel commutant le secteur, lisez la commande de relais Raspberry Pi avec MQTT pour la sécurité du câblage.

Une règle pratique pour les actionneurs : c'est l'équipement, et non le tableau de bord, qui détient la vérité. Publiez toujours l'état réellement atteint par le matériel, et faites afficher ce topic d'état par les interfaces utilisateur plutôt que de supposer que la commande a fonctionné.

Étape 5 : ajouter un vrai capteur

La température du CPU valide le pipeline, mais la plupart des projets mesurent la pièce. Remplacez read_cpu_temp() par une fonction de lecture de capteur et ajoutez les valeurs au dictionnaire du payload. Le tableau ci-dessous résume les choix courants et où aller ensuite :

Capteur Interface Ce qu'il mesure Guide détaillé
DHT22 / AM2302 Une GPIO, sensible au timing Température, humidité DHT22 avec MQTT
DS18B20 1-Wire Température, sondes étanches DS18B20 avec MQTT
Sense HAT HAT I2C Température, humidité, pression, centrale inertielle Sense HAT vers MQTT
HC-SR04 Deux GPIO Distance, niveau de cuve Capteur de distance vers MQTT

Gardez les lectures de capteurs hors des callbacks MQTT. Les callbacks s'exécutent sur le thread réseau, et une lecture de capteur lente à cet endroit retarde la gestion du keepalive et des acquittements. La boucle principale du script ci-dessus est le bon endroit pour tout ce qui est bloquant.

Utilisez une forme JSON cohérente entre équipements : valeurs numériques, unités SI dans le nom de la clé ou dans un champ unit séparé, et un horodatage Unix. Chaque consommateur que vous ajouterez plus tard, de Grafana à Node-RED, vous en remerciera.

Étape 6 : lancer le script MQTT au démarrage avec systemd

Un script lancé depuis une session SSH s'arrête quand vous vous déconnectez. Transformez-le en service systemd pour qu'il démarre au boot et redémarre en cas d'échec. Créez /etc/systemd/system/pi-mqtt.service :

[Unit]
Description=Raspberry Pi MQTT client
After=network-online.target
Wants=network-online.target

[Service]
User=pi
WorkingDirectory=/home/pi/pi-mqtt
EnvironmentFile=/home/pi/pi-mqtt/.env
ExecStart=/home/pi/pi-mqtt/.venv/bin/python /home/pi/pi-mqtt/pi_mqtt.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

Remplacez pi par votre nom d'utilisateur, ajoutez l'utilisateur au groupe gpio si nécessaire (sudo usermod -aG gpio pi) et créez le fichier .env :

cat > ~/pi-mqtt/.env <<'EOF'
DEVICE_ID=pi-7f3a
PUBLISH_INTERVAL=10
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now pi-mqtt
journalctl -u pi-mqtt -f

Comme le script gère SIGTERM, systemctl stop pi-mqtt publie un statut offline propre avant de quitter. Pour la rotation des journaux, les watchdogs et les alternatives comme cron @reboot, voir lancer un script Python MQTT au démarrage.

Étape 7 : passer du broker public à un broker privé

Le serveur MQTT public gratuit est parfait pour apprendre, mais il est partagé, anonyme et limité en débit (par exemple 10 messages par seconde et par client et 64 Ko par message). Pour tout ce dont vous dépendez, il vous faut vos propres identifiants, du chiffrement et de l'isolation. Deux options s'offrent à vous :

Option Adaptée pour Ce dont vous êtes responsable
Mosquitto sur le Pi lui-même Réseaux locaux hors ligne, automatisation uniquement locale Mises à jour, certificats TLS, sauvegardes, accès à distance
Un broker MQTT managé Équipements en de nombreux lieux, tableaux de bord à distance, équipes Uniquement votre code client

L'exécution locale de Mosquitto est traitée dans installer Mosquitto sur un Raspberry Pi. Si vous optez pour un broker MQTT managé, ConnectMQ vous fournit un broker privé en quelques minutes : inscrivez-vous, choisissez un plan, créez un broker, et le portail affiche un nom d'utilisateur, un mot de passe et un client ID générés. Modifiez ensuite uniquement le fichier .env :

cat > ~/pi-mqtt/.env <<'EOF'
MQTT_HOST=broker.connectmq.com
MQTT_PORT=8883
MQTT_TLS=1
MQTT_USERNAME=YOUR_USERNAME
MQTT_PASSWORD=YOUR_PASSWORD
MQTT_CLIENT_ID=YOUR_CLIENT_ID
DEVICE_ID=pi-7f3a
TOPIC_PREFIX=home/livingroom/pi-7f3a
EOF
sudo systemctl restart pi-mqtt

Le port 8883 utilise TLS avec un certificat Let's Encrypt publiquement reconnu ; tls_set() le valide donc avec le bundle CA fourni avec Raspberry Pi OS, sans qu'il soit nécessaire de copier des fichiers de certificat sur le Pi. Sur ConnectMQ, les client ID sont liés aux identifiants émis : utilisez donc le client ID du portail plutôt qu'un identifiant aléatoire. Testez depuis votre portable avec les mêmes identifiants :

mosquitto_sub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID-cli -v -t "home/#"

Si le portail a émis un seul client ID, créez un second jeu d'identifiants pour le portable au lieu de réutiliser celui du Pi ; deux connexions avec le même ID s'éjectent mutuellement. Le portail inclut aussi un client MQTT dans le navigateur et un explorateur de topics en direct, souvent le moyen le plus rapide de voir arriver les messages de votre Pi sans rien installer.

Checklist du tutoriel MQTT Raspberry Pi pour des équipements fiables

La plupart des problèmes du type « ça marchait hier » viennent de la même courte liste. Avant de laisser un Pi dans un placard, parcourez-la :

  1. Un client ID unique par connexion. Les doublons provoquent des boucles de reconnexion sans fin.
  2. Les abonnements dans on_connect. Sinon, les commandes s'arrêtent après la première reconnexion.
  3. Last Will et statut retenu. Les tableaux de bord doivent pouvoir distinguer « silencieux » de « mort ».
  4. TLS sur le port 8883 avec identifiants pour tout ce qui sort d'un labo. Voir la liste complète des bonnes pratiques de sécurité MQTT.
  5. systemd avec Restart=on-failure et des journaux dans journald.
  6. Mettre les mesures en tampon hors ligne si les trous comptent. Paho met en file d'attente les messages QoS 1 pendant la déconnexion, mais uniquement en mémoire ; mettre en tampon les messages MQTT hors ligne en Python présente une approche fondée sur SQLite qui survit aux redémarrages.
  7. Une bonne alimentation et une carte SD de qualité, ou un démarrage sur SSD. Les sous-tensions provoquent plus de déconnexions aléatoires que n'importe quel bug logiciel.
  8. Durcir l'OS : clés SSH uniquement, mises à jour de sécurité automatiques, aucun mot de passe par défaut. Sécuriser un équipement IoT Raspberry Pi détaille la démarche.

Dépannage

Connect failed: Not authorized signifie que le nom d'utilisateur, le mot de passe ou le client ID ne correspond pas à ce que le broker a émis. Recopiez-les depuis le portail et vérifiez qu'il n'y a pas d'espaces en fin de ligne dans .env.

ConnectionRefusedError ou des délais dépassés sur le 8883 signifient généralement qu'un pare-feu ou un réseau invité bloque les ports sortants. Testez avec nc -vz broker.connectmq.com 8883. Certains réseaux d'entreprise n'autorisent que le 443 ; dans ce cas, MQTT sur WebSocket sécurisé via le port 8084 peut aussi être bloqué : testez-le avant de vous engager.

ssl.SSLCertVerificationError signifie presque toujours que l'horloge du Pi est fausse. TLS a besoin d'une date correcte ; vérifiez timedatectl et assurez-vous que NTP est activé.

La LED ne réagit pas alors que les messages arrivent indique un problème de permissions GPIO ou de câblage. Exécutez pinctrl get 17 sur les versions récentes de Raspberry Pi OS pour voir l'état de la broche, et vérifiez que l'utilisateur appartient au groupe gpio.

Une boucle de reconnexion toutes les quelques secondes révèle un client ID en double ou une seconde copie du script encore en cours d'exécution. Vérifiez avec ps aux | grep pi_mqtt.

Pour aller plus loin

Ce tutoriel MQTT Raspberry Pi vous donne une base solide, et le reste de notre série Raspberry Pi s'appuie exactement sur ce script :

Démarrer avec ConnectMQ

Quand votre projet Pi dépasse le serveur MQTT public gratuit, créez un broker privé sur ConnectMQ. Le plan Serverless gratuit ne demande aucune carte bancaire, prend en charge jusqu'à 25 connexions et vous offre d'emblée TLS sur le port 8883, MQTT 5 et l'accès WebSocket, largement de quoi équiper un labo domestique ou un premier pilote. Les parcs plus importants peuvent passer aux plans Serverless payant ou Dedicated sans modifier une ligne de code client. Créez votre broker gratuit sur app.connectmq.com et pointez-y votre fichier .env. Si vous voulez d'abord une vue d'ensemble des options d'hébergement, lisez notre présentation pour choisir un broker MQTT cloud.

Questions fréquentes

Quelle bibliothèque MQTT utiliser sur un Raspberry Pi ?

En Python, paho-mqtt 2.x est la plus utilisée et c'est celle de ce guide. Les utilisateurs de Node.js peuvent utiliser MQTT.js, et les adeptes du low-code peuvent exécuter Node-RED sur le Pi avec les mêmes réglages de broker.

Un Raspberry Pi peut-il être à la fois broker et client MQTT ?

Oui. Vous pouvez exécuter Mosquitto sur le Pi et connecter des scripts locaux à localhost, mais vous gérez alors vous-même la sécurité, les mises à jour et l'accès à distance. De nombreux projets gardent le Pi comme client et utilisent un broker MQTT managé afin que des équipements et des tableaux de bord situés en différents lieux puissent communiquer.

Pourquoi mon Pi se déconnecte-t-il et se reconnecte-t-il sans cesse ?

Les causes les plus fréquentes sont un client ID en double, une seconde copie du script en cours d'exécution ou une alimentation instable. Vérifiez que chaque connexion utilise un ID unique et recherchez les avertissements de sous-tension avec dmesg.

Le serveur MQTT public gratuit est-il sûr pour mon projet Raspberry Pi ?

Il est sûr pour apprendre et faire des démos, mais n'importe quel client peut lire les topics publics : n'envoyez donc jamais de données personnelles ou sensibles. Utilisez un broker privé avec TLS et identifiants pour les déploiements réels.

Ce code fonctionne-t-il sur le Raspberry Pi 5 ?

Oui. Le script utilise gpiozero avec le backend lgpio, qui prend en charge le Pi 5. Les bibliothèques qui écrivent dans les anciens registres mémoire GPIO, comme RPi.GPIO, ne fonctionnent pas sur le Pi 5.

Articles liés

Journal d'accès RFID MQTT sur Raspberry Pi avec le lecteur RC522

Câblez un lecteur RFID RC522 sur un Raspberry Pi, lisez les badges en Python, vérifiez-les dans une liste blanche locale et publiez chaque tentative d'accès sous forme d'événement MQTT exploitable par vos outils de journalisation, tableaux de bord et alertes.

8 min de lecture

Installer Mosquitto sur Raspberry Pi comme broker MQTT local sécurisé

Installez Mosquitto sur un Raspberry Pi, sécurisez-le avec des mots de passe et une configuration de listener raisonnable, testez-le avec mosquitto_pub et mosquitto_sub, et découvrez quand un broker local doit faire un pont vers un broker cloud.

9 min de lecture

Tous les articles →

Votre broker MQTT privé, à quelques clics

Créez un compte, récupérez les identifiants de votre broker et connectez votre premier appareil — aucun serveur à installer, mettre à jour ou dimensionner.