You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32如何在Arduino IoT Cloud运行时通过AP修改WiFi SSID

基于Arduino IoT Cloud实现浏览器修改WiFi凭证的方案

问题背景

尝试结合WiFi.h、WebServer.h、EEPROM.h与ArduinoIoTCloud.h、Arduino_ConnectionHandler.h,实现无需重新上传固件即可修改WiFi凭证。但将WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS)移至setup()内后,无论是使用常量形式的凭证,还是从EEPROM读取的凭证(如WiFiConnectionHandler ArduinoIoTPreferredConnection(esid.c_str(), epass.c_str());)均无法正常工作,ESP会因IoT库无法找到SSID和密码而重启。此前在Blynk等库中通过AP配网+网页输入的方式实现过类似功能,现在需要在Arduino IoT Cloud环境下实现该需求。

错误原因

原代码中WiFiConnectionHandler是全局实例,生命周期覆盖整个程序运行过程;修改后将其放在setup()内声明为局部变量,setup()执行完毕后该实例会被销毁,后续ArduinoCloud.update()调用时依赖的连接对象已不存在,导致系统崩溃重启。

可行实现方案

核心思路

  1. 将WiFiConnectionHandler声明为全局指针,在setup()内根据读取到的WiFi凭证动态初始化,保证其生命周期全局有效
  2. 实现SoftAP配网逻辑:当EEPROM中无有效WiFi凭证,或使用凭证连接WiFi失败时,启动ESP的SoftAP模式,搭建简易Web服务器,让用户通过浏览器输入新的WiFi SSID和密码,写入EEPROM后重启设备,加载新凭证连接Arduino IoT Cloud

完整代码示例

#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>
#include <WiFi.h>
#include <WebServer.h>
#include <EEPROM.h>

// Arduino IoT Cloud 配置
const char DEVICE_LOGIN_NAME[] = "你的设备登录名";
const char DEVICE_KEY[] = "你的设备密钥";

// WiFi 凭证存储参数(EEPROM地址)
#define EEPROM_SIZE 128
#define SSID_ADDR 0
#define PASS_ADDR 32

// 全局变量
float temperature;
WiFiConnectionHandler *ArduinoIoTPreferredConnection = nullptr;
WebServer apServer(80);

// 函数声明
void initProperties();
void onTemperatureChange();
void readWiFiCredentials(String &ssid, String &pass);
void writeWiFiCredentials(const String &ssid, const String &pass);
void startSoftAP();
void handleRoot();
void handleSaveCredentials();

void initProperties()
{
  ArduinoCloud.setBoardId(DEVICE_LOGIN_NAME);
  ArduinoCloud.setSecretDeviceKey(DEVICE_KEY);
  ArduinoCloud.addProperty(temperature, READWRITE, ON_CHANGE, onTemperatureChange);
}

void onTemperatureChange() {}

void setup() {
  Serial.begin(115200);
  delay(1000);

  // 初始化EEPROM
  EEPROM.begin(EEPROM_SIZE);

  // 读取存储的WiFi凭证
  String storedSSID, storedPASS;
  readWiFiCredentials(storedSSID, storedPASS);

  // 尝试连接WiFi
  WiFi.begin(storedSSID.c_str(), storedPASS.c_str());
  unsigned long startMillis = millis();
  while (WiFi.status() != WL_CONNECTED && millis() - startMillis < 10000) {
    delay(500);
    Serial.print(".");
  }

  if (WiFi.status() == WL_CONNECTED) {
    // WiFi连接成功,初始化IoT连接对象
    ArduinoIoTPreferredConnection = new WiFiConnectionHandler(storedSSID.c_str(), storedPASS.c_str());
    
    // 启动Arduino IoT Cloud连接
    initProperties();
    ArduinoCloud.begin(*ArduinoIoTPreferredConnection);
    setDebugMessageLevel(2);
    ArduinoCloud.printDebugInfo();
    Serial.println("\nConnected to Arduino IoT Cloud");
  } else {
    // WiFi连接失败,启动SoftAP配网
    Serial.println("\nWiFi connection failed, starting SoftAP for configuration");
    startSoftAP();
  }
}

