打印

多台 ESP32 BLE 设备使用相同的 UUID(服务+特征),但不同设备名称(bleName)时是否相互干扰

[复制链接]
1311|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
keer_zu|  楼主 | 2025-6-4 16:24 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

答案是 会干扰,因为 BLE 的发现和连接机制不仅依赖设备名,还依赖广播数据和服务 UUID。以下是详细分析和解决方案:


1. 问题原因分析

(1) 相同 UUID 的冲突

  • 所有设备广播相同的 SERVICE_UUID: 当 Python 端扫描设备时,会看到多个设备都广播 00001101-0000-1000-8000-00805F9B34FB,客户端可能无法区分它们,导致随机连接或连接失败。
  • 特征 UUID 也相同: 即使连接成功,如果 Python 端同时尝试读写多台设备,数据可能发送到错误的设备(因为特征 UUID 完全一致)。

(2) 设备名称(bleName)的作用有限

  • bleName 仅在扫描时显示,但 BLE 连接实际依赖的是设备的 MAC 地址和广播数据
  • 如果 Python 端未明确绑定目标设备的 MAC 地址,可能会错误地连接到同名设备(尤其在广播缓存干扰时)。

(3) 经典蓝牙 vs. BLE 的区别

  • 你使用的 UUID 00001101-...经典蓝牙 SPP 的标准 UUID,但在 BLE 模式下,它只是一个普通 UUID,没有特殊作用。
  • 经典蓝牙 SPP 的 UUID 不能直接用于 BLE,因为两者的协议栈完全不同。

2. 解决方案

(1) 为每台设备生成唯一的服务 UUID

修改代码,让每台设备使用 不同的服务 UUID(特征 UUID 可以相同):

// 设备1
#define SERVICE_UUID "00001101-0000-1000-8000-00805F9B34F1" 

// 设备2
#define SERVICE_UUID "00001101-0000-1000-8000-00805F9B34F2"

// 设备3
#define SERVICE_UUID "00001101-0000-1000-8000-00805F9B34F3"

优点

  • Python 端可以明确选择连接特定设备(通过不同的 SERVICE_UUID)。
  • 完全避免 UUID 冲突。

(2) 动态生成 UUID(推荐)

在设备启动时,基于 MAC 地址生成唯一 UUID:

#include "BLEAddress.h"

String generateUniqueUUID() {
  String mac = BLEDevice::getAddress().toString().c_str();
  mac.replace(":", "");
  return "0000" + mac.substring(0, 4) + "-0000-1000-8000-00805F9B34FB";
}

// 在 setup() 中:
String SERVICE_UUID = generateUniqueUUID();

优点

  • 完全自动化,无需手动配置。
  • 保证每台设备的 UUID 唯一。

(3) Python 端明确指定目标设备

在 Python 代码中,先扫描设备,再通过 设备名或 MAC 地址 过滤目标设备:

import asyncio
from bleak import BleakScanner, BleakClient

async def connect_to_device(device_name):
    devices = await BleakScanner.discover()
    for d in devices:
        if d.name == device_name:
            client = BleakClient(d.address)
            await client.connect()
            return client
    raise Exception("Device not found")

# 使用示例
client = await connect_to_device("ESP32_Device1")

优点

  • 直接绑定物理设备,避免 UUID 冲突问题。

(4) 避免使用经典蓝牙的 SPP UUID

如果确实需要 BLE 通信,建议使用 随机生成的 UUID,而非经典蓝牙的固定 UUID。例如:

// 随机生成(符合 UUID v4 规范)
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" 
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"

(注:这是 Nordic UART Service 的 UUID,常用于 BLE 串口透传)


3. 现场问题排查步骤

如果多台设备仍然异常,按以下步骤检查:

  1. 确认 Python 端是否正确过滤设备
    • 打印扫描到的所有设备,检查 bleName 和 MAC 地址是否唯一。
  2. 检查 ESP32 的广播数据
    • 确保 pAdvertising->addServiceUUID(SERVICE_UUID) 使用的是动态 UUID。
  3. 验证单设备连接稳定性
    • 如果单台设备偶尔断开,可能是电源或信号干扰问题。
  4. 监听 BLE 广播包
    • 使用手机 App(如 nRF Connect)扫描,确认每台设备的 UUID 和名称是否唯一。

4. 总结

问题根源 解决方案
所有设备 UUID 相同 为每台设备生成不同的服务 UUID
Python 端未绑定具体设备 通过设备名或 MAC 地址过滤
使用经典蓝牙 UUID 于 BLE 改用随机生成的 BLE UUID
广播冲突 动态生成 UUID(基于 MAC 地址)

最终建议

  • 优先使用动态 UUID 生成(方案 2),确保唯一性。
  • Python 端严格绑定设备 MAC 地址(方案 3),避免误连接。
  • 如果仍有问题,提供具体的错误日志(如连接超时、数据错乱等),可以进一步分析。

