背景介绍

在我将ESP8266采集代码灌入之后,它已经可以实现自动采集按钮信号了。核心逻辑实现之后,我需要能够连接网络,因为网络是连接MQTT的前置条件。

在连接之前,我需要将路由器的WIFI密码告知ESP8266芯片,这不同于Debug的时候,在代码内固定填写WIFI账号密码。我需要动态的获取并写入到ESP8266芯片。

网络配置有很多种方式,我选择了SoftAP配网,虽然配置有点繁琐,但这是一种很可靠的配网方案,兼容性极高,不依赖手机硬件的特殊协议。

准确来说,这不应该算是一个项目,但因为它具有通用性和一点实用性。我决定把它记录下来,可以方便地应用到我的其它项目中。

Soft配网原理

  1. 初始化模式:ESP8266 启动后进入 WIFI_AP_STA 模式。它会开启一个无密码(或已知密码)的热点(AP),并运行一个轻量级的 Web 服务器(HTTP Server)。
  2. 通道建立:手机通过小程序或系统设置连接到该热点。此时手机与 ESP8266 处于同一个局域网内。
  3. 数据交互:小程序通过 HTTP Post 请求将目标 WiFi 的 SSID 和 Password 发送给 ESP8266 的固定接口(如 /config)。
  4. 校验与切换:ESP8266 收到参数后,尝试作为客户端(STA)连接路由器。如果连接成功,则关闭 AP 热点,保存参数到 Flash;如果失败,则返回错误信息并维持 AP 状态。

ESP8266端核心代码(Arduino IDE)

在Arduino IDE打开项目后,需要安装ESP8266 WebServer库。这个库提供了Web服务,可以接收其它HTTP客户端的连接。

以下代码实现了一个非常简单的Web服务,它监听/config接口并能够接收WIFI信息,以及接收之后可以本地存储,实现动态配置的功能。

注意:当存储在本地之后,下次启动可以直接使用。而不需要重新配置。

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// 定义AP热点的名称
const char* ap_ssid = "ESP8266_Config_Device";
ESP8266WebServer server(80);

void handleConfig() {
  if (server.hasArg("ssid") && server.hasArg("pass")) {
    String target_ssid = server.arg("ssid");
    String target_pass = server.arg("pass"); // 确保这里是 pass

    // 1. 先回复小程序,否则一旦开始连WiFi,AP就会失效,小程序收不到回复会报错
    server.sendHeader("Access-Control-Allow-Origin", "*");
    server.send(200, "text/plain", "SUCCESS");
  
    Serial.println("配置信息已收到,准备连接...");
  
    // 2. 延迟一下再连接,给 HTTP 响应留出传输时间
    delay(1000); 
  
    WiFi.begin(target_ssid.c_str(), target_pass.c_str());
    
    int counter = 0;
    while (WiFi.status() != WL_CONNECTED && counter < 20) { // 等待10秒
      delay(500);
      Serial.print(".");
      counter++;
    }

    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("\nWiFi连接成功!");
      WiFi.mode(WIFI_STA); // 关闭AP模式,切换为STA模式
      WiFi.setAutoConnect(true);
      WiFi.persist(true);   // 将账号密码永久保存到Flash
    } else {
      Serial.println("\n连接失败,请检查账号密码");
      // 保持AP模式,等待下次尝试
    }
  } else {
    server.send(400, "text/plain", "FAIL: Missing Params");
  }
}

void setup() {
  Serial.begin(115200);
  
  // 设置为AP+STA模式
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP(ap_ssid);
  
  Serial.println("AP热点已启动,IP地址: " + WiFi.softAPIP().toString());

  // 注册接口
  server.on("/config", HTTP_POST, handleConfig);
  server.begin();
  Serial.println("HTTP服务器已启动");
}

void loop() {
  server.handleClient();
  
  // 如果连接成功,可以根据需要在这里处理业务逻辑
  if (WiFi.status() == WL_CONNECTED) {
    static bool connected_msg = false;
    if (!connected_msg) {
      Serial.println("设备已联网,IP: " + WiFi.localIP().toString());
      connected_msg = true;
    }
  }
}

参考上面的原理,设备上电之后,启动AP模式,接收配置,这个时候可以通过指示灯来显示状态。接收完毕后,可以正常连接到WIFI,则将WIFI配置信息保存到本地并进入核心业务逻辑。

小程序端核心代码

小程序充当了HTTP客户端,它用来作为输入WIFI信息的终端。这个界面非常简单,一个WiFi信息提交表单,包含了SSID信息和密码信息,以及一个提交按钮。

下面是小程序端提交WiFi配置信息的核心代码,需要注意的是,在操作的时候,需要将手机先连接到ESP8266热点,然后让用户填写的WIFI账号和密码,并点击提交按钮,调用JS通过HTTP接口传送给ESP8266 Web服务。

sendConfig(e) {
    const that = this;
    let obj = e.detail.value;

    if (utils.isEmpty(obj.ssid)) {
      wx.showToast({ title: 'WiFi名称为空', icon: 'none' });
      return;
    }

    wx.showLoading({ title: '配置中...', mask: true });

    const url = "http://192.168.4.1/config";

    const requestTask = wx.request({
      url: url,
      method: "POST",
      timeout: 10000, // 10秒超时
      header: {
        'content-type': 'application/x-www-form-urlencoded',
      },
      data: {
        ssid: obj.ssid,
        pass: obj.pass,
      },
      success: (res) => {
        wx.hideLoading();
        // 兼容处理:只要服务器返回了200,基本代表ESP8266已收到指令
        if (res.statusCode === 200) {
          that.setData({ status: "指令下发成功,观察设备状态" });
          wx.showModal({
            title: '配置已发送',
            content: '设备正在尝试连接路由器,请观察设备指示灯或稍后切换网络查看。',
            showCancel: false
          });
        }
      },
      fail: (err) => {
        wx.hideLoading();
        // 在SoftAP模式下,ESP8266切换网络会导致热点消失,常触发 errno: 600001 (连接超时/断开)
        if (err.errMsg.indexOf('timeout') !== -1) {
          that.setData({ status: "连接超时,请检查热点连接" });
        } else {
          // 关键逻辑:如果是由于热点消失导致的断开,其实很可能是已经成功去连接WiFi了
          that.setData({ status: "已下发配网,请查看设备状态" });
        }
      }
    });
  },

开发建议

  • 小程序端建议:小程序在发送 POST 请求时,URL 应设为 192.168.4.1(这是 ESP8266 默认的 AP 地址),如果需要其它地址,需要ESP8266芯片代码和小程序端代码同时修改。
  • 持久化:代码中的 WiFi.persist(true) 会将最后一次成功的配置写入 Flash。下次开机时,在 setup() 中调用 WiFi.begin() 且不传参数,它会自动尝试连接上次的 WiFi。这块逻辑需要根据自身情况去完善。
  • 异常处理:示例代码非常简单,在实际实现时,需要在小程序端加入超时逻辑。如果 10 秒内设备热点没消失(说明没切到 STA 模式),则提示用户“密码可能输入错误”。