IoT Eğitimleri

ESP32 MQTT Bağlantısı: Arduino IDE ile Sensör Verisi Yayınlayın ve LED Kontrol Edin

Bir ESP32'yi Arduino IDE ve PubSubClient ile bir MQTT broker'a bağlayın, JSON sıcaklık ölçümleri yayınlayın, kart üzerindeki LED'i komut satırından kontrol edin ve portal kimlik bilgileriyle TLS'e geçin.

ESP32 MQTT eğitiminde MQTT üzerinden sıcaklık verisi gönderen ESP32 geliştirme kartı
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

Bu ESP32 MQTT eğitimi sizi boş bir Arduino sketch'inden; JSON telemetri yayınlayan, komutları dinleyen ve kart üzerindeki LED'i yakıp söndüren bir karta götürüyor. Önce broker.connectmq.com'un ücretsiz public alanına bağlanacak, ardından aynı sketch'i ConnectMQ portalından alınan kimlik bilgileriyle 8883 portunda TLS'e yükselteceksiniz. Her adım bilgisayarınızdan mosquitto_sub ve mosquitto_pub ile doğrulanır.

Ne Geliştireceksiniz?

Tamamlanmış cihaz üç şey yapar:

  1. Otomatik yeniden bağlanmayla Wi-Fi'a ve bir MQTT broker'a bağlanır.
  2. Beş saniyede bir {"temperature":23.41,"uptime":125} gibi bir JSON mesajı yayınlar.
  3. Bir komut topic'ine abone olur ve ON, OFF veya TOGGLE aldığında kart üzerindeki LED'i açar ya da kapatır.

Topic düzeni her şeyi tek ve benzersiz bir önek altında tutar:

Topic Yön Örnek payload
connectmq/demo/<deviceId>/telemetry ESP32 yayınlar {"temperature":23.41,"uptime":125}
connectmq/demo/<deviceId>/led/set ESP32 abone olur ON, OFF, TOGGLE
connectmq/demo/<deviceId>/led/state ESP32 yayınlar (retained) ON veya OFF

Topic, QoS veya retained message gibi MQTT terimleri size yeniyse önce MQTT Broker Nedir? yazısını okuyun.

