Raspberry Pi

Raspberry Pi DHT22 MQTT: Python ile Güvenilir Sıcaklık ve Nem Yayını

Bir DHT22'yi Raspberry Pi'ye bağlayın, Python ile okuyun ve hatalı ölçümleri panolarınızdan uzak tutan yeniden denemeler, medyan filtreleme ve hata sayaçlarıyla doğrulanmış sıcaklık ve nem JSON'unu MQTT üzerinden yayınlayın.

Bir Raspberry Pi DHT22 MQTT projesinde breadboard üzerinde Raspberry Pi'ye bağlı ve ölçümleri bir bulut broker'a gönderen DHT22 sıcaklık ve nem sensörü
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

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:

  1. Okumalar arasında en az iki saniye bekleyin; sensör daha hızlı örnekleme yapamaz.
  2. Kütüphanenin fırlattığı RuntimeError hatasını yakalayın ve yeniden deneyin.
  3. Sensörün fiziksel aralığı dışındaki değerleri reddedin.
  4. Birkaç iyi ölçüm alın ve medyanı yayınlayın.
  5. 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

  1. 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.
  2. "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.
  3. Değerler doğru görünüyor ama ara sıra sıçrıyor: medyan filtrelemeyi açık tutun ve SAMPLES değerini 5'e çıkarın.
  4. Nem 99,9'da takılı kalıyor: sensör üzerinde yoğuşma var; DHT22'ler sürekli doygunluktan hoşlanmaz.
  5. Ölçümler duruyor ama durum online kalıyor: betik okumada takılmış; bir watchdog ekleyin veya Restart=always ile systemd üzerinden yeniden başlatın.
  6. 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.

İlgili yazılar

RC522 Okuyucu ile Raspberry Pi RFID MQTT Erişim Kaydı

Bir RC522 RFID okuyucuyu Raspberry Pi'ye bağlayın, etiketleri Python ile okuyun, yerel bir izin listesiyle karşılaştırın ve her erişim denemesini kayıt araçlarının, panellerin ve uyarı araçlarının tüketebileceği bir MQTT olayı olarak yayınlayın.

6 dk okuma

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.