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

4. ünite / 10

MQTT temelleri: broker, konular ve jokerler

Yayımla-abone ol modeli, broker, istemci kimliği, konu tasarımı, + ve # jokerleri, $SYS ve PubSubClient ile umqtt.simple.

Bu ünitenin sonunda

  • Yayımla-abone ol modelini istek-yanıt modeliyle karşılaştırmak
  • Bir cihaz filosu için tutarlı bir konu ağacı tasarlamak
  • + ve # jokerlerinin hangi konularla eşleştiğini önceden söylemek
  • ESP32'de MQTT ile yayımlayan ve komut dinleyen bir istemci yazmak

Ders notları

HTTP'de istemci sunucuya sorar. Peki bir sensör yüz pano ekranına veri göndermek isterse ya da telefon, ağın arkasındaki bir röleye komut vermek isterse? MQTT bunun için tasarlanmış hafif bir protokoldür. Ortada bir broker vardır; cihazlar birbirini tanımaz, yalnız broker'a bağlanır. Yayımlayan bir konuya mesaj gönderir, o konuya abone olan herkes mesajı alır.

Parçalar

  • Broker: Mosquitto, EMQX, HiveMQ gibi bir sunucu. Varsayılan port 1883 (açık metin), TLS ile 8883.
  • İstemci kimliği: her bağlantının broker'daki adı. Benzersiz olmalı: aynı kimlikle ikinci bir istemci bağlanırsa broker eskisini düşürür.
  • Konu: eğik çizgiyle ayrılmış seviyeler, örneğin sera/01/sicaklik. Önceden tanımlanmaz; ilk yayında var olur.
  • Yük: bayt dizisi. Metin, JSON ya da ikili olabilir; broker içine bakmaz.

Konu tasarımı

Konu ağacı, filonun adres defteridir. Genelden özele git: yer/cihaz/ölçüm. Komutları ayrı bir dalda tut (sera/01/led/set), durumu ayrı dalda (sera/01/led). Küçük harf, boşluksuz ve başında eğik çizgi olmayan adlar kullan: /sera ile sera farklı konulardır.

Jokerler

Abonelik süzgeci joker içerebilir, yayın konusu içeremez.

sera/+/sicaklik → sera/01/sicaklik ✓   sera/01/kat/sicaklik ✗    sera/# → sera ✓, sera/01/nem ✓
  • + tam olarak bir seviyenin yerini tutar ve seviyenin tamamı olmalıdır: sera/0+ geçersizdir.
  • # kalan tüm seviyeleri kapsar, yalnız sonda ve tek başına yazılır; üst seviyenin kendisiyle de eşleşir.
  • $ ile başlayan konular ($SYS/broker/uptime) baştaki bir jokerle eşleşmez; broker istatistiklerini bilerek istemelisin.

Açık broker'lar

test.mosquitto.org ve broker.hivemq.com denemek için ücretsizdir ama herkese açıktır: konunu bilen herkes okur ve yazar. Ders denemeleri için benzersiz bir önek seç, gerçek veri ve komut için kendi broker'ını kimlik doğrulama ve TLS ile kur (9. ünite).

Simülasyonlar

Tarayıcıda MQTT broker'ı

Üç simüle cihaz ve bir pano aynı broker'a bağlı. Joker karakterli (+ ve #) abonelikler kur, mesaj yayımla, kalıcı (retained) mesajı ve bir cihazın kablosunu çekince yayımlanan son vasiyeti (LWT) izle.

sera-01
sera/01/led/set Q1
sera-02
sera/02/fan/set Q1
sera-03
abonelik yok
pano
abonelik yok
  1. –Bir şey yayımla ya da cihazlara telemetri gönderttir.
Broker'da kalıcı: sera/01/durum = online · sera/02/durum = online · sera/03/durum = online
Süzgeç sınaması: "sera/#" × "sera/02/nem" → EŞLEŞİR

3B akıllı sera: cihazlar, broker ve MQTT paketleri

Seranın 24 saatini kural motoruyla oynat. Sensör düğümü her 10 dakikada sıcaklık yayımlar, eyleyici düğümü durum değiştirince kalıcı durum mesajı yollar; her paket broker'dan geçerek abonelerine uçar. Panodan elle komut gönder, pencere, fan, ısıtıcı ve sulamanın sahnede değiştiğini izle.

3B sahne yükleniyor…

Sürükle: döndür · iki parmak / tekerlek: yakınlaş · sağ tuş: kaydır

  • telemetri
  • komut
  • durum (retained)
11:00 · içeride 26,8 °C, dışarıda 22,0 °C, toprak %54 pencere kapalı · fan kapalı · ısıtıcı kapalı · sulama kapalı · havada 2 paket
  1. 11:00sera/01/sicaklik 26.8 sensor → broker → actuator, dashboard
  2. 10:50sera/01/sicaklik 26.2 sensor → broker → actuator, dashboard
  3. 10:40sera/01/sicaklik 25.7 sensor → broker → actuator, dashboard
  4. 10:30sera/01/sicaklik 25.1 sensor → broker → actuator, dashboard
