ESP32蓝牙配网

2023-05-16

注意********menuconfig 配置(必须打开蓝牙我这是C2所以使用NimBLE )可以直接从demo的配置文件拷贝

Component config ---> Bluetooth ---> NimBLE - BLE only

Component config ---> Bluetooth ---> NimBLE Options ---> Enable blufi functionality

相关头文件:

#include "esp_bt.h"          //蓝牙控制器和VHCI设置头文件
#include "esp_gap_ble_api.h" //GAP设置头文件,广播和连接相关参数配置
#include "esp_gatts_api.h"   //GATT配置头文件,创建Service和Characteristic
#include "esp_bt_main.h"     //蓝牙栈空间的初始化头文件

一、BluFi 流程 官方demo-----bluetooth/blufi API编程介绍

BluFi 配网流程包含配置 SoftAP 和配置 Station 两部分。

下面以配置 Station 为例,介绍了广播、连接、服务发现、协商共享密钥、传输数据、回传连接状态等关键步骤。

  1. ESP32-C2 开启 GATT Server 模式,发送带有特定 advertising data 的广播。该广播不属于 BluFi Profile,您可以按需对其进行自定义。
  2. 使用手机应用程序搜索到该广播后,手机将作为 GATT Client 连接 ESP32-C2。该步骤对具体使用哪款手机应用程序并无特殊要求。
  3. 成功建立 GATT 连接后,手机会向 ESP32-C2 发送数据帧进行密钥协商(详见 BluFi 中定义的帧格式 )。
  4. ESP32-C2 收到密钥协商的数据帧后,会按照您自定义的协商方法进行解析。
  5. 手机与 ESP32-C2 进行密钥协商。协商过程可使用 DH/RSA/ECC 等加密算法。
  6. 协商结束后,手机端向 ESP32-C2 发送控制帧,用于设置安全模式。
  7. ESP32-C2 收到控制帧后,使用共享密钥以及安全配置对通信数据进行加密和解密。
  8. 手机向 ESP32-C2 发送 BluFi 中定义的帧格式 中定义的数据帧,包括 SSID、密码等 Wi-Fi 配置信息。
  9. 手机向 ESP32-C2 发送 Wi-Fi 连接请求的控制帧。ESP32-C2 收到控制帧后,即默认手机已完成必要信息的传输,准备连接 Wi-Fi。
  10. 连接到 Wi-Fi 后,ESP32-C2 发送 Wi-Fi 连接状态报告的控制帧到手机。至此,配网结束。

一、 WIFI部分事件处理

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

wifi_event_handler

二、NETIF部分事件处理

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

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

ip_event_handler

ESP-NETIF : IP 网络层协议

  • ESP-NETIF 目的
    • 为 TCP/IP 栈之上的 APP 提供了一个抽象层。这将允许 APP 将来在 IP 栈之间进行选择。
    • 其提供的 API 是线程安全的,即使其底层的 TCP/IP 栈是不安全的。
    • 一些 API 旨在由 APP 代码调用,例如获取/设置接口 IP 地址、配置 DHCP。其它 API 旨在供网络驱动层在内部使用。
    • 在许多情况下,APP 是不需要直接调用 ESP-NETIF API 的,因为它们是从默认网络事件处理程序调用的。
  • WIFI 默认初始化
    • 初始化代码以及为默认接口(例如 station 和 soft-AP)注册事件处理程序在两个单独的 API 中提供,以方便大多数 APP 的简单启动方式。
esp_netif_create_default_wifi_ap()
esp_netif_create_default_wifi_sta()
    • 这些函数返回 esp_netif 句柄,即指向使用默认设置分配和配置的网络接口对象的指针。
      • 如果 APP 提供了网络取消初始化,则必须销毁创建的对象。
      • 这些默认接口不得多次创建,除非使用删除创建的句柄 esp_netif_destroy()
      • 当使用 AP + STA 模式时,这些接口都要创建。
  • 头文件
    • esp_netif/include/esp_netif.h

esp_err_t esp_netif_init(void) //初始化底层 TCP/IP 栈。 //当 APP 启动时,这个函数应该从 APP 代码中调用一次。

  • return
    • ESP_OK: 成功
    • ESP_FALL: 初始化失败

