ESP32 ve Arduino

ESP32 WiFiManager MQTT Kurulumu: Wi-Fi ve Broker Ayarlarını Captive Portal'da Yapılandırın

Kimlik bilgilerini koda gömmeyi bırakın: kullanıcıların bir WiFiManager captive portal'ında Wi-Fi ile birlikte MQTT host, port, client ID, kullanıcı adı ve parolayı girmesine izin verin, bunları Preferences ile saklayın ve varsayılan olarak broker.connectmq.com'a bağlanın.

ESP32 WiFiManager MQTT yapılandırması için broker alanları bulunan captive portal'ı gösteren telefon
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

ESP32 WiFiManager MQTT parametreleriyle, başka birine teslim ettiğiniz bir cihaz telefondan yapılandırılabilir: cihaz bir captive portal açar, kullanıcı bir Wi-Fi ağı seçip broker ayarlarını doldurur ve cihaz her şeyi yeniden başlatmalar boyunca hatırlar. Bu eğitim, bu akışı WiFiManager kütüphanesi ve Preferences ile kurar; varsayılan olarak broker.connectmq.com kullanıldığı için kutudan çıktığı gibi çalışır.

Koda Gömülü Ayarların Sorunu

Çoğu MQTT örneği const char* WIFI_SSID = "..." ve const char* MQTT_PASS = "..." gibi satırlarla başlar. Masanızda bu sorun değildir, ancak her yeni ağ veya kimlik bilgisi değişikliği yeniden derleme ve yeniden yükleme anlamına gelir. Ayrıca firmware ikili dosyasının sırlar içermesi ve aynı ikili dosyayı iki müşteriye verememeniz anlamına gelir.

Bir provisioning portalı bunu çözer. İlk açılışta veya kullanıcı bir butona basılı tuttuğunda ESP32 kendi erişim noktasını başlatır. Bir telefonla ona bağlanmak, kullanıcının şunları girdiği bir web sayfası açar:

  • Wi-Fi ağı ve parolası.
  • MQTT broker host'u ve portu.
  • MQTT client ID'si, kullanıcı adı ve parolası.
  • Bu cihaz için bir topic öneki.

Cihaz değerleri kalıcı belleğe kaydeder, Wi-Fi ağına katılır ve broker'a bağlanır. Aynı ikili dosya herkes için çalışır.

Kütüphaneler ve Donanım

  • tzapu'nun WiFiManager kütüphanesi (2.x); Arduino Library Manager'dan veya PlatformIO'dan tzapu/WiFiManager olarak kurulabilir.
  • MQTT için PubSubClient.
  • Arduino-ESP32 core ile birlikte gelen ve anahtar–değer çiftlerini NVS flash'ta saklayan Preferences.
  • Herhangi bir ESP32 kartı. Örnek, portalı yeniden açmak için çoğu DevKit'teki BOOT butonunu (GPIO 0) kullanır.

ESP32 WiFiManager MQTT Akışı Nasıl Çalışır?

Durum Ne olur
İlk açılış, kayıtlı Wi-Fi yok Portal Sensor-Setup-xxxx erişim noktası olarak başlar
Kayıtlı Wi-Fi erişilebilir Cihaz sessizce bağlanır, MQTT ayarlarını Preferences'tan yükler
Kayıtlı Wi-Fi erişilemez Bağlantı denemesi başarısız olduktan sonra portal yeniden açılır
Açılışta BOOT butonu 3 sn basılı tutulur Kullanıcının ayarları değiştirebilmesi için portal isteğe bağlı açılır
Portal 3 dakika kullanılmadan kalır Cihaz yeniden başlar ve tekrar dener; böylece asla sonsuza kadar takılı kalmaz

WiFiManager Wi-Fi kimlik bilgilerini kendisi saklar. MQTT alanları ise portala eklediğiniz ve kendiniz kalıcı hale getirdiğiniz özel parametrelerdir.

Eksiksiz Sketch

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

const int CONFIG_BUTTON = 0;    // BOOT button on most ESP32 DevKits

Preferences prefs;
WiFiClient net;
PubSubClient mqtt(net);

char mqttHost[64]   = "broker.connectmq.com";
char mqttPort[6]    = "1883";
char mqttClient[48] = "";
char mqttUser[48]   = "";
char mqttPass[64]   = "";
char topicPrefix[64] = "connectmq/demo/d93f2a";

bool shouldSave = false;
unsigned long lastPublish = 0;

