Yönetilen MQTT Bulutu

ESP32'yi TLS Üzerinden Bulut MQTT Broker'a Bağlamak

Bir ESP32 projesini yerel Mosquitto broker'dan kullanıcı adı, parola ve doğrulanmış sertifikayla TLS üzerinden bir bulut MQTT broker'a taşımak için adım adım rehber.

TLS üzerinden bir bulut broker'a şifreli telemetri gönderen bir ESP32 kartını gösteren ESP32 bulut MQTT broker illüstrasyonu
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 ESP32'yi TLS üzerinden bir bulut MQTT broker'a bağlamak, masa üstündeki bir prototipi ev ağınızın dışında kullanılabilecek bir şeye dönüştüren adımdır. Bu eğitimde bir ESP32 sketch'ini 1883 portundaki yerel bir Mosquitto broker'dan 8883 portundaki bir ConnectMQ Serverless broker'a; düzgün sertifika doğrulaması, kimlik bilgileri, bir durum topic'i ve güvenilir yeniden bağlanmalarla taşıyacaksınız.

Yerel Broker'dan Ayrıldığınızda Neler Değişir

Çoğu ESP32 projesi bir Raspberry Pi veya dizüstü bilgisayardaki Mosquitto ile başlar: 1883'te düz TCP, kimlik doğrulama yok, yalnızca yerel ağınızdan erişilebilir. Bir bulut MQTT broker'a geçmek dört şeyi değiştirir:

Özellik Yerel broker Bulut broker
Host 192.168.1.20 broker.connectmq.com
Port 1883 (düz TCP) 8883 (TLS)
Kimlik doğrulama Çoğu zaman yok Kullanıcı adı, parola, client ID
Ağ istemcisi WiFiClient WiFiClientSecure
Sertifika Yok Sunucu sertifikası bir CA'ya karşı doğrulanır
Erişilebilirlik Yalnızca yerel ağ İnternet olan her yerden

MQTT mantığının kendisi (topic'ler, yayınlar ve abonelikler) aynı kalır. Daha önce hiç bir ESP32'yi MQTT'ye bağlamadıysanız ESP32 MQTT eğitimi ile başlayın ve buraya geri dönün.

Ön Koşullar

  • Bir ESP32 geliştirme kartı ve USB kablosu.
  • ESP32 Arduino core kurulu Arduino IDE 2.x veya PlatformIO (resmi Espressif Arduino core belgelerine bakın).
  • Nick O'Leary'nin PubSubClient kütüphanesi.
  • Ücretsiz bir Serverless broker. Portalda kaydolun, Serverless (Free) planını seçin, bir broker oluşturun ve üretilen kullanıcı adını, parolayı ve client ID'yi kopyalayın.

Adım 1: Kök CA Sertifikasını Edinin

Broker bir Let's Encrypt sertifikası sunar. ESP32'nin zinciri imzalayan köke güvenmesi gerekir. Let's Encrypt zincirleri ISRG Root X1'e kadar uzanır, dolayısıyla gömülmesi gereken sertifika budur. Zinciri OpenSSL yüklü herhangi bir makineden kendiniz doğrulayabilirsiniz:

openssl s_client -connect broker.connectmq.com:8883 -servername broker.connectmq.com -showcerts </dev/null

Çıktının üst kısmındaki issuer satırlarına bakın. Ardından ISRG Root X1'i Let's Encrypt'in sertifika sayfasından PEM formatında indirin ve sketch'inize ham bir dize olarak yapıştırın. Sunucunun kendi sertifikası yerine uzun ömürlü kökü gömmek, sunucu sertifikası birkaç ayda bir yenilendiğinde cihazları yeniden flaşlamanız gerekmediği anlamına gelir.

Adım 2: Eksiksiz Sketch

Bu sketch Wi-Fi'a bağlanır, saati senkronize eder (TLS sertifika doğrulaması doğru bir saat gerektirir), kimlik bilgileriyle TLS üzerinden broker'a bağlanır, Last Will ile retained bir çevrimiçi durumu yayımlar, bir komut topic'ine abone olur ve her on saniyede bir telemetri yayımlar.

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

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

// ---- ConnectMQ ----
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";

const char* TOPIC_TELEMETRY = "devices/esp32-01/telemetry";
const char* TOPIC_STATUS    = "devices/esp32-01/status";
const char* TOPIC_COMMAND   = "devices/esp32-01/cmd";

// ISRG Root X1 (Let's Encrypt'ten aldığınız tam PEM'i buraya yapıştırın)
static const char ROOT_CA[] PROGMEM = R"EOF(
-----BEGIN CERTIFICATE-----
PASTE_ISRG_ROOT_X1_PEM_CONTENT_HERE
-----END CERTIFICATE-----
)EOF";