Ön Koşullar

  • Bir ESP32 geliştirme kartı (herhangi bir ESP32 DevKit uygundur; çoğunda GPIO 2'de mavi bir LED bulunur).
  • Boards Manager üzerinden esp32 kart paketi kurulmuş Arduino IDE 2.x.
  • Library Manager üzerinden kurulmuş, Nick O'Leary'nin PubSubClient kütüphanesi.
  • 2,4 GHz bir Wi-Fi ağı (ESP32, 5 GHz'i desteklemez).
  • İsteğe bağlı: Test için bilgisayarınızda Mosquitto komut satırı client'ları (mosquitto_sub, mosquitto_pub).
  • İsteğe bağlı: Bir DHT22 sensörü. Sketch varsayılan olarak sıcaklığı simüle eder, bu yüzden donanım gerekmez.

ESP32 MQTT İçin Broker Uç Noktaları

broker.connectmq.com dört listener sunar. ESP32 ilk ikisini kullanır; WebSocket portları tarayıcılar içindir.

Protokol Port Bu eğitimde kullanım
MQTT (TCP) 1883 Bölüm 1, anonim public alan
TLS üzerinden MQTT 8883 Bölüm 2, portal kimlik bilgileri
WebSocket 8083 Kullanılmıyor (tarayıcı client'ları)
Güvenli WebSocket 8084 Kullanılmıyor (tarayıcı client'ları)

Public alan hesap gerektirmez: kullanıcı adı veya parola olmadan, boş olmayan ve benzersiz bir client ID ile bağlanın. Orada yayınlanan her şeyin herkes tarafından okunabildiğini unutmayın, bu yüzden yalnızca demo verisi gönderin. Public alan mesaj başına 64 KB'a, client başına saniyede 10 mesaja ve 10 aboneliğe ve en fazla 8 topic seviyesine izin verir; bu proje için fazlasıyla yeterli. Ayrıntılar için ücretsiz public MQTT broker rehberine bakın.

Bölüm 1: Düz TCP Üzerinden ESP32 MQTT (Port 1883)

MAC adresinden benzersiz bir client ID üretin

Client ID'ler benzersiz olmalıdır: iki client aynı ID ile bağlanırsa broker eskisinin bağlantısını keser. Her ESP32'nin fabrikada programlanmış bir MAC adresi vardır; bu da kalıcı ve benzersiz bir ID için mükemmel bir kaynaktır. Sketch esp32-a1b2c3d4e5f6 gibi bir değer oluşturur ve bunu topic önekinde yeniden kullanır.

Eksiksiz sketch

Yeni bir sketch oluşturun, aşağıdaki kodu yapıştırın ve Wi-Fi SSID'nizi ve parolanızı girin.

#include <WiFi.h>
#include <PubSubClient.h>

// ---- Wi-Fi ----
const char* WIFI_SSID     = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";

// ---- MQTT ----
const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 1883;

const int LED_PIN = 2;                 // çoğu ESP32 DevKit'te kart üzerindeki LED
const unsigned long PUBLISH_INTERVAL_MS = 5000;

WiFiClient netClient;
PubSubClient mqtt(netClient);

String deviceId;
String topicTelemetry, topicLedSet, topicLedState;
unsigned long lastPublish = 0;
unsigned long lastReconnectAttempt = 0;
bool ledOn = false;

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nWi-Fi connected, IP: ");
  Serial.println(WiFi.localIP());
}

String makeDeviceId() {
  uint8_t mac[6];
  WiFi.macAddress(mac);
  char buf[20];
  snprintf(buf, sizeof(buf), "esp32-%02x%02x%02x%02x%02x%02x",
           mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  return String(buf);
}

void publishLedState() {
  mqtt.publish(topicLedState.c_str(), ledOn ? "ON" : "OFF", true);  // retained
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  String msg;
  for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];
  msg.trim();
  Serial.printf("Message on %s: %s\n", topic, msg.c_str());

  if (String(topic) != topicLedSet) return;
  if (msg.equalsIgnoreCase("ON"))          ledOn = true;
  else if (msg.equalsIgnoreCase("OFF"))    ledOn = false;
  else if (msg.equalsIgnoreCase("TOGGLE")) ledOn = !ledOn;
  else return;                             // diğer her şeyi yok say

  digitalWrite(LED_PIN, ledOn ? HIGH : LOW);
  publishLedState();
}

bool connectMqtt() {
  Serial.printf("Connecting to MQTT as %s ... ", deviceId.c_str());
  if (mqtt.connect(deviceId.c_str())) {     // kullanıcı adı/parola yok: public alan
    Serial.println("connected");
    mqtt.subscribe(topicLedSet.c_str(), 1);
    publishLedState();
    return true;
  }
  Serial.printf("failed, state=%d\n", mqtt.state());
  return false;
}

float readTemperature() {
  // Simüle edilmiş sensör: biraz gürültüyle 22-25 °C
  return 23.5 + 1.5 * sin(millis() / 60000.0) + random(-20, 20) / 100.0;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);

  connectWiFi();
  deviceId = makeDeviceId();
  String base = "connectmq/demo/" + deviceId;
  topicTelemetry = base + "/telemetry";
  topicLedSet    = base + "/led/set";
  topicLedState  = base + "/led/state";
  Serial.println("Topic prefix: " + base);

  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
  mqtt.setBufferSize(512);   // varsayılan 256 bayttır, aşağıya bakın
  mqtt.setKeepAlive(30);
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    connectWiFi();
  }

  if (!mqtt.connected()) {
    unsigned long now = millis();
    if (now - lastReconnectAttempt > 5000) {   // 5 sn'de bir bloklamayan yeniden deneme
      lastReconnectAttempt = now;
      if (connectMqtt()) lastReconnectAttempt = 0;
    }
    return;
  }

  mqtt.loop();   // gelen mesajları ve keepalive'ı işle

  if (millis() - lastPublish >= PUBLISH_INTERVAL_MS) {
    lastPublish = millis();
    char json[96];
    snprintf(json, sizeof(json), "{\"temperature\":%.2f,\"uptime\":%lu}",
             readTemperature(), millis() / 1000);
    mqtt.publish(topicTelemetry.c_str(), json);
    Serial.printf("Published %s\n", json);
  }
}

Kartınızı ve portunuzu seçin, yükleyin ve Serial Monitor'ü 115200 baud'da açın. IP adresini, topic önekini ve beş saniyede bir Published satırını görmelisiniz. Cihaz ID'sini topic önekinden kopyalayın; bir sonraki adımda ihtiyacınız olacak.

Yeniden bağlanma mantığı nasıl çalışır?

Sketch broker'ı beklerken asla sonsuza dek bloklanmaz. Bağlantı koparsa loop(), programın geri kalanı çalışmaya devam ederken beş saniyede bir yeniden dener. İki ayrıntı önemlidir:

  • mqtt.loop() sık sık çalışmalıdır. Gelen paketleri okur ve keepalive ping'leri gönderir; döngünüzde delay(10000) çağırırsanız broker client'ı ölü kabul eder.
  • Yeniden bağlandıktan sonra sketch tekrar abone olur. Varsayılan clean session ile abonelikler bağlantı kopmasından sonra korunmaz; bu yüzden connectMqtt() içinde yeniden abone olmak şarttır.

mqtt.state() hata durumunda sayısal bir kod döndürür: -2 genellikle bir ağ sorunu anlamına gelir (yanlış host, internet yok); pozitif değerler ise broker'ın CONNACK'inden gelir, örneğin reddedilen tanımlayıcı için 2.

Gerçek bir DHT22 sensörü kullanmak

Gerçek veri kullanmak için Adafruit'in "DHT sensor library" kütüphanesini kurun, sensörün veri pinini GPIO 4'e bağlayın ve readTemperature() fonksiyonunu değiştirin:

#include <DHT.h>
DHT dht(4, DHT22);   // setup() içinde dht.begin() çağırın

float readTemperature() {
  float t = dht.readTemperature();
  return isnan(t) ? -127.0 : t;   // NaN yerine bir işaret değeri gönder
}

mosquitto_sub ve mosquitto_pub ile Doğrulayın

Bir terminal açın ve cihazınızın öneki altındaki her şeye abone olun. esp32-a1b2c3d4e5f6 yerine Serial Monitor'deki ID'yi yazın.

mosquitto_sub -h broker.connectmq.com -p 1883 -i laptop-watch-81f3 \
  -t "connectmq/demo/esp32-a1b2c3d4e5f6/#" -v

Çıktı şöyle görünür:

connectmq/demo/esp32-a1b2c3d4e5f6/led/state OFF
connectmq/demo/esp32-a1b2c3d4e5f6/telemetry {"temperature":23.41,"uptime":125}
connectmq/demo/esp32-a1b2c3d4e5f6/telemetry {"temperature":23.47,"uptime":130}

Şimdi ikinci bir terminalden LED'i değiştirin:

mosquitto_pub -h broker.connectmq.com -p 1883 -i laptop-cmd-81f3 \
  -t "connectmq/demo/esp32-a1b2c3d4e5f6/led/set" -q 1 -m "TOGGLE"

LED değişir ve subscriber yeni retained led/state değerini yazdırır. Durum retained olduğu için daha sonra abone olan her dashboard mevcut değeri anında alır. Abonelik QoS 1 kullanır, böylece komut broker tarafından onaylanır; artı ve eksileri MQTT QoS seviyeleri yazısında ele alınıyor.

Cihazın gelip gidişini de izleyebilirsiniz: $SYS/broker/connection/esp32-a1b2c3d4e5f6/state topic'ine abone olun; cihaz bağlandığında 1, bağlantısı kesildiğinde 0 görürsünüz.

PubSubClient Tampon Boyutu

PubSubClient, gelen ve giden paketler için tek bir tampon ayırır ve bu tampon varsayılan olarak yalnızca 256 bayttır. Bu tampon MQTT paketinin tamamını tutmalıdır: sabit başlık, topic adı ve payload. Uzun bir topic ile orta boyutlu bir JSON belgesi onu hızla aşar; bu olduğunda publish() sessizce false döndürür ve sığmayan gelen mesajlar düşürülür.

Bağlanmadan önce setBufferSize() çağırın ve publish()'in dönüş değerini kontrol edin:

Payload boyutu (yaklaşık) Önerilen setBufferSize()
~150 bayta kadar 256 (varsayılan)
~400 bayta kadar 512
~1.800 bayta kadar 2048
Daha büyük belgeler Mesajı bölün veya yalnızca değişen alanları gönderin

Her ek bayt ESP32'nin RAM'inden gider; bu yüzden tamponu broker'ın maksimumuna göre değil, gerçek mesajlarınıza göre boyutlandırın.

Bölüm 2: 8883 Portunda TLS ile Güvenli ESP32 MQTT

Public alan öğrenmek için mükemmeldir; ancak üretim cihazları TLS ve kendi kimlik bilgilerini kullanmalıdır. https://app.connectmq.com adresinde oturum açın, bir broker oluşturun ve üretilen kullanıcı adı, parola ve client ID'yi kopyalayın. Kimliği doğrulanmış client'lar public alan yerine size ait izole kiracıya düşer.

Kimliği doğrulanmış bağlantılarda client ID'ler verilen ID ve onun _suffix varyantlarıyla sınırlıdır. Her cihaza kendi sonekini verin, örneğin YOUR_CLIENT_ID_esp32a; dizüstü bilgisayarınıza da başka bir sonek.

Sketch'teki değişiklikler

Yalnızca ağ client'ı, port, kimlik bilgileri ve topic'ler değişir. ISRG Root X1 sertifikasını (isrgrootx1.pem) Let's Encrypt'ten indirin; broker'ın sertifika zinciri bu köke dayanır. İçeriğini sketch'e yapıştırın:

#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <time.h>

const char* MQTT_HOST = "broker.connectmq.com";
const uint16_t MQTT_PORT = 8883;
const char* MQTT_USER = "YOUR_USERNAME";
const char* MQTT_PASS = "YOUR_PASSWORD";
const char* MQTT_CLIENT_ID = "YOUR_CLIENT_ID_esp32a";

// ISRG Root X1 (isrgrootx1.pem içindeki PEM'in tamamını yapıştırın)
static const char ROOT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
...paste the certificate body here...
-----END CERTIFICATE-----
)EOF";