void loadSettings() {
  prefs.begin("mqtt", true);
  prefs.getString("host", mqttHost, sizeof(mqttHost));
  prefs.getString("port", mqttPort, sizeof(mqttPort));
  prefs.getString("client", mqttClient, sizeof(mqttClient));
  prefs.getString("user", mqttUser, sizeof(mqttUser));
  prefs.getString("pass", mqttPass, sizeof(mqttPass));
  prefs.getString("prefix", topicPrefix, sizeof(topicPrefix));
  prefs.end();

  if (strlen(mqttClient) == 0) {   // never connect with an empty client ID
    snprintf(mqttClient, sizeof(mqttClient), "esp32-%08x", (uint32_t)ESP.getEfuseMac());
  }
}

void saveSettings() {
  prefs.begin("mqtt", false);
  prefs.putString("host", mqttHost);
  prefs.putString("port", mqttPort);
  prefs.putString("client", mqttClient);
  prefs.putString("user", mqttUser);
  prefs.putString("pass", mqttPass);
  prefs.putString("prefix", topicPrefix);
  prefs.end();
}

void runWifiManager(bool forcePortal) {
  WiFiManager wm;

  WiFiManagerParameter pHost("host", "MQTT host", mqttHost, sizeof(mqttHost) - 1);
  WiFiManagerParameter pPort("port", "MQTT port (1883 or 8883)", mqttPort, sizeof(mqttPort) - 1);
  WiFiManagerParameter pClient("client", "MQTT client ID", mqttClient, sizeof(mqttClient) - 1);
  WiFiManagerParameter pUser("user", "MQTT username (optional)", mqttUser, sizeof(mqttUser) - 1);
  WiFiManagerParameter pPass("pass", "MQTT password (optional)", mqttPass, sizeof(mqttPass) - 1,
                             "type='password'");
  WiFiManagerParameter pPrefix("prefix", "Topic prefix", topicPrefix, sizeof(topicPrefix) - 1);

  wm.addParameter(&pHost);
  wm.addParameter(&pPort);
  wm.addParameter(&pClient);
  wm.addParameter(&pUser);
  wm.addParameter(&pPass);
  wm.addParameter(&pPrefix);

  wm.setSaveParamsCallback([]() { shouldSave = true; });
  wm.setConfigPortalTimeout(180);

  char apName[32];
  snprintf(apName, sizeof(apName), "Sensor-Setup-%04x", (uint16_t)ESP.getEfuseMac());

  bool connected = forcePortal ? wm.startConfigPortal(apName)
                               : wm.autoConnect(apName);
  if (!connected) {
    ESP.restart();               // portal timed out: try again from scratch
  }

  if (shouldSave) {
    strlcpy(mqttHost, pHost.getValue(), sizeof(mqttHost));
    strlcpy(mqttPort, pPort.getValue(), sizeof(mqttPort));
    strlcpy(mqttClient, pClient.getValue(), sizeof(mqttClient));
    strlcpy(mqttUser, pUser.getValue(), sizeof(mqttUser));
    strlcpy(mqttPass, pPass.getValue(), sizeof(mqttPass));
    strlcpy(topicPrefix, pPrefix.getValue(), sizeof(topicPrefix));
    saveSettings();
    loadSettings();              // re-applies the client ID fallback
  }
}

bool buttonHeld(unsigned long ms) {
  pinMode(CONFIG_BUTTON, INPUT_PULLUP);
  unsigned long start = millis();
  while (digitalRead(CONFIG_BUTTON) == LOW) {
    if (millis() - start > ms) return true;
    delay(10);
  }
  return false;
}

void connectMqtt() {
  while (!mqtt.connected()) {
    bool ok = strlen(mqttUser) > 0
                ? mqtt.connect(mqttClient, mqttUser, mqttPass)
                : mqtt.connect(mqttClient);
    if (ok) {
      String cmd = String(topicPrefix) + "/cmd";
      mqtt.subscribe(cmd.c_str());
    } else {
      Serial.printf("MQTT failed state=%d, retrying\n", mqtt.state());
      delay(5000);
    }
  }
}

void setup() {
  Serial.begin(115200);
  loadSettings();
  delay(200);
  runWifiManager(buttonHeld(3000));

  mqtt.setServer(mqttHost, atoi(mqttPort));
  Serial.printf("Broker %s:%s as %s\n", mqttHost, mqttPort, mqttClient);
}

void loop() {
  if (!mqtt.connected()) connectMqtt();
  mqtt.loop();

  if (millis() - lastPublish > 10000) {
    lastPublish = millis();
    String topic = String(topicPrefix) + "/telemetry";
    String payload = "{\"uptime\":" + String(millis() / 1000) + "}";
    mqtt.publish(topic.c_str(), payload.c_str());
  }
}

