ESP32学习笔记(36)——BluFi(蓝牙配网)接口使用

发布者:RadiantGaze最新更新时间:2025-02-27 来源: jianshu关键字:ESP32 手机看文章 扫描二维码
随时随地手机看文章

一、简介

ESP32 的 BluFi 是通过蓝牙通道的 Wi-Fi 网络配置功能。它提供了一个安全协议来将 Wi-Fi 配置和凭据传递给 ESP32。使用这些信息,ESP32 可以连接到一个 AP 或建立一个 SoftAP。

BluFi 层中的分片、数据加密、校验和验证是此过程的关键要素。

您可以自定义对称加密、非对称加密和校验和支持自定义。这里我们使用DH算法进行密钥协商,128-AES算法进行数据加密,CRC16算法进行校验和验证。


二、BluFi流程

  1. 将 ESP32 设置为 GATT Server 模式,然后它将发送带有特定广告数据的广播。您可以根据需要自定义此广播,这不是 BluFi 配置文件的一部分。

  2. 使用安装在手机上的应用程序搜索此特定广播。确认广播后,手机将作为 GATT Client 连接到 ESP32。这部分使用的应用程序由您决定。

  3. GATT连接建立成功后,手机会向ESP32发送密钥协商的数据帧(详见BluFi中定义的帧格式部分)。

  4. ESP32 收到密钥协商的数据帧后,会根据用户自定义的协商方式解析内容。

  5. 手机配合ESP32使用DH、RSA或ECC等加密算法进行密钥协商。

  6. 协商完成后,手机会向ESP32发送安全模式设置的控制帧。

  7. ESP32 收到此控制帧后,将能够使用共享密钥和安全配置对通信数据进行加密和解密。

  8. 手机将BluFi中定义的帧格式部分定义的数据帧连同Wi-Fi配置信息发送到ESP32,包括SSID、密码等。

  9. 手机向ESP32发送Wi-Fi连接请求的控制帧。ESP32 收到此控制帧后,会认为基本信息的通信已完成,并准备连接到 Wi-Fi。

  10. 连接到 Wi-Fi 后,ESP32 会向手机发送 Wi-Fi 连接状态报告控制帧,以报告连接状态。至此,组网过程完成。

注意:

  • ESP32 收到安全模式配置的控制帧后,会按照定义的安全模式执行操作。

  • 对称加密/解密前后的数据长度必须保持不变。它还支持就地加密和解密。

三、API说明

以下 BluFi 接口位于 bt/common/api/include/api/esp_blufi_api.h

3.1 esp_blufi_register_callbacks

3.2 esp_blufi_profile_init

3.3 esp_blufi_send_wifi_conn_report

3.4 esp_blufi_send_wifi_list

3.5 esp_blufi_send_error_info

3.6 esp_blufi_send_custom_data

四、程序结构

使用 esp-idfexamplesbluetoothbluedroidbleblufi 中的例程


4.1 四个事件处理

4.1.1 WIFI部分事件处理

主要负责WIFI的连接、断开重连、扫描


