背景介绍
在我将ESP8266采集代码灌入之后,它已经可以实现自动采集按钮信号了。核心逻辑实现之后,我需要能够连接网络,因为网络是连接MQTT的前置条件。
在连接之前,我需要将路由器的WIFI密码告知ESP8266芯片,这不同于Debug的时候,在代码内固定填写WIFI账号密码。我需要动态的获取并写入到ESP8266芯片。
网络配置有很多种方式,我选择了SoftAP配网,虽然配置有点繁琐,但这是一种很可靠的配网方案,兼容性极高,不依赖手机硬件的特殊协议。
准确来说,这不应该算是一个项目,但因为它具有通用性和一点实用性。我决定把它记录下来,可以方便地应用到我的其它项目中。
Soft配网原理
- 初始化模式:ESP8266 启动后进入 WIFI_AP_STA 模式。它会开启一个无密码(或已知密码)的热点(AP),并运行一个轻量级的 Web 服务器(HTTP Server)。
- 通道建立:手机通过小程序或系统设置连接到该热点。此时手机与 ESP8266 处于同一个局域网内。
- 数据交互:小程序通过 HTTP Post 请求将目标 WiFi 的 SSID 和 Password 发送给 ESP8266 的固定接口(如 /config)。
- 校验与切换: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 模式),则提示用户“密码可能输入错误”。