Portalda Adım Adım

  1. Sketch'i yükleyin ve seri monitörü açın.
  2. Telefonunuzda Sensor-Setup-xxxx adlı Wi-Fi ağına katılın. Çoğu telefon captive portal'ı otomatik olarak açar; açmazsa 192.168.4.1 adresine gidin.
  3. Configure WiFi'a dokunun, ağınızı seçin ve parolasını girin.
  4. broker.connectmq.com'un public alanını kullanmak için varsayılanları bırakın veya kendi ayarlarınızı girin, ardından kaydedin.
  5. Cihaz ağınıza katılır, broker'a bağlanır ve <prefix>/telemetry topic'ine yayın yapmaya başlar.

Bir bilgisayardan doğrulayın:

mosquitto_sub -h broker.connectmq.com -p 1883 -i pc-d93f2a -t 'connectmq/demo/d93f2a/#' -v

Varsayılan öneki koruyan her cihaz aynı topic'e yayın yapar; bu yüzden birden fazla cihaz kuruyorsanız portalda her birine kendi önekini verin.

Güvenilir Kılan Ayrıntılar

Portalı oluşturmadan önce yükleyin. Özel parametreler mevcut değerler varsayılan olacak şekilde oluşturulur; böylece portal boş bir form değil, kayıtlı olanı gösterir. Bir alanı düzenleyen kullanıcılar diğerlerini kaybetmez.

Asla boş bir client ID ile bağlanmayın. Kullanıcı alanı temizlerse loadSettings(), çipin MAC adresinden türetilen bir ID'ye geri döner. Boş veya yinelenen bir client ID, cihazların bağlanamamasının veya birbirini düşürmesinin başlıca nedenlerinden biridir; tam liste için ESP32'nin bir MQTT broker'a neden bağlanamadığı yazısına bakın.

Portal zaman aşımını kullanın. setConfigPortalTimeout() olmadan, router'ı geçici olarak kapalı olan bir cihaz sonsuza kadar portal modunda bekler. Zaman aşımıyla yeniden başlar ve kayıtlı ağı tekrar dener.

Sayıları portalda dizgi olarak saklayın, bir kez dönüştürün. WiFiManager parametreleri metin alanlarıdır. Portu depolamada dizgi olarak tutun ve istemciyi yapılandırırken atoi() ile dönüştürün.

Parola alanını gizleyin. Ek argüman type='password', portalda MQTT parolasını maskeler. Değer yine de açık erişim noktası üzerinden düz HTTP ile gönderilir; bu yüzden yalnızca güvenilir bir yerde yapılandırma yapın.

Kullanıcıların Girdiklerini Doğrulamak

