跳转至

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:配网结果

配网状态机

IDLE → RECEIVING → CONNECTING → SUCCESS / FAILED → IDLE
状态 说明 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);
    }
}