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

Swift开发欧姆龙BP7000 BLE设备:血压数据读取及时间读写问题求助

解决欧姆龙BP7000 BLE血压数据读取及时间写入错误(CBATTErrorDomain Code:128)

问题概述

已成功配对欧姆龙BP7000,能读取电池等其他服务数据,但读写当前时间特征、读取血压测量特征时触发CBATTErrorDomain Code:128错误,didUpdateValueFor无法获取血压数据。

核心问题分析与修复方案

1. 移除BLE操作并发冲突(触发128错误的主要原因)

在didUpdateValueFor的currentTimeCBUUID分支中,你在收到特征更新后立即发起readValue和writeValue操作,会导致BLE命令并发冲突,设备无法处理直接返回128错误。

修复代码:
移除peripheral.readValue(for: characteristic),且不在didUpdateValueFor回调内执行写操作。建议在发现特征后直接处理,比如在didDiscoverCharacteristicsFor代理方法中操作:

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    guard let characteristics = service.characteristics else { return }
    for char in characteristics {
        switch char.uuid {
        case currentTimeCBUUID:
            // 发现当前时间特征后直接写入时间
            writeCurrentTime(to: char, in: peripheral)
        case bloodPressureMeasurementCBUUID:
            // 开启血压特征的通知(血压数据为主动推送)
            peripheral.setNotifyValue(true, for: char)
        case batteryLevelCBUUID:
            peripheral.readValue(for: char)
        default:
            break
        }
    }
}

2. 修正当前时间特征的写入格式(格式错误导致写入失败)

你的writeCurrentTime方法存在多处不符合蓝牙**Current Time Characteristic(UUID:2A2B)**规范的错误,设备拒绝写入并返回128错误:

  • 多余的空数据写入value.append(Data(bytes: "", count: 0))
  • Year字节序处理错误,未使用大端字节序
  • 误将Fractions of a second设为2字节(规范为1字节的Fractions256)

修复后的writeCurrentTime方法:

func writeCurrentTime(to characteristic: CBCharacteristic, in peripheral: CBPeripheral) {
    let currentDate = Date()
    let calendar = Calendar.current
    let components = calendar.dateComponents([.year, .month, .day, .hour, .minute, .second, .weekday], from: currentDate)
    
    guard let year = components.year,
          let month = components.month,
          let day = components.day,
          let hour = components.hour,
          let minute = components.minute,
          let second = components.second,
          let weekday = components.weekday else {
        print("Failed to get date components")
        return
    }
    
    var value = Data()
    // Year: 2字节大端
    let yearBigEndian = year.bigEndian
    value.append(Data(bytes: &yearBigEndian, count: 2))
    // Month: 1字节
    value.append(UInt8(month))
    // Day: 1字节
    value.append(UInt8(day))
    // Hours: 1字节
    value.append(UInt8(hour))
    // Minutes: 1字节
    value.append(UInt8(minute))
    // Seconds: 1字节
    value.append(UInt8(second))
    // Day of Week: 1字节(1=周日,7=周六)
    value.append(UInt8(weekday))
    // Fractions256: 1字节(当前秒的1/256,取0即可)
    value.append(UInt8(0))
    
    peripheral.writeValue(value, for: characteristic, type: .withResponse)
}

3. 修复血压数据的读取与解码逻辑

关键前提:必须开启血压特征的通知

血压测量特征(UUID:2A35)通过通知主动推送数据,不是主动读取,确保在发现特征后调用peripheral.setNotifyValue(true, for: char)(参考步骤1代码)。

修正解码逻辑(适配Flags字节的动态偏移)

你的解码逻辑忽略了Flags字节的影响,且血压值为SFloat格式(16位有符号,乘以1/10),直接相加会得到错误值:

func decodeBloodPressureMeasurementData(from characteristic: CBCharacteristic) {
    guard let data = characteristic.value else {
        print("No blood pressure data")
        return
    }
    
    let flags = data[0]
    let isKpa = (flags & 0b00000001) != 0 // Bit0: 0=mmHg, 1=kPa
    let hasTimestamp = (flags & 0b00000010) != 0 // Bit1: 是否包含时间戳
    let hasPulseRate = (flags & 0b00001000) != 0 // Bit3: 是否包含脉搏率
    
    var offset = 1 // 跳过Flags字节
    
    // 解码血压值(SFloat格式)
    let systolicRaw = UInt16(data[offset]) | (UInt16(data[offset+1]) << 8)
    let systolic = Float(Int16(bitPattern: systolicRaw)) / 10.0
    offset += 2
    
    let diastolicRaw = UInt16(data[offset]) | (UInt16(data[offset+1]) << 8)
    let diastolic = Float(Int16(bitPattern: diastolicRaw)) / 10.0
    offset += 2
    
    let meanRaw = UInt16(data[offset]) | (UInt16(data[offset+1]) << 8)
    let mean = Float(Int16(bitPattern: meanRaw)) / 10.0
    offset += 2
    
    // 跳过时间戳(如果存在)
    if hasTimestamp {
        offset += 7 // 时间戳固定7字节
    }
    
    // 解码脉搏率(如果存在)
    var pulseRate: Float?
    if hasPulseRate {
        let pulseRaw = UInt16(data[offset]) | (UInt16(data[offset+1]) << 8)
        pulseRate = Float(Int16(bitPattern: pulseRaw)) / 10.0
    }
    
    let unit = isKpa ? "kPa" : "mmHg"
    print("收缩压: \(systolic) \(unit)")
    print("舒张压: \(diastolic) \(unit)")
    print("平均动脉压: \(mean) \(unit)")
    if let rate = pulseRate {
        print("脉搏率: \(rate) bpm")
    }
}

4. 完善错误处理

在didUpdateValueFor开头添加错误判断,及时定位问题:

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    if let error = error {
        print("特征更新错误: \(error)")
        return
    }
    
    // 后续的特征判断逻辑...
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 09:08:14