Raspberry Pi

Raspberry Pi DHT22 MQTT : publier température et humidité de façon fiable en Python

Câblez un DHT22 sur un Raspberry Pi, lisez-le en Python et publiez en MQTT un JSON de température et d'humidité validé, avec nouvelles tentatives, filtrage par médiane et compteurs d'erreurs qui tiennent les mesures aberrantes à l'écart de vos tableaux de bord.

Capteur de température et d'humidité DHT22 câblé sur une platine d'essai à un Raspberry Pi et envoyant ses mesures vers un broker cloud via MQTT
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

Un capteur Raspberry Pi DHT22 MQTT est un premier projet IoT classique, mais aussi une source classique de frustration : le DHT22 est bon marché et suffisamment précis pour des pièces et des serres, mais son protocole très sensible au timing fait échouer certaines lectures sur une carte Linux. Dans ce tutoriel, vous câblerez le capteur, le lirez depuis Python et publierez un JSON propre de température et d'humidité vers un broker MQTT, en gérant correctement les lectures ratées, les valeurs invraisemblables et les coupures réseau.

Pourquoi le DHT22 échoue parfois

Le DHT22 (aussi vendu sous le nom AM2302) n'utilise ni l'I2C ni le 1-Wire. Le Pi doit basculer une ligne GPIO puis chronométrer une salve d'impulsions de quelques dizaines de microsecondes. Raspberry Pi OS n'est pas un système d'exploitation temps réel : lorsque le noyau ordonnance autre chose au mauvais moment, un bit est perdu et la somme de contrôle échoue. C'est un comportement normal, pas un capteur défectueux. La solution est logicielle :

  1. Attendez au moins deux secondes entre deux lectures ; le capteur ne peut pas échantillonner plus vite.
  2. Interceptez la RuntimeError levée par la bibliothèque et réessayez.
  3. Rejetez les valeurs hors de la plage physique du capteur.
  4. Prenez plusieurs lectures valides et publiez la médiane.
  5. Comptez les échecs et publiez-les, afin de remarquer quand un capteur meurt vraiment.

Câblage

Broche DHT22 Raspberry Pi
VCC (broche 1) 3,3 V (broche physique 1)
DATA (broche 2) GPIO4 (broche physique 7)
NC (broche 3) Non connectée
GND (broche 4) GND (broche physique 9)

Un DHT22 nu nécessite une résistance de rappel (pull-up) de 4,7 k à 10 k entre DATA et 3,3 V. Les modules à trois broches l'intègrent généralement. Gardez un câble court au début ; les grandes longueurs fonctionnent mais sont plus sensibles au bruit, et baisser la valeur du pull-up peut aider sur des câbles plus longs. Alimentez-le en 3,3 V, jamais en 5 V, car la ligne de données arrive directement sur une broche GPIO qui ne tolère pas le 5 V.

Installer les bibliothèques

sudo apt update
sudo apt install -y python3-venv libgpiod2
mkdir -p ~/dht22-mqtt && cd ~/dht22-mqtt
python3 -m venv .venv
source .venv/bin/activate
pip install "paho-mqtt>=2.0" adafruit-circuitpython-dht

adafruit-circuitpython-dht installe Adafruit Blinka, qui fournit le module board. Testez le capteur seul avant d'ajouter MQTT :

python -c "import time, board, adafruit_dht; d = adafruit_dht.DHT22(board.D4); time.sleep(2); print(d.temperature, d.humidity); d.exit()"

Si vous voyez une erreur du type « A full buffer was not returned », relancez la commande ; un échec isolé est attendu. Si toutes les tentatives échouent, vérifiez le câblage et le pull-up. Sur certains modèles de Raspberry Pi et certaines versions du système, l'assistant de lecture d'impulsions ne fonctionne pas ; dans ce cas, créez le capteur avec adafruit_dht.DHT22(board.D4, use_pulseio=False) pour utiliser la méthode de repli par bit-banging.

Payload et topics

Le script publie un document JSON par intervalle ainsi qu'un statut retenu :

{
  "temperature": 22.4,
  "humidity": 48.1,
  "samples": 3,
  "read_errors": 2,
  "ts": 1792152000
}
Topic Contenu Retenu
connectmq/demo/c3f19a/greenhouse/dht22 Mesure JSON toutes les 30 s Non
connectmq/demo/c3f19a/greenhouse/status online / offline (Last Will) Oui

Remplacez c3f19a par une chaîne aléatoire de votre choix. Inclure read_errors dans chaque message coûte quelques octets et transforme un problème matériel silencieux en donnée que vous pouvez tracer et surveiller.

Le script Raspberry Pi DHT22 MQTT

Enregistrez ceci sous dht22_mqtt.py :

#!/usr/bin/env python3
"""Read a DHT22 and publish validated readings to MQTT."""
import json
import os
import statistics
import time
import uuid

