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

Flutter中flutter_reactive_ble读取BLE设备血压数据的解析问题

解析BLE血压测量特征数据获取血压与心率

问题描述

我使用flutter_reactive_ble包编写代码,尝试从BLE设备读取收缩压、舒张压(单位mmHg)及心率(单位bpm),但不知如何解析数据。控制台输出如下:
D/BluetoothGatt(21288): setCharacteristicNotification() - uuid: 00002a35-0000-1000-8000-00805f9b34fb enable: true
I/flutter (21288): Received raw data for blood pressure measurement: [222, 136, 244, 32, 243, 255, 7, 228, 7, 1, 19, 22, 55, 0, 188, 242, 1, 68, 1]

用户的Flutter代码如下:

@override
Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
            title: Text('BLE Scanner'),
        ),
        body: Center(
            child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                    ElevatedButton(
                        onPressed: _scanForDevices,
                        child: Text('Scan for Devices'),
                    ),
                    SizedBox(height: 20),
                    Text('Discovered Devices:'),
                    Expanded(
                        child: ListView.builder(
                            itemCount: devices.length,
                            itemBuilder: (context, index) {
                                final device = devices[index];
                                return ListTile(
                                    title: Text(device.name ?? 'Unknown'),
                                    subtitle: Text(device.id),
                                    onTap: () {
                                        _connectToDevice(device.id);
                                        _subscribeToBloodPressureMeasurement(device.id);
                                    },
                                );
                            },
                        ),
                    ),
                ],
            ),
        ),
    );
}

void _scanForDevices() {
    flutterReactiveBle.scanForDevices(
        withServices: [],
        scanMode: ScanMode.lowLatency,
    ).listen(
        (device) {
            final existingDeviceIndex =
                devices.indexWhere((d) => d.id == device.id);
            if (existingDeviceIndex != -1) {
                setState(() {
                    devices[existingDeviceIndex] = device;
                });
            } else {
                setState(() {
                    devices.add(device);
                });
            }
        },
        onError: (error) {
            print('Error: $error');
        },
    );
}

void _connectToDevice(String deviceId) {
    flutterReactiveBle
        .connectToDevice(
        id: deviceId,
        servicesWithCharacteristicsToDiscover: {
            Uuid.parse('00001810-0000-1000-8000-00805f9b34fb'): [
                // 血压测量特征
                Uuid.parse('00002a35-0000-1000-8000-00805f9b34fb'),
                // 血压特征
                Uuid.parse('00002a49-0000-1000-8000-00805f9b34fb'),
            ],
        },
        connectionTimeout: const Duration(seconds: 2),
    )
        .listen(
        (connectionState) {
            // 处理连接状态更新
            if (connectionState == DeviceConnectionState.connected) {
                print("Connected successfully to device: $deviceId");
                _subscribeToBloodPressureMeasurement(deviceId);
            }
        },
        onError: (error) {
            print('Error connecting to device: $error');
            // 处理连接错误
        },
    );
}

void _subscribeToBloodPressureMeasurement(String deviceId) {
    final bloodPressureCharacteristic = QualifiedCharacteristic(
        characteristicId: Uuid.parse('00002a35-0000-1000-8000-00805f9b34fb'),
        deviceId: deviceId,
        serviceId: Uuid.parse('00001810-0000-1000-8000-00805f9b34fb'),
    );

    // 订阅血压测量特征
    flutterReactiveBle
        .subscribeToCharacteristic(bloodPressureCharacteristic)
        .listen(
        (data) {
            print('Received raw data for blood pressure measurement: $data');
            // 在此处处理通知数据
        },
        onError: (error) {
            print('Error subscribing to blood pressure measurement: $error');
            // 处理订阅错误
        },
    );
}

解析方案

一、BLE血压测量特征(0x2A35)标准格式