static void wifi_event_handler(void* arg, esp_event_base_t event_base,

                                int32_t event_id, void* event_data){

    wifi_event_sta_connected_t *event;

    wifi_mode_t mode;


    switch (event_id) {

    case WIFI_EVENT_STA_START:

        esp_wifi_connect();

        break;

    case WIFI_EVENT_STA_CONNECTED:

        gl_sta_connected = true;

        event = (wifi_event_sta_connected_t*) event_data;

        memcpy(gl_sta_bssid, event->bssid, 6);

        memcpy(gl_sta_ssid, event->ssid, event->ssid_len);

        gl_sta_ssid_len = event->ssid_len;

        break; 

    case WIFI_EVENT_STA_DISCONNECTED:

        /* This is a workaround as ESP32 WiFi libs don't currently

           auto-reassociate. */

        gl_sta_connected = false;

        memset(gl_sta_ssid, 0, 32);

        memset(gl_sta_bssid, 0, 6);

        gl_sta_ssid_len = 0;

        esp_wifi_connect();

        xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);

        break;

    case WIFI_EVENT_AP_START:

        esp_wifi_get_mode(&mode);


        /* TODO: get config or information of softap, then set to report extra_info */

        if (ble_is_connected == true) {

            if (gl_sta_connected) {  

                esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, NULL);

            } else {

                esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, 0, NULL);

            }

        } else {

            BLUFI_INFO('BLUFI BLE is not connected yetn');

        }

        break;

    case WIFI_EVENT_SCAN_DONE: {

        uint16_t apCount = 0;

        esp_wifi_scan_get_ap_num(&apCount);

        if (apCount == 0) {

            BLUFI_INFO('Nothing AP found');

            break;

        }

        wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);

        if (!ap_list) {

            BLUFI_ERROR('malloc error, ap_list is NULL');

            break;

        }

        ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list));

        esp_blufi_ap_record_t * blufi_ap_list = (esp_blufi_ap_record_t *)malloc(apCount * sizeof(esp_blufi_ap_record_t));

        if (!blufi_ap_list) {

            if (ap_list) {

                free(ap_list);

            }

            BLUFI_ERROR('malloc error, blufi_ap_list is NULL');

            break;

        }

        for (int i = 0; i < apCount; ++i)

        {

            blufi_ap_list[i].rssi = ap_list[i].rssi;

            memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));

        }

        

        if (ble_is_connected == true) {

            esp_blufi_send_wifi_list(apCount, blufi_ap_list);

        } else {

            BLUFI_INFO('BLUFI BLE is not connected yetn');

        }


        esp_wifi_scan_stop();

        free(ap_list);

        free(blufi_ap_list);

        break;

    }

    default:

        break;

    }

    return;}

4.1.2 NETIF部分事件处理

获取网络IP地址,完成IP接口搭建(默认IO口);

更多netif功能介绍与使用参考链接:ESP-NETIF


static void ip_event_handler(void* arg, esp_event_base_t event_base,

                                int32_t event_id, void* event_data){

    wifi_mode_t mode;


    switch (event_id) {

    case IP_EVENT_STA_GOT_IP: {

        esp_blufi_extra_info_t info;


        xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);

        esp_wifi_get_mode(&mode);


        memset(&info, 0, sizeof(esp_blufi_extra_info_t));

        memcpy(info.sta_bssid, gl_sta_bssid, 6);

        info.sta_bssid_set = true;

        info.sta_ssid = gl_sta_ssid;

        info.sta_ssid_len = gl_sta_ssid_len;

        if (ble_is_connected == true) {

            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);

        } else {

            BLUFI_INFO('BLUFI BLE is not connected yetn');

        }

        break;

    }

    default:

        break;

    }

    return;}

4.1.3 BLUFI配网部分事件处理

此过程事件的处理均按照收到的请求作相应的功能处理,可按照个人需求进行修改


ESP_BLUFI_EVENT_INIT_FINISH:完成blufi功能初始化,设置设备名称(Device Name) 并发送特定的 adv data 广播;


ESP_BLUFI_EVENT_DEINIT_FINISH:处理deinit配置事件;


ESP_BLUFI_EVENT_BLE_CONNECT:连接Blufi Ble,并设备进入安全模式;


ESP_BLUFI_EVENT_BLE_DISCONNECT:设置ble断开重连;


ESP_BLUFI_EVENT_SET_WIFI_OPMODE:设置WiFi进入运行模式——op_mode;


ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:设置断开原有的WiFi连接,并连接指定WiFi;


ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:断开当前WiIFi连接到的AP;


ESP_BLUFI_EVENT_REPORT_ERROR:上报错误信息;


ESP_BLUFI_EVENT_GET_WIFI_STATUS:获取WiFi状态信息,包括:WiFi当前模式、以及是否连接成功;


ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:关闭blufi的gatt服务连接;


ESP_BLUFI_EVENT_RECV_STA_BSSID:设置进入STA模式,获取目标AP的bssid;


