Bir Raspberry Pi DHT22 MQTT sensörü klasik bir ilk IoT projesidir ve aynı zamanda klasik bir hayal kırıklığı kaynağıdır: DHT22 ucuzdur ve odalar ile seralar için yeterince doğrudur, ancak zamanlamaya duyarlı protokolü, bir Linux kartında bazı okumaların başarısız olması anlamına gelir. Bu eğitimde sensörü bağlayacak, Python ile okuyacak ve başarısız okumaları, akla yatkın olmayan değerleri ve ağ kopmalarını düzgün şekilde ele alarak temiz sıcaklık ve nem JSON'unu bir MQTT broker'a yayınlayacaksınız.
DHT22 Neden Bazen Başarısız Olur?
DHT22 (AM2302 olarak da satılır) I2C veya 1-Wire kullanmaz. Pi'nin bir GPIO hattını değiştirmesi ve ardından onlarca mikrosaniye süren bir darbe dizisini zamanlaması gerekir. Raspberry Pi OS gerçek zamanlı bir işletim sistemi değildir; bu yüzden çekirdek yanlış anda başka bir şeyi zamanladığında bir bit kaybolur ve checksum başarısız olur. Bu bozuk bir sensör değil, normal bir davranıştır. Çözüm yazılımdadır:
- Okumalar arasında en az iki saniye bekleyin; sensör daha hızlı örnekleme yapamaz.
- Kütüphanenin fırlattığı
RuntimeErrorhatasını yakalayın ve yeniden deneyin. - Sensörün fiziksel aralığı dışındaki değerleri reddedin.
- Birkaç iyi ölçüm alın ve medyanı yayınlayın.
- Hataları sayın ve yayınlayın; böylece bir sensör gerçekten bozulduğunda fark edersiniz.
Kablolama
| DHT22 pini | Raspberry Pi |
|---|---|
| VCC (pin 1) | 3,3 V (fiziksel pin 1) |
| DATA (pin 2) | GPIO4 (fiziksel pin 7) |
| NC (pin 3) | Bağlı değil |
| GND (pin 4) | GND (fiziksel pin 9) |
Çıplak bir DHT22, DATA ile 3,3 V arasında 4,7 k ile 10 k arası bir pull-up direncine ihtiyaç duyar. Üç pinli breakout modüller genellikle bunu içerir. Başlangıçta kabloyu kısa tutun; uzun hatlar çalışır ama gürültüye daha duyarlıdır ve daha uzun kablolarda pull-up değerini düşürmek yardımcı olabilir. Sensörü asla 5 V'tan değil, 3,3 V'tan besleyin; çünkü veri hattı doğrudan 5 V toleranslı olmayan bir GPIO pinine gider.
Kütüphanelerin Kurulumu
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, board modülünü sağlayan Adafruit Blinka'yı da kurar. MQTT eklemeden önce sensörü tek başına test edin:
python -c "import time, board, adafruit_dht; d = adafruit_dht.DHT22(board.D4); time.sleep(2); print(d.temperature, d.humidity); d.exit()"
"A full buffer was not returned" gibi bir hata görürseniz komutu yeniden çalıştırın; tek bir başarısızlık beklenen bir durumdur. Her deneme başarısız oluyorsa kablolamayı ve pull-up direncini kontrol edin. Bazı Raspberry Pi modellerinde ve işletim sistemi sürümlerinde pulse-input yardımcısı çalışmaz; bu durumda bit-banging yedeğini kullanmak için sensörü adafruit_dht.DHT22(board.D4, use_pulseio=False) ile oluşturun.
Payload ve Topic'ler
Betik her aralıkta bir JSON belgesi ve retained bir durum yayınlar:
{
"temperature": 22.4,
"humidity": 48.1,
"samples": 3,
"read_errors": 2,
"ts": 1792152000
}
| Topic | İçerik | Retained |
|---|---|---|
connectmq/demo/c3f19a/greenhouse/dht22 |
Her 30 saniyede bir JSON ölçüm | Hayır |
connectmq/demo/c3f19a/greenhouse/status |
online / offline (last will) |
Evet |
c3f19a değerini kendi rastgele dizenizle değiştirin. Her mesaja read_errors eklemek birkaç bayta mal olur ve sessiz bir donanım sorununu grafiğe dökebileceğiniz ve alarm kurabileceğiniz bir şeye dönüştürür.
Raspberry Pi DHT22 MQTT Betiği
Bunu dht22_mqtt.py olarak kaydedin:
#!/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:
# Checksum or timing errors are expected now and then.
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()
Birkaç ayrıntı özellikle belirtilmeye değer. Okumalar arasındaki iki saniyeyi aşan bekleme, sensörün örnekleme sınırına uyar. Üç ölçümün medyanı, checksum'dan geçen ama yine de yanlış olan ara sıra tekil sıçramaları ortadan kaldırır. Her deneme başarısız olduğunda betik yine de error alanı içeren bir mesaj yayınlar; böylece aboneler "sensör bozuk" durumunu, retained durum topic'inin kapsadığı "Pi çevrimdışı" durumundan ayırt edebilir. Son olarak sensor.exit() GPIO hattını serbest bırakır; bunu atlamak pini bir sonraki çalıştırma için meşgul bırakabilir.
Verileri İzlemek
Mesajların geldiğini doğrulamak için dizüstü bilgisayarınızdan abone olun:
mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-c3f19a \
-t 'connectmq/demo/c3f19a/greenhouse/#' -v
Hemen status online mesajını (retained olduğu için) ve yaklaşık her 30 saniyede bir JSON ölçümünü görmelisiniz. Pi'nin ağ bağlantısını bir dakikalığına kesip yeniden takın: paho otomatik olarak yeniden bağlanır. Bağlantı kopukken yayınlanan QoS 1 mesajları, süreç çalışmaya devam ettiği sürece bellekte kuyruğa alınır ve yeniden bağlandıktan sonra gönderilir. Ölçümlerin bir kesinti sırasında yeniden başlatmaya dayanması gerekiyorsa SQLite ile Python'da MQTT mesajlarını çevrimdışı tamponlama yazısına bakın.
Yayın Aralığını Seçmek
Bir odadaki veya seradaki sıcaklık ve nem yavaş değişir. Her 30 ila 60 saniyede bir yayın yapmak, broker'ı veya veritabanınızı boğmadan pürüzsüz grafikler sağlar. Bir DHT22'den 10 saniyeden daha sık okuma nadiren ek bilgi sağlar ve yeniden denemelerle her okuma döngüsü zaten birkaç saniye sürer. Yalnızca değişikliklerle ilgileniyorsanız değer 0,2 °C'den veya %1 nemden fazla değiştiğinde yayınlayın, ayrıca birkaç dakikada bir heartbeat gönderin.
Sensörün yerleşimi en az aralık kadar önemlidir. DHT22'yi Pi'nin kendisinden uzağa, doğrudan güneş ışığından, ısıtıcılardan veya havalandırma ağızlarından uzak, gövdesindeki deliklerin etrafında serbest hava akışı olacak şekilde monte edin. Pi kasasına bantlanmış bir sensör çoğunlukla işlemciyi ölçer. Bir serada üst üste dizilmiş beyaz plakalardan yapılmış küçük bir radyasyon kalkanı, güneş ışığının sıcaklık ölçümünü şişirmesini önler.
DHT22 ve Diğer Sensörler
DHT22 iç mekan izleme için uygundur, ancak tek seçenek değildir. Su geçirmez bir DS18B20 probu yalnızca sıcaklık için çok daha dayanıklıdır ve tek bir hat üzerinde çok sayıda probu destekler; Raspberry Pi DS18B20 MQTT rehberine bakın. Aynı sensörü pille çalışan bir mikrodenetleyicide kullanmayı tercih ederseniz ESP32 DHT22 MQTT eğitimi aynı payload'ı kullanır; böylece her iki cihaz da aynı panoyu besleyebilir. Yayınlama, abone olma ve betikleri açılışta çalıştırma konusunda daha geniş bir bakış için Raspberry Pi MQTT eğitimimizle başlayın.
Özel Bir Broker'a Geçiş
broker.connectmq.com adresindeki ücretsiz genel MQTT broker test için mükemmeldir, ancak oradaki her topic herkes tarafından okunabilir. Gerçek bir sera veya sunucu odası için ConnectMQ üzerinde özel bir broker oluşturun, ardından ortam değişkenlerini ayarlayıp yeniden başlatın:
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
ConnectMQ portalında ölçümleri canlı topic gezgininde izleyebilir ve ek bir abone yazmadan, örneğin %85'in üzerindeki nem için bir eşik alarm kuralı oluşturabilirsiniz.
Sorun Giderme Kontrol Listesi
- Her okuma başarısız oluyor: DATA'nın GPIO4'te olduğunu, pull-up direncinin bulunduğunu ve VCC'nin 3,3 V olduğunu kontrol edin.
- "Unable to set line to input" veya GPIO meşgul: pini başka bir süreç tutuyor; eski betikleri durdurun ve
sensor.exit()çağrısının çalıştığından emin olun. - Değerler doğru görünüyor ama ara sıra sıçrıyor: medyan filtrelemeyi açık tutun ve
SAMPLESdeğerini 5'e çıkarın. - Nem 99,9'da takılı kalıyor: sensör üzerinde yoğuşma var; DHT22'ler sürekli doygunluktan hoşlanmaz.
- Ölçümler duruyor ama durum
onlinekalıyor: betik okumada takılmış; bir watchdog ekleyin veyaRestart=alwaysile systemd üzerinden yeniden başlatın. - Bağlantı reddedildi, yetkisiz: kimlik bilgileri veya client ID broker ile eşleşmiyor.
ConnectMQ ile Başlayın
Sensörünüzü test tezgahından bir bulut MQTT broker üzerindeki gerçek bir kuruluma taşıyın. Kredi kartı gerekmeden ücretsiz bir Serverless broker oluşturun, otomatik oluşturulan kimlik bilgilerini ortamınıza kopyalayın ve 8883 portunda TLS üzerinden bağlanın. DHT22 ölçümleriniz dakikalar içinde panolar, Node-RED akışları ve alarm kuralları için kullanılabilir hale gelir.
Sık Sorulan Sorular
DHT22'm neden Raspberry Pi'de "Checksum did not validate" hatası veriyor?
Linux, DHT22'nin ihtiyaç duyduğu hassas zamanlamayı zaman zaman keser; bu yüzden bazı okumalar başarısız olur. Hatayı yakalayın, iki saniye bekleyin ve yeniden deneyin; saatte birkaç başarısızlık normaldir.
DHT22'yi ne sıklıkla okuyabilirim?
İki saniyede birden daha sık değil. MQTT yayını için oda ve sera izlemede 30 ila 60 saniyelik bir aralık fazlasıyla yeterlidir.
Sensör ölçümleri için QoS 0 mı yoksa QoS 1 mi kullanmalıyım?
QoS 1, az ek yükle teslimatı garanti ettiği için iyi bir varsayılandır. Birinin kaybolmasının önemli olmadığı çok sık ölçümler için QoS 0 kabul edilebilir.
Bir Raspberry Pi'ye birden fazla DHT22 sensörü bağlayabilir miyim?
Evet; her birine kendi GPIO pinini verin ve pin başına bir DHT22 nesnesi oluşturun. Hepsini aynı anda değil, art arda okuyun ve her birini kendi topic'ine yayınlayın.



