Ein Raspberry Pi DHT22 MQTT Sensor ist ein klassisches erstes IoT-Projekt – und zugleich eine klassische Quelle für Frust: Der DHT22 ist günstig und für Räume und Gewächshäuser genau genug, aber durch sein zeitkritisches Protokoll schlagen auf einem Linux-Board manche Lesevorgänge fehl. In diesem Tutorial verdrahten Sie den Sensor, lesen ihn aus Python aus und veröffentlichen saubere Temperatur- und Feuchtewerte als JSON an einen MQTT-Broker – mit sauberer Behandlung von Lesefehlern, unplausiblen Werten und Netzwerkaussetzern.
Warum der DHT22 manchmal versagt
Der DHT22 (auch als AM2302 verkauft) nutzt weder I2C noch 1-Wire. Der Pi muss eine GPIO-Leitung umschalten und dann eine Folge von Impulsen messen, die nur einige zehn Mikrosekunden dauern. Raspberry Pi OS ist kein Echtzeitbetriebssystem; plant der Kernel im falschen Moment etwas anderes ein, geht ein Bit verloren und die Prüfsumme schlägt fehl. Das ist normales Verhalten, kein defekter Sensor. Die Lösung liegt in der Software:
- Warten Sie mindestens zwei Sekunden zwischen den Lesevorgängen; schneller kann der Sensor nicht messen.
- Fangen Sie den
RuntimeErrorab, den die Bibliothek auslöst, und versuchen Sie es erneut. - Verwerfen Sie Werte außerhalb des physikalischen Messbereichs des Sensors.
- Nehmen Sie mehrere gültige Messwerte und veröffentlichen Sie den Median.
- Zählen Sie Fehler und veröffentlichen Sie sie, damit Sie merken, wenn ein Sensor wirklich ausfällt.
Verdrahtung
| DHT22-Pin | Raspberry Pi |
|---|---|
| VCC (Pin 1) | 3,3 V (physischer Pin 1) |
| DATA (Pin 2) | GPIO4 (physischer Pin 7) |
| NC (Pin 3) | Nicht verbunden |
| GND (Pin 4) | GND (physischer Pin 9) |
Ein einzelner DHT22 braucht einen Pull-up-Widerstand von 4,7 k bis 10 k zwischen DATA und 3,3 V. Dreipolige Breakout-Module bringen ihn meist mit. Halten Sie das Kabel anfangs kurz; lange Leitungen funktionieren, sind aber störanfälliger, und ein kleinerer Pull-up-Wert kann bei längeren Kabeln helfen. Versorgen Sie ihn mit 3,3 V, nie mit 5 V, denn die Datenleitung geht direkt an einen GPIO-Pin, der nicht 5-V-tolerant ist.
Die Bibliotheken installieren
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 zieht Adafruit Blinka nach, das das Modul board bereitstellt. Testen Sie den Sensor allein, bevor Sie MQTT hinzufügen:
python -c "import time, board, adafruit_dht; d = adafruit_dht.DHT22(board.D4); time.sleep(2); print(d.temperature, d.humidity); d.exit()"
Sehen Sie einen Fehler wie „A full buffer was not returned“, führen Sie den Befehl erneut aus; ein einzelner Fehlschlag ist zu erwarten. Schlägt jeder Versuch fehl, prüfen Sie Verdrahtung und Pull-up. Auf manchen Raspberry-Pi-Modellen und Betriebssystemversionen funktioniert der Pulse-Input-Helper nicht; legen Sie den Sensor dann mit adafruit_dht.DHT22(board.D4, use_pulseio=False) an, um den Bit-Banging-Fallback zu nutzen.
Payload und Topics
Das Skript veröffentlicht pro Intervall ein JSON-Dokument plus einen Retained-Status:
{
"temperature": 22.4,
"humidity": 48.1,
"samples": 3,
"read_errors": 2,
"ts": 1792152000
}
| Topic | Inhalt | Retained |
|---|---|---|
connectmq/demo/c3f19a/greenhouse/dht22 |
JSON-Messwert alle 30 s | Nein |
connectmq/demo/c3f19a/greenhouse/status |
online / offline (Last Will) |
Ja |
Ersetzen Sie c3f19a durch eine eigene Zufallszeichenfolge. read_errors in jeder Nachricht kostet ein paar Bytes und macht aus einem stillen Hardwareproblem etwas, das Sie grafisch darstellen und alarmieren können.
Das Raspberry Pi DHT22 MQTT Skript
Speichern Sie dies als 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:
# Prüfsummen- oder Timingfehler sind ab und zu zu erwarten.
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()
Einige Details verdienen Beachtung. Die Pause von gut zwei Sekunden zwischen den Lesevorgängen respektiert das Abtastlimit des Sensors. Der Median aus drei Messwerten entfernt gelegentliche einzelne Ausreißer, die die Prüfsumme bestehen, aber trotzdem falsch sind. Schlägt jeder Versuch fehl, veröffentlicht das Skript dennoch eine Nachricht mit einem Feld error, sodass Abonnenten „Sensor defekt“ von „Pi offline“ unterscheiden können – Letzteres deckt das Retained-Status-Topic ab. Schließlich gibt sensor.exit() die GPIO-Leitung frei; ohne diesen Aufruf kann der Pin beim nächsten Lauf belegt bleiben.
Die Daten verfolgen
Abonnieren Sie auf Ihrem Laptop, um zu prüfen, ob Nachrichten ankommen:
mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-c3f19a \
-t 'connectmq/demo/c3f19a/greenhouse/#' -v
Sie sollten sofort status online sehen (es ist retained) und etwa alle 30 Sekunden einen JSON-Messwert. Trennen Sie den Pi für eine Minute vom Netzwerk und verbinden Sie ihn wieder: paho stellt die Verbindung automatisch wieder her. QoS-1-Nachrichten, die während der Unterbrechung veröffentlicht werden, liegen im Arbeitsspeicher und werden nach dem Reconnect gesendet, solange der Prozess weiterläuft. Sollen Messwerte einen Neustart während eines Ausfalls überstehen, sehen Sie sich an, wie Sie MQTT-Nachrichten in Python offline puffern – mit SQLite.
Das Sendeintervall wählen
Temperatur und Luftfeuchte in einem Raum oder Gewächshaus ändern sich langsam. Alle 30 bis 60 Sekunden zu veröffentlichen ergibt glatte Diagramme, ohne Broker oder Datenbank zu fluten. Häufiger als alle 10 Sekunden bringt bei einem DHT22 selten zusätzliche Information, und jeder Lesezyklus mit Wiederholungen dauert ohnehin mehrere Sekunden. Interessieren Sie nur Änderungen, veröffentlichen Sie, wenn sich der Wert um mehr als 0,2 °C oder 1 % Luftfeuchte ändert, plus einen Heartbeat alle paar Minuten.
Die Platzierung des Sensors ist so wichtig wie das Intervall. Montieren Sie den DHT22 mit Abstand zum Pi, außerhalb direkter Sonneneinstrahlung und fern von Heizkörpern oder Lüftungsauslässen, mit freier Luftzirkulation um die Öffnungen seines Gehäuses. Ein Sensor, der auf das Pi-Gehäuse geklebt ist, misst vor allem den Prozessor. Im Gewächshaus verhindert ein kleiner Strahlungsschutz aus gestapelten weißen Tellern, dass Sonnenlicht den Temperaturwert verfälscht.
DHT22 im Vergleich zu anderen Sensoren
Der DHT22 eignet sich gut zur Überwachung in Innenräumen, ist aber nicht die einzige Option. Ein wasserdichter DS18B20-Fühler ist für reine Temperaturmessung weit robuster und unterstützt viele Fühler an einer Leitung; siehe den Leitfaden Raspberry Pi DS18B20 MQTT. Wenn Sie denselben Sensor lieber an einem batteriebetriebenen Mikrocontroller betreiben, nutzt das Tutorial ESP32 DHT22 MQTT einen identischen Payload, sodass beide Geräte dasselbe Dashboard speisen können. Für den Gesamtüberblick zu Publish, Subscribe und dem Start von Skripten beim Booten beginnen Sie mit unserem Raspberry Pi MQTT Tutorial.
Wechsel auf einen privaten Broker
Der kostenlose öffentliche MQTT-Broker unter broker.connectmq.com ist perfekt zum Testen, aber jedes Topic dort ist für jeden lesbar. Für ein echtes Gewächshaus oder einen Serverraum erstellen Sie einen privaten Broker bei ConnectMQ, setzen dann die Umgebungsvariablen und starten neu:
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
Im ConnectMQ-Portal können Sie die Messwerte im Live-Topic-Explorer verfolgen und eine Schwellwert-Alarmregel anlegen, etwa für eine Luftfeuchte über 85 %, ohne einen zusätzlichen Subscriber zu schreiben.
Checkliste zur Fehlerbehebung
- Jeder Lesevorgang schlägt fehl: Prüfen Sie, ob DATA an GPIO4 liegt, der Pull-up vorhanden ist und VCC 3,3 V beträgt.
- „Unable to set line to input“ oder GPIO belegt: Ein anderer Prozess hält den Pin; beenden Sie alte Skripte und stellen Sie sicher, dass
sensor.exit()ausgeführt wird. - Werte wirken plausibel, springen aber gelegentlich: Lassen Sie den Medianfilter aktiv und erhöhen Sie
SAMPLESauf 5. - Luftfeuchte hängt bei 99,9: Kondensat auf dem Sensor; DHT22-Sensoren vertragen dauerhafte Sättigung schlecht.
- Messwerte bleiben aus, aber der Status steht auf
online: Das Skript hängt beim Lesen; ergänzen Sie einen Watchdog oder starten Sie über systemd mitRestart=alwaysneu. - Verbindung abgelehnt, nicht autorisiert: Zugangsdaten oder Client ID passen nicht zum Broker.
Jetzt mit ConnectMQ starten
Bringen Sie Ihren Sensor vom Labortisch in einen echten Einsatz auf einem Cloud-MQTT-Broker. Erstellen Sie einen kostenlosen Serverless-Broker ohne Kreditkarte, übernehmen Sie die generierten Zugangsdaten in Ihre Umgebung und verbinden Sie sich über TLS auf Port 8883. Ihre DHT22-Messwerte stehen innerhalb weniger Minuten Dashboards, Node-RED-Flows und Alarmregeln zur Verfügung.
Häufig gestellte Fragen
Warum meldet mein DHT22 auf dem Raspberry Pi „Checksum did not validate“?
Linux unterbricht gelegentlich das präzise Timing, das der DHT22 braucht, daher schlagen manche Lesevorgänge fehl. Fangen Sie den Fehler ab, warten Sie zwei Sekunden und versuchen Sie es erneut; einige Fehlschläge pro Stunde sind normal.
Wie oft kann ich einen DHT22 auslesen?
Höchstens einmal alle zwei Sekunden. Für das Veröffentlichen per MQTT reicht ein Intervall von 30 bis 60 Sekunden für die Raum- und Gewächshausüberwachung völlig aus.
Sollte ich für Sensorwerte QoS 0 oder QoS 1 verwenden?
QoS 1 ist ein guter Standard, weil es die Zustellung bei geringem Overhead garantiert. QoS 0 ist für sehr häufige Messwerte akzeptabel, bei denen der Verlust eines Werts keine Rolle spielt.
Kann ich mehrere DHT22-Sensoren an einen Raspberry Pi anschließen?
Ja. Geben Sie jedem einen eigenen GPIO-Pin und legen Sie pro Pin ein DHT22-Objekt an. Lesen Sie sie nacheinander statt gleichzeitig aus und veröffentlichen Sie jeden auf einem eigenen Topic.



