Okullar için Robotik ve Mühendislik · anaokulundan liseye

6. ünite / 10

Sensörden buluta: okuma, yük biçimi ve trafik

DHT11, DHT22 ve BME280'i doğru hızda oku; JSON, CSV ya da ikili yükle gönder, "değişince bildir" ile trafiği azalt.

Bu ünitenin sonunda

  • DHT11, DHT22 ve BME280'i doğruluk, okuma aralığı ve arayüz bakımından karşılaştırmak
  • Aynı okumayı JSON, CSV ve ikili yük olarak kodlayıp MQTT paket boyutunu hesaplamak
  • Yayın aralığı, TLS ve ölü bantla günlük mesaj ve veri miktarını tahmin etmek
  • Okumaya NTP'den alınmış zaman damgası eklemek ve okunamayan örneği doğru işlemek

Ders notları

Bir IoT cihazının asıl işi ölçmek ve ölçümü güvenilir biçimde bir yere ulaştırmaktır. Laboratuvardaki üç sensör üç farklı arayüz kullanır: DHT11/DHT22 tek telli kendi protokolüyle, BME280 I²C ile (adres 0x76 ya da 0x77, SDO pinine göre), LDR ise bir gerilim bölücüyle ADC1 pinine bağlanır.

Sensörü tanı

  • DHT11: 0–50 °C, ±2 °C, tam sayı çözünürlük, saniyede en çok bir okuma. Eğitim için yeter, sera için kaba.
  • DHT22: −40–80 °C, ±0,5 °C, 0,1 °C çözünürlük, en çok 2 saniyede bir okuma. Daha sık okursan bir önceki değeri ya da hata alırsın.
  • BME280: sıcaklık, nem ve basınç; I²C üzerinden hızlı, ±1 hPa basınç. Kendi ısınmasını azaltmak için "forced mode" ile yalnız gerektiğinde ölç.

Okunamayan örnek (NaN) normaldir: DHT22 zaman aşımına uğrar, kablo uzundur. Doğru davranış o örneği atlamak, son değeri tekrar göndermemektir; aksi halde bulut "sabit sıcaklık" görür.

Yük biçimi ve paket boyutu

Aynı okuma üç biçimde gidebilir: JSON ({"t":23.4,"h":51.2}, okunur ve kendini anlatır), CSV (23.4,51.2, sıra anlaşması gerekir) ya da ikili (int16 × 10, sabit 8 bayt). MQTT PUBLISH paketinin boyutu şöyledir:

boyut = 1 + kalan_uzunluk_baytı + (2 + konu) + (QoS > 0 ? 2 : 0) + yük

Buna TCP/IP başlıkları (yaklaşık 40 bayt) ve TLS kaydı (yaklaşık 29 bayt) eklenir. Küçük yüklerde başlıklar baskındır: 60 bayt JSON yerine 8 bayt ikili yük toplam trafiği yarıya bile indirmeyebilir. Önce aralığı ve ne zaman gönderdiğini düşün.

Değişince bildir

Sıcaklık 10 dakikada 0,1 °C değişiyorsa her 10 saniyede bir yayımlamak boşa enerjidir. Ölü bant: son gönderilenden en az Δ kadar farklıysa gönder. Kalp atışı: değişim olmasa da belirli sürede bir gönder, böylece sessizlik "cihaz öldü" ile karışmaz. Her yayına NTP'den alınmış bir zaman damgası koy; ağ gecikmesi ve kuyruk yüzünden broker'ın gördüğü an ölçüm anı değildir.

Simülasyon

Sensörden buluta: yük ve trafik hesabı

DHT22/BME280 okumasını JSON, CSV ya da 8 baytlık ikili yük olarak gönder. Yayın aralığı, QoS, TLS ve "değişince bildir" ölü bandıyla paket boyutunu, günlük mesaj ve veri miktarını hesapla.

PUBLISH sera/01/olcum QoS 0 {"id":"sera-01","t":24.6,"h":48.7,"p":1015,"l":888} yük 51 B · MQTT paketi 68 B
Bir günlük sıcaklık; noktalar gerçekten yayımlanan örnekler14.617.921.124.327.604.89.5914.419.224saat°C
Her örnek: günde 1440 mesaj, 192,7 KB/gün, ayda 5,6 MB Değişince bildir: günde 615 mesaj (%43), 82,3 KB/gün

Kod

Arduino C++: BME280 + DHT22, değişince bildir ve NTP zaman damgası
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_BME280.h>
#include <DHT.h>
#include <time.h>
#include "secrets.h"            // WIFI_SSID, WIFI_PASS, MQTT_HOST: git'e girmez

Adafruit_BME280 bme;            // I2C: SDA 21, SCL 22, adres 0x76 ya da 0x77
DHT dht(4, DHT22);              // DHT22 veri pini GPIO4 (10k pull-up)
WiFiClient net;
PubSubClient mqtt(net);

const float DEADBAND = 0.3;     // °C: bundan küçük değişim yayımlanmaz
const uint32_t HEARTBEAT_MS = 10UL * 60 * 1000;  // en geç 10 dakikada bir yine de yayımla
float lastSent = NAN;
uint32_t lastMs = 0;

