AI-WB2蓝牙配网

蓝牙配网
原理:手机 App → 通过蓝牙 → 发送 Wi-Fi SSID & 密码 → Wi-Fi 设备接收 & 连接网络
1️⃣ 设备进入蓝牙配网模式
- 设备(如 AI-WB2、ESP32 等)启用 BLE 并作为 ****蓝牙从设备(Peripheral)
- 设备会广播 BLE 服务 UUID,等待手机或 PC 连接
2️⃣ 手机 App 连接蓝牙
- 手机打开蓝牙,扫描附近的 BLE 设备(可以筛选特定 UUID)
- 连接到目标设备后,发现自定义 BLE 服务 & 特征(Characteristic)
3️⃣ 手机发送 Wi-Fi 信息
- 通过 BLE 特征(Characteristic) 向设备写入:
- SSID(Wi-Fi 名称)
- 密码
- 加密方式(可选)
- 设备解析收到的数据,并存储到 Flash 或 RAM 中。
4️⃣ 设备尝试连接 Wi-Fi
- 设备断开蓝牙连接,尝试用接收到的 SSID & 密码连接 Wi-Fi。
- 连接成功后,可以返回成功状态给手机。

代码示例
#include <FreeRTOS.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <task.h>
#include <timers.h>
#include <lwip/tcpip.h>
#include <bl602_glb.h>
#include <bl_sys.h>
#include <bl_uart.h>
#include <cli.h>
//////////////////////////////////
#include "axk_blufi.h"
#include "ble_interface.h"
#include "blufi.h"
#include "blufi_api.h"
#include "blufi_hal.h"
#include "blufi_init.h"
#include "blufi_security.h"
#include "wifi_interface.h"
#include <../wifi_mgmr.h>
//////////////////////////////////
static int scan_counter;
static bool ble_is_connected = false;
static bool gl_sta_connected = false;
blufi_config_t g_blufi_config = {0};
static void blufi_wifi_event(int event, void *param) { //wifi事件回调
switch (event) {
case BLUFI_STATION_CONNECTED:
gl_sta_connected = true;
break;
case BLUFI_STATION_DISCONNECTED:
gl_sta_connected = false;
break;
case BLUFI_STATION_GOT_IP: {
axk_blufi_extra_info_t info;
memset(&info, 0, sizeof(axk_blufi_extra_info_t));
wifi_conn_ap_info_get(&g_blufi_config.wifi.sta);
memcpy(info.sta_bssid, g_blufi_config.wifi.sta.cwjap_param.bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = (uint8_t *)g_blufi_config.wifi.sta.cwjap_param.ssid;
info.sta_ssid_len = strlen(g_blufi_config.wifi.sta.cwjap_param.ssid);
if (ble_is_connected == true) {
axk_blufi_send_wifi_conn_report(g_blufi_config.wifi.cwmode,
_BLUFI_STA_CONN_SUCCESS, 0, &info);
} else {
printf("BLUFI BLE is not connected yet\r\n");
}
printf("BLUFI save ssid&&pwd \r\n");
printf("START YOUR FOUTION:\r\n"); //一般联网成功这里开始写用户自定义任务
g_blufi_config.wifi.cwmode = WIFIMODE_STA;
} break;
default:
break;
}
}
static void example_event_callback(_blufi_cb_event_t event,
_blufi_cb_param_t *param) { //蓝牙事件回调
switch (event) {
case AXK_BLUFI_EVENT_INIT_FINISH://BLUFI初始化完成开启蓝牙广播
printf("BLUFI init finish\n");
axk_blufi_adv_start();
break;
case AXK_BLUFI_EVENT_DEINIT_FINISH://反初始化
printf("BLUFI deinit finish\n");
break;
case AXK_BLUFI_EVENT_BLE_CONNECT: //蓝牙已连接
printf("BLUFI ble connect\n");
ble_is_connected = true;
axk_blufi_adv_stop();
blufi_security_init();
break;
case AXK_BLUFI_EVENT_BLE_DISCONNECT: //蓝牙断开连接
printf("BLUFI ble disconnect\n");
ble_is_connected = false;
blufi_security_deinit();
axk_blufi_adv_start();
break;
case AXK_BLUFI_EVENT_SET_WIFI_OPMODE: //设置WIFI工作模式,一般都是配网,也就是用wb2连接别人,那就是STA
printf("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode);
g_blufi_config.wifi.cwmode = WIFIMODE_STA;
break;
case AXK_BLUFI_EVENT_REQ_CONNECT_TO_AP: { //蓝牙端获取WIFI信息并请求连接ap
cwjap_param_t cwjap_param = {0};
printf("BLUFI requset wifi connect to AP\n");
cwjap_param = g_blufi_config.wifi.sta.cwjap_param;
if (axk_hal_conn_ap_info_set(&cwjap_param) != BLUFI_ERR_SUCCESS) {
printf("BLUFI axk_hal_conn_ap_info_set fail\r\n");
break;
}
g_blufi_config.wifi.sta.state = BLUFI_WIFI_STATE_CONNECTING;
}
break;
case AXK_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP://请求设备断开 Wi-Fi
printf("BLUFI requset wifi disconnect from AP\n");
axk_hal_disconn_ap();
break;
case AXK_BLUFI_EVENT_REPORT_ERROR: //Wi-Fi 连接或 BLUFI 发生错误
printf("BLUFI report error, error code %d\n", param->report_error.state);
axk_blufi_send_error_info(param->report_error.state);
break;
case AXK_BLUFI_EVENT_GET_WIFI_STATUS: { //查询 Wi-Fi 连接状态
wifi_mode_t mode;
mode = g_blufi_config.wifi.cwmode;
if (gl_sta_connected) {
axk_blufi_extra_info_t info;
memset(&info, 0, sizeof(axk_blufi_extra_info_t));
wifi_conn_ap_info_get(&g_blufi_config.wifi.sta);
memcpy(info.sta_bssid, g_blufi_config.wifi.sta.cwjap_param.bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = (uint8_t *)g_blufi_config.wifi.sta.cwjap_param.ssid;
info.sta_ssid_len = strlen(g_blufi_config.wifi.sta.cwjap_param.ssid);
axk_blufi_send_wifi_conn_report(mode, _BLUFI_STA_CONN_SUCCESS, 0, &info);
} else {
axk_blufi_send_wifi_conn_report(mode, _BLUFI_STA_CONN_FAIL, 0, NULL);
}
printf("BLUFI get wifi status from AP\n");
break;
}
case AXK_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE: //设备主动断开 BLE 连接
printf("blufi close a gatt connection\r\n");
axk_blufi_disconnect();
break;
case AXK_BLUFI_EVENT_RECV_STA_BSSID: // 接收 Wi-Fi 路由器的 BSSID
memset(g_blufi_config.wifi.sta.cwjap_param.bssid, 0, 6);
memcpy(g_blufi_config.wifi.sta.cwjap_param.bssid, param->sta_bssid.bssid,
6);
// sta_config.sta.bssid_set = 1;
// esp_wifi_set_config(WIFI_IF_STA, &sta_config);
printf("Recv STA BSSID %s\r\n", param->sta_bssid.bssid);
break;
case AXK_BLUFI_EVENT_RECV_STA_SSID: //接收 Wi-Fi SSID
memset(g_blufi_config.wifi.sta.cwjap_param.ssid, 0, 33);
strncpy(g_blufi_config.wifi.sta.cwjap_param.ssid,
(char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
printf("Recv STA SSID %s\r\n",
(char *)g_blufi_config.wifi.sta.cwjap_param.ssid);
break;
case AXK_BLUFI_EVENT_RECV_STA_PASSWD: //接收 Wi-Fi 密码
// 先清空 Wi-Fi 密码存储区域,避免旧数据干扰
memset(g_blufi_config.wifi.sta.cwjap_param.pwd, 0, 64);
// 这里 `param->sta_ssid.ssid` 实际上是 Wi-Fi 密码,虽然名字容易误导
// 由于结构体内存复用,所以它存的是密码,而非 SSID
strncpy(g_blufi_config.wifi.sta.cwjap_param.pwd,
(char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
// 打印收到的 Wi-Fi 密码,确保传输正确
printf("Recv STA PASSWORD %s\r\n",
(char *)g_blufi_config.wifi.sta.cwjap_param.pwd);
break;
default:
break;
}
}
static _blufi_callbacks_t example_callbacks = {
.event_cb = example_event_callback,
.negotiate_data_handler = blufi_dh_negotiate_data_handler,
.encrypt_func = blufi_aes_encrypt,
.decrypt_func = blufi_aes_decrypt,
.checksum_func = blufi_crc_checksum,
};
int at_blufi_start(void) {
int ret = -1;
axk_hal_blufi_init();
ret = _blufi_host_and_cb_init(&example_callbacks);
if (ret) {
printf("%s initialise failed: %d\n", __func__, ret);
}
return ret;
}
static void proc_main_entry(void *pvParameters) {
wifi_interface_init(blufi_wifi_event);
at_blufi_start();
vTaskDelete(NULL);
}
void main() {
static TaskHandle_t proc_main_task;
bl_sys_init();
xTaskCreate(proc_main_entry, (char *)"main_entry", 1024, NULL, 15,
&proc_main_task);
tcpip_init(NULL, NULL);
printf("blufi demo test\r\n");
}
流程分析
结合日志来分析连接的流程;
- 我先烧录好程序,打开串口检测日志
- 手机微信小程序安心可IoT的配网里有个BLUFI配网就是蓝牙配网,记得打开蓝牙,并给小程序使用蓝牙的权限。
- 扫描设备

- 名字是
AXK_BLUFI
,点击连接

- 保证手机连接的2.4G的WIFI,输入密码,然后点配置WIFI

- 然后看,我们串口输出的日志

注意【blufi】这几行的输出,这几行是从小程序连接到蓝牙后一直到配网成功过程
消息中有两个函数:
btc_transfer_context
:用于跨线程传输 BLE 任务,确保数据安全传输。
btc_thread_handler
:在 BTC 线程中执行 BLE 事件(如 Wi-Fi 连接)
一个是蓝牙端发出的事件标志。一个是执行对应事件的任务。总之就是要执行一个任务.
例如:第三行 BLUFI ble connect
根据蓝牙事件回调函数可知,这是已经完成连接蓝牙。那么推测前两行传递的任务就是执行连接蓝牙,也就是我在小程序扫描后点击AXK_BLUFI后,通过手机端发起的任务。
[blufi]btc_transfer_context msg 1 3 0x42023634
[blufi] btc_thread_handler msg 1 3 0x4201bad0
//act=3 <====> AXK_BLUFI_EVENT_BLE_CONNECT
BLUFI ble connect
[BLE] connected
[BLE] conn param updated: int 0x0006 lat 0 to 500
[BLE] conn param updated: int 0x0027 lat 0 to 500
[BLE] mtu updated:247
[BLUFI] ccc change 1 客户端已启用通知(用于接收 Wi-Fi 连接状态)
[BLE] conn param updated: int 0x0020 lat 0 to 400
[blufi]btc_transfer_context msg 1 10 0x42023584
[blufi] btc_thread_handler msg 1 10 0x4201bad0
//act=10 <====>AXK_BLUFI_EVENT_RECV_STA_SSID
Recv STA SSID CU_5ZPu
[blufi]btc_transfer_context msg 1 11 0x42023584
[blufi] btc_thread_handler msg 1 11 0x4201bad0
//act=11<====>AXK_BLUFI_EVENT_RECV_STA_PASSWD
Recv STA PASSWORD HYGS3305
[blufi]btc_transfer_context msg 1 5 0x00000000
[blufi] btc_thread_handler msg 1 5 0x00000000
//act=5
<====>AXK_BLUFI_EVENT_REQ_CONNECT_TO_AP
BLUFI requset wifi connect to AP
// 往下隔了wifi连接的日志还有几行
...
[blufi]btc_transfer_context msg 0 2 0x4201989c
[blufi] btc_thread_handler msg 0 2 0x4201b780
//act=2 <====> AXK_BLUFI_EVENT_REQ_CONNECT_TO_AP
BLUFI save ssid&&pwd
START YOUR FOUTION // 这里就表示已经连接好了wifi,后面写自己的逻辑代码
验证推测就从代码里找日志从那里输出的。
全局搜索这个函数 btc_transfer_context
位于ble_btc.c
里边发现了
printf("[blufi]%s msg %u %u %p\n", __func__, msg->sig, msg->act, arg);
是不是刚好与第一行对应上了
[blufi]函数名 msg msg->sig msg->act ,arg
sig:消息类型。 以第一行举例,sig=1,也就是协议栈向应用层响应。
typedef enum {
BTC_SIG_API_CALL = 0, // APP TO STACK
BTC_SIG_API_CB, // STACK TO APP
BTC_SIG_NUM,
} btc_sig_t; //btc message type
act:具体的应答事件号。这里还以第一行举例,事件号是3 刚好对应AXK_BLUFI_EVENT_BLE_CONNECT 就是蓝牙连接的事件,猜测得到验证

- 连接成功


后面就可以写自己任务函数了。