Panodan elle komut
Komut paketi pano → broker → eyleyici yolunu izler. Cihazdaki kurallar bir sonraki değişimde yeniden karar verir: hangisi kazanmalı, düşün (10. ünite).

Kod

Arduino C++: PubSubClient ile yayımla ve abone ol
#include <WiFi.h>
#include <PubSubClient.h>
#include "secrets.h"                     // WIFI_SSID, WIFI_PASS, MQTT_HOST

WiFiClient net;
PubSubClient mqtt(net);
const char* ID = "sera-01";              // broker'da benzersiz olmalı
uint32_t lastPub = 0, nextTry = 0;

void onMessage(char* topic, byte* payload, unsigned int len) {
  String msg((char*)payload, len);
  if (String(topic) == "sera/01/led/set") digitalWrite(2, msg == "1");
}

void mqttTask() {
  if (mqtt.connected()) { mqtt.loop(); return; }   // loop() gelen mesajları ve PING'i işler
  if (millis() < nextTry) return;
  if (mqtt.connect(ID)) mqtt.subscribe("sera/01/+/set");
  else nextTry = millis() + 5000;                   // bloklamadan sonra yeniden dene
}

void setup() {
  pinMode(2, OUTPUT);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  mqtt.setServer(MQTT_HOST, 1883);                  // 1883 açık metin; gerçek kurulumda 8883 + TLS
  mqtt.setCallback(onMessage);
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) return;
  mqttTask();
  if (mqtt.connected() && millis() - lastPub > 10000) {
    lastPub = millis();
    mqtt.publish("sera/01/sicaklik", String(temperatureRead(), 1).c_str());  // çip sıcaklığı; DHT22 sonraki ünitelerde
  }
}
MicroPython: umqtt.simple
from umqtt.simple import MQTTClient
from machine import Pin
import time, esp32
from secrets import MQTT_HOST

led = Pin(2, Pin.OUT)

def on_msg(topic, msg):                  # konu ve yük bytes olarak gelir
    if topic == b'sera/01/led/set':
        led.value(msg == b'1')

c = MQTTClient('sera-01', MQTT_HOST, keepalive=30)
c.set_callback(on_msg)
c.connect()
c.subscribe(b'sera/01/+/set')            # + tek seviye: led/set, fan/set…

last = 0
while True:
    c.check_msg()                        # bloklamaz; bekleyen mesaj varsa on_msg çağrılır
    if time.ticks_diff(time.ticks_ms(), last) > 10000:
        last = time.ticks_ms()
        t = (esp32.raw_temperature() - 32) / 1.8
        c.publish(b'sera/01/sicaklik', str(round(t, 1)))
    time.sleep_ms(50)

Kendin dene

Simülasyonda panoyu sera/+/sicaklik konusuna abone et ve üç cihazın yayınlarını izle; sonra süzgeci sera/# yap: neler eklendi? sera/01/kat/sicaklik konusuna elle yayın yap: + süzgeci yakaladı mı? Geçersiz bir süzgeç dene (sera/#/nem). Bir cihazın kablosunu çek ve son vasiyetin hangi abonelere gittiğini gör. Ardından Wokwi'de PubSubClient kodunu test.mosquitto.org ile çalıştır, kendi benzersiz önekini kullan ve bir MQTT istemcisinden sera/01/led/set konusuna 1 gönder.

Sık yapılan hatalar

  • İki cihaza aynı istemci kimliğini vermek: biri bağlanınca öbürü düşer, sonsuz bir bağlan-düş döngüsü oluşur.
  • Konunun başına eğik çizgi koymak (/sera/01): sera/01 ile aynı konu değildir, abonelik eşleşmez.
  • Üretimde # ile her şeye abone olmak: istemci gereksiz trafikle boğulur ve başka cihazların verisini görür.
  • Açık bir test broker'ına gerçek veri ya da komut göndermek: herkes okuyup yazabilir.
  • mqtt.loop() çağırmayı unutmak: gelen mesajlar işlenmez ve keepalive PING'i gitmez, bağlantı kopar.

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

Yayımla-abone ol modeli gevşek bağlılık sağlar: sensör, verisini kimin kullandığını bilmez.

  • Konu ağacını bir arayüz belgesi gibi yönet: her konunun yükü, birimi, sıklığı ve sahibi yazılı olsun. Konu adını değiştirmek, bir API'den alan silmek kadar kırıcıdır.
  • Yeni bir tüketici (veri kaydedici, ML modeli, pano) eklemek cihaz yazılımına dokunmadan olur: yalnız abone olur.
  • Simülasyondaki topicMatches saf bir fonksiyondur; joker kurallarını tablo tabanlı testlerle sınamak kolaydır.

Kendini sına

  1. sera/+/sicaklik süzgeci hangi konuyla eşleşir?

  2. Hangi abonelik süzgeci geçersizdir?

  3. İki cihaz aynı istemci kimliğiyle aynı broker'a bağlanıyor. Ne olur?

  4. # süzgeciyle abone olan bir istemci $SYS/broker/uptime mesajlarını alır mı?

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ç