/** * @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 #include "nvs_flash.h" #include "nvs.h" #include /// 日志标签,用于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初始化完成"); ESP_LOGI(TAG, "初始化蓝牙控制器..."); esp_bt_controller_status_t ctl_status = esp_bt_controller_get_status(); #if CONFIG_IDF_TARGET_ESP32 ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT)); #else esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT); #endif if (ctl_status == ESP_BT_CONTROLLER_STATUS_ENABLED) { esp_bt_controller_disable(); ctl_status = esp_bt_controller_get_status(); } if (ctl_status == ESP_BT_CONTROLLER_STATUS_INITED) { esp_bt_controller_deinit(); } esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); ret = esp_bt_controller_init(&bt_cfg); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "蓝牙控制器初始化失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "蓝牙控制器启用失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ESP_LOGI(TAG, "初始化Bluedroid协议栈..."); auto bd_status = esp_bluedroid_get_status(); if (bd_status == ESP_BLUEDROID_STATUS_ENABLED) { esp_bluedroid_disable(); bd_status = esp_bluedroid_get_status(); } if (bd_status == ESP_BLUEDROID_STATUS_INITIALIZED) { esp_bluedroid_deinit(); } ret = esp_bluedroid_init(); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "Bluedroid初始化失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::FAILED); return false; } ret = esp_bluedroid_enable(); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { 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; } ret = esp_blufi_profile_init(); if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { ESP_LOGE(TAG, "BLUFI配置文件初始化失败: %s", esp_err_to_name(ret)); SetState(BluetoothProvisioningState::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; } for (uint16_t i = 0; i < ap_count; 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)); } ESP_LOGI(TAG, "向客户端发送WiFi列表,共%d个AP", ap_count); esp_blufi_send_wifi_list(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(old_state)], state_names[static_cast(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(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(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(param->sta_ssid.ssid), param->sta_ssid.ssid_len);//保存Wi-Fi的 SSID // 设置WiFi配置 { wifi_config_t wifi_config = {}; strncpy(reinterpret_cast(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(param->sta_passwd.passwd), param->sta_passwd.passwd_len);// 保存WI-FI密码凭证 // 设置WiFi配置 { wifi_config_t wifi_config = {}; strncpy(reinterpret_cast(wifi_config.sta.ssid), instance_->wifi_credentials_.ssid.c_str(), sizeof(wifi_config.sta.ssid) - 1); strncpy(reinterpret_cast(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(wifi_config.sta.ssid), instance_->wifi_credentials_.ssid.c_str(), sizeof(wifi_config.sta.ssid) - 1);// 复制SSID到配置 strncpy(reinterpret_cast(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(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(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(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(arg); switch (event_id) { case IP_EVENT_STA_GOT_IP: { ip_event_got_ip_t* event = static_cast(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);// 设置WiFi存储模式为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;// 定义WiFi配置结构体 esp_err_t get_config_ret = esp_wifi_get_config(WIFI_IF_STA, &wifi_config);// 获取当前WiFi配置 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)); } auto& application = Application::GetInstance(); bool skip_session = application.ShouldSkipDialogIdleSession();// 是否跳过对话待机会话 ESP_LOGI(TAG, "BluetoothProvisioning WIFI_CONNECTED skip_session=%d", (int)skip_session); if (!skip_session) { if(strcmp(CONFIG_DEVICE_ROLE, "KAKA") == 0){ application.PlaySound(Lang::Sounds::P3_KAKA_LIANJIEWANGLUO); } else if(strcmp(CONFIG_DEVICE_ROLE, "RTC_Test") == 0){ application.PlaySound(Lang::Sounds::P3_LALA_LIANJIEWANGLUO); } } else { application.ClearDialogIdleSkipSession();// 清除对话待机会话标志位 } // 更新状态和触发回调 ESP_LOGI(TAG, "🔍 准备设置状态为SUCCESS并触发回调"); self->SetState(BluetoothProvisioningState::SUCCESS); self->TriggerCallback(BluetoothProvisioningEvent::WIFI_CONNECTED, &event->ip_info.ip); self->ReportWiFiStatus(true, 0); ESP_LOGI(TAG, "📋 配网流程完成,状态: %s, client_connected_: %s", self->GetStateString().c_str(), self->client_connected_ ? "true" : "false"); // 延迟2000ms后强制重启设备 ESP_LOGI(TAG, "⏰ 延迟2000ms后重启设备以确保配置生效..."); vTaskDelay(pdMS_TO_TICKS(2000));// 配网成功后,设备重启,会自动连接到新的WiFi网络 ESP_LOGI(TAG, "🔄 强制重启设备..."); esp_restart(); break; } default: break; } }