Puck.js使用nobleJs获取BLE广播数据异常问题排查
问题根因
- 核心概念混淆:你混淆了BLE广播和GATT连接通信两种模式。你在Puck.js端调用
NRF.setAdvertising仅配置了无连接的广播报文,没有实现GATT服务端的温度服务/特征值逻辑,也没有在连接后主动推送温度数据。你连接设备后发现的6e400001开头的服务是Puck.js默认的Nordic UART串口服务,和你配置在广播里的0x1809温度服务无关,给串口特征开启notify后收到的Data <- Serial1就是串口默认输出,自然拿不到温度值。 - 逻辑流程错误:你需要的周期性温度数据本身就在广播报文中,完全不需要停止扫描、建立GATT连接,你当前的流程主动中断了扫描流程,自然无法收到每秒更新的广播数据。另外noble默认扫描模式下同一个设备仅上报一次discover事件,即使不停止扫描也拿不到后续更新的广播内容。
修复方案
优先选择无连接广播接收方案,和你现有Puck.js端代码完全匹配,功耗更低实现更简单:
- 调整noble接收端逻辑:
- 启动扫描时开启重复上报,允许同一个设备的多次广播触发discover事件
- 移除停止扫描、连接设备、发现服务特征、开启notify的冗余逻辑
- 直接在discover事件回调中从广播报文里解析温度值和厂商数据
修正后的接收端代码:
import noble from "@abandonware/noble"; noble.on("stateChange", async (state) => { if (state === "poweredOn") { // 第二个参数传true允许重复广播上报,才能拿到每秒更新的数据 await noble.startScanningAsync([], true); } }); noble.on("discover", async (peripheral) => { if (peripheral.id !== "7515300cdefc6fee0cf2d840f8e4a9cf") { return; } // 解析厂商数据 const manufacturerData = peripheral.advertisement.manufacturerData; console.log("厂商数据:", manufacturerData.slice(2).toString()); // 前2字节是厂商ID0x0590,后面是写入的"Moin" // 解析0x1809温度服务的广播数据 const tempServiceData = peripheral.advertisement.serviceData.find(item => item.uuid === '1809'); if (tempServiceData) { // Puck端写入的是单字节整数温度,直接读第一个字节即可 const temperature = tempServiceData.data.readUInt8(0); console.log("当前温度:", temperature, "℃"); } });
- 如果你确实需要通过GATT连接+notify方式获取数据(比如需要双向通信),则需要修改Puck.js端代码,注册自定义的0x1809温度服务和对应特征,在定时器中更新特征值并触发通知,这种方案不需要依赖广播传输数据。
补充说明
你之前看到厂商数据前的乱码字符是厂商ID0x0590的二进制内容,直接toString会显示乱码,从第3个字节(索引2)开始读取才是你写入的"Moin"字符串。
内容的提问来源于stack exchange,提问作者ppulwey
相关产品推荐
相关产品推荐

