1182 lines
47 KiB
C++
1182 lines
47 KiB
C++
/**
|
||
* @file bluetooth_provisioning.cc
|
||
* @brief BluFi蓝牙配网模块实现文件
|
||
*
|
||
* 本文件实现了BluFi蓝牙配网的核心功能,包括:
|
||
* - 蓝牙控制器和协议栈的初始化与管理
|
||
* - BluFi服务的启动、停止和事件处理
|
||
* - WiFi凭据的接收、验证和连接管理
|
||
* - 配网状态机的管理和事件回调
|
||
* - WiFi连接状态的监控和报告
|
||
* - 配网成功后的自动保存和重启机制
|
||
*
|
||
* 该实现基于ESP-IDF的BluFi API,提供了完整的蓝牙配网解决方案。
|
||
*/
|
||
|
||
#include "bluetooth_provisioning.h"
|
||
#include "esp_log.h"
|
||
#include "esp_bt.h"
|
||
#include "esp_bt_main.h"
|
||
#include "esp_bt_device.h"
|
||
#include "esp_gap_ble_api.h"
|
||
#include "esp_blufi.h"
|
||
#include "esp_blufi_api.h"
|
||
#include "esp_wifi.h"
|
||
#include "esp_netif.h"
|
||
#include "freertos/event_groups.h"
|
||
#include "freertos/timers.h"
|
||
#include "freertos/task.h"
|
||
#include "esp_system.h"
|
||
#include "application.h"
|
||
#include "assets/lang_config.h"
|
||
#include <ssid_manager.h>
|
||
#include "nvs_flash.h"
|
||
#include "nvs.h"
|
||
#include <cstring>
|
||
|
||
/// 日志标签,用于ESP_LOG系列函数的日志输出
|
||
#define TAG "BluetoothProvisioning"
|
||
|
||
/// WiFi连接成功事件位
|
||
#define WIFI_CONNECTED_BIT BIT0
|
||
/// WiFi连接失败事件位
|
||
#define WIFI_FAIL_BIT BIT1
|
||
|
||
/// 静态单例实例指针,用于C回调函数访问类成员
|
||
BluetoothProvisioning* BluetoothProvisioning::instance_ = nullptr;
|
||
|
||
/// WiFi事件组句柄,用于同步WiFi连接状态
|
||
static EventGroupHandle_t s_wifi_event_group = nullptr;
|
||
|
||
/// WiFi连接重试计数器
|
||
static int s_retry_num = 0;
|
||
/// 最大重试次数
|
||
static const int MAX_RETRY = 2;//Wi-Fi连接最大重试次数(wifi连接失败最大重试次数)
|
||
/// WiFi连接超时时间(毫秒)
|
||
static const int WIFI_CONNECT_TIMEOUT_MS = 30000; // 增强:从15秒延长到30秒
|
||
/// WiFi连接超时定时器句柄
|
||
static TimerHandle_t wifi_connect_timer = nullptr;
|
||
|
||
/**
|
||
* @brief BLUFI回调函数配置结构体
|
||
*
|
||
* 配置BluFi服务的各种回调函数,包括事件处理、数据协商、
|
||
* 加密解密和校验等功能。当前实现仅使用事件回调。
|
||
*/
|
||
static esp_blufi_callbacks_t blufi_callbacks = {
|
||
.event_cb = BluetoothProvisioning::BlufiEventCallback, ///< 事件回调函数
|
||
.negotiate_data_handler = nullptr, ///< 数据协商处理器(可选)
|
||
.encrypt_func = nullptr, ///< 加密函数(可选)
|
||
.decrypt_func = nullptr, ///< 解密函数(可选)
|
||
.checksum_func = nullptr, ///< 校验函数(可选)
|
||
};
|
||
|
||
/**
|
||
* @brief 构造函数
|
||
*
|
||
* 初始化蓝牙配网对象的所有成员变量,设置初始状态,
|
||
* 清空WiFi凭据,并设置静态实例指针用于回调函数访问。
|
||
*/
|
||
BluetoothProvisioning::BluetoothProvisioning()
|
||
: state_(BluetoothProvisioningState::IDLE) ///< 初始状态为空闲
|
||
, callback_(nullptr) ///< 回调函数指针初始化为空
|
||
, client_connected_(false) ///< 客户端连接状态初始化为未连接
|
||
, initialized_(false) ///< 初始化状态标志为未初始化
|
||
, delayed_disconnect_(false) ///< 延迟断开标志初始化为false
|
||
, wifi_connecting_(false) ///< WiFi连接状态标志初始化为false
|
||
, mac_address_sent_(false) { ///< MAC地址发送状态初始化为未发送
|
||
|
||
// 清空WiFi凭据结构体
|
||
wifi_credentials_.ssid.clear();
|
||
wifi_credentials_.password.clear();
|
||
memset(wifi_credentials_.bssid, 0, sizeof(wifi_credentials_.bssid));
|
||
wifi_credentials_.bssid_set = false;
|
||
|
||
// 设置静态实例指针,用于C风格回调函数访问类成员
|
||
instance_ = this;
|
||
|
||
ESP_LOGI(TAG, "蓝牙配网对象创建完成");
|
||
}
|
||
|
||
/**
|
||
* @brief 析构函数
|
||
*
|
||
* 清理蓝牙配网对象的所有资源,包括停止配网服务、
|
||
* 释放蓝牙资源、清空静态实例指针等。
|
||
*/
|
||
BluetoothProvisioning::~BluetoothProvisioning() {
|
||
// 确保资源被正确释放,如果已初始化则进行反初始化
|
||
if (initialized_) {
|
||
Deinitialize();
|
||
}
|
||
|
||
// 清空静态实例指针
|
||
instance_ = nullptr;
|
||
ESP_LOGI(TAG, "蓝牙配网对象销毁完成");
|
||
}
|
||
|
||
/**
|
||
* @brief 初始化蓝牙配网功能
|
||
*
|
||
* 按顺序初始化以下组件:
|
||
* 1. WiFi模块(STA模式)
|
||
* 2. 蓝牙控制器
|
||
* 3. Bluedroid协议栈
|
||
* 4. BluFi服务和回调
|
||
* 5. WiFi事件处理器
|
||
*
|
||
* @return true 初始化成功,false 初始化失败
|
||
*/
|
||
bool BluetoothProvisioning::Initialize() {
|
||
if (initialized_) {
|
||
ESP_LOGW(TAG, "蓝牙配网已经初始化");
|
||
return true;
|
||
}
|
||
|
||
SetState(BluetoothProvisioningState::INITIALIZING);
|
||
|
||
esp_err_t ret;
|
||
|
||
// 步骤1: 初始化WiFi模块
|
||
ESP_LOGI(TAG, "初始化WiFi...");
|
||
|
||
// 创建默认WiFi STA网络接口
|
||
esp_netif_create_default_wifi_sta();
|
||
|
||
// 使用默认配置初始化WiFi
|
||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||
ret = esp_wifi_init(&cfg);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "WiFi初始化失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 设置WiFi工作模式为STA(Station)模式
|
||
ret = esp_wifi_set_mode(WIFI_MODE_STA);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "WiFi模式设置失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 启动WiFi服务
|
||
ret = esp_wifi_start();
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "WiFi启动失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "WiFi初始化完成");
|
||
|
||
// 步骤2: 初始化蓝牙控制器
|
||
ESP_LOGI(TAG, "初始化蓝牙控制器...");
|
||
|
||
#if CONFIG_IDF_TARGET_ESP32
|
||
// ESP32芯片需要释放经典蓝牙内存以节省空间
|
||
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
|
||
#endif
|
||
|
||
// 使用默认配置初始化蓝牙控制器
|
||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||
ret = esp_bt_controller_init(&bt_cfg);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "蓝牙控制器初始化失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 启用蓝牙控制器,仅使用BLE模式
|
||
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "蓝牙控制器启用失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 步骤3: 初始化Bluedroid协议栈
|
||
ESP_LOGI(TAG, "初始化Bluedroid协议栈...");
|
||
|
||
// 初始化Bluedroid蓝牙协议栈
|
||
ret = esp_bluedroid_init();
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "Bluedroid初始化失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 启用Bluedroid协议栈
|
||
ret = esp_bluedroid_enable();
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "Bluedroid启用失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 注意:设备名称将在StartProvisioning中设置
|
||
ESP_LOGI(TAG, "蓝牙初始化完成,设备名称将在启动配网时设置");
|
||
|
||
// 步骤4: 注册BluFi服务和回调函数
|
||
ESP_LOGI(TAG, "注册BLUFI回调函数...");
|
||
|
||
// 注册BluFi事件回调函数
|
||
ret = esp_blufi_register_callbacks(&blufi_callbacks);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "BLUFI回调注册失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 注册BLE GAP(Generic Access Profile)事件处理器
|
||
ret = esp_ble_gap_register_callback(esp_blufi_gap_event_handler);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "BLE GAP事件处理器注册失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 初始化BluFi配置文件
|
||
ret = esp_blufi_profile_init();
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "BLUFI配置文件初始化失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);//BLUFI配置文件初始化失败,设置状态为FAILED
|
||
return false;
|
||
}
|
||
|
||
// 步骤5: 创建WiFi事件同步机制
|
||
if (s_wifi_event_group == nullptr) {
|
||
s_wifi_event_group = xEventGroupCreate();
|
||
if (s_wifi_event_group == nullptr) {
|
||
ESP_LOGE(TAG, "WiFi事件组创建失败");
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
// 步骤6: 注册WiFi和IP事件处理器
|
||
ESP_LOGI(TAG, "注册WiFi事件处理器...");
|
||
|
||
// 注册WiFi事件处理器,监听所有WiFi相关事件
|
||
ret = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &WiFiEventHandler, this);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "WiFi事件处理器注册失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 注册IP事件处理器,监听IP地址获取事件
|
||
ret = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &IPEventHandler, this);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "IP事件处理器注册失败: %s", esp_err_to_name(ret));
|
||
SetState(BluetoothProvisioningState::FAILED);
|
||
return false;
|
||
}
|
||
|
||
// 标记初始化完成,设置状态为空闲
|
||
initialized_ = true;
|
||
SetState(BluetoothProvisioningState::IDLE);
|
||
|
||
ESP_LOGI(TAG, "蓝牙配网初始化完成");
|
||
ESP_LOGI(TAG, "蓝牙MAC地址: " ESP_BD_ADDR_STR, ESP_BD_ADDR_HEX(esp_bt_dev_get_address()));
|
||
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* @brief 反初始化蓝牙配网功能
|
||
*
|
||
* 按相反顺序清理所有初始化的组件和资源:
|
||
* 1. 停止配网服务
|
||
* 2. 注销事件处理器
|
||
* 3. 销毁WiFi事件组
|
||
* 4. 反初始化BluFi服务
|
||
* 5. 反初始化Bluedroid协议栈
|
||
* 6. 反初始化蓝牙控制器
|
||
*
|
||
* @return true 反初始化成功,false 反初始化失败
|
||
*/
|
||
bool BluetoothProvisioning::Deinitialize() {
|
||
if (!initialized_) {
|
||
ESP_LOGW(TAG, "蓝牙配网未初始化");
|
||
return true;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "开始反初始化蓝牙配网...");
|
||
|
||
// 步骤1: 停止配网服务(如果正在运行)
|
||
if (state_ != BluetoothProvisioningState::IDLE &&
|
||
state_ != BluetoothProvisioningState::STOPPED) {
|
||
StopProvisioning();
|
||
}
|
||
|
||
// 步骤2: 注销事件处理器
|
||
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, &WiFiEventHandler);
|
||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, &IPEventHandler);
|
||
|
||
// 步骤3: 销毁WiFi事件同步机制
|
||
if (s_wifi_event_group != nullptr) {
|
||
vEventGroupDelete(s_wifi_event_group);
|
||
s_wifi_event_group = nullptr;
|
||
}
|
||
|
||
// 步骤4: 反初始化BluFi服务
|
||
esp_blufi_profile_deinit();
|
||
|
||
// 步骤5: 反初始化Bluedroid协议栈
|
||
esp_bluedroid_disable();
|
||
esp_bluedroid_deinit();
|
||
|
||
// 步骤6: 反初始化蓝牙控制器
|
||
esp_bt_controller_disable();
|
||
esp_bt_controller_deinit();
|
||
|
||
// 标记为未初始化状态
|
||
initialized_ = false;
|
||
SetState(BluetoothProvisioningState::STOPPED);
|
||
|
||
ESP_LOGI(TAG, "蓝牙配网反初始化完成");
|
||
return true;
|
||
}
|
||
// 开始配网
|
||
bool BluetoothProvisioning::StartProvisioning(const char* device_name) {
|
||
ESP_LOGI(TAG, "🔵 开始启动BluFi配网服务...");
|
||
ESP_LOGI(TAG, "🔍 检查初始化状态: initialized_ = %s", initialized_ ? "true" : "false");
|
||
|
||
if (!initialized_) {
|
||
ESP_LOGE(TAG, "❌ 蓝牙配网未初始化,无法启动");
|
||
return false;
|
||
}
|
||
|
||
if (state_ == BluetoothProvisioningState::ADVERTISING ||
|
||
state_ == BluetoothProvisioningState::CONNECTED ||
|
||
state_ == BluetoothProvisioningState::PROVISIONING) {
|
||
ESP_LOGW(TAG, "⚠️ 蓝牙配网已在运行中");
|
||
return true;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "🚀 开始蓝牙配网,设备名称: %s", device_name);
|
||
|
||
// 重置状态
|
||
client_connected_ = false;
|
||
s_retry_num = 0;
|
||
|
||
// 重置MAC地址发送状态,为新的配网会话做准备
|
||
ResetMacSendingState();
|
||
ESP_LOGI(TAG, "🔄 MAC地址发送状态已重置");
|
||
|
||
// 清空之前的WiFi凭据
|
||
ESP_LOGI(TAG, "🧹 清除之前的WiFi凭据...");
|
||
if (!wifi_credentials_.ssid.empty()) {
|
||
ESP_LOGI(TAG, "🗑️ 删除已保存的SSID: %s", wifi_credentials_.ssid.c_str());
|
||
}
|
||
if (!wifi_credentials_.password.empty()) {
|
||
ESP_LOGI(TAG, "🗑️ 删除已保存的WiFi密码 (长度: %d)", wifi_credentials_.password.length());
|
||
}
|
||
wifi_credentials_.ssid.clear();
|
||
wifi_credentials_.password.clear();
|
||
wifi_credentials_.bssid_set = false;
|
||
ESP_LOGI(TAG, "✅ WiFi凭据清除完成,准备接收新的配网信息");
|
||
|
||
// 开始BLUFI广播
|
||
esp_blufi_adv_start();
|
||
ESP_LOGI(TAG, "BLUFI广播已启动");
|
||
|
||
// // 配置自定义广播数据包以确保设备名称正确显示(改蓝牙名称 必备操作)
|
||
// //=====================================================================================================
|
||
// esp_ble_adv_data_t adv_data = {};
|
||
// adv_data.set_scan_rsp = false;
|
||
// adv_data.include_name = true; // 包含设备名称
|
||
// adv_data.include_txpower = true;
|
||
// adv_data.min_interval = 0x0006;
|
||
// adv_data.max_interval = 0x0010;
|
||
// adv_data.appearance = 0x00;
|
||
|
||
// // 添加厂商特定数据
|
||
// static uint8_t manufacturer_data[] = {0xFF, 0xFF, 0x00, 0x00}; // ESP厂商ID
|
||
// adv_data.manufacturer_len = sizeof(manufacturer_data);
|
||
// adv_data.p_manufacturer_data = manufacturer_data;
|
||
|
||
// adv_data.service_data_len = 0;
|
||
// adv_data.p_service_data = NULL;
|
||
// // 添加BluFi服务UUID,确保ESP官方APP能够识别
|
||
// // UUID: 0000FFFF-0000-1000-8000-00805F9B34FB (小端序)
|
||
// static uint8_t blufi_service_uuid128[16] = {
|
||
// 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x10,
|
||
// 0x00, 0x80, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
|
||
// };
|
||
// adv_data.service_uuid_len = sizeof(blufi_service_uuid128);
|
||
// adv_data.p_service_uuid = blufi_service_uuid128;
|
||
// adv_data.flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT);
|
||
// //===================================================
|
||
|
||
// // 重新设置设备名称并配置广播数据
|
||
// esp_err_t ret = esp_ble_gap_set_device_name(device_name);
|
||
// if (ret != ESP_OK) {
|
||
// ESP_LOGE(TAG, "❌ 设置蓝牙设备名称失败: %s", esp_err_to_name(ret));
|
||
// return false;
|
||
// }
|
||
|
||
// ret = esp_ble_gap_config_adv_data(&adv_data);
|
||
// if (ret != ESP_OK) {
|
||
// ESP_LOGE(TAG, "❌ 配置广播数据失败: %s", esp_err_to_name(ret));
|
||
// return false;
|
||
// }
|
||
|
||
// // 配置广播参数(按官方示例设置)
|
||
// //==================================================
|
||
// esp_ble_adv_params_t adv_params = {};
|
||
// adv_params.adv_int_min = 0x100; // 100ms间隔
|
||
// adv_params.adv_int_max = 0x100; // 100ms间隔
|
||
// adv_params.adv_type = ADV_TYPE_IND;
|
||
// adv_params.own_addr_type = BLE_ADDR_TYPE_PUBLIC;
|
||
// adv_params.channel_map = ADV_CHNL_ALL;
|
||
// adv_params.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY;
|
||
// // 配置完所有广播数据后再启动广播
|
||
// //==================================================
|
||
|
||
// ret = esp_ble_gap_start_advertising(&adv_params);
|
||
// if (ret != ESP_OK) {
|
||
// ESP_LOGE(TAG, "❌ 启动广播失败: %s", esp_err_to_name(ret));
|
||
// return false;
|
||
// }
|
||
// ESP_LOGI(TAG, "✅ 蓝牙设备名称和广播数据配置成功: %s", device_name);
|
||
// //=====================================================================================================
|
||
|
||
SetState(BluetoothProvisioningState::ADVERTISING);// 设置蓝牙状态为广播中
|
||
ESP_LOGI(TAG, "蓝牙配网广播已启动,等待客户端连接...");
|
||
|
||
return true;
|
||
}
|
||
|
||
// 停止蓝牙配网
|
||
bool BluetoothProvisioning::StopProvisioning() {
|
||
if (state_ == BluetoothProvisioningState::IDLE ||
|
||
state_ == BluetoothProvisioningState::STOPPED) {
|
||
ESP_LOGW(TAG, "蓝牙配网未在运行");
|
||
return true;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "停止蓝牙配网...");
|
||
|
||
// 停止BLUFI广播
|
||
esp_blufi_adv_stop();
|
||
|
||
// 如果有客户端连接,断开连接
|
||
if (client_connected_) {
|
||
esp_blufi_disconnect();
|
||
}
|
||
|
||
SetState(BluetoothProvisioningState::IDLE);
|
||
ESP_LOGI(TAG, "蓝牙配网已停止");
|
||
|
||
return true;
|
||
}
|
||
|
||
// 向客户端/小程序 报告WiFi连接状态
|
||
void BluetoothProvisioning::ReportWiFiStatus(bool success, uint8_t reason) {
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] ReportWiFiStatus调用: success=%s, client_connected_=%s",
|
||
success ? "true" : "false", client_connected_ ? "true" : "false");
|
||
if (!client_connected_) {
|
||
ESP_LOGW(TAG, "客户端未连接,无法发送WiFi状态");
|
||
return;
|
||
}
|
||
|
||
wifi_mode_t mode;
|
||
esp_wifi_get_mode(&mode);//获取当前WiFi模式
|
||
|
||
if (success) {
|
||
ESP_LOGI(TAG, "向客户端报告设备连接WiFi成功!");
|
||
esp_err_t ret = esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, nullptr);
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] WiFi成功报告发送结果: %s", esp_err_to_name(ret));
|
||
} else {
|
||
ESP_LOGI(TAG, "向客户端报告连接WiFi失败,原因: %d", reason);
|
||
esp_blufi_extra_info_t info;
|
||
memset(&info, 0, sizeof(info));
|
||
info.sta_conn_end_reason_set = true;
|
||
info.sta_conn_end_reason = reason;
|
||
esp_err_t ret = esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, 0, &info);
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] WiFi失败报告发送结果: %s", esp_err_to_name(ret));
|
||
}
|
||
}
|
||
|
||
// 将WI-FI扫描列表 发送给客户端(Wi-Fi扫描)
|
||
void BluetoothProvisioning::SendWiFiList(const wifi_ap_record_t* ap_list, uint16_t ap_count) {
|
||
if (!client_connected_) {
|
||
ESP_LOGW(TAG, "客户端未连接,无法发送WiFi列表");
|
||
return;
|
||
}
|
||
|
||
if (ap_list == nullptr || ap_count == 0) {
|
||
ESP_LOGW(TAG, "WiFi列表为空");
|
||
return;
|
||
}
|
||
|
||
// 转换为BLUFI格式
|
||
esp_blufi_ap_record_t* blufi_ap_list = new esp_blufi_ap_record_t[ap_count];
|
||
if (blufi_ap_list == nullptr) {
|
||
ESP_LOGE(TAG, "内存分配失败");
|
||
return;
|
||
}
|
||
|
||
// 用于SSID去重的映射表
|
||
std::map<std::string, int> ssid_map;
|
||
|
||
uint16_t valid_ap_count = 0;
|
||
for (uint16_t i = 0; i < ap_count; i++) {
|
||
// ESP32-S3只支持2.4GHz WiFi(信道1-14),过滤掉5GHz WiFi
|
||
if (ap_list[i].primary < 1 || ap_list[i].primary > 14) {
|
||
ESP_LOGD(TAG, "跳过5GHz WiFi: %s, Channel: %d (ESP32-S3只支持2.4GHz)",
|
||
ap_list[i].ssid, ap_list[i].primary);
|
||
continue;
|
||
}
|
||
|
||
// SSID去重:只保留RSSI最强的AP
|
||
std::string ssid_str((char*)ap_list[i].ssid);
|
||
if (ssid_map.find(ssid_str) != ssid_map.end()) {
|
||
// 检查是否比已保存的AP信号更强
|
||
if (ap_list[i].rssi > ssid_map[ssid_str]) {
|
||
ESP_LOGD(TAG, "发现更强信号的同名AP: %s, 新RSSI=%d, 旧RSSI=%d",
|
||
ssid_str.c_str(), ap_list[i].rssi, ssid_map[ssid_str]);
|
||
// 替换为更强的信号
|
||
for (uint16_t j = 0; j < valid_ap_count; j++) {
|
||
if (strcmp((char*)blufi_ap_list[j].ssid, ssid_str.c_str()) == 0) {
|
||
blufi_ap_list[j].rssi = ap_list[i].rssi;
|
||
ssid_map[ssid_str] = ap_list[i].rssi;
|
||
break;
|
||
}
|
||
}
|
||
} else {
|
||
ESP_LOGD(TAG, "跳过较弱信号的同名AP: %s, RSSI=%d, 已有RSSI=%d",
|
||
ssid_str.c_str(), ap_list[i].rssi, ssid_map[ssid_str]);
|
||
continue;
|
||
}
|
||
} else {
|
||
// 首次遇到该SSID,直接添加
|
||
blufi_ap_list[valid_ap_count].rssi = ap_list[i].rssi;
|
||
memcpy(blufi_ap_list[valid_ap_count].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));
|
||
ssid_map[ssid_str] = ap_list[i].rssi;
|
||
valid_ap_count++;
|
||
}
|
||
}
|
||
|
||
ESP_LOGI(TAG, "向客户端发送WiFi列表,共%d个AP(过滤后%d个2.4GHz AP,去重后%d个唯一SSID)",
|
||
ap_count, valid_ap_count, ssid_map.size());
|
||
esp_blufi_send_wifi_list(valid_ap_count, blufi_ap_list);
|
||
|
||
delete[] blufi_ap_list;
|
||
}
|
||
|
||
bool BluetoothProvisioning::SendMacAddressReliably() {
|
||
// 第一重检查:基本连接状态
|
||
if (!client_connected_) {
|
||
ESP_LOGW(TAG, "客户端未连接,无法发送MAC地址");
|
||
return false;
|
||
}
|
||
|
||
// 获取设备MAC地址
|
||
uint8_t mac[6];
|
||
esp_err_t ret = esp_wifi_get_mac(WIFI_IF_STA, mac);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "获取MAC地址失败: %s", esp_err_to_name(ret));
|
||
return false;
|
||
}
|
||
|
||
// 格式化MAC地址字符串
|
||
char mac_str[18];
|
||
snprintf(mac_str, sizeof(mac_str), "%02X:%02X:%02X:%02X:%02X:%02X",
|
||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||
|
||
// 检查是否已经发送过MAC地址(WiFi MAC地址不会因重启而变化)
|
||
if (mac_address_sent_) {
|
||
ESP_LOGI(TAG, "MAC地址已发送过,跳过重复发送: %s", mac_str);
|
||
return true;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "开始可靠发送MAC地址: %s", mac_str);
|
||
|
||
// 多次重试发送机制
|
||
const int MAX_SEND_ATTEMPTS = 3;
|
||
const int RETRY_DELAY_MS = 50;
|
||
|
||
for (int attempt = 1; attempt <= MAX_SEND_ATTEMPTS; attempt++) {
|
||
// 第二重检查:发送前再次确认连接状态
|
||
if (!client_connected_) {
|
||
ESP_LOGW(TAG, "发送前检查发现客户端已断开连接 (尝试 %d/%d)", attempt, MAX_SEND_ATTEMPTS);
|
||
return false;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "发送MAC地址尝试 %d/%d: %s", attempt, MAX_SEND_ATTEMPTS, mac_str);
|
||
|
||
// 创建包含MAC地址的自定义数据(还原原有格式)
|
||
char mac_data[32];
|
||
snprintf(mac_data, sizeof(mac_data), "STA_MAC:%02x:%02x:%02x:%02x:%02x:%02x",
|
||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||
|
||
// 发送带前缀的MAC地址数据
|
||
ret = esp_blufi_send_custom_data((uint8_t*)mac_data, strlen(mac_data));
|
||
|
||
if (ret == ESP_OK) {
|
||
ESP_LOGI(TAG, "✅ MAC地址发送成功 (尝试 %d/%d): %s", attempt, MAX_SEND_ATTEMPTS, mac_str);
|
||
|
||
// 记录发送状态
|
||
mac_address_sent_ = true;
|
||
|
||
// 发送成功后的确认延迟
|
||
vTaskDelay(pdMS_TO_TICKS(100));
|
||
|
||
// 第三重检查:发送后确认连接仍然有效
|
||
if (client_connected_) {
|
||
ESP_LOGI(TAG, "MAC地址发送完成,连接状态正常");
|
||
return true;
|
||
} else {
|
||
ESP_LOGW(TAG, "MAC地址发送后检测到连接断开");
|
||
return false;
|
||
}
|
||
} else {
|
||
ESP_LOGW(TAG, "❌ MAC地址发送失败 (尝试 %d/%d): %s, 错误: %s",
|
||
attempt, MAX_SEND_ATTEMPTS, mac_str, esp_err_to_name(ret));
|
||
|
||
// 如果不是最后一次尝试,等待后重试
|
||
if (attempt < MAX_SEND_ATTEMPTS) {
|
||
vTaskDelay(pdMS_TO_TICKS(RETRY_DELAY_MS));
|
||
}
|
||
}
|
||
}
|
||
|
||
ESP_LOGE(TAG, "MAC地址发送失败,已达到最大重试次数: %s", mac_str);
|
||
return false;
|
||
}
|
||
|
||
void BluetoothProvisioning::ResetMacSendingState() {
|
||
mac_address_sent_ = false;
|
||
ESP_LOGI(TAG, "MAC地址发送状态已重置");
|
||
}
|
||
|
||
void BluetoothProvisioning::SetState(BluetoothProvisioningState new_state) {
|
||
if (state_ != new_state) {
|
||
BluetoothProvisioningState old_state = state_;
|
||
state_ = new_state;
|
||
|
||
const char* state_names[] = {
|
||
"IDLE", "INITIALIZING", "ADVERTISING", "CONNECTED",
|
||
"PROVISIONING", "SUCCESS", "FAILED", "STOPPED"
|
||
};
|
||
|
||
ESP_LOGI(TAG, "🔄 BluFi状态变化: %s -> %s",
|
||
state_names[static_cast<int>(old_state)],
|
||
state_names[static_cast<int>(new_state)]);
|
||
|
||
TriggerCallback(BluetoothProvisioningEvent::STATE_CHANGED, nullptr);
|
||
}
|
||
}
|
||
|
||
void BluetoothProvisioning::TriggerCallback(BluetoothProvisioningEvent event, void* data) {
|
||
if (callback_) {
|
||
callback_(event, data);
|
||
}
|
||
}
|
||
|
||
std::string BluetoothProvisioning::GetStateString() const {
|
||
const char* state_names[] = {
|
||
"IDLE", "INITIALIZING", "ADVERTISING", "CONNECTED",
|
||
"PROVISIONING", "SUCCESS", "FAILED", "STOPPED"
|
||
};
|
||
return std::string(state_names[static_cast<int>(state_)]);
|
||
}
|
||
|
||
// BLUFI事件回调函数
|
||
void BluetoothProvisioning::BlufiEventCallback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t* param) {
|
||
if (instance_ == nullptr) {
|
||
ESP_LOGE(TAG, "实例指针为空");
|
||
return;
|
||
}
|
||
|
||
// 打印事件详细信息
|
||
const char* event_name = "UNKNOWN";
|
||
switch (event) {
|
||
case ESP_BLUFI_EVENT_INIT_FINISH: event_name = "INIT_FINISH"; break;
|
||
case ESP_BLUFI_EVENT_DEINIT_FINISH: event_name = "DEINIT_FINISH"; break;
|
||
case ESP_BLUFI_EVENT_BLE_CONNECT: event_name = "BLE_CONNECT"; break;
|
||
case ESP_BLUFI_EVENT_BLE_DISCONNECT: event_name = "BLE_DISCONNECT"; break;
|
||
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA: event_name = "RECV_CUSTOM_DATA"; break;
|
||
case ESP_BLUFI_EVENT_RECV_STA_SSID: event_name = "RECV_STA_SSID"; break;
|
||
case ESP_BLUFI_EVENT_RECV_STA_PASSWD: event_name = "RECV_STA_PASSWD"; break;
|
||
case ESP_BLUFI_EVENT_GET_WIFI_LIST: event_name = "GET_WIFI_LIST"; break;
|
||
default: break;
|
||
}
|
||
// 打印事件参数
|
||
ESP_LOGI(TAG, "🔔 BluFi事件回调: %d (%s), param=%p", event, event_name, param);
|
||
|
||
switch (event) {
|
||
case ESP_BLUFI_EVENT_INIT_FINISH:
|
||
ESP_LOGI(TAG, "✅ BLUFI初始化完成");
|
||
break;
|
||
|
||
case ESP_BLUFI_EVENT_DEINIT_FINISH:
|
||
ESP_LOGI(TAG, "BLUFI反初始化完成");
|
||
break;
|
||
|
||
// 客户端连接事件
|
||
case ESP_BLUFI_EVENT_BLE_CONNECT:
|
||
ESP_LOGI(TAG, "📱 BluFi客户端已连接");//GATT连接成功建立
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] 设置client_connected_为true");
|
||
instance_->client_connected_ = true;//GATT连接成功建立,标志位设置为true
|
||
// 重置MAC地址发送状态,为新的配网会话做准备
|
||
instance_->ResetMacSendingState();
|
||
ESP_LOGI(TAG, "🔄 MAC地址发送状态已重置");
|
||
instance_->SetState(BluetoothProvisioningState::CONNECTED); //GATT连接成功建立,状态设置为CONNECTED
|
||
instance_->TriggerCallback(BluetoothProvisioningEvent::CLIENT_CONNECTED, nullptr);//回调通知,通知上层应用有客户端连接
|
||
|
||
// // 在Wi-Fi连接前向客户端发送Mac地址
|
||
// // 🆕 在BluFi客户端连接成功后立即发送MAC地址
|
||
// ESP_LOGI(TAG, "📡 BluFi客户端连接成功,立即发送设备MAC地址");
|
||
// if (instance_->SendMacAddressReliably()) {
|
||
// ESP_LOGI(TAG, "✅ BluFi连接后MAC地址发送成功");
|
||
// } else {
|
||
// ESP_LOGW(TAG, "⚠️ BluFi连接后MAC地址发送失败,将在Wi-Fi连接成功后重试");
|
||
// }
|
||
|
||
// 停止广播
|
||
esp_blufi_adv_stop();
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] BLE连接处理完成,client_connected_=%s",
|
||
instance_->client_connected_ ? "true" : "false");
|
||
break;
|
||
// 客户端断开连接事件
|
||
case ESP_BLUFI_EVENT_BLE_DISCONNECT:
|
||
ESP_LOGI(TAG, "📱 BluFi客户端已断开连接,当前状态: %s",
|
||
instance_->GetStateString().c_str());
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] 设置client_connected_为false");
|
||
instance_->client_connected_ = false;
|
||
|
||
// 如果正在配网过程中,延迟处理断开事件,给WiFi连接更多时间
|
||
if (instance_->state_ == BluetoothProvisioningState::PROVISIONING) {
|
||
ESP_LOGW(TAG, "⚠️ 配网过程中BLE断开,延迟5秒后处理以等待WiFi连接完成");
|
||
// 设置一个标志,延迟处理断开
|
||
instance_->delayed_disconnect_ = true;
|
||
// 创建延迟任务
|
||
xTaskCreate([](void* param) {
|
||
vTaskDelay(pdMS_TO_TICKS(2000)); // 缩短延迟到2秒
|
||
BluetoothProvisioning* self = static_cast<BluetoothProvisioning*>(param);
|
||
if (self->delayed_disconnect_) {
|
||
if (self->state_ == BluetoothProvisioningState::PROVISIONING && self->wifi_connecting_) {
|
||
ESP_LOGW(TAG, "⏰ BLE延迟断开,但WiFi仍在连接中,继续等待");
|
||
// WiFi仍在连接,不断开BLE,让WiFi超时定时器处理
|
||
} else if (self->state_ == BluetoothProvisioningState::PROVISIONING) {
|
||
ESP_LOGW(TAG, "⏰ 延迟处理BLE断开,WiFi连接可能已超时");
|
||
self->SetState(BluetoothProvisioningState::ADVERTISING);
|
||
self->TriggerCallback(BluetoothProvisioningEvent::CLIENT_DISCONNECTED, nullptr);
|
||
esp_blufi_adv_start();
|
||
}
|
||
self->delayed_disconnect_ = false;
|
||
}
|
||
vTaskDelete(nullptr);
|
||
}, "delayed_disconnect", 2048, instance_, 1, nullptr);
|
||
} else {
|
||
instance_->SetState(BluetoothProvisioningState::ADVERTISING);
|
||
instance_->TriggerCallback(BluetoothProvisioningEvent::CLIENT_DISCONNECTED, nullptr);
|
||
// 重新开始广播
|
||
esp_blufi_adv_start();
|
||
}
|
||
break;
|
||
|
||
// 设置WiFi模式
|
||
case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
|
||
ESP_LOGI(TAG, "设置WiFi模式: %d", param->wifi_mode.op_mode);
|
||
esp_wifi_set_mode(param->wifi_mode.op_mode);
|
||
break;
|
||
|
||
// 请求连接到AP (Wi-Fi)
|
||
case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
|
||
ESP_LOGI(TAG, "📡 请求连接到AP,SSID: %s", instance_->wifi_credentials_.ssid.c_str());
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] 当前状态: %s, client_connected_: %s",
|
||
instance_->GetStateString().c_str(),
|
||
instance_->client_connected_ ? "true" : "false");
|
||
instance_->SetState(BluetoothProvisioningState::PROVISIONING);
|
||
instance_->delayed_disconnect_ = false; // 重置延迟断开标志
|
||
s_retry_num = 0; // 重置重试计数
|
||
ESP_LOGI(TAG, "🔄 重置WiFi重试计数,开始连接流程");
|
||
// 断开当前WiFi连接(如果有)
|
||
esp_wifi_disconnect();
|
||
vTaskDelay(pdMS_TO_TICKS(100)); // 短暂延迟确保断开完成
|
||
// 连接到新的AP
|
||
esp_wifi_connect();//连接到新的 Wi-Fi
|
||
ESP_LOGI(TAG, "🚀 已发起WiFi连接请求");
|
||
break;
|
||
|
||
// 请求断开AP连接
|
||
case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
|
||
ESP_LOGI(TAG, "请求断开AP连接");
|
||
esp_wifi_disconnect();//断开当前连接的AP
|
||
break;
|
||
|
||
// 接收到WI-FI的 SSID
|
||
case ESP_BLUFI_EVENT_RECV_STA_SSID:
|
||
ESP_LOGI(TAG, "📶 收到WiFi SSID: %.*s", param->sta_ssid.ssid_len, param->sta_ssid.ssid);
|
||
instance_->wifi_credentials_.ssid.assign(
|
||
reinterpret_cast<const char*>(param->sta_ssid.ssid),
|
||
param->sta_ssid.ssid_len);//保存Wi-Fi的 SSID
|
||
|
||
// 设置WiFi配置
|
||
{
|
||
wifi_config_t wifi_config = {};
|
||
strncpy(reinterpret_cast<char*>(wifi_config.sta.ssid),
|
||
instance_->wifi_credentials_.ssid.c_str(),
|
||
sizeof(wifi_config.sta.ssid) - 1);
|
||
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);//设置WiFi配置
|
||
}
|
||
break;
|
||
|
||
// 接收到WI-FI的 密码
|
||
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
|
||
ESP_LOGI(TAG, "🔐 收到WiFi密码 (长度: %d)", param->sta_passwd.passwd_len);
|
||
instance_->wifi_credentials_.password.assign(
|
||
reinterpret_cast<const char*>(param->sta_passwd.passwd),
|
||
param->sta_passwd.passwd_len);// 保存WI-FI密码凭证
|
||
|
||
// 设置WiFi配置
|
||
{
|
||
wifi_config_t wifi_config = {};
|
||
strncpy(reinterpret_cast<char*>(wifi_config.sta.ssid),
|
||
instance_->wifi_credentials_.ssid.c_str(),
|
||
sizeof(wifi_config.sta.ssid) - 1);
|
||
strncpy(reinterpret_cast<char*>(wifi_config.sta.password),
|
||
instance_->wifi_credentials_.password.c_str(),
|
||
sizeof(wifi_config.sta.password) - 1);
|
||
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));//设置WiFi配置
|
||
}
|
||
|
||
// 重置重试计数器
|
||
s_retry_num = 0;
|
||
instance_->wifi_connecting_ = true;
|
||
|
||
// 启动WiFi连接超时定时器
|
||
if (wifi_connect_timer) {
|
||
xTimerStop(wifi_connect_timer, 0);
|
||
xTimerDelete(wifi_connect_timer, 0);
|
||
}
|
||
wifi_connect_timer = xTimerCreate("wifi_timeout",
|
||
pdMS_TO_TICKS(WIFI_CONNECT_TIMEOUT_MS),
|
||
pdFALSE, nullptr,
|
||
[](TimerHandle_t timer) {
|
||
ESP_LOGW(TAG, "⏰ WiFi连接超时,强制失败处理");
|
||
if (instance_ && instance_->wifi_connecting_) {
|
||
instance_->wifi_connecting_ = false;
|
||
instance_->delayed_disconnect_ = false;
|
||
instance_->SetState(BluetoothProvisioningState::FAILED);
|
||
instance_->TriggerCallback(BluetoothProvisioningEvent::WIFI_FAILED, nullptr);
|
||
instance_->ReportWiFiStatus(false, WIFI_REASON_UNSPECIFIED);
|
||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||
}
|
||
});
|
||
xTimerStart(wifi_connect_timer, 0);
|
||
|
||
esp_wifi_connect(); // 核心连接函数,连接到WiFi
|
||
ESP_LOGI(TAG, "📡 已发起WiFi连接请求,启动15秒超时监控");
|
||
|
||
instance_->TriggerCallback(BluetoothProvisioningEvent::WIFI_CREDENTIALS,
|
||
&instance_->wifi_credentials_);
|
||
break;
|
||
|
||
// 接收到WI-FI的 BSSID 特定接入点MAC地址
|
||
case ESP_BLUFI_EVENT_RECV_STA_BSSID:
|
||
ESP_LOGI(TAG, "收到BSSID");
|
||
memcpy(instance_->wifi_credentials_.bssid, param->sta_bssid.bssid, 6);
|
||
instance_->wifi_credentials_.bssid_set = true;// 标记BSSID已设置
|
||
|
||
// 设置WiFi配置
|
||
{
|
||
wifi_config_t wifi_config = {};
|
||
strncpy(reinterpret_cast<char*>(wifi_config.sta.ssid),
|
||
instance_->wifi_credentials_.ssid.c_str(),
|
||
sizeof(wifi_config.sta.ssid) - 1);// 复制SSID到配置
|
||
strncpy(reinterpret_cast<char*>(wifi_config.sta.password),
|
||
instance_->wifi_credentials_.password.c_str(),
|
||
sizeof(wifi_config.sta.password) - 1);// 复制密码到配置
|
||
memcpy(wifi_config.sta.bssid, instance_->wifi_credentials_.bssid, 6);
|
||
wifi_config.sta.bssid_set = true;
|
||
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);//设置WiFi配置
|
||
}
|
||
break;
|
||
|
||
// 客户端请求WiFi状态
|
||
case ESP_BLUFI_EVENT_GET_WIFI_STATUS:
|
||
ESP_LOGI(TAG, "客户端请求WiFi状态");
|
||
// 这里可以发送当前WiFi状态
|
||
break;
|
||
|
||
// 新增代码
|
||
//========================================================================
|
||
// 客户端请求WiFi列表
|
||
case ESP_BLUFI_EVENT_GET_WIFI_LIST:
|
||
ESP_LOGI(TAG, "📱 手机APP请求获取WiFi列表,开始扫描周围WiFi网络");
|
||
// 启动WiFi扫描
|
||
{
|
||
wifi_scan_config_t scan_config = {};
|
||
scan_config.ssid = nullptr; // 扫描所有SSID
|
||
scan_config.bssid = nullptr; // 扫描所有BSSID
|
||
scan_config.channel = 0; // 扫描所有信道
|
||
scan_config.show_hidden = true; // 显示隐藏网络
|
||
scan_config.scan_type = WIFI_SCAN_TYPE_ACTIVE;
|
||
scan_config.scan_time.active.min = 100;
|
||
scan_config.scan_time.active.max = 300;
|
||
|
||
esp_err_t ret = esp_wifi_scan_start(&scan_config, false);
|
||
if (ret == ESP_OK) {
|
||
ESP_LOGI(TAG, "🔍 WiFi扫描已启动,等待扫描结果");
|
||
} else {
|
||
ESP_LOGE(TAG, "❌ WiFi扫描启动失败: %s", esp_err_to_name(ret));
|
||
}
|
||
}
|
||
break;
|
||
//========================================================================
|
||
|
||
// 客户端请求断开BLE连接
|
||
case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
|
||
ESP_LOGI(TAG, "收到断开BLE连接请求");
|
||
esp_blufi_disconnect();
|
||
break;
|
||
|
||
default:
|
||
ESP_LOGD(TAG, "未处理的BLUFI事件: %d", event);
|
||
break;
|
||
}
|
||
}
|
||
|
||
// 处理WiFi事件
|
||
void BluetoothProvisioning::WiFiEventHandler(void* arg, esp_event_base_t event_base,
|
||
int32_t event_id, void* event_data) {
|
||
BluetoothProvisioning* self = static_cast<BluetoothProvisioning*>(arg);
|
||
|
||
if (event_base == WIFI_EVENT) {
|
||
switch (event_id) {
|
||
case WIFI_EVENT_STA_START:
|
||
ESP_LOGI(TAG, "WiFi STA启动");
|
||
break;
|
||
|
||
case WIFI_EVENT_STA_CONNECTED: {
|
||
wifi_event_sta_connected_t* event = static_cast<wifi_event_sta_connected_t*>(event_data);
|
||
ESP_LOGI(TAG, "✅ WiFi连接成功,SSID: %.*s,等待获取IP地址", event->ssid_len, event->ssid);
|
||
|
||
// 停止WiFi连接超时定时器
|
||
if (wifi_connect_timer) {
|
||
xTimerStop(wifi_connect_timer, 0);
|
||
}
|
||
|
||
// 清除连接状态标志
|
||
self->wifi_connecting_ = false;
|
||
self->delayed_disconnect_ = false;
|
||
break;
|
||
}
|
||
|
||
case WIFI_EVENT_STA_DISCONNECTED: {
|
||
wifi_event_sta_disconnected_t* event = static_cast<wifi_event_sta_disconnected_t*>(event_data);
|
||
ESP_LOGI(TAG, "WiFi断开连接,原因: %d", event->reason);
|
||
|
||
// 如果不是在配网状态,不处理断开事件
|
||
if (self->state_ != BluetoothProvisioningState::PROVISIONING) {
|
||
ESP_LOGD(TAG, "非配网状态下的WiFi断开,忽略处理");
|
||
break;
|
||
}
|
||
|
||
if (s_retry_num < MAX_RETRY) {
|
||
// 立即重试连接,不等待
|
||
esp_err_t ret = esp_wifi_connect();//连接到WiFi
|
||
s_retry_num++;
|
||
ESP_LOGI(TAG, "🔄 立即重试连接WiFi (%d/%d),断开原因: %d,重试结果: %s",
|
||
s_retry_num, MAX_RETRY, event->reason,
|
||
ret == ESP_OK ? "成功" : "失败");
|
||
|
||
// 重新启动超时定时器
|
||
if (wifi_connect_timer && ret == ESP_OK) {
|
||
xTimerReset(wifi_connect_timer, 0);
|
||
}
|
||
} else {
|
||
ESP_LOGE(TAG, "❌ WiFi连接失败,已达到最大重试次数,断开原因: %d", event->reason);
|
||
|
||
// 停止超时定时器
|
||
if (wifi_connect_timer) {
|
||
xTimerStop(wifi_connect_timer, 0);
|
||
}
|
||
|
||
// 清除状态标志
|
||
self->wifi_connecting_ = false;
|
||
self->delayed_disconnect_ = false;
|
||
|
||
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
|
||
self->SetState(BluetoothProvisioningState::FAILED);
|
||
self->TriggerCallback(BluetoothProvisioningEvent::WIFI_FAILED, &event->reason);
|
||
self->ReportWiFiStatus(false, event->reason);
|
||
}
|
||
break;
|
||
}
|
||
// 新增代码
|
||
//========================================================================
|
||
case WIFI_EVENT_SCAN_DONE: {
|
||
ESP_LOGI(TAG, "📡 WiFi扫描完成,准备发送WiFi列表给手机APP");
|
||
|
||
// 获取扫描结果
|
||
uint16_t ap_count = 0;
|
||
esp_err_t ret = esp_wifi_scan_get_ap_num(&ap_count);
|
||
if (ret != ESP_OK) {
|
||
ESP_LOGE(TAG, "❌ 获取WiFi扫描结果数量失败: %s", esp_err_to_name(ret));
|
||
break;
|
||
}
|
||
|
||
ESP_LOGI(TAG, "📊 扫描到 %d 个WiFi热点", ap_count);
|
||
|
||
if (ap_count > 0) {
|
||
// 分配内存存储扫描结果
|
||
wifi_ap_record_t* ap_list = (wifi_ap_record_t*)malloc(sizeof(wifi_ap_record_t) * ap_count);
|
||
if (ap_list == nullptr) {
|
||
ESP_LOGE(TAG, "❌ 分配WiFi扫描结果内存失败");
|
||
break;
|
||
}
|
||
|
||
// 获取扫描结果详细信息
|
||
ret = esp_wifi_scan_get_ap_records(&ap_count, ap_list);
|
||
if (ret == ESP_OK) {
|
||
ESP_LOGI(TAG, "✅ 成功获取WiFi扫描结果,准备发送给手机APP");
|
||
|
||
// 打印扫描到的WiFi列表(调试用)
|
||
for (int i = 0; i < ap_count; i++) {
|
||
ESP_LOGD(TAG, "WiFi[%d]: SSID=%s, RSSI=%d, 加密=%d",
|
||
i, ap_list[i].ssid, ap_list[i].rssi, ap_list[i].authmode);
|
||
}
|
||
|
||
// 发送WiFi列表给手机APP
|
||
self->SendWiFiList(ap_list, ap_count);
|
||
ESP_LOGI(TAG, "📤 WiFi列表已发送给手机APP,包含 %d 个热点", ap_count);
|
||
} else {
|
||
ESP_LOGE(TAG, "❌ 获取WiFi扫描结果详细信息失败: %s", esp_err_to_name(ret));
|
||
}
|
||
|
||
// 释放内存
|
||
free(ap_list);
|
||
} else {
|
||
ESP_LOGW(TAG, "⚠️ 未扫描到任何WiFi热点");
|
||
// 发送空列表
|
||
self->SendWiFiList(nullptr, 0);
|
||
}
|
||
break;
|
||
}
|
||
//========================================================================
|
||
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void BluetoothProvisioning::IPEventHandler(void* arg, esp_event_base_t event_base,
|
||
int32_t event_id, void* event_data) {
|
||
BluetoothProvisioning* self = static_cast<BluetoothProvisioning*>(arg);
|
||
|
||
switch (event_id) {
|
||
case IP_EVENT_STA_GOT_IP: {
|
||
ip_event_got_ip_t* event = static_cast<ip_event_got_ip_t*>(event_data);
|
||
ESP_LOGI(TAG, "✅ WiFi获取IP地址成功: " IPSTR, IP2STR(&event->ip_info.ip));
|
||
|
||
s_retry_num = 0;
|
||
|
||
// 停止WiFi连接超时定时器
|
||
if (wifi_connect_timer) {
|
||
xTimerStop(wifi_connect_timer, 0);
|
||
xTimerDelete(wifi_connect_timer, 0);
|
||
wifi_connect_timer = nullptr;
|
||
}
|
||
|
||
// 清除状态标志
|
||
self->wifi_connecting_ = false;
|
||
self->delayed_disconnect_ = false;
|
||
|
||
// 设置WiFi连接成功标志
|
||
if (s_wifi_event_group) {
|
||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||
}
|
||
|
||
// 如果BluFi客户端已连接,发送WiFi连接成功报告
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] 检查BluFi客户端连接状态: client_connected_=%s",
|
||
self->client_connected_ ? "true" : "false");
|
||
if (self && self->client_connected_) {
|
||
// ==================================================================================
|
||
// 使用专用的可靠MAC地址发送函数(优化版本2)
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] 使用专用函数发送设备MAC地址...");
|
||
bool mac_sent = self->SendMacAddressReliably();
|
||
if (mac_sent) {
|
||
ESP_LOGI(TAG, "✅ 设备MAC地址发送成功");
|
||
} else {
|
||
ESP_LOGW(TAG, "⚠️ 设备MAC地址发送失败");
|
||
}
|
||
// ==================================================================================
|
||
|
||
// ==================================================================================
|
||
// 注释:由于只需要发送设备MAC地址,暂时注释掉WiFi连接报告相关代码
|
||
// 这样可以避免发送不必要的信息(如SSID等)
|
||
// ==================================================================================
|
||
/*
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] 准备发送WiFi连接成功报告给手机APP");
|
||
wifi_mode_t mode;
|
||
esp_wifi_get_mode(&mode);
|
||
|
||
esp_blufi_extra_info_t info;
|
||
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
|
||
|
||
// 获取当前连接的WiFi信息
|
||
wifi_ap_record_t ap_info;
|
||
if (esp_wifi_sta_get_ap_info(&ap_info) == ESP_OK) {
|
||
// memcpy(info.sta_bssid, ap_info.bssid, 6); // 发送路由器MAC地址
|
||
// info.sta_bssid_set = true; // 设置BSSID已获取
|
||
info.sta_bssid_set = false; // 明确标记不发送BSSID
|
||
|
||
info.sta_ssid = ap_info.ssid;
|
||
info.sta_ssid_len = strlen((char*)ap_info.ssid);
|
||
// ESP_LOGI(TAG, "🔍 [DEBUG] 获取到WiFi信息: SSID=%.*s",info.sta_ssid_len, info.sta_ssid);
|
||
}
|
||
|
||
// 发送WiFi连接成功报告
|
||
esp_err_t ret = esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, 0, &info);
|
||
if (ret == ESP_OK) {
|
||
ESP_LOGI(TAG, "✅ 已向手机APP发送WiFi连接成功报告");
|
||
} else {
|
||
ESP_LOGW(TAG, "⚠️ 发送WiFi连接成功报告失败: %s", esp_err_to_name(ret));
|
||
}
|
||
*/
|
||
ESP_LOGI(TAG, "🔍 [DEBUG] 已跳过WiFi连接报告发送,仅发送设备MAC地址");
|
||
} else {
|
||
ESP_LOGW(TAG, "🔍 [DEBUG] 无法发送WiFi连接成功报告: client_connected_=%s",
|
||
self->client_connected_ ? "true" : "false");
|
||
}
|
||
|
||
// 启用WiFi配置自动保存到NVS存储
|
||
ESP_LOGI(TAG, "💾 启用WiFi配置自动保存到NVS存储...");
|
||
esp_err_t storage_ret = esp_wifi_set_storage(WIFI_STORAGE_FLASH);
|
||
if (storage_ret == ESP_OK) {
|
||
ESP_LOGI(TAG, "✅ WiFi配置将自动保存到NVS存储");
|
||
} else {
|
||
ESP_LOGW(TAG, "⚠️ 设置WiFi存储模式失败: %s", esp_err_to_name(storage_ret));
|
||
}
|
||
|
||
// 手动获取当前WiFi配置并保存到NVS列表
|
||
wifi_config_t wifi_config;
|
||
esp_err_t get_config_ret = esp_wifi_get_config(WIFI_IF_STA, &wifi_config);
|
||
if (get_config_ret == ESP_OK) {
|
||
ESP_LOGI(TAG, "📋 获取当前WiFi配置成功,SSID: %s", wifi_config.sta.ssid);
|
||
auto& ssid_manager = SsidManager::GetInstance();
|
||
ssid_manager.AddSsid((const char*)wifi_config.sta.ssid, (const char*)wifi_config.sta.password);
|
||
ESP_LOGI(TAG, "✅ WiFi凭据已保存到NVS列表");
|
||
} else {
|
||
ESP_LOGW(TAG, "⚠️ 获取当前WiFi配置失败: %s", esp_err_to_name(get_config_ret));
|
||
}
|
||
vTaskDelay(pdMS_TO_TICKS(2000));// 配网成功后,设备重启,会自动连接到新的WiFi网络
|
||
ESP_LOGI(TAG, "🔄 强制重启设备...");
|
||
esp_restart();
|
||
break;
|
||
}
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|