ESP_BLUFI_EVENT_RECV_STA_SSID:设置进入STA模式,获取目标AP的WiFi账号;


ESP_BLUFI_EVENT_RECV_STA_PASSWD:设置进入STA模式,获取目标AP的WiFi密码;


ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:设置进入Soft AP模式,获取AP自定义账号;


ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:设置进入Soft AP模式,获取AP自定义密码;


ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:设置Soft AP模式下最大可连接设备数量;


ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:设置Soft AP模式下进入认证模式;


ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:设置Soft AP模式下的通讯通道;


ESP_BLUFI_EVENT_GET_WIFI_LIST:获取扫描到的空中WiFi账号、通信通道以及站点MAC地址


ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:将接收到的数据打印出来;


static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param){

    /* actually, should post to blufi_task handle the procedure,

     * now, as a example, we do it more simply */

    switch (event) {

    case ESP_BLUFI_EVENT_INIT_FINISH:

        BLUFI_INFO('BLUFI init finishn');


        esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME);

        esp_ble_gap_config_adv_data(&example_adv_data);

        break;

    case ESP_BLUFI_EVENT_DEINIT_FINISH:

        BLUFI_INFO('BLUFI deinit finishn');

        break;

    case ESP_BLUFI_EVENT_BLE_CONNECT:

        BLUFI_INFO('BLUFI ble connectn');

        ble_is_connected = true;

        server_if = param->connect.server_if;

        conn_id = param->connect.conn_id;

        esp_ble_gap_stop_advertising();

        blufi_security_init();

        break;

    case ESP_BLUFI_EVENT_BLE_DISCONNECT:

        BLUFI_INFO('BLUFI ble disconnectn');

        ble_is_connected = false;

        blufi_security_deinit();

        esp_ble_gap_start_advertising(&example_adv_params);

        break;

    case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:

        BLUFI_INFO('BLUFI Set WIFI opmode %dn', param->wifi_mode.op_mode);

        ESP_ERROR_CHECK( esp_wifi_set_mode(param->wifi_mode.op_mode) );

        break;

[1] [2] [3]
关键字:ESP32 引用地址:ESP32学习笔记(36)——BluFi(蓝牙配网)接口使用

上一篇:ESP32学习笔记(37)——搭建ESP-ADF(乐鑫音频开发框架)
下一篇:ESP32学习笔记(35)——蓝牙MAC地址

推荐阅读最新更新时间:2026-02-26 16:26

博流科技:WiFi+蓝牙Combo解决智能家居配网痛点
在日前举行的第十届松山湖中国IC创新高峰论坛上,博流智能销售副总裁刘占领推荐了公司近两年主打产品,业界首款基于RISC-V核的WIFI+BLE二合一SoC芯片BL602。 刘占领表示,随着智能家居从单品智能向全屋智能演进,如果家中有30多个智能设备,那么复杂的配网、联网和组网会带来糟糕的用户体验。而蓝牙配网可以解决用户体验,保证设备易用性。同时,随着WiFi链接越来越多,有可能出现断网或拥堵等路由器饱和局面,利用蓝牙Mesh功能,可以有效减轻低速率的联网设备对路由器造成负担,增强用户体验。 也正因此,WiFi+蓝牙的Combo产品越来越受到市场欢迎。 同时,刘占领也强调采用了RISC-V的原因,作为物联网应用RISC-
[手机便携]
ESP32高分辨率计时器笔记
尽管FreeRTOS提供了软件计时器,但这些计时器有一些限制: 最大分辨率等于RTOS滴答周期 计时器回调从低优先级任务分派 硬件计时器不受这两个限制,但是通常它们使用起来不太方便。例如,应用组件可能需要定时器事件在将来的特定时间触发,但是硬件定时器仅包含一个用于中断产生的“比较”值。这意味着需要在硬件计时器之上构建一些功能来管理挂起事件列表,以便在发生相应的硬件中断时可以调度这些事件的回调。 esp_timer 一组API提供了一次性的计时器和定期的计时器,微秒级的时间分辨率以及64位范围。 基于ESP-IDF4.1 1 #include stdio.h 2 #include string.h 3 #
[单片机]
按键控制LED灯-ESP32中断处理
#include driver/gpio.h #include esp_task_wdt.h #include freertos/FreeRTOS.h #include freertos/queue.h #include freertos/semphr.h #include freertos/task.h #include math.h #include sdkconfig.h #define MIN_DELAY 500 #define BUTTON_GPIO GPIO_NUM_14 #define BLINK_GPIO GPIO_NUM_13 static char *TAG = SMART-WATER ;
[单片机]
ESP32 ADF windows开发环境搭建 适配ADF到ESP32A1S
搭建ESP32A1S的ADF开发环境 一,获取IDF和IDF-TOOL adf是乐鑫的音频开发框架,里面有许多乐鑫的音频开发API,同时ADF是基于IDF的。 这一部分可以按照官网的教程一步一步来。 官网教程地址: ADF安装指南 首先下载esp-idf,如果是第一次使用idf,可以在官网下载一个 idf工具安装器 ,通过这个安装器直接安装idf,同时还可以安装编译工具链。下载的速度也还可以接受。大概三十分钟就可以搞定。 本安装器可为您安装所需的交叉编译器、OpenOCD、cmake 和 Ninja 编译工具,以及一款 mconf-idf 配置工具。此外,本安装器还可在有需要时下载、运行 Python 3.7 和 Git
[单片机]
<font color='red'>ESP32</font> ADF windows开发环境搭建 适配ADF到ESP32A1S
ESP32智能配网笔记
基于ESP-IDF4.1 #include string.h #include stdlib.h #include freertos/FreeRTOS.h #include freertos/task.h #include freertos/event_groups.h #include esp_wifi.h #include esp_wpa2.h #include esp_event.h #include esp_log.h #include esp_system.h #include nvs_flash.h #include esp_netif.h #include esp_smartconfig.
[单片机]
ESP32存储blog笔记
基于ESP-IDF4.1 1 #include stdio.h 2 #include freertos/FreeRTOS.h 3 #include freertos/task.h 4 #include esp_system.h 5 #include nvs_flash.h 6 #include nvs.h 7 #include driver/gpio.h 8 9 #define STORAGE_NAMESPACE storage 10 11 12 //保存设备重启数 13 esp_err_t save_restart_counter(void) 14 { 15 nvs_hand
[单片机]
(4)ESP32 Python 用OLED播放Bad Apple
之前已经实现过了,把OLED当作一个状态显示器。但是,仅仅显示文字肯定是不够炫酷的,因为有屏幕的地方就应该有Bad Apple。 这次我们尝试一下把OLED播放一下 Bad Apple. Bad Apple看似是一段视频,但是我们这么来想这个问题。视频打散成很多张图片,按照每秒12贞的播放,那不就是一个视频了么。 首先,我们来体验一次把图片展示在OLED上面,需要展示的图片要是pbm格式(PBM格式由Jef Poskanzer在20世纪80年代发明,为了便于通过电子邮件,用ASCII码表示单色位图,能够承受一般的文本格式的变动。) from ssd1306 import SSD1306_I2C ,framebuf from
[单片机]
API调用小记(Touchdesigner和ESP32
调用 调用网络API通常是通过HTTP来做的,对于TD这种上位机软件来说,可以直接选择GET、POST这些方式,通过地址传入参数。一般的形式是地址后面加'?'然后跟参数名=值,不同的参数之间通过‘&’连接,例如 地址?参数名1=值1&参数名2=值2...... 例如调用心知天气的API,可以查到官方的文档是这样的 TD 所以在TD可以新建一个web client,在URL填入 https://api.seniverse.com/v3/weather/now.json ,方法选择GET 然后新建一个table在里面按照文档说明写入参数,传入OP里 点request就可以获取了,TD会自动用上面提到
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved