Skip to content

Contributed by WildboarG, organized by Ai-Thinker

AI-WB2 Provisioning [Part 3]

AI-WB2 Bluetooth Provisioning


Bluetooth Provisioning


Principle: phone App → via Bluetooth → sends Wi-Fi SSID & password → Wi-Fi device receives & connects to the network

1. Device Enters Bluetooth Provisioning Mode

  • The device (e.g. AI-WB2, ESP32) enables BLE and acts as a ****Bluetooth Peripheral
  • The device broadcasts the BLE service UUID and waits for a phone or PC to connect

2. Phone App Connects via Bluetooth

  • The phone turns on Bluetooth and scans for nearby BLE devices (can filter by a specific UUID)
  • After connecting to the target device, discover the custom BLE service & characteristics

3. Phone Sends Wi-Fi Information

  • Write to the device through BLE characteristics:
    • SSID (Wi-Fi name)
    • Password
    • Encryption method (optional)
  • The device parses the received data and stores it in Flash or RAM.

4. Device Attempts to Connect to Wi-Fi

  • The device disconnects the Bluetooth link and tries to connect to Wi-Fi with the received SSID & password.
  • Once connected, it can return a success status to the phone.

Code Example


Click to expand full code
c
#
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"
);
}

Flow Analysis


Let's analyze the connection flow with the logs;

  1. First, I flash the program and open the serial port to check the logs
  2. In the provisioning section of the Ai-Thinker IoT WeChat mini program, there is a BLUFI provisioning option, which is Bluetooth provisioning. Remember to turn on Bluetooth and grant the mini program Bluetooth permission.
  3. Scan for devices

  1. The name is AXK_BLUFI; tap to connect

  1. Make sure the phone is connected to 2.4G Wi-Fi, enter the password, then tap "Configure Wi-Fi"

  1. Then look at the logs printed on our serial port

Pay attention to the [blufi] lines in the output; these lines cover the process from the mini program connecting to Bluetooth all the way to successful provisioning

Two functions appear in the messages:

btc_transfer_context: used to transfer BLE tasks across threads, ensuring safe data transfer.

btc_thread_handler: executes BLE events (such as Wi-Fi connection) in the BTC thread

One is the event flag issued by the Bluetooth side; the other is the task that executes the corresponding event. In short, a task needs to be executed.

For example, the third line BLUFI ble connect — based on the Bluetooth event callback function, this means the Bluetooth connection is complete. So the tasks passed in the first two lines are to execute the Bluetooth connection, i.e., the task initiated from the phone side after I scanned and tapped AXK_BLUFI in the mini program.

[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,后面写自己的逻辑代码

To verify the guess, find in the code where these logs are printed.

Search the whole project for this function btc_transfer_context — it is located in ble_btc.c

Inside, we find:

Click to expand full code
c
printf
(
"[blufi]%s msg %u %u %p\n"
, __func__, msg->sig, msg->act, arg);

Doesn't it exactly match the first line?

Click to expand full code
html
[blufi]函数名 msg msg->sig msg->act ,arg

sig: the message type. Taking the first line as an example, sig=1 means the protocol stack is responding to the application layer.

Click to expand full code
c
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: the specific response event number. Again taking the first line as an example, the event number is 3, which exactly corresponds to AXK_BLUFI_EVENT_BLE_CONNECT, the Bluetooth connection event — the guess is verified

  1. Connection successful

After that, you can write your own task functions.

Released under the MIT License. Build Time 2026-09-11 14:52:23