React Native对接Accu-check Guide-me血糖仪插试纸断连问题
React Native 对接 Accu-check Guide Me 血糖仪插入试纸断连解决方案
问题背景
- 技术栈:基于React Native框架、
react-native-ble-plx库开发多设备适配的蓝牙健康测量应用,目前已完成部分血压计、体重秤的对接,需输入序列号配对的血糖仪类设备连通存在异常。 - 已验证通用连接流程:扫描设备 -> 发现目标设备 -> 停止扫描 -> 建立连接 -> 发现全部服务与特征值 -> 拉取服务列表 -> 过滤测量类服务 -> 从目标服务下查找特征值列表 -> 开启特征值监听
- 异常表现:Accu-check Guide Me 血糖仪完成配对、连接成功后,只要插入检测试纸就会触发蓝牙断连,其余已适配设备无该问题。
- 复现路径:发起连接 -> 弹出序列号输入弹窗 -> 输入序列号 -> 提示连接成功 -> 插入检测试纸 -> 连接断开
- 初步判断:该设备在通用BLE连接流程外存在额外的交互要求,公开资料检索未找到明确适配方案。
现有问题代码
const scanAndConnectAcucheckGlucoseMeter = () => { return new Promise((resolve, reject) => { let result = 0; console.log('scanStart'); manager.startDeviceScan(null, null, (error, device) => { if (error) { console.log('error : ' + error); return; } const deviceName = device.name; if (deviceName != null) { if (deviceName.includes('meter+')) { console.log('detected!!'); manager.stopDeviceScan(); resolve(device); } } }); }); }; const MonitoringForAcucheckGuideMe = device => { return new Promise((resolve, reject) => { device .connect() .then(device => { const result = device.discoverAllServicesAndCharacteristics(); return result; }) .then(device => { return device.services(); }) .then(services => { // 180A : device information // 1800 : generic access // 1808 : glucose // 00000000-0000-1000-1000-00000000000 : custom service const result = services.filter(id => id.uuid.indexOf('1808') != -1); // Glucose Service return result[0].characteristics(); }) .then(characters => { // Glucose Measurement :00002A18 / Descriptors 2902 // Glucose Feature : 2A51 // Record Access Control Point 2A52 / Descriptors 2902 // DateTime 2A08 const glucoseMeasurement = characters.filter( data => data.uuid.indexOf('2a18') != -1, // 2a35 is for blood sugar measurement ); // popup to insert pin number on mobile when monitor() glucoseMeasurement[0].monitor((error, characteristic) => { if (error) { console.log('error:::::', error); reject(error); } const Valuebytes = Buffer.from(characteristic.value, 'base64'); console.log(Valuebytes); const result = "Not yet" resolve(result) }); }) .catch(error => console.log(error)); }); };
问题根因
Accu-check Guide Me 严格遵循蓝牙SIG 血糖服务(GLS,Service UUID 0x1808)规范实现,现有代码仅做了血糖测量特征的监听,缺失四个强制流程,设备检测到客户端未完成规范配置,会在测量动作触发时主动断开连接:
- 特征值UUID匹配逻辑存在缺陷:使用
indexOf做字符串模糊匹配,容易误命中包含相同字符的厂商自定义服务/特征,导致后续操作作用在错误的特征上。 - 未显式开启特征通知:虽然
react-native-ble-plx的monitor方法在部分设备上会自动写入客户端特征配置描述符(CCCD,UUID0x2902)开启通知,但罗氏设备要求必须显式对**血糖测量特征(0x2A18)、记录访问控制点特征(0x2A52)**两个特征写入CCCD值开启通知,缺一不可。 - 未做时间同步:罗氏设备在启动测量前会校验连接是否已同步当前时间,未向日期时间特征(
0x2A08)写入正确时间的连接会被主动断开。 - 连接参数配置不足:未申请足够的MTU值,设备传输测量数据时若包长超过默认MTU会触发断连。
修正后实现代码
// 标准蓝牙SIG UUID常量,避免字符串匹配错误 const GLUCOSE_SERVICE_UUID = '00001808-0000-1000-8000-00805f9b34fb'; const GLUCOSE_MEASUREMENT_CHAR_UUID = '00002a18-0000-1000-8000-00805f9b34fb'; const GLUCOSE_RACP_CHAR_UUID = '00002a52-0000-1000-8000-00805f9b34fb'; const DATE_TIME_CHAR_UUID = '00002a08-0000-1000-8000-00805f9b34fb'; const CCCD_UUID = '00002902-0000-1000-8000-00805f9b34fb'; const scanAndConnectAcucheckGlucoseMeter = () => { return new Promise((resolve, reject) => { console.log('Start scanning for glucose meter'); // 扫描时指定服务UUID,减少无关设备扫描结果,降低功耗 manager.startDeviceScan([GLUCOSE_SERVICE_UUID], null, (error, device) => { if (error) { console.log('Scan error:', error); reject(error); return; } // 精确匹配设备名,避免误连同前缀其他设备 if (device.name && device.name.toLowerCase().includes('meter+')) { console.log('Target Accu-check device found'); manager.stopDeviceScan(); resolve(device); } }); }); }; const MonitoringForAcucheckGuideMe = device => { return new Promise((resolve, reject) => { let glucoseChar, racpChar, dateTimeChar; device .connect({ requestMTU: 247 // 申请最大MTU,避免大数据包传输断连 }) .then(device => device.discoverAllServicesAndCharacteristics()) .then(device => device.services()) .then(services => { // 全串匹配精确查找血糖服务 const glucoseService = services.find(s => s.uuid.toLowerCase() === GLUCOSE_SERVICE_UUID); if (!glucoseService) throw new Error('Standard glucose service not found on device'); return glucoseService.characteristics(); }) .then(characters => { // 精确查找三个所需特征值 glucoseChar = characters.find(c => c.uuid.toLowerCase() === GLUCOSE_MEASUREMENT_CHAR_UUID); racpChar = characters.find(c => c.uuid.toLowerCase() === GLUCOSE_RACP_CHAR_UUID); dateTimeChar = characters.find(c => c.uuid.toLowerCase() === DATE_TIME_CHAR_UUID); if (!glucoseChar || !racpChar || !dateTimeChar) throw new Error('Required glucose characteristics missing'); // 封装通用通知开启方法,显式写入CCCD const enableNotification = async (char) => { const descriptors = await char.descriptors(); const cccd = descriptors.find(d => d.uuid.toLowerCase() === CCCD_UUID); // 写入0x0001(小端序)开启通知 await cccd.writeWithResponse(Buffer.from([0x01, 0x00]).toString('base64')); }; // 同时开启两个特征的通知 return Promise.all([enableNotification(glucoseChar), enableNotification(racpChar)]); }) .then(() => { // 按蓝牙SIG标准日期时间格式编码当前时间,写入设备完成同步 const now = new Date(); const timeBuffer = Buffer.alloc(7); timeBuffer.writeUInt16LE(now.getFullYear(), 0); timeBuffer.writeUInt8(now.getMonth() + 1, 2); // 月份从1开始计数 timeBuffer.writeUInt8(now.getDate(), 3); timeBuffer.writeUInt8(now.getHours(), 4); timeBuffer.writeUInt8(now.getMinutes(), 5); timeBuffer.writeUInt8(now.getSeconds(), 6); return dateTimeChar.writeWithResponse(timeBuffer.toString('base64')); }) .then(() => { // 所有前置配置完成后,再开启测量数据监听 glucoseChar.monitor((error, characteristic) => { if (error) { console.log('Glucose data monitor error:', error); reject(error); return; } if (!characteristic?.value) return; const rawData = Buffer.from(characteristic.value, 'base64'); console.log('Received raw glucose measurement:', rawData); // 此处按蓝牙GLS服务规范解析血糖值、单位、测量时间等字段即可 resolve("Glucose data channel initialized successfully"); }); // 按需开启RACP特征监听,处理历史记录查询响应 racpChar.monitor((error, characteristic) => { if (error || !characteristic?.value) return; const racpResp = Buffer.from(characteristic.value, 'base64'); console.log('RACP response received:', racpResp); }); }) .catch(error => { console.log('Glucose meter connection flow failed:', error); reject(error); }); }); };
补充注意事项
- 不要在测量值监听回调中提前结束Promise,后续每次测量完成都会触发该回调,需要持续处理解析逻辑。
- 若修改后插入试纸仍断连,优先检查系统蓝牙配对状态:罗氏设备要求连接必须达到加密配对等级,未完成系统层面的配对绑定会被设备拒绝传输测量数据。
- 若需要拉取设备历史测量记录,必须通过RACP特征发送标准操作指令,不能直接读取测量特征值。
内容的提问来源于stack exchange,提问作者Miguel
相关产品推荐
相关产品推荐