WiFiClientSecure net;
PubSubClient mqtt(net);

unsigned long lastPublish = 0;
unsigned long lastReconnectAttempt = 0;
unsigned long reconnectDelay = 1000;

void connectWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.print("Connecting to Wi-Fi");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.printf("\nWi-Fi connected, IP %s\n", WiFi.localIP().toString().c_str());
}

void syncTime() {
  configTime(0, 0, "pool.ntp.org", "time.google.com");
  Serial.print("Syncing time");
  time_t now = time(nullptr);
  while (now < 1700000000) {
    delay(500);
    Serial.print(".");
    now = time(nullptr);
  }
  Serial.println(" done");
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  String msg;
  for (unsigned int i = 0; i < length; i++) msg += (char)payload[i];
  Serial.printf("Command on %s: %s\n", topic, msg.c_str());
  if (msg == "led:on")  digitalWrite(LED_BUILTIN, HIGH);
  if (msg == "led:off") digitalWrite(LED_BUILTIN, LOW);
}

bool connectMqtt() {
  Serial.print("Connecting to ConnectMQ... ");
  bool ok = mqtt.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS,
                         TOPIC_STATUS, 1, true, "offline");
  if (!ok) {
    Serial.printf("failed, state=%d\n", mqtt.state());
    return false;
  }
  Serial.println("connected");
  mqtt.publish(TOPIC_STATUS, "online", true);
  mqtt.subscribe(TOPIC_COMMAND, 1);
  return true;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);
  connectWiFi();
  syncTime();

  net.setCACert(ROOT_CA);
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
  mqtt.setKeepAlive(30);
  mqtt.setBufferSize(512);
}

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

  if (!mqtt.connected()) {
    unsigned long now = millis();
    if (now - lastReconnectAttempt > reconnectDelay) {
      lastReconnectAttempt = now;
      if (connectMqtt()) {
        reconnectDelay = 1000;
      } else {
        reconnectDelay = min(reconnectDelay * 2, 60000UL);
      }
    }
    return;
  }

  mqtt.loop();

  if (millis() - lastPublish > 10000) {
    lastPublish = millis();
    char payload[128];
    snprintf(payload, sizeof(payload),
             "{\"uptime_s\":%lu,\"rssi\":%d,\"heap\":%u}",
             millis() / 1000, WiFi.RSSI(), ESP.getFreeHeap());
    mqtt.publish(TOPIC_TELEMETRY, payload);
    Serial.println(payload);
  }
}

Tercihlere dair notlar:

  • Retained durum artı Last Will. ESP32 temiz bir bağlantı kesme olmadan düşerse broker sizin adınıza offline yayımlar ve yeni aboneler her zaman son durumu görür. Bu desen hakkında daha fazlası ESP32 MQTT Last Will yazısında.
  • Bloklamayan backoff. Yeniden bağlanma denemeleri bir saniyeden bir dakikaya kadar ikiye katlanır; böylece bir filo bir kesintiden sonra broker'a yüklenmez.
  • Tampon boyutu. PubSubClient'ın varsayılan 256 baytlık tamponu daha büyük mesajları sessizce düşürür; 512 bayt pay bırakır.
  • Bazı kartlarda LED_BUILTIN yoktur. Bunu kartınızın LED pini olarak tanımlayın; çoğu zaman GPIO 2'dir.

Adım 3: Bilgisayarınızdan Doğrulayın

Portalın tarayıcı içi istemcisini veya topic gezginini açın ve devices/# konusuna abone olun. Her on saniyede bir telemetri ve durum topic'inde retained online değerini görmelisiniz. Komut satırından bir komut göndermek için:

