HarmonyOS 鸿蒙Next ConnectivityKit中BLE低功耗蓝牙设备扫描设备ID会发生变化
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">(() => {
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) => {
})
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错误
是的 类似IOS 做了加密的 可以通过硬件侧 广播信息中获取
回到顶部