import adafruit_dht
import board
import paho.mqtt.client as mqtt

BROKER = os.getenv("MQTT_HOST", "broker.connectmq.com")
PORT = int(os.getenv("MQTT_PORT", "1883"))
USERNAME = os.getenv("MQTT_USERNAME")
PASSWORD = os.getenv("MQTT_PASSWORD")
CLIENT_ID = os.getenv("MQTT_CLIENT_ID", f"dht22-{uuid.uuid4().hex[:8]}")
PREFIX = os.getenv("MQTT_PREFIX", "connectmq/demo/c3f19a/greenhouse")
INTERVAL = int(os.getenv("PUBLISH_INTERVAL", "30"))
SAMPLES = 3
MAX_ATTEMPTS = 10

sensor = adafruit_dht.DHT22(board.D4)
total_errors = 0


def plausible(temp, hum):
    return (
        temp is not None and hum is not None
        and -40.0 <= temp <= 80.0
        and 0.0 <= hum <= 100.0
    )


def read_median():
    """Collect SAMPLES good readings and return their medians, or None."""
    global total_errors
    temps, hums = [], []
    attempts = 0
    while len(temps) < SAMPLES and attempts < MAX_ATTEMPTS:
        attempts += 1
        try:
            t, h = sensor.temperature, sensor.humidity
            if plausible(t, h):
                temps.append(t)
                hums.append(h)
            else:
                total_errors += 1
        except RuntimeError as err:
            # Les erreurs de checksum ou de timing sont attendues de temps en temps.
            total_errors += 1
            print(f"Read failed ({err}); retrying")
        time.sleep(2.2)
    if not temps:
        return None
    return statistics.median(temps), statistics.median(hums), len(temps)


def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code.is_failure:
        print(f"Connection refused: {reason_code}")
        return
    print(f"Connected as {CLIENT_ID}")
    client.publish(f"{PREFIX}/status", "online", qos=1, retain=True)


client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID)
client.on_connect = on_connect
client.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.reconnect_delay_set(min_delay=1, max_delay=60)
if USERNAME:
    client.username_pw_set(USERNAME, PASSWORD)
if PORT == 8883:
    client.tls_set()

client.connect(BROKER, PORT, keepalive=60)
client.loop_start()

try:
    while True:
        started = time.monotonic()
        result = read_median()
        if result is None:
            payload = {"error": "no valid reading", "read_errors": total_errors,
                       "ts": int(time.time())}
        else:
            temp, hum, n = result
            payload = {
                "temperature": round(temp, 1),
                "humidity": round(hum, 1),
                "samples": n,
                "read_errors": total_errors,
                "ts": int(time.time()),
            }
        info = client.publish(f"{PREFIX}/dht22", json.dumps(payload), qos=1)
        if info.rc != mqtt.MQTT_ERR_SUCCESS:
            print(f"Publish queued while offline (rc={info.rc})")
        print(payload)
        elapsed = time.monotonic() - started
        time.sleep(max(0, INTERVAL - elapsed))
except KeyboardInterrupt:
    pass
finally:
    client.publish(f"{PREFIX}/status", "offline", qos=1, retain=True).wait_for_publish(2)
    client.loop_stop()
    client.disconnect()
    sensor.exit()

Quelques détails méritent d'être soulignés. Le délai d'un peu plus de deux secondes entre deux lectures respecte la limite d'échantillonnage du capteur. La médiane de trois lectures élimine le pic isolé qui passe la somme de contrôle tout en étant faux. Lorsque toutes les tentatives échouent, le script publie quand même un message avec un champ error, afin que les abonnés puissent distinguer « capteur en panne » de « Pi hors ligne », ce dernier cas étant couvert par le topic de statut retenu. Enfin, sensor.exit() libère la ligne GPIO ; l'omettre peut laisser la broche occupée pour l'exécution suivante.

Observer les données

Abonnez-vous depuis votre ordinateur portable pour confirmer l'arrivée des messages :

mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-c3f19a \
  -t 'connectmq/demo/c3f19a/greenhouse/#' -v

Vous devriez voir status online immédiatement (il est retenu) et une mesure JSON environ toutes les 30 secondes. Débranchez le réseau du Pi pendant une minute puis rebranchez-le : paho se reconnecte automatiquement. Les messages QoS 1 publiés pendant la coupure sont mis en file en mémoire et envoyés après la reconnexion, tant que le processus continue de tourner. Si vous avez besoin que les mesures survivent à un redémarrage pendant une coupure, voyez comment mettre en tampon les messages MQTT hors ligne en Python avec SQLite.

Choisir un intervalle de publication

