From d7ec6a5e63b14b5bfd2d50555c82b8506e67a388 Mon Sep 17 00:00:00 2001 From: Rdzleo Date: Tue, 10 Feb 2026 16:16:28 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=8F=96=E6=B6=88=E4=BA=86=E8=93=9D?= =?UTF-8?q?=E7=89=99=E8=BF=9E=E6=8E=A5=E6=88=90=E5=8A=9F=E5=90=8E=E5=8F=91?= =?UTF-8?q?=E9=80=81=E8=93=9D=E7=89=99MAC=E5=9C=B0=E5=9D=80=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91=EF=BC=9B=202=E3=80=81=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=BA=86=E8=93=9D=E7=89=99=E5=90=8D=E7=A7=B0=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E4=B8=BA=E2=80=9CAirhub=5F=E2=80=9D=E6=8E=A5=E8=93=9D=E7=89=99?= =?UTF-8?q?MAC=E5=9C=B0=E5=9D=80=E7=9A=84=E6=98=8E=E6=96=87=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=EF=BC=9B=203=E3=80=81=E5=8F=96=E6=B6=88SDK=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E8=93=9D=E7=89=99=E5=90=8D=E7=A7=B0=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/Kconfig.projbuild | 8 -- main/bluetooth_provisioning.cc | 133 +++++++++++-------------- main/bluetooth_provisioning.h | 7 +- main/bluetooth_provisioning_example.cc | 5 +- main/boards/common/wifi_board.cc | 32 +++--- 5 files changed, 74 insertions(+), 111 deletions(-) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 20e58c5..6691b5a 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -346,14 +346,6 @@ menu "蓝牙配网 (Bluetooth Provisioning)" 启用蓝牙配网功能,允许通过蓝牙BLE连接配置WiFi网络。 需要ESP-IDF的蓝牙和BLUFI组件支持。 - config BLUETOOTH_PROVISIONING_DEVICE_NAME - string "默认设备名称" - depends on BLUETOOTH_PROVISIONING_ENABLE - default "Airhub_Ble" - help - 蓝牙配网时显示的默认设备名称。 - 可以在运行时通过API修改。 - config BLUETOOTH_PROVISIONING_SECURITY bool "启用安全模式" depends on BLUETOOTH_PROVISIONING_ENABLE diff --git a/main/bluetooth_provisioning.cc b/main/bluetooth_provisioning.cc index 92c5835..9cdc542 100644 --- a/main/bluetooth_provisioning.cc +++ b/main/bluetooth_provisioning.cc @@ -122,6 +122,10 @@ static esp_ble_adv_params_t prov_adv_params = { static uint8_t prov_adv_raw_data[31]; static uint8_t prov_adv_raw_len = 0; +// 扫描响应数据 (携带 TX Power + BLE MAC 地址) +static uint8_t prov_scan_rsp_data[31]; +static uint8_t prov_scan_rsp_len = 0; + // ============================================================ // 构造 / 析构 // ============================================================ @@ -133,8 +137,7 @@ BluetoothProvisioning::BluetoothProvisioning() , initialized_(false) , delayed_disconnect_(false) , wifi_connecting_(false) - , mac_address_sent_(false) - , ble_mac_sent_(false) { + , mac_address_sent_(false) { wifi_credentials_.ssid.clear(); wifi_credentials_.password.clear(); @@ -351,7 +354,7 @@ bool BluetoothProvisioning::Deinitialize() { // StartProvisioning — 构建原始广播数据并启动广播 // ============================================================ -bool BluetoothProvisioning::StartProvisioning(const char* device_name) { +bool BluetoothProvisioning::StartProvisioning() { ESP_LOGI(TAG, "🔵 开始启动蓝牙配网服务 (GATT Server)..."); ESP_LOGI(TAG, "🔍 检查初始化状态: initialized_ = %s", initialized_ ? "true" : "false"); @@ -367,8 +370,6 @@ bool BluetoothProvisioning::StartProvisioning(const char* device_name) { return true; } - ESP_LOGI(TAG, "🚀 开始蓝牙配网,设备名称: %s", device_name); - // 重置状态 client_connected_ = false; s_retry_num = 0; @@ -389,15 +390,30 @@ bool BluetoothProvisioning::StartProvisioning(const char* device_name) { wifi_credentials_.bssid_set = false; ESP_LOGI(TAG, "✅ WiFi凭据清除完成,准备接收新的配网信息"); + // 构建设备名称: "Airhub_" + BLE MAC 明文 + char ble_device_name[32]; + const uint8_t* ble_addr = esp_bt_dev_get_address(); + if (ble_addr) { + snprintf(ble_device_name, sizeof(ble_device_name), + "Airhub_%02x:%02x:%02x:%02x:%02x:%02x", + ble_addr[0], ble_addr[1], ble_addr[2], + ble_addr[3], ble_addr[4], ble_addr[5]); + } else { + strcpy(ble_device_name, "Airhub_Ble"); + ESP_LOGW(TAG, "获取BLE MAC失败,使用默认名称: %s", ble_device_name); + } + // 设置设备名称 - esp_err_t ret = esp_ble_gap_set_device_name(device_name); + esp_err_t ret = esp_ble_gap_set_device_name(ble_device_name); if (ret != ESP_OK) { ESP_LOGE(TAG, "❌ 设置蓝牙设备名称失败: %s", esp_err_to_name(ret)); return false; } - // 构建原始广播数据 (dzbj 方式: 直接放入设备名,手机系统蓝牙可搜索) - uint8_t name_len = strlen(device_name); + ESP_LOGI(TAG, "📡 蓝牙设备名称: %s", ble_device_name); + + // 构建广播数据 (Flags + 设备名) + uint8_t name_len = strlen(ble_device_name); int offset = 0; // Flags: LE General Discoverable + BR/EDR Not Supported @@ -408,28 +424,35 @@ bool BluetoothProvisioning::StartProvisioning(const char* device_name) { // Complete Local Name prov_adv_raw_data[offset++] = name_len + 1; prov_adv_raw_data[offset++] = ESP_BLE_AD_TYPE_NAME_CMPL; - memcpy(&prov_adv_raw_data[offset], device_name, name_len); + memcpy(&prov_adv_raw_data[offset], ble_device_name, name_len); offset += name_len; - // TX Power Level - prov_adv_raw_data[offset++] = 0x02; - prov_adv_raw_data[offset++] = ESP_BLE_AD_TYPE_TX_PWR; - prov_adv_raw_data[offset++] = 0x09; - - // 16-bit Service UUID Complete - prov_adv_raw_data[offset++] = 0x03; - prov_adv_raw_data[offset++] = ESP_BLE_AD_TYPE_16SRV_CMPL; - prov_adv_raw_data[offset++] = PROV_SERVICE_UUID & 0xFF; - prov_adv_raw_data[offset++] = (PROV_SERVICE_UUID >> 8) & 0xFF; - prov_adv_raw_len = offset; - ESP_LOGI(TAG, "📡 原始广播数据构建完成,长度: %d 字节", prov_adv_raw_len); + ESP_LOGI(TAG, "📡 广播数据构建完成,长度: %d 字节", prov_adv_raw_len); - // 配置原始广播数据 (GAP回调中会启动广播) + // 构建扫描响应数据 (TX Power + Service UUID) + int rsp_offset = 0; + + // TX Power Level + prov_scan_rsp_data[rsp_offset++] = 0x02; + prov_scan_rsp_data[rsp_offset++] = ESP_BLE_AD_TYPE_TX_PWR; + prov_scan_rsp_data[rsp_offset++] = 0x09; + + // 16-bit Service UUID Complete + prov_scan_rsp_data[rsp_offset++] = 0x03; + prov_scan_rsp_data[rsp_offset++] = ESP_BLE_AD_TYPE_16SRV_CMPL; + prov_scan_rsp_data[rsp_offset++] = PROV_SERVICE_UUID & 0xFF; + prov_scan_rsp_data[rsp_offset++] = (PROV_SERVICE_UUID >> 8) & 0xFF; + + prov_scan_rsp_len = rsp_offset; + + ESP_LOGI(TAG, "📡 扫描响应数据构建完成,长度: %d 字节", prov_scan_rsp_len); + + // 配置广播数据 (GAP回调中会依次设置扫描响应数据并启动广播) ret = esp_ble_gap_config_adv_data_raw(prov_adv_raw_data, prov_adv_raw_len); if (ret != ESP_OK) { - ESP_LOGE(TAG, "❌ 配置原始广播数据失败: %s", esp_err_to_name(ret)); + ESP_LOGE(TAG, "❌ 配置广播数据失败: %s", esp_err_to_name(ret)); return false; } @@ -484,8 +507,18 @@ void BluetoothProvisioning::GapEventHandler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t* param) { switch (event) { case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: - // 原始广播数据设置完成,启动广播 (dzbj 方式) - ESP_LOGI(TAG, "📡 广播数据设置完成,启动广播"); + // 广播数据设置完成,接着配置扫描响应数据 + ESP_LOGI(TAG, "📡 广播数据设置完成,配置扫描响应数据"); + if (prov_scan_rsp_len > 0) { + esp_ble_gap_config_scan_rsp_data_raw(prov_scan_rsp_data, prov_scan_rsp_len); + } else { + esp_ble_gap_start_advertising(&prov_adv_params); + } + break; + + case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: + // 扫描响应数据设置完成,启动广播 + ESP_LOGI(TAG, "📡 扫描响应数据设置完成,启动广播"); esp_ble_gap_start_advertising(&prov_adv_params); break; @@ -714,11 +747,6 @@ void BluetoothProvisioning::HandleGattsEvent(esp_gatts_cb_event_t event, uint16_t cccd_value = param->write.value[0] | (param->write.value[1] << 8); notify_enabled_ = (cccd_value == 0x0001); ESP_LOGI(TAG, "NOTIFY %s", notify_enabled_ ? "已启用" : "已禁用"); - - // NOTIFY启用后立即发送BLE MAC地址,确保iOS/Android都能获取 - if (notify_enabled_) { - SendBleMacAddress(); - } } if (param->write.need_rsp) { @@ -1098,54 +1126,9 @@ bool BluetoothProvisioning::SendMacAddressReliably() { void BluetoothProvisioning::ResetMacSendingState() { mac_address_sent_ = false; - ble_mac_sent_ = false; ESP_LOGI(TAG, "MAC地址发送状态已重置"); } -// ============================================================ -// SendBleMacAddress — 通过 GATT NOTIFY 发送蓝牙MAC地址 -// 在客户端启用NOTIFY后立即调用,确保iOS/Android都能获取BLE MAC -// ============================================================ - -bool BluetoothProvisioning::SendBleMacAddress() { - if (!client_connected_ || !notify_enabled_) { - ESP_LOGW(TAG, "无法发送BLE MAC: connected=%d, notify=%d", - client_connected_, notify_enabled_); - return false; - } - - if (ble_mac_sent_) { - ESP_LOGI(TAG, "BLE MAC已发送过,跳过"); - return true; - } - - const uint8_t* ble_addr = esp_bt_dev_get_address(); - if (!ble_addr) { - ESP_LOGE(TAG, "获取BLE MAC地址失败"); - return false; - } - - // 构建数据包: 0x84 + "BLE_MAC:xx:xx:xx:xx:xx:xx" - char mac_data[32]; - snprintf(mac_data, sizeof(mac_data), "BLE_MAC:%02x:%02x:%02x:%02x:%02x:%02x", - ble_addr[0], ble_addr[1], ble_addr[2], - ble_addr[3], ble_addr[4], ble_addr[5]); - - uint8_t buf[1 + 32]; - buf[0] = PROV_RESP_CUSTOM_DATA; - uint8_t data_len = strlen(mac_data); - memcpy(&buf[1], mac_data, data_len); - - if (SendNotify(buf, 1 + data_len)) { - ble_mac_sent_ = true; - ESP_LOGI(TAG, "✅ BLE MAC地址发送成功: %s", mac_data); - return true; - } - - ESP_LOGW(TAG, "❌ BLE MAC地址发送失败"); - return false; -} - // ============================================================ // 状态管理 // ============================================================ diff --git a/main/bluetooth_provisioning.h b/main/bluetooth_provisioning.h index 9e1ad38..41ad231 100644 --- a/main/bluetooth_provisioning.h +++ b/main/bluetooth_provisioning.h @@ -12,9 +12,6 @@ #include #include -// 蓝牙设备名称 广播名称 宏定义,自动引用SDK配置,可打开SDK修改蓝牙名称 -#define BLU_NAME CONFIG_BLUETOOTH_PROVISIONING_DEVICE_NAME - // 使用条件编译避免IDE环境中的头文件错误 #ifdef ESP_PLATFORM #include "esp_gap_ble_api.h" @@ -114,7 +111,7 @@ public: bool Initialize(); bool Deinitialize(); - bool StartProvisioning(const char* device_name = BLU_NAME); + bool StartProvisioning(); bool StopProvisioning(); BluetoothProvisioningState GetState() const { return state_; } @@ -126,7 +123,6 @@ public: void ReportWiFiStatus(bool success, uint8_t reason = 0); void SendWiFiList(const wifi_ap_record_t* ap_list, uint16_t ap_count); bool SendMacAddressReliably(); - bool SendBleMacAddress(); void ResetMacSendingState(); private: @@ -138,7 +134,6 @@ private: bool delayed_disconnect_; bool wifi_connecting_; bool mac_address_sent_; - bool ble_mac_sent_; static BluetoothProvisioning* instance_; diff --git a/main/bluetooth_provisioning_example.cc b/main/bluetooth_provisioning_example.cc index 1a07fe6..d83c8d8 100644 --- a/main/bluetooth_provisioning_example.cc +++ b/main/bluetooth_provisioning_example.cc @@ -157,9 +157,8 @@ void bluetooth_provisioning_task(void* pvParameters) { return; } - // 4. 启动配网服务 - const char* device_name = BLU_NAME; - if (!g_bt_provisioning->StartProvisioning(device_name)) { + // 4. 启动配网服务 (设备名自动构建: Airhub_ + BLE MAC) + if (!g_bt_provisioning->StartProvisioning()) { ESP_LOGE(TAG, "蓝牙配网启动失败"); g_bt_provisioning->Deinitialize(); delete g_bt_provisioning; diff --git a/main/boards/common/wifi_board.cc b/main/boards/common/wifi_board.cc index 0a13e18..5054a84 100644 --- a/main/boards/common/wifi_board.cc +++ b/main/boards/common/wifi_board.cc @@ -370,15 +370,13 @@ bool WifiBoard::StartBleProvisioning() { OnBleProvisioningEvent(event, data); }); - // 使用设备名称启动BLE配网服务(2.设备发现,设备名称 Airhub777) - std::string device_name = BLU_NAME; - // 蓝牙配网服务启动失败,StartProvisioning为蓝牙服务启动函数 - if (!bluetooth_provisioning_.StartProvisioning(device_name.c_str())) { + // 启动BLE配网服务(设备名称由 StartProvisioning 内部构建: Airhub_ + BLE MAC) + if (!bluetooth_provisioning_.StartProvisioning()) { ESP_LOGE(TAG, "❌ BLE蓝牙配网启动失败"); return false; } - ESP_LOGI(TAG, "✅ BLE蓝牙配网启动成功,设备名称: %s", device_name.c_str()); + ESP_LOGI(TAG, "✅ BLE蓝牙配网启动成功"); ESP_LOGI(TAG, "📱 请使用支持BLE的手机APP连接设备进行配网"); ble_provisioning_active_ = true; // 标记BLE配网服务已激活 @@ -388,18 +386,16 @@ bool WifiBoard::StartBleProvisioning() { // 显示BLE配网通知 auto display = GetDisplay(); if (display) { - std::string notification = "BLE配网模式\n设备名: " + device_name; - display->ShowNotification(notification.c_str(), 30000); + display->ShowNotification("BLE配网模式", 30000); } - // Play BLE provisioning sound + // 播放配网提示音 auto& application = Application::GetInstance(); - // application.Alert("BLE配网模式", ("请使用手机APP连接设备: " + device_name).c_str(), "", Lang::Sounds::P3_WIFICONFIG); 原有蜡笔小新音色 if(strcmp(CONFIG_DEVICE_ROLE, "KAKA") == 0){ - application.Alert("BLE配网模式", ("请使用手机APP连接设备: " + device_name).c_str(), "", Lang::Sounds::P3_KAKA_WIFICONFIG); + application.Alert("BLE配网模式", "请使用手机APP搜索Airhub_开头的蓝牙设备", "", Lang::Sounds::P3_KAKA_WIFICONFIG); } else if(strcmp(CONFIG_DEVICE_ROLE, "RTC_Test") == 0){ - application.Alert("BLE配网模式", ("请使用手机APP连接设备: " + device_name).c_str(), "", Lang::Sounds::P3_LALA_WIFICONFIG); + application.Alert("BLE配网模式", "请使用手机APP搜索Airhub_开头的蓝牙设备", "", Lang::Sounds::P3_LALA_WIFICONFIG); } @@ -433,14 +429,13 @@ bool WifiBoard::StartBleJsonProvisioning() { Application::GetInstance().HandleBleJsonCommand(cmd, msg_id, data, ble_json_service_); }); - // 使用与 BLE 相同的设备名启动 - std::string device_name = BLU_NAME; - if (!ble_json_service_.Start(device_name.c_str())) { + // 启动 BLE JSON 服务 + if (!ble_json_service_.Start("Airhub_Ble")) { ESP_LOGE(TAG, "❌ BLE JSON服务启动失败"); return false; } - ESP_LOGI(TAG, "✅ BLE JSON配网启动成功,设备名称: %s", device_name.c_str()); + ESP_LOGI(TAG, "✅ BLE JSON配网启动成功"); ble_provisioning_active_ = true; ble_start_time_ = xTaskGetTickCount(); @@ -448,16 +443,15 @@ bool WifiBoard::StartBleJsonProvisioning() { // 显示配网通知 auto display = GetDisplay(); if (display) { - std::string notification = "BLE配网模式\n设备名: " + device_name; - display->ShowNotification(notification.c_str(), 30000); + display->ShowNotification("BLE配网模式", 30000); } // 播放配网提示音 auto& application = Application::GetInstance(); if (strcmp(CONFIG_DEVICE_ROLE, "KAKA") == 0) { - application.Alert("BLE配网模式", ("请使用手机APP连接设备: " + device_name).c_str(), "", Lang::Sounds::P3_KAKA_WIFICONFIG); + application.Alert("BLE配网模式", "请使用手机APP搜索Airhub_开头的蓝牙设备", "", Lang::Sounds::P3_KAKA_WIFICONFIG); } else if (strcmp(CONFIG_DEVICE_ROLE, "RTC_Test") == 0) { - application.Alert("BLE配网模式", ("请使用手机APP连接设备: " + device_name).c_str(), "", Lang::Sounds::P3_LALA_WIFICONFIG); + application.Alert("BLE配网模式", "请使用手机APP搜索Airhub_开头的蓝牙设备", "", Lang::Sounds::P3_LALA_WIFICONFIG); } // 配网状态等待循环