BLE官方定义的血压测量特征(UUID: 00002a35-0000-1000-8000-00805f9b34fb)数据结构如下:

  1. 第1字节:Flags标志位,用于标记后续字段的存在状态和单位:
    • Bit 0: 0=血压单位为mmHg,1=kPa
    • Bit 4: 1=数据包含心率(脉率)
    • Bit 6: 1=数据包含舒张压
    • Bit 7: 1=数据包含收缩压
  2. 后续字段:根据Flags的标记,依次出现以下数据(每个数值为2字节的SFLOAT浮点数):
    • 收缩压 → 舒张压 → 心率(若对应标志位为1)
    • SFLOAT格式规则:数值 = 尾数 × 10^指数,其中尾数是12位补码,指数为3位值减4(范围-4到+3)

二、实现解析代码

在_subscribeToBloodPressureMeasurement的listen回调中添加解析逻辑:

void _subscribeToBloodPressureMeasurement(String deviceId) {
    final bloodPressureCharacteristic = QualifiedCharacteristic(
        characteristicId: Uuid.parse('00002a35-0000-1000-8000-00805f9b34fb'),
        deviceId: deviceId,
        serviceId: Uuid.parse('00001810-0000-1000-8000-00805f9b34fb'),
    );

    flutterReactiveBle
        .subscribeToCharacteristic(bloodPressureCharacteristic)
        .listen(
        (data) {
            print('Received raw data for blood pressure measurement: $data');
            _parseBloodPressureData(data);
        },
        onError: (error) {
            print('Error subscribing to blood pressure measurement: $error');
        },
    );
}

void _parseBloodPressureData(List<int> data) {
    if (data.isEmpty) return;

    // 解析Flags标志位
    final flags = data[0];
    final isMmhg = (flags & 0x01) == 0; // Bit0=0 → mmHg
    final hasSystolic = (flags & 0x80) != 0; // Bit7=1 → 有收缩压
    final hasDiastolic = (flags & 0x40) != 0; // Bit6=1 → 有舒张压
    final hasHeartRate = (flags & 0x10) != 0; // Bit4=1 → 有心率

    int offset = 1; // 跳过Flags字节

    // 解析收缩压
    if (hasSystolic) {
        final systolic = _parseSfloat(data[offset], data[offset+1]);
        print('收缩压: ${systolic.toStringAsFixed(1)} ${isMmhg ? 'mmHg' : 'kPa'}');
        offset +=2;
    }

    // 解析舒张压
    if (hasDiastolic) {
        final diastolic = _parseSfloat(data[offset], data[offset+1]);
        print('舒张压: ${diastolic.toStringAsFixed(1)} ${isMmhg ? 'mmHg' : 'kPa'}');
        offset +=2;
    }

    // 跳过平均动脉压(如果存在,Bit5=1)
    if ((flags & 0x20) !=0) offset +=2;

    // 解析心率
    if (hasHeartRate) {
        final heartRate = _parseSfloat(data[offset], data[offset+1]);
        print('心率: ${heartRate.toStringAsFixed(0)} bpm');
        offset +=2;
    }

    // 若需要解析时间戳、用户ID等其他字段,可继续按规范扩展
}

double _parseSfloat(int byte1, int byte2) {
    // 小端字节序,组合成16位值
    final int16Value = (byte2 << 8) | byte1;

    // 拆分SFLOAT的符号位、指数位、尾数位
    final sign = (int16Value >> 15) & 0x01;
    final exponent = ((int16Value >> 12) & 0x07) -4;
    int mantissa = int16Value & 0x0FFF;

    // 处理负数尾数
    if (mantissa > 0x07FF) {
        mantissa -= 0x1000;
    }

    // 计算最终数值
    double value = mantissa * pow(10, exponent);
    return sign == 1 ? -value : value;
}

三、针对你的原始数据的说明

将你的数据代入上述标准解析代码后,得到的结果不符合实际血压/心率范围,说明你的设备可能未遵循BLE官方规范,使用了自定义编码格式。建议:

  1. 查阅设备官方文档,确认数据编码规则
  2. 尝试调换字节序解析,或按无符号整数×0.01等简化规则测试
  3. 联系设备厂商获取专属协议文档

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 08:13:12