HarmonyOS 鸿蒙Next ConnectivityKit中BLE低功耗蓝牙设备扫描设备ID会发生变化

发布于 1周前 作者 bupafengyu 来自 鸿蒙OS

HarmonyOS 鸿蒙Next ConnectivityKit中BLE低功耗蓝牙设备扫描设备ID会发生变化
<markdown _ngcontent-gem-c237="" class="markdownPreContainer">

背景

最近研发一款养老项目,发现一个问题,使用ConnectivityKit中 BLE 低功耗蓝牙模块扫描设备时,获取到设备 DeviceID 在不同时间段会发生变化,造成无法判别设备唯一性问题

    let scanOptions: ble.ScanOptions = {
      interval: 500,
      dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
      matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE,
    }
    ble.startBLEScan(null, scanOptions);
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

解决

方案 1

通过设备广播截取 扫描设备的时候可以获取设备的广播数据,设备的 mac地址一般包含在特定位置,代码如下:

  /**
   * 通过广播数据获取血糖设备mac
   * [@param](/user/param) data
   * [@returns](/user/returns) FF-FF-11-57-B6-5B
   */
  getMac(data: ArrayBuffer) {
    //  1. Uint8Array处理二进制(高效)
    const arr = new Uint8Array(data).slice(6, 12)
    let mac = ''
    // 2. 转换 16 进制
    arr.forEach((item, i) => {
      mac += i === 0 ? '' : '-'
      mac += item.toString(16)
        .padStart(2, '0')
        .toUpperCase()
    })
    return mac
  }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

注意:大部分设备适用

方案 2

通过给设备名称添加标识 falg 方式匹配,核心代码如下:

      const validDevices = devices.filter(dv => {
        if (scanFilter.type === 'mac') {
          let flag: boolean
          if (!scanFilter.door) {
            // 广播匹配
            flag = this.getMac(dv.data) === scanFilter.value
          } else {
            // 名称 falg匹配
            flag = this.isMatchDoor(scanFilter.value, dv.deviceName)
          }
          return list.some(item => item.deviceId === dv.deviceId) === false && flag
        } else {
          return list.some(item => item.deviceId === dv.deviceId) === false &&
          dv.deviceName.startsWith(scanFilter.value)
        }
      })
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

这样就可以解决 DeviceID 变化问题,从而确定设备唯一性,保障后续设备的连接和控制操作正常进行。

最后贴下扫描完整代码:

  /**
   * 扫描蓝牙设备
   * [@param](/user/param) scanFilter
   * [@param](/user/param) callback
   */
  scanDevice(scanFilter: ScanFilter, callback: ScanCallback) {
    if (this.timer) {
      clearTimeout(this.timer)
    }
    // 1. 监听扫描结果
    let list: ble.ScanResult[] = []
    ble.on("BLEDeviceFind", (devices: ble.ScanResult[]) => {
      // 打印扫到设备
      devices.forEach(item => {
        Log.warn(`扫描中...\n ${item.deviceName || '--'} ${item.deviceId}`)
      })
      // const validDevices = devices.filter(dv => {
      //   return list.some(item => item.deviceId === dv.deviceId) === false
      // })
      const validDevices = devices.filter(dv => {
        if (scanFilter.type === 'mac') {
          let flag: boolean
          if (!scanFilter.door) {
            // 血糖匹配
            flag = this.getMac(dv.data) === scanFilter.value
          } else {
            // 门禁匹配
            flag = this.isMatchDoor(scanFilter.value, dv.deviceName)
          }
          return list.some(item => item.deviceId === dv.deviceId) === false && flag
        } else {
          return list.some(item => item.deviceId === dv.deviceId) === false &&
          dv.deviceName.startsWith(scanFilter.value)
        }
      })
      if (validDevices.length > 0) {
        list.push(...validDevices)
        // 精确匹配到后直接结束扫描
        if (scanFilter.type === 'mac') {
          callback(list)
          clearTimeout(this.timer)
          ble.off('BLEDeviceFind')
          ble.stopBLEScan()
        }
      }
    });
    //  2. 开启扫描
    let scanOptions: ble.ScanOptions = {
      interval: 500,
      dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER,
      matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE,
    }
    ble.startBLEScan(null, scanOptions);
// 3. 开启定时器控制时长
</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">this</span></span></span><span class="hljs-function">.</span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">timer</span></span></span><span class="hljs-function"> = </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">setTimeout</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(() =&gt; {
  callback(list)
  ble.</span></span><span class="hljs-literal"><span class="hljs-function"><span class="hljs-params"><span class="hljs-literal">off</span></span></span></span><span class="hljs-function"><span class="hljs-params">(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">'BLEDeviceFind'</span></span></span></span><span class="hljs-function"><span class="hljs-params">)
  ble.stopBLEScan()
}, </span></span><span class="hljs-number"><span class="hljs-function"><span class="hljs-params"><span class="hljs-number">10000</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function">

} <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

</markdown>

关于HarmonyOS 鸿蒙Next ConnectivityKit中BLE低功耗蓝牙设备扫描设备ID会发生变化的问题,您也可以访问:https://www.itying.com/category-93-b0.html 联系官网客服。

14 回复

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

兄弟,有一个问题请教一下.蓝牙连接成功之后怎么获取服务和特征?

找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17

使用createGattClientDevice实例上的getServices方法获取服务,根据serviceUuid获取特征值
贴个代码参考:
    this.dev = ble.createGattClientDevice(deviceId)
    // 1. 连接设备
    this.dev.connect()
    this.dev.on('BLEConnectionStateChange', async (res) => {
      if (res.state === constant.ProfileConnectionState.STATE_CONNECTED) {
        try {
          // 2. 发现服务
          const res = await this.dev?.getServices()
          // 3. 找到服务
          const ser = res?.find(item => item.serviceUuid.startsWith('00001000'))
          if (ser) {
            // 写入特征值对象(给蓝牙设备发送数据)
            const writeChar = ser.characteristics.find(c => c.characteristicUuid.startsWith('00001001'))
            // 通知特征值对象(获取蓝牙设备发送数据)
            const notifyChar = ser.characteristics.find(c => c.characteristicUuid.startsWith('00001002'))
        <span class="hljs-comment"><span class="hljs-comment">// 4. 开启特征值监听:获取连接状态和结果</span></span>
        <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.dev?.on(<span class="hljs-string"><span class="hljs-string">'BLECharacteristicChange'</span></span>, (res) =&gt; {
          
        })
        await <span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.dev?.setCharacteristicChangeNotification(notifyChar, <span class="hljs-literal"><span class="hljs-literal">true</span></span>)

   
      }
    } <span class="hljs-keyword"><span class="hljs-keyword">catch</span></span> (e) {
 
    }
  }
})</code><button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 8px; right: 8px; font-size: 14px;">复制</button></pre></div></div>
楼主 你写的这ble连接 可以运行在OpenHarmony 环境 跨平台?

和 open 基本同步的 可以试试

client端向低功耗蓝牙设备写入数据是用的writeDescriptorValue方法吧,我是用这个方法的时候,需要传入BLEDescriptor,这个对象里面有个descriptorUuid字段是必填项,这个descriptorUuid我从哪里获取,目前调用这个接口是报401错误
deviceId获取到的MAC地址就是错的,鸿蒙是否和IOS一样无法直接获取MAC地址

是的 类似IOS 做了加密的 可以通过硬件侧 广播信息中获取

回到顶部