WiFiClientSecure netClient;
PubSubClient mqtt(netClient);

void syncClock() {
  configTime(0, 0, "pool.ntp.org", "time.nist.gov");
  time_t now = time(nullptr);
  while (now < 1700000000) { delay(250); now = time(nullptr); }
}

// setup() içinde, connectWiFi() çağrısından sonra:
//   syncClock();
//   netClient.setCACert(ROOT_CA);
//   mqtt.setServer(MQTT_HOST, MQTT_PORT);
//   topic tabanı: "connectmq/demo/..." yerine "plant1/" + String(MQTT_CLIENT_ID)

bool connectMqtt() {
  if (mqtt.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS)) {
    mqtt.subscribe(topicLedSet.c_str(), 1);
    publishLedState();
    return true;
  }
  return false;
}

Birkaç not:

  • setCACert(), ESP32'nin gerçekten broker.connectmq.com ile konuştuğunu doğrulamasını sağlar. Önce saati NTP ile senkronize etmek, TLS yığınının sertifika geçerlilik tarihlerini kontrol edebilmesini sağlar.
  • setInsecure() doğrulamayı tamamen atlar. Beş dakikalık bir test için kullanışlıdır, ancak ortadaki adam saldırılarına karşı korumayı ortadan kaldırır; bu yüzden asla ürüne koymayın.
  • TLS belirgin şekilde daha fazla RAM kullanır ve ilk el sıkışma biraz zaman alır. ESP32'de bu normaldir.
  • Kimlik bilgilerini Git deponuzun dışında tutun; örneğin .gitignore içinde listelenen ayrı bir secrets.h dosyasında. MQTT güvenliği kontrol listesi cihazda sır saklamayı ve diğer sağlamlaştırma adımlarını ele alır.

