Wi-Fi 配网
BLE GATT Write/Notify、WiFi STA API
前置阅读:Hello Notify
学习目标
- 理解 BLE 配网的完整流程
- 掌握配网协议的数据格式设计
- 掌握配网状态机的设计
- 能够在 WS63 上实现通过手机 App 给设备配 WiFi
规格与功能
手机 App(Central)通过 BLE 向 WS63(Peripheral)发送 WiFi SSID 和 Password,WS63 连接 WiFi 后将结果回传 App。
sequenceDiagram
participant App as 手机 App (Central)
participant Dev as WS63 (Peripheral)
App->>Dev: 连接 BLE
App->>Dev: 服务发现 → 找到配网 Characteristic
App->>Dev: Write: {SSID, Password, Token}
Dev->>Dev: 尝试连接 WiFi
Dev->>App: Notify: {status=CONNECTING}
Dev->>Dev: WiFi 连接 + DHCP
Dev->>App: Notify: {status=SUCCESS, ip=192.168.1.100}
基本概念
配网 Characteristic 设计
| Characteristic | UUID | Property | 用途 |
|---|---|---|---|
| WiFi SSID | 自定义 | WRITE | App → Device:WiFi 名称 |
| WiFi Password | 自定义 | WRITE | App → Device:WiFi 密码 |
| 配网状态 | 自定义 | NOTIFY | Device → App:配网结果 |
配网状态机
| 状态 | 说明 | Notify 内容 |
|---|---|---|
| IDLE | 等待配网请求 | — |
| RECEIVING | 收到 SSID + Password | — |
| CONNECTING | 正在连接 WiFi | {status: "connecting"} |
| SUCCESS | WiFi 连接成功 | {status: "ok", ip: "192.168.1.100"} |
| FAILED | WiFi 连接失败 | {status: "fail", error: 0x01} |
涉及 API
| API | 谁调用 | 用途 |
|---|---|---|
gatts_notify_indicate() |
Device | 回传配网结果 |
| GATT Write handler | Device | 接收 WiFi 凭证 |
wifi_sta_connect() |
Device | 连接 WiFi |
wifi_event_register() |
Device | 监听 WiFi 连接事件 |
案例操作指导
用 BLE 调试 App(如 nRF Connect)写 SSID + Password → Device 连接 WiFi → Notify 返回 IP 地址。
关键配置
- WiFi 连接超时:30 秒
- 配网数据格式:SSID(32B) + Password(64B) + Token(4B)
代码详解
接收 WiFi 凭证
static void wifi_config_write_cb(uint16_t conn_id, uint16_t char_handle,
uint8_t *data, uint16_t len)
{
wifi_config_t *cfg = (wifi_config_t *)data;
// 校验 Token
if (cfg->token != g_expected_token) {
notify_status(conn_id, STATUS_FAIL, "invalid token");
return;
}
// 保存凭证并连接
memcpy(g_ssid, cfg->ssid, 32);
memcpy(g_password, cfg->password, 64);
notify_status(conn_id, STATUS_CONNECTING, NULL);
wifi_sta_connect(g_ssid, g_password);
}
WiFi 连接结果回传
static void wifi_event_cb(wifi_event_t event, void *data)
{
if (event == WIFI_CONNECTED) {
wifi_linked_info_t *info = (wifi_linked_info_t *)data;
char buf[64];
snprintf(buf, sizeof(buf), "{\"ip\":\"%s\"}", inet_ntoa(info->ip));
gatts_notify_indicate(g_conn_id, g_status_char_handle,
(uint8_t *)buf, strlen(buf));
} else if (event == WIFI_CONNECT_FAILED) {
gatts_notify_indicate(g_conn_id, g_status_char_handle,
(uint8_t *)"{\"status\":\"fail\"}", 16);
}
}