mosquitto_pub -h broker.connectmq.com -p 8883 --capath /etc/ssl/certs \
  -u YOUR_USERNAME -P YOUR_PASSWORD -i YOUR_CLIENT_ID-cli \
  -t devices/esp32-01/cmd -m 'led:on' -q 1

ESP32'ninkinden farklı bir client ID kullanın. Planınız kimlik bilgilerine tek bir client ID bağlıyorsa bunun yerine portalın tarayıcı içi istemcisini kullanın veya araçlar için ek kimlik bilgileri oluşturun.

Hesap Olmadan Test Etmek

Kaydolmadan önce sketch'i denemek için ücretsiz herkese açık MQTT broker'ı kullanın: 8883 portunu ve aynı kök CA'yı koruyun, boş kullanıcı adı ve parola geçin (mqtt.connect(clientId)), boş olmayan benzersiz herhangi bir client ID seçin ve her topic'in başına connectmq/demo/x8q2m/esp32-01/... gibi benzersiz bir önek ekleyin. Herkese açık alan herkes tarafından okunabilir, bu yüzden hassas hiçbir şey yayımlamayın ve limitlerini unutmayın: mesaj başına 64 KB ve istemci başına saniyede 10 mesaj.

Sorun Giderme

Belirti Olası neden Çözüm
Hemen state=-2 TLS el sıkışması başarısız Kök CA'yı, saat senkronizasyonunu ve 8883 portunu kontrol edin
Saat senkronizasyonunda takılıyor NTP engelli UDP 123'e izin verin veya erişilebilir bir NTP sunucusu kullanın
state=4 Hatalı kullanıcı adı veya parola Kimlik bilgilerini portaldan yeniden kopyalayın
state=5 Yetkisiz Client ID verilen kimlik bilgileriyle eşleşmiyor
Bağlanıp döngü hâlinde kopuyor Yinelenen client ID Her cihazın ve aracın kendi ID'sini kullandığından emin olun
Büyük mesajlar hiç ulaşmıyor PubSubClient tamponu çok küçük setBufferSize değerini artırın
Evde çalışıyor, sahada başarısız Giden 8883 engelli BT'den 8883'ü açmasını isteyin veya MQTT-over-WebSocket istemcisiyle 8084'te WSS kullanın

Yalnızca geliştirme sırasında net.setInsecure() sertifika doğrulamasını atlar ve sorunun CA olup olmadığını ayırt etmeye yardımcı olur. Bununla asla firmware yayınlamayın. Daha derin TLS sorunları için ESP32 MQTT SSL rehberi daha ileri gidiyor.

Bellek, Güç ve Sertifika Yaşam Döngüsü

ESP32'de TLS rahatça çalışır ama bedava değildir; birkaç tasarım kararı ileride sorun yaşamanızı önler.

Heap kullanımı. Bir TLS oturumu, tamponlar ve el sıkışma için kayda değer miktarda RAM gerektirir. Düz bir ESP32'de bu tek bir bağlantı için sorun değildir; ancak sketch'iniz aynı zamanda bir web sunucusu, bir kamera veya büyük JSON belgeleri çalıştırıyorsa yukarıdaki telemetri payload'ındaki ESP.getFreeHeap() değerini izleyin. Sürekli düşen bir değer genellikle TLS yığınında değil, kendi kodunuzdaki bir sızıntıya, örneğin bir döngü içinde String birleştirmeye işaret eder.

Bağlantıyı açık tutun. Pahalı olan kısım el sıkışmadır. Birkaç saniyede bir bağlanmak, tek bir mesaj yayımlamak ve bağlantıyı kesmek, 30 ila 60 saniyelik bir keep alive ile tek bir oturumu açık tutmaktan çok daha fazla enerji ve zamana mal olur.

Pille çalışan cihazlar. Kart okumalar arasında derin uykuya geçiyorsa her uyanış Wi-Fi ilişkilendirmesi, NTP ve bir TLS el sıkışmasının bedelini öder. Daha seyrek uyanarak ve birkaç okumayı tek bir yayında gruplayarak maliyeti azaltın; kısa uykularda tam senkronizasyonu atlayabilmek için son NTP zamanını RTC belleğinde saklamayı değerlendirin.