esp_netif_t* esp_netif_create_default_wifi_ap(void) //创建默认的 WIFI AP。如果出现任何初始化错误,此 API 将终止。

  • return
    • 指向 esp-netif 实例的指针。

三、 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:将接收到的数据打印出来;

//BLUFI配网部分事件处理
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功能初始化,设置设备名称(Device Name) 并发送特定的 adv data 广播   
        BLUFI_INFO("BLUFI init finish\n");
        //esp_blufi_adv_start();//开始广播
        ble_svc_gap_device_name_set("nimble-default");//目前使用此函数设置广播名称
        esp_blufi_adv_start();//再开始广播 暂时无法自定义广播参数
        break;
    case ESP_BLUFI_EVENT_DEINIT_FINISH: //处理deinit配置事件
        BLUFI_INFO("BLUFI deinit finish\n");
        break;
    case ESP_BLUFI_EVENT_BLE_CONNECT: //连接Blufi Ble,并设备进入安全模式
        BLUFI_INFO("BLUFI ble connect\n");
        ble_is_connected = true;
        esp_blufi_adv_stop(); //停止广播
        blufi_security_init(); //开启安全模式
        esp_err_t err = esp_blufi_send_custom_data(char1_str,sizeof(char1_str));   //发送自定义数据
        BLUFI_INFO("BLUFI send custom data:%s,status:%s\n",char1_str,esp_err_to_name(err));
        break;
    case ESP_BLUFI_EVENT_BLE_DISCONNECT: //设置ble断开重连
        BLUFI_INFO("BLUFI ble disconnect\n");
        ble_is_connected = false;
        blufi_security_deinit();
        esp_blufi_adv_start();
        break;
    case ESP_BLUFI_EVENT_SET_WIFI_OPMODE: //设置WiFi进入运行模式——op_mode
        BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode);
        ESP_ERROR_CHECK( esp_wifi_set_mode(param->wifi_mode.op_mode) );
        break;
    case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP: // 设置断开原有的WiFi连接,并连接指定WiFi 
        BLUFI_INFO("BLUFI requset wifi connect to AP\n");
        /* there is no wifi callback when the device has already connected to this wifi
        so disconnect wifi before connection.
        */
        esp_wifi_disconnect();
        example_wifi_connect();
        break;
    case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP: //断开当前WiIFi连接到的AP
        BLUFI_INFO("BLUFI requset wifi disconnect from AP\n");
        esp_wifi_disconnect();
        break;
    case ESP_BLUFI_EVENT_REPORT_ERROR:
        BLUFI_ERROR("BLUFI report error, error code %d\n", param->report_error.state);
        esp_blufi_send_error_info(param->report_error.state);
        break;
    case ESP_BLUFI_EVENT_GET_WIFI_STATUS: {  //获取WiFi状态信息,包括:WiFi当前模式、以及是否连接成功
        wifi_mode_t mode;
        esp_blufi_extra_info_t info;

        esp_wifi_get_mode(&mode);

        if (gl_sta_connected) {
            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;
            esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info);
        } else if (gl_sta_is_connecting) {
            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info);
        } else {
            esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info);
        }
        BLUFI_INFO("BLUFI get wifi status from AP\n");

        break;
    }
    case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE: // 关闭blufi的gatt服务连接
        BLUFI_INFO("blufi close a gatt connection");
        esp_blufi_disconnect();
        break;
    case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
        /* TODO */
        break;
    case ESP_BLUFI_EVENT_RECV_STA_BSSID: //设置进入STA模式,获取目标AP的bssid
        memcpy(sta_config.sta.bssid, param->sta_bssid.bssid, 6);
        sta_config.sta.bssid_set = 1;
        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("Recv STA BSSID %s\n", sta_config.sta.ssid);
        break;
    case ESP_BLUFI_EVENT_RECV_STA_SSID: //设置进入STA模式,获取目标AP的WiFi账号
        strncpy((char *)sta_config.sta.ssid, (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
        sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0';
        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("Recv STA SSID %s\n", sta_config.sta.ssid);
        break;
    case ESP_BLUFI_EVENT_RECV_STA_PASSWD: //设置进入STA模式,获取目标AP的WiFi密码
        strncpy((char *)sta_config.sta.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
        sta_config.sta.password[param->sta_passwd.passwd_len] = '\0';
        esp_wifi_set_config(WIFI_IF_STA, &sta_config);
        BLUFI_INFO("Recv STA PASSWORD %s\n", sta_config.sta.password);
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
        strncpy((char *)ap_config.ap.ssid, (char *)param->softap_ssid.ssid, param->softap_ssid.ssid_len);
        ap_config.ap.ssid[param->softap_ssid.ssid_len] = '\0';
        ap_config.ap.ssid_len = param->softap_ssid.ssid_len;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP SSID %s, ssid len %d\n", ap_config.ap.ssid, ap_config.ap.ssid_len);
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
        strncpy((char *)ap_config.ap.password, (char *)param->softap_passwd.passwd, param->softap_passwd.passwd_len);
        ap_config.ap.password[param->softap_passwd.passwd_len] = '\0';
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP PASSWORD %s len = %d\n", ap_config.ap.password, param->softap_passwd.passwd_len);
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:
        if (param->softap_max_conn_num.max_conn_num > 4) {
            return;
        }
        ap_config.ap.max_connection = param->softap_max_conn_num.max_conn_num;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP MAX CONN NUM %d\n", ap_config.ap.max_connection);
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:
        if (param->softap_auth_mode.auth_mode >= WIFI_AUTH_MAX) {
            return;
        }
        ap_config.ap.authmode = param->softap_auth_mode.auth_mode;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP AUTH MODE %d\n", ap_config.ap.authmode);
        break;
    case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:
        if (param->softap_channel.channel > 13) {
            return;
        }
        ap_config.ap.channel = param->softap_channel.channel;
        esp_wifi_set_config(WIFI_IF_AP, &ap_config);
        BLUFI_INFO("Recv SOFTAP CHANNEL %d\n", ap_config.ap.channel);
        break;
    case ESP_BLUFI_EVENT_GET_WIFI_LIST:{
        wifi_scan_config_t scanConf = {
            .ssid = NULL,
            .bssid = NULL,
            .channel = 0,
            .show_hidden = false
        };
        esp_err_t ret = esp_wifi_scan_start(&scanConf, true);
        if (ret != ESP_OK) {
            esp_blufi_send_error_info(ESP_BLUFI_WIFI_SCAN_FAIL);
        }
        break;
    }
    case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:    //接受自定义数据
        BLUFI_INFO("Recv Custom Data %d\n", param->custom_data.data_len);
        esp_log_buffer_hex("Custom Data", param->custom_data.data, param->custom_data.data_len);
        break;
    default:
        break;
    }
}

四、GAP广播部分事件处理(自测发现C2在使用nimble后不支持)

用于当adv data数据报组装完成以后发送adv data广播

static esp_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,
};