Güvenli bağlantıyı doğrulayın

Kendi kimlik bilgilerinizle ve farklı bir sonekle abone olun. Linux'ta --capath /etc/ssl/certs ile sistem CA deposunu kullanabilirsiniz; herhangi bir işletim sisteminde indirdiğiniz kök sertifikayı verebilirsiniz:

mosquitto_sub -h broker.connectmq.com -p 8883 --cafile isrgrootx1.pem \
  -u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID_laptop \
  -t "plant1/#" -v

Komutu da aynı şekilde gönderin:

mosquitto_pub -h broker.connectmq.com -p 8883 --cafile isrgrootx1.pem \
  -u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID_cli \
  -t "plant1/YOUR_CLIENT_ID_esp32a/led/set" -q 1 -m "ON"

Hiçbir şey kurmadan telemetriyi izlemek için ConnectMQ portalındaki tarayıcı içi MQTT client'ını veya canlı topic gezginini de açabilirsiniz.

Sorun Giderme

Belirti Olası neden Çözüm
Döngü halinde state=-2 İnternet yok, yanlış host veya engellenmiş port Wi-Fi'ı kontrol edin, 1883 portunu deneyin, güvenlik duvarını kontrol edin
state=2 Client ID reddedildi Boş olmayan benzersiz bir ID kullanın; kimlik bilgileriyle verilen ID'yi veya bir _suffix varyantını kullanın
state=4 veya 5 Hatalı kimlik bilgileri Kullanıcı adını ve parolayı portaldan yeniden kopyalayın
Yayınlar duruyor, hata görünmüyor Mesaj tampondan büyük setBufferSize() değerini artırın, publish() dönüş değerini kontrol edin
Sürekli kopmalar mqtt.loop() yeterince sık çağrılmıyor veya aynı ID'ye sahip başka bir client var Uzun delay() çağrılarını kaldırın, her client'a kendi ID'sini verin
TLS başarısız, düz TCP çalışıyor Yanlış CA, saat ayarlanmamış ISRG Root X1 kullanın, bağlanmadan önce saati NTP ile senkronize edin