Kök sertifika süresinin dolması. Sunucunun yaprak sertifikası yerine kök CA'yı gömmek, rutin yenilemelerin cihazlarınıza hiç dokunmaması anlamına gelir. Yine de kökler eninde sonunda değişir; bu yüzden sertifikayı sahada güncellemenin bir yolunu tutun: OTA firmware güncellemeleriyle veya PEM'i bir provisioning akışının değiştirebileceği flaş bellekte saklayarak.

Üretim Kontrol Listesi

  1. Kimlik bilgilerini kaynak kontrolünde değil, NVS'te saklayın veya üretim sırasında sağlayın.
  2. Her cihaza kendi client ID'sini verin.
  3. Yaprak sertifika yerine kök CA'yı kullanın.
  4. Jitter'lı yeniden bağlanma backoff'u kullanın.
  5. Last Will ile retained bir durum yayımlayın.
  6. Payload'ları küçük ve yapılandırılmış tutun.
  7. Cihazları portal dashboard'unda izleyin ve önemli metrikler için eşik uyarı kuralları belirleyin.

Daha geniş güvenlik tablosu MQTT güvenlik en iyi uygulamaları yazısında.

ESP32'nizi ConnectMQ'ya Bağlayın

app.connectmq.com adresinde kredi kartı olmadan ücretsiz bir Serverless broker oluşturun, kimlik bilgilerini yukarıdaki sketch'e yapıştırın ve ESP32'niz TLS üzerinden bulutla konuşmaya başlasın. ConnectMQ yönetilen bir MQTT broker'dır; siz firmware'e odaklanırken sertifikalar, yamalar ve kapasite sizin için yönetilir.

Sık Sorulan Sorular

ESP32'min TLS için neden doğru saate ihtiyacı var?

Sertifika doğrulaması geçerlilik tarihlerini kontrol eder. NTP olmadan ESP32'nin saati 1970'ten başlar, her sertifika geçersiz görünür ve el sıkışma başarısız olur.

PubSubClient yerine AsyncMqttClient kullanabilir miyim?

Evet. AsyncMqttClient bloklamayan bir kütüphanedir ve core ile derleme seçeneklerinize bağlı olarak TLS'i destekler; WiFiClientSecure ile PubSubClient ise yaygın kullanılan en basit kurulumdur.

ConnectMQ için hangi kök sertifikayı gömmeliyim?

Let's Encrypt kökü olan ISRG Root X1'i. Uzun ömürlüdür, dolayısıyla sunucu sertifikası yenilemeleri firmware güncellemesi gerektirmez.

TLS ESP32'yi gözle görülür şekilde yavaşlatır mı?

El sıkışma biraz zaman alır ve ek RAM kullanır, ancak bağlandıktan sonra mesaj başına ek yük küçüktür. Her yayın için yeniden bağlanmak yerine bağlantıyı açık tutun.

İlgili yazılar

BYOC MQTT Broker: Kendi Bulutunuzu Getirin Modeli Açıklandı

BYOC MQTT broker sizin bulut hesabınızda çalışır ama bir sağlayıcı tarafından işletilir. Modelin nasıl işlediğini, sorumluluk paylaşımını ve hesabınızı buna nasıl hazırlayacağınızı öğrenin.

7 dk okuma

Google Cloud IoT Core Alternatifi: Kapanış Sonrası Seçenekler ve Geçiş

Google, Cloud IoT Core'u Ağustos 2023'te kullanımdan kaldırdı. Bu rehber gerçekçi alternatifleri karşılaştırıyor, IoT Core kavramlarını standart MQTT'ye eşliyor ve verileriniz Google Cloud'a akmaya devam ederken cihazlarınızı yönetilen bir broker'a nasıl taşıyacağınızı gösteriyor.

7 dk okuma

Saniyede MQTT Mesaj Sayısı: Verim Nasıl Tahmin Edilir ve Ölçülür

MQTT verim planlaması birkaç formüle ve tek bir dürüst ölçüme dayanır. Saniyedeki gelen ve giden mesaj sayısını nasıl tahmin edeceğinizi, tepe değerleri nasıl hesaba katacağınızı ve sonucu bir broker planına nasıl eşleyeceğinizi öğrenin.

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.