由 WildboarG 贡献,Ai-Thinker 进行整理
AI-WB2配网【下】
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 ,argsig:消息类型。 以第一行举例,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 typeact:具体的应答事件号。这里还以第一行举例,事件号是3 刚好对应AXK_BLUFI_EVENT_BLE_CONNECT 就是蓝牙连接的事件,猜测得到验证

- 连接成功


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