void loop() {
  if (WiFi.status() == WL_CONNECTED && ArduinoIoTPreferredConnection != nullptr) {
    ArduinoCloud.update();
  } else {
    apServer.handleClient();
  }
}

// 从EEPROM读取WiFi凭证
void readWiFiCredentials(String &ssid, String &pass) {
  ssid = "";
  for (int i = SSID_ADDR; i < SSID_ADDR + 32; i++) {
    char c = EEPROM.read(i);
    if (c == '\0') break;
    ssid += c;
  }

  pass = "";
  for (int i = PASS_ADDR; i < PASS_ADDR + 32; i++) {
    char c = EEPROM.read(i);
    if (c == '\0') break;
    pass += c;
  }
}

// 将WiFi凭证写入EEPROM
void writeWiFiCredentials(const String &ssid, const String &pass) {
  // 清空SSID存储区
  for (int i = SSID_ADDR; i < SSID_ADDR + 32; i++) {
    EEPROM.write(i, '\0');
  }
  // 写入SSID
  for (int i = 0; i < ssid.length() && i < 32; i++) {
    EEPROM.write(SSID_ADDR + i, ssid[i]);
  }

  // 清空密码存储区
  for (int i = PASS_ADDR; i < PASS_ADDR + 32; i++) {
    EEPROM.write(i, '\0');
  }
  // 写入密码
  for (int i = 0; i < pass.length() && i < 32; i++) {
    EEPROM.write(PASS_ADDR + i, pass[i]);
  }

  EEPROM.commit();
}

// 启动SoftAP并配置WebServer
void startSoftAP() {
  const char *apSSID = "ESP-IoT-Config";
  const char *apPASS = "12345678";

  WiFi.softAP(apSSID, apPASS);
  IPAddress apIP = WiFi.softAPIP();
  Serial.printf("SoftAP started: %s, IP: %s\n", apSSID, apIP.toString().c_str());

  // 配置WebServer路由
  apServer.on("/", handleRoot);
  apServer.on("/save", handleSaveCredentials);
  apServer.begin();
}

// 配网首页
void handleRoot() {
  String html = "<!DOCTYPE html><html><head><title>WiFi Config</title></head><body>";
  html += "<h1>Configure WiFi for Arduino IoT Cloud</h1>";
  html += "<form action='/save' method='POST'>";
  html += "SSID: <input type='text' name='ssid' required><br>";
  html += "Password: <input type='password' name='pass'><br>";
  html += "<input type='submit' value='Save & Connect'>";
  html += "</form></body></html>";
  apServer.send(200, "text/html", html);
}

// 处理凭证保存请求
void handleSaveCredentials() {
  String ssid = apServer.arg("ssid");
  String pass = apServer.arg("pass");

  if (!ssid.isEmpty()) {
    writeWiFiCredentials(ssid, pass);
    apServer.send(200, "text/html", "Credentials saved! Rebooting...");
    Serial.println("WiFi credentials saved, rebooting...");
    delay(2000);
    ESP.restart();
  } else {
    apServer.send(400, "text/html", "Invalid SSID!");
  }
}

关键说明

  • 全局连接对象:使用WiFiConnectionHandler *全局指针,在WiFi连接成功后动态创建实例,确保其生命周期覆盖整个程序运行过程
  • EEPROM存储:将WiFi凭证存储在EEPROM中,重启后可直接读取使用,无需重新配置
  • SoftAP配网:当WiFi连接失败时自动启动AP,用户通过浏览器访问AP的IP地址即可输入新的WiFi凭证,保存后设备自动重启并尝试连接新WiFi及Arduino IoT Cloud

内容的提问来源于stack exchange,提问作者Hayder Ismael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 16:46:13