功能

esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t*回调)

调用此函数以接收 blufi 回调事件。参数回调–[在]回调函数返回ESP_OK - 成功,其他 - 失败

esp_err_t esp_blufi_profile_init(无效)

调用此函数以初始化blufi_profile。返回ESP_OK - 成功,其他 - 失败

esp_err_t esp_blufi_profile_deinit(无效)

调用此函数以取消初始化blufi_profile。返回ESP_OK - 成功,其他 - 失败

esp_err_t esp_blufi_send_wifi_conn_report(wifi_mode_topmode,esp_blufi_sta_conn_state_tsta_conn_state,uint8_tsoftap_conn_num,esp_blufi_extra_info_t*extra_info)

调用此函数以发送 wifi 连接报告。参数操作模式–: 无线操作模式sta_conn_state–:工作站是否已连接softap_conn_num–: 软件连接号extra_info– :额外信息,如sta_ssid、softap_ssid等。返回ESP_OK - 成功,其他 - 失败

esp_err_t esp_blufi_send_wifi_list(uint16_tapCount,esp_blufi_ap_record_t*list)

调用此函数以发送 wifi 列表。参数apCount– : wifi list count列表– : 无线列表返回ESP_OK - 成功,其他 - 失败

主函数:

void app_main(void)
{
    esp_err_t ret;

    // Initialize NVS
    ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK( ret );

    initialise_wifi();

    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
    //esp_bt_controller_config_t是蓝牙控制器配置结构体,这里使用了一个默认的参数
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    //初始化蓝牙控制器,此函数只能被调用一次,且必须在其他蓝牙功能被调用之前调用
    ret = esp_bt_controller_init(&bt_cfg);
    if (ret) {
        BLUFI_ERROR("%s initialize bt controller failed: %s\n", __func__, esp_err_to_name(ret));
    }
    //使能蓝牙控制器,mode是蓝牙模式,如果想要动态改变蓝牙模式不能直接调用该函数,
    //应该先用disable关闭蓝牙再使用该API来改变蓝牙模式
    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
    if (ret) {
        BLUFI_ERROR("%s enable bt controller failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }
    //建立蓝牙的FSM(有限状态机)
    //这里使用回调函数来控制每个状态下的响应,需要将其在GAP层的回调函数注册
    ret = esp_blufi_host_and_cb_init(&example_callbacks);
    if (ret) {
        BLUFI_ERROR("%s initialise failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }
    //获取blufi版本号
    BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version());
}

信息存储,上电自动重连。参考

 //存放当前的配网信息
nvs_handle_t wificonfig_set_handle;
ESP_ERROR_CHECK( nvs_open("wificonfig",NVS_READWRITE,&wificonfig_set_handle) );
ESP_ERROR_CHECK( nvs_set_u8(wificonfig_set_handle,"WifiConfigFlag", wifi_configed) );
ESP_ERROR_CHECK( nvs_set_str(wificonfig_set_handle,"SSID",(const char *)ssid) );
ESP_ERROR_CHECK( nvs_set_str(wificonfig_set_handle,"PASSWORD", (const char *)password) );
ESP_ERROR_CHECK( nvs_commit(wificonfig_set_handle) );
nvs_close(wificonfig_set_handle);
//上电检测重连
static void check_wifi_config_in_nvs(void)
{
    nvs_handle_t wificonfig_get_handle;
    wifi_config_t wifi_config;
    esp_err_t err;
    uint8_t u8WifiConfigVal = 0;
    uint8_t u8Ssid[33] = { 0 };
    uint8_t u8Password[65] = { 0 };
    size_t Len = 0;
    uint8_t u8GetWifiFlag = 0;
 
    bzero(&wifi_config, sizeof(wifi_config_t));
 
    nvs_open("wificonfig", NVS_READWRITE, &wificonfig_get_handle);
    nvs_get_u8(wificonfig_get_handle, "WifiConfigFlag", &u8WifiConfigVal);
    printf("wificonfigval:%X \r\n",u8WifiConfigVal);
    if (u8WifiConfigVal == wifi_configed)
    {
        Len = sizeof(u8Ssid);
        err = nvs_get_str(wificonfig_get_handle, "SSID", (char *)u8Ssid, &Len);
        if(err == ESP_OK)
        {
            memcpy(wifi_config.sta.ssid, u8Ssid, sizeof(wifi_config.sta.ssid));
            ESP_LOGI(TAG, "ssid:%s,len:%d",u8Ssid,Len);
            u8GetWifiFlag ++;
        }
        Len = sizeof(u8Password);
        err = nvs_get_str(wificonfig_get_handle, "PASSWORD",(char *)u8Password,&Len);
        if(err == ESP_OK)
        {
            memcpy(wifi_config.sta.password, u8Password, sizeof(wifi_config.sta.password));
            ESP_LOGI(TAG, "password:%s,len:%d",u8Password,Len);
            u8GetWifiFlag ++;
        }
        nvs_close(wificonfig_get_handle);
 
        initialise_wifi();
 
        if(u8GetWifiFlag == 2)
        {
            //使用获取的配网信息链接无线网络
            ESP_ERROR_CHECK( esp_wifi_disconnect() );
            ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
            ESP_ERROR_CHECK( esp_wifi_connect() );
        }
        else
        {
            xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
        }
    }
    else
    {
        nvs_close(wificonfig_get_handle);
 
        initialise_wifi();
        xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
        ESP_LOGI(TAG, "Get WifiConfig Fail,Start SmartConfig......");
    }
 
}

五、使用nimble后再如何使用一些接口

可以查看使用IDF这个目录下的一些接口,来实现。通过调用一些nimble组件下的一些API来达到现有目的。

//使用blufi配网 修改设备名
esp-idf/components/bt/host/nimble/nimble/nimble/host/services/gap/include/services/gap/ble_svc_gap.h
//nimble广播设置例程
examples\bluetooth\nimble\blehr ---暂时不支持C2
examples\bluetooth\nimble\ble_l2cap_coc\coc_bleprph
//部分接口参考
esp-idf/components/bt/host/nimble/nimble/nimble/host/include
int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *rsp_fields);
//配置要包含在后续广告中的字段。这是ble_gap_adv_set_data()的方便包装器。
//@param adv_fields指定广告数据。
//@return哦,成功了,BLE_HS_EBUSY表示广告正在进行中,BLE_HS_EMSGSIZE表示指定的数据太大无法放入广告中,失败时的其他错误代码。
int ble_gap_adv_stop(void);
//停止当前活动的广告过程。成功回归代码表示广告已经完全中止,可以立即启动新的广告过程。

nimble广播不是自定义的服务UUID和属性设置如下

超时关闭蓝牙

esp_err_t ble_close(void)
{
    esp_err_t ret = ESP_FAIL;

    if (G_UpdateInfo.BleBroadcastState == 1)
    {
        // esp_blufi_adv_stop(); //停止广播

        // ret = esp_bt_controller_disable();
        // if (ret != ESP_OK)
        // {
        //     BLUFI_ERROR("%s disable bt controller failed: %s\n", __func__, esp_err_to_name(ret));
        //     return ret;
        // }
        G_UpdateInfo.BleBroadcastState = 0;
        // esp_bt_controller_deinit();
        BLUFI_INFO("BLUFI Stop running\n");
    }
    save_flash_restart(); //配网结束存储重启
    return ret;
}
/*
*是否关闭蓝牙广播 
*@param:无
*@return:0:未连接WiFi不关闭,
          1:连接WiFi后APP关闭,
         -1:连接WiFi后超时设备自动关闭
*/
int is_close_ble()
{
    int ret = 0;
    if (gl_sta_connected && G_Blufi_State.BleBroadcastState == 1)
    {
        int cur_time = 0;
        cur_time = get_sys_time_sec();

        while (get_sys_time_sec() < cur_time + CLOSE_BLE_TIME) 
        {
            if (!ble_is_connected)
            {
                ble_close(); // 配网成功后10秒内蓝牙没有连接关闭蓝牙
                ret = 1;
                BLUFI_INFO("app close bluetooth succeed\n");
                break;
            }

            vTaskDelay(100 / portTICK_PERIOD_MS);
        }
        ble_close(); //连接WiFi后APP超时未断开蓝牙 自动关闭
        BLUFI_INFO("close ble time out disable bt\n");
        ret = -1;
    }

    return ret;
}
//等待配网完成
void reply_app_connect_wait()
{
    int cur_time = 0;
    cur_time = get_sys_time_sec();

    while (get_sys_time_sec() < cur_time + SEND_APP_OUT_TIME) // 没有配网并且超时时间没到 超时时间为1min
    {
        if (gl_sta_connected)
        {
            had_connect_wifi = 1; //成功配网 无超时
            break;
        }
        had_connect_wifi = 0; //配网超时
        vTaskDelay(100 / portTICK_PERIOD_MS);
    }  
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ESP32蓝牙配网 的相关文章

  • esp芯片命名规则

    ESP32芯片命名规则 参考资料 ESP32技术规格书
  • esp-idf的电源管理——电源管理组件

    1 电源锁和动态频率切换 1 1 什么是电源锁 先概括的介绍一下IDF电源管理组件中的电源锁与动态频率切换 对主机CPU有了解的都知道 像Intel的酷睿处理器有个睿频功能 CPU非常聪明 可以在繁忙 需要高性能 的时候抬高频率 在不忙的时
  • ESP32S3系列--SPI主机驱动详解(一)

    一 目的 SPI是一种串行同步接口 可用于与外围设备进行通信 ESP32S3自带4个SPI外设 其中SPI0 SPI1内部专用 共用一组信号线 通过一个仲裁器访问外部Flash和PSRAM SPI2 3各自使用一组独立的信号线 开发者可以使
  • ESP32C3对接阿里云生活物联网平台

    文章目录 1 装好ESP32 VSCode开发环境 2 git阿里云代码 3 先编译例程 看看能否编译成功 4 创建分区表 增加ota分区 5 查看分区空间 6 擦除整片Flash 7 未烧录四元组情况下 看看会报什么错 8 阿里云四元组
  • esp32添加头文件

    环境 linux idf vsode 前言 在按照官方教程安装完成后 虽然可以编译成功 但是有些函数找不到定义 而且强迫症看到波浪号也非常难受 方法 点击小灯泡 点击第一个选项 如下图所示 拉到底点击advanced settings 让v
  • ESP32 上快捷部署 Tensorflow lite 机器学习(TinyML)

    在这篇文章中 我将向您展示使用 Arduino IDE 将 TensorFlow Lite 模型部署到 ESP32 的最简单方法 无需任何编译内容 Arduino 库 这个 Arduino 库是为了简化使用 Arduino IDE 将用于微
  • ESP32(MicroPython)LVGL图形界面 RGB灯闪烁控制器

    ESP32 MicroPython RGB灯闪烁控制器 本程序通过依次调整RGB灯中每个灯的P 频率和占空比实现对RGB灯闪烁的控制 import lvgl as lv import time from espidf import VSPI
  • ESP32+Arduino环境搭建教程 合宙ESP32C3

    1 在arduino官网下载安装包并安装 下载地址 https www arduino cc en software 2 安装Arduino对ESP32支持 1 添加ESP32开发板管理器地址 点击文件 gt 首选项 gt 其他开发板管理器
  • 常用的免费Api接口网址

    收录一下常用的免费Api接口 记录参考 具体使用请自行前往查看 和风天气 https dev qweather com docs api 天气预报 https www juhe cn docs api id 73 手机号码归属地 https
  • ESP32 ADC –使用Arduino IDE读取模拟值

    本文介绍了如何使用Arduino IDE通过ESP32读取模拟输入 模拟读取对于从电位计或模拟传感器等可变电阻读取值非常有用 模拟输入 ADC ADC是非线性的 analogRead 函数 其他有用的功能 使用ESP32从电位计读取模拟值
  • 单片机开发---ESP32S3移植lvgl+触摸屏

    书接上文 单片机开发 ESP32 S3模块上手 本章内容 熟悉一下ESP32S3的开发 修改范例程序的lvgl 使之能够匹配现在的显示屏 具体工作大概为通过SPI接口连接一块SPI串口屏幕 并且适配lvgl 最后加上触摸屏作为输入 屏幕 用
  • C#驱动ESP32控制机器臂

    物料清单 介绍 NET nanoFramework 是一个免费的开源平台 可以为受限嵌入式设备编写托管代码应用程序 它适用于多种类型的项目 包括物联网传感器 可穿戴设备 学术概念验证 机器人技术 业余爱好者 创客创作甚至复杂的工业设备 通过
  • ESP32的液晶中文显示

    上一篇简单说明了ESP32进行SSD1306的液晶显示 然后希望显示字符 使用前一篇的SSD1306是一个入门 但是不能显示中文 因此本篇主要演示显示中文 在arduino中有一个u8g2库 当时用UNO时使用过该库 但是用在ESP32上
  • ESP32基础应用之LVGL基础

    文章目录 1 实验目的 1 1 参考文章 2 实验工具 3 准备工作 3 1 搭建ESP32开发环境 3 2 克隆lv port esp32工程 4 配置lv port esp32工程 5 实验验证 6 使用过程遇到的问题 6 1 触摸功能
  • ESP32引脚参考

    原文链接 ESP32引脚参考 您应该使用哪个GPIO引脚 360doc个人图书馆 总结的相当全面 ESP32简单易懂的GPIO使用注意事项 首先上图 GPIO建议列表 特别的在硬件上要注意使用外接模块时不能将GPIO12拉高 否则将导致ES
  • 全网最简洁的mpy-cross教程

    大家知道我一向精干 不喜欢搞花儿的 如果去mpy官网看mpy cross的相关资料 估计又得绕蒙 跟我来 保证你三分钟学会 但是本文不涉及原理 第一 mpy cross是干嘛滴 答 把py文件转成mpy系统读的mpy文件 术语咱不懂 叫交叉
  • cmake中的编译选项

    CMake是一个跨平台的构建系统 它可以根据简单的配置文件生成各种平台的构建工具 例如Makefile Visual Studio项目文件等 CMake使用CMakeLists txt文件来描述项目的构建规则和依赖关系 在这个文件中 可以设
  • 小白也能快速学会的Micropython编译指南

    小白也能快速学会的Micropython编译指南 大家好 我是CSDN上的 上坂龍二 哦 今天给大家带来的是 如何快速一次成功地将Micropython和自己喜欢的模块编译进自己的Esp32固件中哦 事前准备 Python python的环
  • 【自用】无法通过ESP32创建HomeAssistant实体问题解决(MQTT对ESP32创建实体请求无应答)

    一 问题描述 1 使用 MQTTX 测试客户端能够创建实体 当通过 MQTTX 发送注册实体请求的时候 实体能够在 MQTT 服务器中注册成功 2 使用 ESP32 无法创建实体 在ESP32中通过 publish 函数发送注册请求的时候
  • ADXL345 与 ESP32 I2C 垃圾值问题

    我已根据以下教程使用 I2C 接口将 ESP32 与 ADXL345 连接起来Tutorial http www esp32learning com code esp32 and adxl345 sensor example php 但是

随机推荐

  • STM32的常用C语言

    文章目录 一些被坑了的注意点 int16 define结构体与共用体指针 C语言发展史C语言概述C90 标准C99标准C11标准 C编译o代替c 条件语句else ifdo while 变量定义一个字符串字符串结尾 定义一个字符串数组sta
  • STM32应用霍尔转速传感器基于输入捕获

    这里我用通用定时器3的通道1来测量转速 霍尔转速传感器基本介绍霍尔传感器分类和原理关于为什么选用开关型常开PNP型霍尔传感器 STM32程序实现程序介绍程序源码TIM3 CAP HTIM3 CAP H解读TIM3 CAP CTIM3 CAP
  • Android so库开发——使用Studio生成自己的so库(一)

    一 创建Native项目 1 新建 Native 项目 1 xff09 新建项目 选择最下面的 Native C 43 43 下一步即可 2 xff09 填写项目信息 3 xff09 选择C 43 43 版本可以直接选择默认 2 下载并配置
  • C语言实现线性回归求斜率

    2020 11 22 修改 span class token comment 线性回归求斜率 注意数据类型 参数 count 数据个数 数组行 列 的个数 数组的行列数目相等 参数 dataCol X 数据的列数据 参数 dataRow Y
  • 【C语言】详解位域定义与使用

    位域的定义 span class token keyword struct span span class token class name bit span span class token punctuation span span c
  • C语言实现MQTT协议(一)协议讲解

    MQTT介绍 MQTT是一个客户端服务端架构的发布 订阅模式的消息传输协议 它的设计思想是轻巧 开放 简单 规范 xff0c 易于实现 这些特点使得它对很多场景来说都是很好的选择 xff0c 特别是对于受限的环境如机器与机器的通信 xff0
  • 【STM32】HAL库-外部中断

    外部中断框图 产生中断 硬件触发外部中断 配置中断屏蔽寄存器中的屏蔽位 xff0c 允许该外部中断请求 通过AFIO EXTICRx配置GPIO线上的外部中断 事件 xff0c 必须先使能AFIO时钟 选择外部中断的触发边沿 xff0c 上
  • 【STM32】HAL库-系统滴答定时器SysTick

    SysTick定时器被捆绑在NVIC中 xff0c 是一个简单的定时器 xff0c 对于CM3 CM4内核芯片 xff0c 都有Systick定时器 Systick定时器常用来做延时 xff0c 或者实时系统的心跳时钟 这样可以节省MCU资
  • 【STM32】HAL库-串口USART

    USART简介 通用同步异步收发器 USART 提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换 USART利用分数波特率发生器提供宽范围的波特率选择 一个波特率寄存器 USART BRR xff0c
  • 【STM32】HAL库-通用定时器

    简介 通用定时器是一个通过可编程预分频器驱动的16位自动装载计数器构成 它适用于多种场合 xff0c 包括测量输入信号的脉冲长度 输入捕获 或者产生输出波形 输出比较和PWM 使用定时器预分频器和RCC时钟控制器预分频器 xff0c 脉冲长
  • 【STM32】HAL库-SPI

    3线全双工同步传输 带或不带第三根双向数据线的双线单工同步传输 8或16位传输帧格式选择 主或从操作 支持多主模式 8个主模式波特率预分频系数 最大为fPCLK 2 从模式频率 最大为fPCLK 2 主模式和从模式的快速通信 主模式和从模式
  • 【STM32】标准库-以太网外设-LAN8720A-LWIP-无操作系统

    TCP IP模型 TCP IP 只有四个分层 xff0c 分别为应用层 传输层 网络层以及网络访问层 xff08 物理层 xff09 实际上 xff0c 还有一个 TCP IP 混合模型 xff0c 分为五个层 它实际与 TCP IP四层模
  • 【STM32】标准库-LTDC-DMA2D

    LTDC STM32F429 系列芯片内部自带一个 LTDC 液晶控制器 xff0c 使用 SDRAM 的部分空间作为显存 xff0c 可直 接控制液晶面板 xff0c 无需额外增加液晶控制器芯片 STM32 的 LTDC 液晶控制器最高支
  • 【STM32】HAL库-以太网外设-LAN8720A-LWIP-无操作系统

    开发环境 KEIL MDK ARM 5 27MCU STM32F429IGT6PHY IC LAN8720ALWIP LWIP2 1 2STM32CUBEMX 6 6 1HAL V1 27 1 LAN8720A使用RMII接口与STM32的
  • git学习

    常用命令 查看当前文件夹下的文件与文件夹 xff1a ls ll 进入当前文件夹下的user文件夹 xff1a cd user 查看当前文件夹下的test txt文件 xff1a cat test txt 返回上一级目录 xff1a cd
  • 电赛专题---一.概述【电赛简介 /信号类需要准备什么?/怎么才能打好电赛?】

    1 电赛简介 全国大学生电子设计竞赛 xff08 National Undergraduate Electronics Design Contest xff09 是教育部和工业和信息化部共同发起的大学生学科竞赛之一 xff0c 是面向大学生
  • Postman安装

    1 官网下载 下载链接地址 xff1a https www postman com downloads 点击Download the App 根据自己的电脑以及需求选择对应的32位或者64位的版本 2 双击安装包 xff0c 不用任何操作
  • UART串口通信

    串口是 串行接口 的简称 xff0c 即采用串行通信方式的接口 串行通信将数据字节分成一位一位的形式在一条数据线上逐个传送 xff0c 其特点是通信线路简单 xff0c 但传输速度较慢 因此串口广泛应用于嵌入式 工业控制等领域中对数据传输速
  • Java第四课数据类型(二)

    一 变量类型 1 字节型 byte 2 整型 xff08 1 xff09 int 整型 4字节 xff08 2 xff09 show 短型 2字节 xff08 3 xff09 long 长型 8字节 3 浮点型 xff08 1 xff09
  • ESP32蓝牙配网

    注意 menuconfig 配置 xff08 必须打开蓝牙我这是C2所以使用NimBLE xff09 可以直接从demo的配置文件拷贝 Component config gt Bluetooth gt NimBLE BLE only Com