La température et l'humidité d'une pièce ou d'une serre évoluent lentement. Publier toutes les 30 à 60 secondes donne des courbes lisses sans inonder le broker ni votre base de données. Descendre sous les 10 secondes apporte rarement de l'information avec un DHT22, et chaque cycle de lecture avec nouvelles tentatives prend déjà plusieurs secondes. Si seuls les changements vous intéressent, publiez lorsque la valeur varie de plus de 0,2 °C ou de 1 % d'humidité, avec un heartbeat toutes les quelques minutes.

L'emplacement du capteur compte autant que l'intervalle. Fixez le DHT22 à l'écart du Pi, à l'abri du soleil direct et loin des radiateurs ou des bouches d'aération, en laissant l'air circuler librement autour des ouïes de son boîtier. Un capteur scotché sur le boîtier du Pi mesurera surtout le processeur. Dans une serre, un petit abri anti-rayonnement fait d'assiettes blanches empilées évite que le soleil ne gonfle la mesure de température.

DHT22 ou autres capteurs

Le DHT22 convient au suivi en intérieur, par exemple dans une maison connectée, mais ce n'est pas la seule option. Une sonde étanche DS18B20 est bien plus robuste pour la seule température et accepte de nombreuses sondes sur un même fil ; consultez le guide Raspberry Pi DS18B20 MQTT. Si vous préférez utiliser le même capteur sur un microcontrôleur alimenté par batterie, le tutoriel ESP32 DHT22 MQTT utilise un payload identique, si bien que les deux appareils peuvent alimenter le même tableau de bord. Pour une vue d'ensemble de la publication, de l'abonnement et du lancement de scripts au démarrage, commencez par notre tutoriel MQTT sur Raspberry Pi.

Passer à un broker privé

Le serveur MQTT public gratuit broker.connectmq.com est parfait pour tester, mais chaque topic y est lisible par tout le monde. Pour une vraie serre ou une salle serveur, créez un broker privé sur ConnectMQ, un broker MQTT managé, puis définissez les variables d'environnement et relancez :

export MQTT_PORT=8883
export MQTT_USERNAME=YOUR_USERNAME
export MQTT_PASSWORD=YOUR_PASSWORD
export MQTT_CLIENT_ID=YOUR_CLIENT_ID
export MQTT_PREFIX=site1/greenhouse/zone1
python dht22_mqtt.py

Dans le portail ConnectMQ, vous pouvez suivre les mesures dans l'explorateur de topics en direct et créer une règle d'alerte de seuil, par exemple une humidité supérieure à 85 %, sans écrire d'abonné supplémentaire.

Liste de dépannage

  1. Toutes les lectures échouent : vérifiez que DATA est bien sur GPIO4, que le pull-up est présent et que VCC est en 3,3 V.
  2. « Unable to set line to input » ou GPIO occupé : un autre processus tient la broche ; arrêtez les anciens scripts et assurez-vous que sensor.exit() s'exécute.
  3. Les valeurs semblent correctes mais sautent de temps en temps : gardez le filtrage par médiane et passez SAMPLES à 5.
  4. Humidité bloquée à 99,9 : condensation sur le capteur ; les DHT22 supportent mal une saturation permanente.
  5. Les mesures s'arrêtent mais le statut reste online : le script est bloqué en lecture ; ajoutez un watchdog ou redémarrez via systemd avec Restart=always.
  6. Connexion refusée, non autorisée : les identifiants ou le client ID ne correspondent pas au broker.

Démarrer avec ConnectMQ

Faites passer votre capteur de l'établi à un vrai déploiement sur un broker MQTT cloud. Créez un broker Serverless gratuit, sans carte bancaire, copiez les identifiants générés dans votre environnement et connectez-vous en TLS sur le port 8883. Vos mesures DHT22 seront disponibles pour les tableaux de bord, les flows Node-RED et les règles d'alerte en quelques minutes.

Questions fréquentes

Pourquoi mon DHT22 renvoie-t-il « Checksum did not validate » sur un Raspberry Pi ?

Linux interrompt occasionnellement le timing précis dont le DHT22 a besoin, si bien que certaines lectures échouent. Interceptez l'erreur, attendez deux secondes et réessayez ; quelques échecs par heure sont normaux.

À quelle fréquence peut-on lire un DHT22 ?

Pas plus d'une fois toutes les deux secondes. Pour la publication MQTT, un intervalle de 30 à 60 secondes suffit largement pour surveiller une pièce ou une serre.

Faut-il utiliser la QoS 0 ou la QoS 1 pour les mesures de capteurs ?

La QoS 1 est un bon choix par défaut, car elle garantit la livraison avec un faible surcoût. La QoS 0 est acceptable pour des mesures très fréquentes où en perdre une n'a pas d'importance.

Peut-on connecter plusieurs capteurs DHT22 à un seul Raspberry Pi ?

Oui : attribuez à chacun sa propre broche GPIO et créez un objet DHT22 par broche. Lisez-les l'un après l'autre plutôt qu'en même temps, et publiez chacun sur son propre topic.

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.