Harmony os Next——Ble蓝牙模块的使用
描述
本文将对Ble蓝牙模块的扫描、连接、订阅、发送指令等操作进行阐述。
需要导入如下依赖即可使用ble相关功能
import ble from '@ohos.bluetooth.ble'
权限
对Ble蓝牙进行操作需要系统权限和用户授权权限,其中系统权限包括ohos.permission.USE_BLUETOOTH
和ohos.permission.DISCOVER_BLUETOOTH
,用户授权权限包括ohos.permission.ACCESS_BLUETOOTH
扫描Ble蓝牙设备
其中ble.on("BLEDeviceFind", this.onReceiveEvent)
为定义蓝牙扫描事件,即为如果扫描到Ble蓝牙设备就会回调到此方法中。同时也可以添加过滤事件Array<ScanFilter>
,精确回调自己想要的设备,如果不需要进行过滤就赋值为null
即可
startScanBluetooth() {
try {
ble.on("BLEDeviceFind", this.onReceiveEvent) //订阅蓝牙
let scanOptions: ble.ScanOptions = {
interval: 500, //表示扫描结果上报延迟时间
dutyMode: ble.ScanDuty.SCAN_MODE_LOW_POWER, //表示扫描模式
matchMode: ble.MatchMode.MATCH_MODE_AGGRESSIVE, //表示硬件的过滤匹配模式
}
ble.startBLEScan(null, scanOptions)
} catch (err) {
LoggerJoy.error('BLEDeviceFind---> errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
}
}
传递扫描的Ble设备
从扫描到的蓝牙设备中筛选出自己想要的Ble设备,其中扫描的结果会返回很多DeviceName为空的设备,可以对其进行过滤,其中connectable为false,代表设备已经被配对;为true代表可连接。然后Emitter
进行进程间的通信,将扫描到的设备传递到UI层或者其他需要的地方
//扫描到的设备
private onReceiveEvent(data: Array<ble.ScanResult>) {
let bleObject = BluetoothStatusManager.getInstance()
//如果在极短时间内发现新的设备,则不进行回调
let curTime = new Date().getTime()
let diff: number = curTime - bleObject.lastScanDeviceTime
bleObject.lastScanDeviceTime = curTime
if (diff < 10) return
try {
/*
* 从扫描到的蓝牙设备中筛选出自己想要的Ble设备
* 其中扫描的结果会返回很多deviceName为空的设备,可以对其进行过滤
* 其中connectable为false 代表设备已经被配对;为true代表可连接
* */
let requireDevices = data.filter((ble) => {
return ble.deviceName.length > 0 && ble.connectable
})
// 进程中通信-将扫描到的设备传递到UI层
// 定义一个eventId为1的事件,事件立即被传递
// 发送eventId为1的事件,事件内容为eventData
emitter.emit({
eventId: BluetoothStatusManager.BluetoothScanEventID,
priority: emitter.EventPriority.IMMEDIATE
}, {
data: {
'bleDevices': connectableDevices
}
})
} catch (err) {
LoggerJoy.error('BLEDeviceFind---> errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
}
}
接收扫描到的Ble设备
然后在UI层可以通过emitter.on
订阅指定事件,来获取传递的ble设备
getConnectableDevice(){
//订阅eventId:1的事件-接受来自蓝牙扫描的设备
let innerEvent: emitter.InnerEvent = {
eventId: BluetoothStatusManager.BluetoothScanEventID
}
// 收到eventId为1的事件后执行回调函数
emitter.on(innerEvent, (eventData: emitter.EventData) => {
if (eventData.data === undefined) {
LoggerJoy.info('BLEDeviceFind---> Scan device is empty!')
return
}
let connectableDevice = eventData.data['bleDevices'] as Array<ble.ScanResult>
//对扫描的ble设备进行处理
})
}
取消扫描Ble设备
在停止蓝牙扫描设备时,同样也需要通过emitter.off
取消订阅蓝牙传递事件
//停止扫描蓝牙设备
stopScanBluetooth() {
emitter.off(BluetoothStatusManager.BluetoothScanEventID) //断开订阅蓝牙扫描结果事件
ble.stopBLEScan() //停止扫描蓝牙
}
连接Ble设备
蓝牙状态 | 值 | 备注 |
---|---|---|
STATE_DISCONNECTED | 0 | 已断连 |
STATE_CONNECTING | 1 | 正在连接 |
STATE_CONNECTED | 2 | 已连接 |
STATE_DISCONNECTING | 3 | 正在断连 |
通过device.connect()
连接ble蓝牙设备,需要指定扫描ble蓝牙设备时返回的数据中的deviceId
,此字断即为ble设备的MAC地址
,此地址可能会在ble设备下线、断开连接情况下发生变化。
然后可以通过device.on('BLEConnectionStateChange')
订阅此设备的连接状态
/*
* 连接蓝牙设备--通过ble Mac地址进行连接
* */
connectBleDevice(deviceId: string) {
try {
let objetClass = BluetoothStatusManager.instance
let device: ble.GattClientDevice = ble.createGattClientDevice(deviceId)
LoggerJoy.info(`BLEDeviceFind---> start connection ble device`)
device.connect()
device.on('BLEConnectionStateChange', (state: ble.BLEConnectionChangeState) => {
//0:STATE_DISCONNECTED 已断连
//1:STATE_CONNECTING 正在连接
//2:STATE_CONNECTED 已连接
//3:STATE_DISCONNECTING 正在断连
let connectState: ble.ProfileConnectionState = state.state
if (connectState === constant.ProfileConnectionState.STATE_CONNECTED) {
//连接成功之后的事件处理
} else if (connectState === constant.ProfileConnectionState.STATE_DISCONNECTED) {
//已经断开连接
}
})
} catch (err) {
LoggerJoy.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
}
}
断开连接
在与设备断开连接时,也可以取消订阅连接状态事件
disconnectionBleDevice(deviceId: string) {
try {
if (this.gattClientDevice) {
this.gattClientDevice.disconnect()
this.gattClientDevice.off('BLEConnectionStateChange')
LoggerJoy.info(`BLEDeviceFind---> stop connection ble device`)
}
} catch (err) {
LoggerJoy.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
}
}
发现服务
在连接ble设备之后可以进行发现服务操作,获取Ble设备的相关操作,例如读和写。其中包含Ble设备的ServiceUUID、特征值内容和描述符内容等
device.getServices().then((result: Array<ble.GattService>) => {
//对服务进行操作
}).catch((err: BusinessError) => {
LoggerJoy.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
})
订阅Ble特征值变化事件
订阅特征值通知
只有在发现服务之后,通过发现服务所返回的数据,即可对特定特征值通知进行订阅
/*
* 订阅通知消息-只有打开了订阅,才能接受特征值变化响应
* */
setNotificationChannel() {
if (!this.gattServiceInfo || !this.gattClientDevice) {
LoggerJoy.info('BLEDeviceFind---> bluetooth gattServiceInfo is undefined ');
return
}
//在发现服务中返回的数据中,过滤出自己特定所需事件即可
let readCharacteristic = readCharacteristics[0]
try {
LoggerJoy.info('BLEDeviceFind---> setCharacteristicChangeNotification finish')
this.gattClientDevice?.setCharacteristicChangeNotification(readCharacteristic, true)
} catch (err) {
LoggerJoy.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message);
}
}
订阅特征值变化事件
只有打开特征值通知订阅(上节内容),才能接受特征值变化响应。
然后通过 this.gattClientDevice?.on('BLECharacteristicChange')
即可响应特征值变化事件
onBleCharacteristicChange() {
if (!this.gattClientDevice) {
LoggerJoy.info('BLEDeviceFind---> bluetooth device is disconnected')
return
}
try {
this.gattClientDevice?.on('BLECharacteristicChange', (characteristicChangeReq: ble.BLECharacteristic) => {
LoggerJoy.info(`BLEDeviceFind---> onBleCharacteristicChange: ${JSON.stringify(characteristicChangeReq)}`)
} catch (err) {
LoggerJoy.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
}
}
取消订阅特征值变化事件
offBleCharacteristicChange() {
if (!this.gattClientDevice) {
LoggerJoy.info('BLEDeviceFind---> bluetooth device is disconnected')
return
}
try {
this.gattClientDevice.off('BLECharacteristicChange')
LoggerJoy.info('BLEDeviceFind---> cancel BLECharacteristicChange')
} catch (err) {
LoggerJoy.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
}
}
写入特征值
同意需要在发现服务中过滤出写入特征值的服务。此处以传入Uint8Array
为例,因为writeCharacteristic.characteristicValue
所需要数据为ArrayBuffer
,所以通过buffer.from(需要转换的数据).buffer
进行转换。最后通过this.gattClientDevice?.writeCharacteristicValue(writeCharacteristic, ble.GattWriteType.WRITE)
完成特征值写入事件。
async writeCharacteristicValue(command: Uint8Array) {
if (!this.gattServiceInfo || !this.gattClientDevice) {
return
}
//从发现服务中过滤出写入事件
let writeCharacteristic = writeCharacteristics[0]
//Uint8Array转ArrayBuffer
writeCharacteristic.characteristicValue = buffer.from(command).buffer
try {
this.gattClientDevice?.writeCharacteristicValue(writeCharacteristic, ble.GattWriteType.WRITE, ()=>{
LoggerJoy.info('BLEDeviceFind---> writeCharacteristicValue success')
})
} catch (err) {
LoggerJoy.error('errCode: ' + (err as BusinessError).code + ', errMessage: ' + (err as BusinessError).message)
}
}