使用特权

评论回复

相关帖子

沙发
keer_zu|  楼主 | 2025-6-4 18:41 | 只看该作者
代码:
#include "protocol.h"

// 全局变量
BLEServer* pServer = nullptr;
BLECharacteristic* pRxCharacteristic = nullptr;
String receivedData;
message_para_t g_message_para;
int g_current_score = 0;

// 回调类实现
class MyServerCallbacks : public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) override {
        Serial.println("设备已连接");
    }

    void onDisconnect(BLEServer* pServer) override {
        Serial.println("设备已断开");
        BLEDevice::startAdvertising();
        Serial.println("重新开始广播...");
    }
};

class RxCharacteristicCallbacks : public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic* pCharacteristic) override {
        String rxValue = pCharacteristic->getValue().c_str(); // 修正类型转换
        if (rxValue.length() > 0) {
            receivedData += rxValue;
            Serial.print("收到数据: ");
            Serial.println(rxValue);
        }
    }
};

void processReceivedData(String data) {
    data.trim();
   
    // 使用ArduinoJson解析
    StaticJsonDocument<256> doc; // 改用StaticJsonDocument避免动态内存分配
    DeserializationError error = deserializeJson(doc, data);
   
    if (error) {
        Serial.print("JSON解析错误: ");
        Serial.println(error.c_str());
        return;
    }

    // 提取数据
    const char* status = doc["status"];
    int score = doc["score"];

    // 验证数据
    if (status == nullptr || score < 0 || score > 10) {
        Serial.println("无效数据");
        return;
    }

    // 状态处理
    if (g_message_para.status != status) {
        g_message_para.status = status;
        
        if (strcmp(status, "start") == 0) {
            Serial.println("疗愈开始");
            stopAllEffects();
            startFastChase();
        }
        else if (strcmp(status, "listening") == 0) {
            stopAllEffects();
            startClockwiseChase();
        }
        else if (strcmp(status, "thinking") == 0) {
            stopAllEffects();
            startFastBreathing();
        }
        else if (strcmp(status, "speaking") == 0) {
            stopAllEffects();
            startAnticlockwiseChase();
        }
        else if (strcmp(status, "stop") == 0) {
            Serial.println("疗愈停止");
            stopAllEffects();
            startSlowBreathing();
        }
    }

    // 评分处理
    if (g_message_para.score != score) {
        g_message_para.score = score;
        on_new_score();
    }

    Serial.printf("状态更新: %s, 评分: %d\n", status, score);
}

void blue_setup() {
    Serial.begin(115200);
   
    // 生成设备SN
    uint64_t chipid = ESP.getEfuseMac();
    char sn[5];
    snprintf(sn, sizeof(sn), "%04X", (uint16_t)(chipid >> 32));
    Serial.printf("设备SN: %s\n", sn);

    // 生成UUID
    char service_uuid[37];
    char characteristic_uuid[37];
    snprintf(service_uuid, sizeof(service_uuid), "6E400001-B5A3-F393-E0A9-E50E24DC%s", sn);
    snprintf(characteristic_uuid, sizeof(characteristic_uuid), "6E400002-B5A3-F393-E0A9-E50E24DC%s", sn);

    // 初始化BLE
    BLEDevice::init(String("BW-LED-") + sn);
    pServer = BLEDevice::createServer();
    pServer->setCallbacks(new MyServerCallbacks());

    // 创建服务
    BLEService* pService = pServer->createService(service_uuid);

    // 创建特征
    pRxCharacteristic = pService->createCharacteristic(
        characteristic_uuid,
        BLECharacteristic::PROPERTY_WRITE
    );
    pRxCharacteristic->setCallbacks(new RxCharacteristicCallbacks());

    // 启动服务
    pService->start();

    // 开始广播
    BLEAdvertising* pAdvertising = BLEDevice::getAdvertising();
    pAdvertising->addServiceUUID(service_uuid);
    pAdvertising->setScanResponse(true);
    BLEDevice::startAdvertising();

    Serial.println("BLE初始化完成");
    Serial.printf("服务UUID: %s\n", service_uuid);
    Serial.printf("特征UUID: %s\n", characteristic_uuid);
}

void data_process() {
    if (receivedData.length() > 0 && receivedData.endsWith("\r\n")) {
        processReceivedData(receivedData);
        receivedData = "";
    }
}

void update_outer_ring() {
    if (g_message_para.status == "start") {
        updateFastChase();
    }
    else if (g_message_para.status == "listening") {
        updateClockwiseChase();
    }
    else if (g_message_para.status == "thinking") {
        updateFastBreathing();
    }
    else if (g_message_para.status == "speaking") {
        updateAnticlockwiseChase();
    }
    else if (g_message_para.status == "stop") {
        updateSlowBreathing();
    }
}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:qq群:49734243 Email:zukeqiang@gmail.com

1464

主题

12866

帖子

53

粉丝