Bir captive portal kullanıcının girdiği her şeyi kabul eder; bu yüzden firmware hatalarla başa çıkabilmelidir. Kaydettikten sonra yapılacak birkaç kontrol, bir cihazın hatalı ayarlarla kendini kullanılamaz hale getirmesini önler:

  • Port: yalnızca 1 ile 65535 arasındaki değerleri kabul edin. Alan metin içerdiği için atoi() 0 döndürürse 1883'e geri dönün.
  • Host: boşlukları kırpın ve boş bir dizgiyi reddedin. Kullanıcılar sıklıkla mqtt://broker.connectmq.com gibi bir URL yapıştırır; şemayı ve host adından sonraki her şeyi çıkarın.
  • Topic öneki: sondaki eğik çizgiyi kaldırın ve publish topic'lerinde izin verilmeyen wildcard'ları (+ ve #) reddedin.
  • Kimlik bilgileri: bir kullanıcı adı ayarlanmış ancak parola boşsa seri konsolda uyarı verin, çünkü broker bağlantıyı reddedecektir.

MQTT bağlantısı pozitif bir mqtt.state() koduyla (hatalı kimlik bilgileri veya yetkisiz) art arda başarısız olduğunda bu genellikle bir ağ sorunu değil, ayar sorunudur. İyi bir kalıp, bu başarısızlıkları saymak ve art arda birkaç kez olduktan sonra portalı otomatik olarak yeniden açmaktır; böylece kullanıcı bir butona veya seri kabloya ihtiyaç duymadan değerleri düzeltebilir.

Üretim Broker'ları İçin TLS Eklemek

1883 portu düz metindir ve public test alanı için uygundur. Özel bir broker için, kullanıcı 8883 portunu seçtiğinde WiFiClientSecure'a geçin:

#include <WiFiClientSecure.h>

WiFiClientSecure secureNet;

void configureTransport() {
  if (atoi(mqttPort) == 8883) {
    secureNet.setCACert(ISRG_ROOT_X1);   // Let's Encrypt root, stored as a PEM string
    mqtt.setClient(secureNet);
  } else {
    mqtt.setClient(net);
  }
  mqtt.setServer(mqttHost, atoi(mqttPort));
}

setup() içindeki düz setServer() satırı yerine configureTransport()'u çağırın. ConnectMQ ile kullanıcılar daha sonra broker'ları için oluşturulan client ID, kullanıcı adı ve parolayı portala girer (YOUR_CLIENT_ID, YOUR_USERNAME, YOUR_PASSWORD). Client ID bu kimlik bilgilerine bağlıdır; bu yüzden tam olarak verildiği şekilde girilmelidir. ESP32 MQTT SSL/TLS rehberi kök sertifikanın nasıl gömüleceğini açıklar.

Sorun Giderme

Sorun Olası neden Çözüm
Portal hiç görünmüyor Kayıtlı Wi-Fi hâlâ bağlanıyor Reset sırasında BOOT butonunu basılı tutun veya bir kez wm.resetSettings() çağırın
Parametreler kaydedilmiyor Kaydetme callback'i tetiklenmedi setSaveParamsCallback() kullanın ve portal sayfasında Save'e basın
Değerler kesiliyor Alan uzunluğu girdiden küçük Tampon boyutunu ve parametre uzunluğunu artırın
Wi-Fi'a bağlanıyor ama MQTT'ye bağlanmıyor Taşıma için yanlış port veya yanlış kimlik bilgileri mqtt.state() değerini ve port/TLS kombinasyonunu kontrol edin
Telefon portalı açmıyor Captive algılama engellenmiş Elle 192.168.4.1 adresine gidin

Sonraki Adımlar

Ayarlar yapılandırılabilir hale geldiğinde doğal sonraki adımlar uzaktan güncellemeler ve durum raporlamadır: MQTT üzerinden tetiklenen ESP32 OTA güncellemeleri USB olmadan yeni firmware göndermeyi gösterir; ESP32 IoT eğitimi de provisioning'i eksiksiz bir cihaz projesine yerleştirir.

Cihazları ConnectMQ İçin Yapılandırın

Varsayılan ayarlar ücretsiz public MQTT broker'ı gösterir; böylece yeni bir cihaz Wi-Fi'a katıldığı anda çalışır. Kurulumlar için ConnectMQ üzerinde özel bir broker oluşturun ve kimlik bilgilerini portala girin. ConnectMQ yönetilen bir MQTT broker'dır; bu yüzden cihazları yapılandıran kişilerin hiçbir zaman bir sunucu çalıştırması gerekmez. app.connectmq.com adresinde kredi kartı gerekmeden ücretsiz Serverless planıyla başlayın.

Sık Sorulan Sorular

WiFiManager Wi-Fi parolasını nerede saklar?

ESP32 Wi-Fi sürücüsü ağ kimlik bilgilerini NVS flash'ta saklar. Bu sketch'te MQTT alanları ayrı olarak, Preferences kullanılarak mqtt ad alanı altında saklanır.

WiFiManager portalını daha sonra nasıl yeniden açarım?

Bu sketch'te açılış sırasında BOOT butonunu üç saniye basılı tutun; bu startConfigPortal()'ı çağırır. Cihaz hâlâ erişilebilir olduğu sürece bunu bir MQTT komutuyla da tetikleyebilirsiniz.

WiFiManager'ı AsyncMqttClient ile kullanabilir miyim?

Evet. WiFiManager yalnızca provisioning'i yönetir. Geri döndüğünde, saklanan değerleri tercih ettiğiniz MQTT istemcisini yapılandırmak için kullanın.

Captive portal güvenli mi?

Portal düz HTTP üzerinden açık bir erişim noktası olarak çalışır; bu yüzden yakındaki herkes kurulum sırasında değerleri gözlemleyebilir. Güvenilir bir yerde yapılandırma yapın ve kurulum erişim noktasına bir parola koymayı değerlendirin.

İlgili yazılar

ESP32 NTP MQTT Zaman Damgası: Her Mesaja Doğru Zaman Ekleyin

ESP32 saatini NTP ile eşitleyin, ISO 8601 ve epoch milisaniye zaman damgalarını biçimlendirin ve bunları MQTT payload'larına ekleyin; böylece ölçümler geç yayınlansa bile gerçek alınma zamanlarını korur.

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.