4. AP模式配网原理

AP模式配网,说白了就是让设备先扮演一个“小路由器”。

手机连上这个热点,然后通过Socket把家里的WiFi密码告诉它。设备拿到密码后,再切换角色去连真正的路由器。

这是最经典、兼容性最好的配网方式。几乎所有带屏幕的设备(比如智能音箱、扫地机器人)都在用。

4.1 核心流程:三步走

整个过程其实就三个大步骤。我画了一张图,你先看个全貌:

AP模式配网核心流程 ① 设备开启AP热点 ② Socket通信传密码 ③ 连接目标路由器 子步骤 • 初始化SoftAP • 设置SSID/密码 • 启动DHCP服务器 子步骤 • 手机连接设备热点 • 建立TCP Socket • 接收SSID/Password 子步骤 • 关闭AP模式 • 切换为Station模式 • 连接目标路由器 关键设计要点 • 设备热点SSID通常包含设备标识(如:SmartBulb_ABC123) • Socket通信建议使用TCP,端口号固定(如8266、8888) • 密码传输建议做简单加密或校验,防止中间人窃听

4.2 第一步:设备开启AP热点

设备上电后,默认进入配网模式。这时候它不会去连任何路由器,而是自己开一个WiFi热点。

关键点:设备热点通常没有密码,或者使用固定密码(比如12345678)。目的是让手机能快速连上来。

以ESP32为例,初始化AP模式的代码大概长这样:

#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  
  // 设置设备为AP模式
  WiFi.mode(WIFI_AP);
  
  // 配置热点SSID和密码
  // 注意:SSID最好带上设备唯一标识
  String ssid = "SmartDevice_" + String(ESP.getChipId());
  WiFi.softAP(ssid.c_str(), "12345678");
  
  Serial.print("AP IP地址: ");
  Serial.println(WiFi.softAPIP());
  
  // 启动DHCP服务器(默认自动启动)
  // 手机连上后会自动获取IP
}

这里有个细节:DHCP服务器。设备开启AP后,必须能自动给手机分配IP地址。否则手机连上热点也拿不到IP,后面的Socket通信根本没法建立。

我的习惯:我会在SSID里嵌入设备类型和MAC地址后四位。比如“Bulb_A3F2”。这样用户在手机WiFi列表里一眼就能认出自己的设备。

4.3 第二步:Socket通信传密码

手机连上设备热点后,真正的重头戏来了。手机需要把家里的WiFi名称和密码告诉设备。

怎么传?通过TCP Socket。

4.3.1 通信架构

设备作为TCP服务器,手机作为客户端。设备监听一个固定端口(比如8266),手机主动连接。

角色 IP地址 端口 职责
设备(服务器) 192.168.4.1(固定) 8266 监听连接、接收数据、回复确认
手机(客户端) 192.168.4.x(DHCP分配) 随机 主动连接、发送SSID/密码

为什么设备IP是固定的?因为AP模式下,设备自己就是网关。默认IP通常是192.168.4.1。手机App只要写死这个地址就行。

4.3.2 数据包格式

传什么?怎么传?我建议定义一个简单的协议:

// 数据包格式(JSON)
{
  "cmd": "config",
  "ssid": "MyHomeWiFi",
  "password": "MyPassword123",
  "timestamp": 1700000000
}

// 或者更紧凑的二进制格式
// [0xAA][0x55][len][ssid_len][ssid][pwd_len][pwd][checksum]

我曾经踩过的坑:一开始我用纯文本传密码,结果有用户的WiFi密码包含特殊字符(比如&、#),导致解析出错。后来我统一用URL编码或者Base64,再也没出过问题。

4.3.3 设备端代码示例

#include <WiFi.h>
#include <ArduinoJson.h>

WiFiServer server(8266);

void setup() {
  // ... 前面AP初始化代码 ...
  
  server.begin();
  Serial.println("TCP服务器已启动,端口: 8266");
}

void loop() {
  WiFiClient client = server.available();
  
  if (client) {
    Serial.println("手机已连接");
    
    // 等待数据到达
    while (client.connected() && !client.available()) {
      delay(10);
    }
    
    // 读取数据
    String data = client.readStringUntil('\n');
    Serial.println("收到数据: " + data);
    
    // 解析JSON
    StaticJsonDocument<256> doc;
    DeserializationError error = deserializeJson(doc, data);
    
    if (error) {
      client.println("{\"status\":\"error\",\"msg\":\"parse failed\"}");
      return;
    }
    
    String ssid = doc["ssid"];
    String password = doc["password"];
    
    // 保存到全局变量
    // 后续用于连接路由器
    saveConfig(ssid, password);
    
    // 回复确认
    client.println("{\"status\":\"ok\"}");
    
    delay(100);
    client.stop();
  }
}

4.4 第三步:连接目标路由器

设备拿到SSID和密码后,就该干正事了——连上家里的路由器。

这一步有个关键动作:切换WiFi模式。

void connectToRouter(String ssid, String password) {
  // 1. 关闭AP模式(释放资源)
  WiFi.softAPdisconnect(true);
  
  // 2. 切换为Station模式
  WiFi.mode(WIFI_STA);
  
  // 3. 开始连接
  WiFi.begin(ssid.c_str(), password.c_str());
  
  // 4. 等待连接成功
  int retry = 0;
  while (WiFi.status() != WL_CONNECTED && retry < 20) {
    delay(500);
    Serial.print(".");
    retry++;
  }
  
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("\n连接成功!IP地址: " + WiFi.localIP().toString());
    
    // 保存配网成功标志
    saveWiFiConfig(ssid, password);
  } else {
    Serial.println("\n连接失败,重新进入配网模式");
    // 重新开启AP,让用户再试一次
    startAPMode();
  }
}

注意:连接路由器时,设备会短暂“断网”。因为从AP切换到Station,WiFi硬件需要重新初始化。这个时间大约1-2秒,用户可能感觉到设备指示灯闪烁。

4.5 避坑指南与经验总结

做了这么多年物联网,AP模式配网看起来简单,但坑其实不少。我列几个常见的:

  • 热点被手机自动忽略:有些手机连过没有互联网的热点后,会自动标记为“低质量网络”,下次不再自动连接。解决方案:在SSID里加特殊字符,或者提示用户手动连接。
  • Socket超时:用户输入密码太慢,设备等不及就关闭了Socket。我一般设置30秒超时,超时后重新开启监听。
  • 密码包含空格:很多用户WiFi密码前后有空格,App端没trim,设备端也没trim,导致连接失败。两端都做trim处理。
  • 路由器5G频段:有些老旧设备只支持2.4G,如果用户的路由器开了5G优先,设备可能搜不到信号。建议在App端提示用户切换到2.4G。

我的经验:AP模式配网的成功率其实很高(95%以上),但用户体验的关键在于“引导”。App上要清晰告诉用户:第一步连设备热点,第二步返回App。很多用户卡在第二步,是因为他们不知道连完热点后要切回App。

4.6 本章小结

AP模式配网,说白了就是三步:设备开热点、手机传密码、设备连路由。

它不需要路由器做任何配合,兼容性最好。缺点是需要用户手动切换WiFi连接,操作步骤多一点。