void setup() {
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(250);
  configTime(3 * 3600, 0, "pool.ntp.org");        // UTC+3, NTP ile saat
  if (!bme.begin(0x76) && !bme.begin(0x77)) Serial.println("BME280?");
  dht.begin();
  mqtt.setServer(MQTT_HOST, 1883);
}

void loop() {
  if (!mqtt.connected()) mqtt.connect("sera-01");
  mqtt.loop();
  static uint32_t lastRead = 0;
  if (millis() - lastRead < 2000) return;         // DHT22 en fazla 2 s'de bir okunur
  lastRead = millis();
  float t = bme.readTemperature(), h = dht.readHumidity(), p = bme.readPressure() / 100.0;
  if (isnan(h)) return;                           // okunamadı: uydurma değer gönderme
  bool changed = isnan(lastSent) || fabs(t - lastSent) >= DEADBAND;
  if (!changed && millis() - lastMs < HEARTBEAT_MS) return;
  char buf[96];
  snprintf(buf, sizeof buf, "{\"ts\":%ld,\"t\":%.1f,\"h\":%.1f,\"p\":%.1f}", (long)time(nullptr), t, h, p);
  mqtt.publish("sera/01/telemetri", buf);         // QoS 0, kalıcı değil
  lastSent = t; lastMs = millis();
}
MicroPython: umqtt.simple ile ikili (8 bayt) yük
import struct, time, ntptime
from machine import Pin, I2C
from umqtt.simple import MQTTClient
import dht
import secrets                      # cihaza ayrı yüklenir, depoda yok

d = dht.DHT22(Pin(4))
c = MQTTClient("sera-01", secrets.MQTT_HOST)
c.connect()
ntptime.settime()                   # RTC saatini NTP'den al (UTC)

while True:
    try:
        d.measure()
    except OSError:
        time.sleep(2); continue     # okunamadı: atla
    t, h = d.temperature(), d.humidity()
    # int16 sıcaklık x10, uint16 nem x10, uint32 zaman: 8 bayt, küçük-endian
    yuk = struct.pack("<hHI", round(t * 10), round(h * 10), time.time())
    c.publish(b"sera/01/bin", yuk)
    time.sleep(60)

Kendin dene

Telemetri simülasyonunda biçimi JSON, CSV ve ikili arasında değiştir: paket boyutu kaç bayt oluyor? Aralığı 10 s yap, TLS'i aç ve günlük veri miktarını not et; sonra ölü bandı 0,3 °C'ye çıkar ve mesaj sayısının ne kadar düştüğünü karşılaştır. Wokwi'de ESP32 + DHT22 + BME280 devresini kur, C++ kodunu çalıştır ve seri monitörde yalnız değişimde yayın yapıldığını gör.

Sık yapılan hatalar

  • DHT22'yi 2 saniyeden sık okumak: değer güncellenmez ya da okuma hatası artar.
  • Okunamayan örnekte son değeri yeniden göndermek: bulut sensörün sağlıklı olduğunu sanır.
  • LDR'yi ADC2 pinine bağlamak: Wi-Fi açıkken okuma çalışmaz, ADC1 (GPIO32–39) kullan.
  • Zaman damgasını broker'ın alış anı saymak: kuyruklu ya da derin uykudan dönen cihazda ölçüm anı farklıdır.
  • Ölü bant koyup kalp atışı koymamak: değişmeyen ortamda sessizlik "cihaz çevrim dışı" ile karışır.

Yazılım mühendisliği bağlantısı

Telemetri biçimi bir sözleşmedir: cihaz ve bulut ayrı ayrı güncellenir, biçim ikisini birden kırmamalıdır.

  • Yükte bir sürüm alanı ("v":1) taşı; yeni alan eklemek geriye uyumlu, alanın anlamını değiştirmek değildir.
  • Kodlayıcı ve çözücüyü saf fonksiyon yaz ve "kodla sonra çöz = aynı değer" testini ekle; ikili biçimde bayt sırası hatası en sık hatadır.

Kendini sına

  1. Seradaki bir sıcaklık için DHT11 yerine DHT22 seçmenin ana nedeni nedir?

  2. BME280 I²C taramasında bulunamıyor. İlk denenecek şey hangisi?

  3. Ölü bant 0,3 °C, kalp atışı 10 dakika. Sıcaklık bir saat boyunca hiç değişmezse kaç yayın yapılır?

  4. Okunamayan (NaN) bir DHT22 örneğinde doğru davranış nedir?

Parçalar ve ilgili sayfalar

Esc
  • PanelAna sayfaSayfa
  • ModüllerTüm modüllerSayfa
  • ParçalarParça ansiklopedisiSayfa
  • Mühendislik yoluBüyükler için robotik: 128 parça, 7 seviyeSayfa
  • Robotik dersi (ESOF 323)Üniversite robotik dersi, 14 haftaSayfa
  • Drone dersiBüyükler için: parça, simülasyon, yazılım; 10 üniteSayfa
  • Blok atölyesiSerbest blok programlamaAraç
  • Devre laboratuvarıSanal Arduino ve devreAraç
  • Robot arenasıSanal robot sürüşüAraç
  • OyunlarBloklarla 8 öğretici oyunAraç
  • Mikro Kart atölyesiSanal LED kartı bloklarla programlaAraç
  • Robot atölyesiMikro Kart'ı robota tak, bloklarla görev yapAraç