ConnectMQ ile Başlayın

Artık önce public alanda, ardından kendi kimlik bilgileriyle TLS üzerinden MQTT ile telemetri gönderen ve komut alan bir ESP32'niz var. Demo verisinin ötesine geçmeye hazır olduğunuzda https://app.connectmq.com adresinde ücretsiz Serverless planında bir broker oluşturun (kredi kartı gerekmez) ve filonuzu takip etmek için portalın dashboard'unu, cihaz görünümünü ve eşik alarmlarını kullanın.

Sık Sorulan Sorular

Arduino IDE ile ESP32'de hangi MQTT kütüphanesini kullanmalıyım?

En yaygın tercih PubSubClient'tır: küçük ve kararlıdır, hem WiFiClient hem de WiFiClientSecure ile çalışır. QoS 0 yayınları ve QoS 0 veya 1 abonelikleriyle MQTT 3.1.1'i destekler; bu da çoğu sensör projesini karşılar.

ESP32'mdeki yayın neden hatasız şekilde başarısız oluyor?

Çoğu zaman paket, PubSubClient'ın varsayılan 256 baytlık tamponundan büyüktür. Bağlanmadan önce mqtt.setBufferSize(512) veya daha büyük bir değer çağırın ve publish()'in döndürdüğü boolean değeri kontrol edin.

broker.connectmq.com ile ESP32 MQTT'yi test etmek için hesaba ihtiyacım var mı?

Hayır. Public alanı kullanmak için kullanıcı adı olmadan ve benzersiz bir client ID ile 1883 veya 8883 portuna bağlanın. Gerçek veriler için ücretsiz bir hesap oluşturun ve üretilen kimlik bilgilerini kullanın.

WiFiClientSecure ile setInsecure() kullanabilir miyim?

Yalnızca hızlı testler için. Trafiği şifreler ancak sunucu doğrulamasını atlar; dolayısıyla bir saldırgan broker'ı taklit edebilir. Dağıttığınız her şeyde ISRG Root X1 ile setCACert() kullanın.

Tek bir broker üzerinde birden fazla ESP32 kartına kendi client ID'lerini nasıl veririm?

Portalda verilen client ID'ye YOUR_CLIENT_ID_esp32a ve YOUR_CLIENT_ID_esp32b gibi bir sonek ekleyin. ConnectMQ, kimliği doğrulanmış bağlantılarda verilen ID'yi ve onun _suffix varyantlarını kabul eder.

İlgili yazılar

Test, Betik ve Hata Ayıklama için En İyi MQTT CLI Araçları

mosquitto_pub/sub, MQTTX CLI, HiveMQ MQTT CLI, MQTT.js CLI, curl ve mqttui'nin uygulamalı karşılaştırması; betik yazma ve hata ayıklama için doğru aracı seçebilmeniz için aynı test broker.connectmq.com üzerinde çalıştırıldı.

7 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.