You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ESP32双模BLE Beacon异常求助:iBeacon与Eddystone URL切换问题

问题分析与修复方案

核心问题拆解

你的问题根源在于BLE连接状态下的广播行为,以及GATT特征的权限配置——单独运行单模式时这些问题被掩盖,双模切换时才暴露出来:

  • 写入标识消失:大概率是GATT特征未正确配置WRITE权限,或是连接后BLE服务未保持可访问状态。
  • 连接后扫描设备消失:ESP32在BLE建立连接后会自动停止广播,断开连接后未重新启动广播,导致扫描不到。

具体修复步骤

1. 修复GATT特征的写入权限配置

确保接收切换指令的GATT特征同时包含ESP_GATT_CHAR_PROP_WRITE和ESP_GATT_CHAR_PROP_READ属性,且对应的描述符配置正确。示例代码片段:

// 定义GATT属性数据库
static esp_gatts_attr_db_t gatts_db[] = {
    // 主服务声明
    [IDX_SVC] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
                  sizeof(primary_service_uuid), sizeof(primary_service_uuid), (uint8_t *)&primary_service_uuid}},
    // 可写入特征声明
    [IDX_CHAR] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
                  sizeof(uint8_t), 0, NULL}},
    // 特征值存储(用于接收切换指令)
    [IDX_VAL] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
                 1, 1, (uint8_t *)&switch_mode}},
    // 客户端特征配置描述符(可选,用于模式切换通知)
    [IDX_CFG] = {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&char_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
                 sizeof(uint16_t), sizeof(uint16_t), (uint8_t *)&client_config}},
};

同时在GATT事件处理函数中,确保ESP_GATTS_CONNECT_EVT触发时,不会注销服务或修改特征属性。

2. 连接断开后自动重启广播

在BLE事件回调中监听ESP_GATTS_DISCONNECT_EVT事件,一旦断开连接,立即重启当前模式的广播。示例代码:

static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
    switch (event) {
        // ...其他事件处理逻辑
        case ESP_GATTS_DISCONNECT_EVT:
            // 断开连接后重启对应模式的广播
            if (current_mode == MODE_IBEACON) {
                esp_ble_beacon_config_t ibeacon_config = {
                    .uuid = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef},
                    .major = 0x0001,
                    .minor = 0x0001,
                    .measured_power = 0xc5
                };
                esp_ble_config_ibeacon_data(&ibeacon_config);
                esp_ble_gap_start_advertising(&adv_params);
            } else if (current_mode == MODE_EDDYSTONE) {
                esp_ble_eddystone_url_config_t eddystone_config = {
                    .url = "https://your-target-url.com",
                    .tx_power = 0
                };
                esp_ble_config_eddystone_data(ESP_BLE_EDDYSTONE_FRAME_TYPE_URL, &eddystone_config);
                esp_ble_gap_start_advertising(&adv_params);
            }
            break;
        // ...其他事件处理逻辑
    }
}

注意:adv_params需提前配置完成,确保广播参数在两种模式下都能正常使用(比如选择ADV_TYPE_CONN_IND类型,支持设备连接)。

3. 优化模式切换时的广播逻辑

接收到切换指令后,先停止当前广播,再配置新的Beacon数据,最后启动新广播。示例代码:

// 处理GATT特征写入事件
case ESP_GATTS_WRITE_EVT:
    if (param->write.handle == gatts_table[IDX_VAL].attr_handle) {
        uint8_t new_mode = param->write.value[0];
        // 切换到Eddystone URL模式
        if (new_mode == 1 && current_mode != MODE_EDDYSTONE) {
            esp_ble_gap_stop_advertising();
            current_mode = MODE_EDDYSTONE;
            esp_ble_eddystone_url_config_t eddystone_config = {
                .url = "https://your-target-url.com",
                .tx_power = 0
            };
            esp_ble_config_eddystone_data(ESP_BLE_EDDYSTONE_FRAME_TYPE_URL, &eddystone_config);
            esp_ble_gap_start_advertising(&adv_params);
        }
        // 切换回iBeacon模式
        else if (new_mode == 0 && current_mode != MODE_IBEACON) {
            esp_ble_gap_stop_advertising();
            current_mode = MODE_IBEACON;
            esp_ble_beacon_config_t ibeacon_config = {
                .uuid = {0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef},
                .major = 0x0001,
                .minor = 0x0001,
                .measured_power = 0xc5
            };
            esp_ble_config_ibeacon_data(&ibeacon_config);
            esp_ble_gap_start_advertising(&adv_params);
        }
    }
    break;

4. 验证广播参数配置

确保广播参数adv_params支持连接需求,示例配置:

esp_ble_adv_params_t adv_params = {
    .adv_int_min        = 0x20,
    .adv_int_max        = 0x40,
    .adv_type           = ADV_TYPE_CONN_IND, // 必须选支持连接的广播类型
    .own_addr_type      = BLE_ADDR_TYPE_PUBLIC,
    .channel_map        = ADV_CHNL_ALL,
    .adv_filter_policy  = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};

若使用ADV_TYPE_NONCONN_IND,设备无法被连接,会导致NRF Connect无法写入指令。

额外注意事项

  • 确认ESP32的BLE栈初始化无重复或资源泄漏问题。
  • 测试时,切换模式后断开连接,检查是否能重新扫描到设备。
  • NRF Connect写入指令时,确保数据格式正确(比如写入1字节的0或1来切换模式)。

内容的提问来源于stack exchange,提问作者moaz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:35:26