迟来的更新。从4月份以来项目中断续在对接好几个共享产品,关于蓝牙BLE
设备,通过蓝牙
与设备
之间通信进行使用产品。 开发中也遇到不少问题哈,后面抽时间续篇。写得不好,请各位大神多多指教。
此篇主要介绍一些API
操作及一些返回数据结构, 项目已上线。后面抽时间上demo
关于字节
字节(Byte):
是计算机 信息技术 用于计量存储容量的一种计量单位,作为一个单位来处理的一个二进制数字串。
其中下发指令或处理数据时都可以应用到
1B(byte,字节)= 8 bit(比特)
, 相当于一个字符
一个字节能表示的最大
的整数就是255
例如 : 数据为5d000001be5d
理解为6个
字节(6B)
流程图
BLE执行大致流程,为了节省空间,画的比较乱哈。
使用步骤 微信小程序低功耗蓝牙API
微信小程序官方_蓝牙说明
初始化数据
根据需求定义,个人在一个项目中开发好几个产品,同时对接不同蓝牙协议供应商,有些变量放全局,根据不同供应商来操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 var serviceUUID = [] var writeUUID = "" ; var notifyUUID = "" ; var filterServiceUUID = "" ; var filterDeviceName = "" ; var macAddress = "" ; var flagFromTypes = '' ; var _discoveryStarted = false ;var deviceId = '' ; var _deviceId = '' ;var _serviceId = '' ;var _characteristicId = '' ;var status = false ; var action_type = '' ; var code = -1 ;var isnotExist = true
给变量赋值
设备相关服务通常蓝牙协议文档上有说明,Read
、Write
、 Notify
。如果没有说明可通过搜索设备看到
某些供应商读写通过
统一用一个服务
的
1 2 3 4 5 6 serviceUUID[0 ] = "0000*E0-00*0-*0*0-*0*0-00**5F9**4*B" ; writeUUID = "00*0**E2-00*0-*0*0-*0*0-00**5F9**4*B" ; notifyUUID = "00*0**E1-00*0-*0*0-*0*0-00**5F9**4*B" ; filterServiceUUID = "*E0" ; filterDeviceName = getNameMac(macAddress, 6 , 'abc_' );
1. 初始化蓝牙
模块
1 wx.openBluetoothAdapter(Object obj)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 function initBle (fromMac, flagTypes, currentSerial ) { closeBLEConnection(); macAddress = fromMac; flagFromTypes = flagTypes currentSerialVal = currentSerial wx.openBluetoothAdapter({ success : (res ) => { console .log('openBluetoothAdapter 初始化蓝牙模块是否成功:' , res) onBluetoothDeviceFound(); startBluetoothDevicesDiscovery(); }, fail : (res ) => { console .log('初始化蓝牙失败' , res); asddErrorCallback(res.errCode, "" ); } }) }
2. 监听寻找新设备
事件
1 wx.onBluetoothDeviceFound(function callback)
广播数据
: 可以得到当前蓝牙设备的相关数据,另外,如果设备有返回其他数据时在advertisData
数据段中得到,【有些供应商是没有返回的】
设备返回数据效果图
下图是两家供应商设备返回的数据, 左图advertisData
返回8个字节
数据【数据需转换】。右图则没有。同时可以看到返回name
格式也是不一样的【自定义】
注意:
安卓下部分机型需要有位置权限才能搜索到设备,需留意是否开启了位置权限
说明:
为了保证准确性
建议通过mac
地址匹配。
在advertisData
获取mac
地址匹配。
通过设备name
进行匹配设备,如FIC_992f3e
。根据实际情况操作
以下demo
提供两种
匹配设备方式. 通过mac
或name
匹配设备【每个供应商返回的name格式不一样 】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 function onBluetoothDeviceFound ( ) { wx.onBluetoothDeviceFound((res ) => { console .log('广播数据结果:' , res); res.devices.forEach(device => { if (!device.name && !device.localName) { return } var hexStr = ab2hex(device.advertisData); console .log("广播数据中转换后:advertisData---->" + hexStr); if ((macAddress != "" ) && (macAddress == device.deviceId) && isnotExist) { isnotExist = false ; deviceId = device.deviceId; console .log('android-->tempDeviceId:' + deviceId); stopBluetoothDevicesDiscovery(); createBLEConnection(); } let deviceName = device.name.toUpperCase(); if ((deviceName.indexOf(filterDeviceName) != -1 ) && isnotExist) { isnotExist = false ; deviceId = device.deviceId; console .log('ios or android-->tempDeviceId:' + deviceId); stopBluetoothDevicesDiscovery(); createBLEConnection(); } }) }) }
3. 开始
搜寻附近的蓝牙设备
1 2 wx.startBluetoothDevicesDiscovery(Object object) 注意:`此操作`比较耗费系统资源`,请在`搜索并连接到设备`后调用 `wx.stopBluetoothDevicesDiscovery`方法`停止搜索
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function startBluetoothDevicesDiscovery ( ) { console .log("执行连接蓝牙设备 回调空===" + _discoveryStarted); if (_discoveryStarted) { return ; } _discoveryStarted = true wx.startBluetoothDevicesDiscovery({ services : serviceUUID, allowDuplicatesKey : false , success : (res ) => { console .log('启动搜索蓝牙设备, 结果 :' , res) }, fail (res ) { asddErrorCallback(res.errCode, "" ); console .log('startBluetoothDevicesDiscovery fail' , res); } }) }
4. 停止
搜寻附近的蓝牙设备
wx.stopBluetoothDevicesDiscovery(Object object)
1 2 3 4 function stopBluetoothDevicesDiscovery ( ) { wx.stopBluetoothDevicesDiscovery() }
5. 连接
低功耗蓝牙设备
wx.createBLEConnection(Object object)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 function createBLEConnection ( ) { var that = this ; wx.createBLEConnection({ deviceId : deviceId, success : (res ) => { wx.showToast({ title : '设备连接成功' , duration : 2000 }) getBLEDeviceServices(deviceId) }, fail : (res ) => { console .log('createBLEConnection fail' , res); asddErrorCallback(res.errCode, "" ); } }) stopBluetoothDevicesDiscovery(); }
6. 获取蓝牙所有服务
1 2 wx.onBLEConnectionStateChange(function callback) wx.getBLEDeviceServices(Object object)
注意:
有些供应商会返回多个服务
,只要找自己需要的服务就好
监听蓝牙连接状态,可以处理连接连接意外断开
等情况
获取需要的蓝牙服务
后,再调用获取蓝牙特征值
方法
设备返回数据效果图
假设: 需要的服务是包含EE0
的,只需要过滤下就可以【这里通过indexOf
】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 function getBLEDeviceServices (deviceId ) { wx.onBLEConnectionStateChange(function (res ) { console .log("onBLEConnectionStateChange:" , res); console .log(`device ${res.deviceId} state has changed, connected: ${res.connected} ` ) if (res.connected == false ) { console .log("连接意外断开等****" , _deviceId); _deviceId = '' ; if (flagFromTypes == 1 && flagFromTypes == 2 ) { asddErrorCallback(1010 , "" ); } } }); wx.getBLEDeviceServices({ deviceId : deviceId, success : (res ) => { for (let i = 0 ; i < res.services.length; i++) { let tmpUuid = res.services[i].uuid; if ((res.services[i].isPrimary) && (tmpUuid.indexOf(filterServiceUUID) != -1 )) { getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) return } } }, fail : (res ) => { console .log('getBLEDeviceServices fail' , res); asddErrorCallback(res.errCode, "" ); } }) }
7. 获取某个服务中所有特征值
wx.getBLEDeviceCharacteristics(Object object)
获取蓝牙设备某个服务中所有特征值
wx.onBLECharacteristicValueChange(function callback)
监听低功耗蓝牙设备的特征值变化事件
注意:
返回数据中的**properties 的结构**
, 里面返回该服务下的特征值
是否支持read
、write
、notify
、indicate
操作。
返回数据结构效果图
注意:
根据文档协议读、写、通知
服务【前面定义的变量】,遍历对象来获取想要的特征值uuid
处理相关逻辑
启用
低功耗蓝牙设备特征值变化时的notify
功能,注意:
必须 设备的特征值
支持notify
或者indicate
才可以成功调用。
监听
低功耗蓝牙设备的特征值变化
事件。注意:
必须先启用 notifyBLECharacteristicValueChange
接口才能接收到设备推送的 notification。
监听onBLECharacteristicValueChange
,第一时间获取设备返回的数据
如果需要找到设备
后,先获取一些设备信息
操作,可以在write
中发送相关指令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 function getBLEDeviceCharacteristics (deviceId, serviceId ) { console .log("设备:" + deviceId + '******************服务:' + serviceId); wx.getBLEDeviceCharacteristics({ deviceId : deviceId, serviceId : serviceId, success : (res ) => { console .log('getBLEDeviceCharacteristics success' , res.characteristics) for (let i = 0 ; i < res.characteristics.length; i++) { let item = res.characteristics[i] var itemUUID = item.uuid.toUpperCase(); if (item.properties.read && itemUUID == writeUUID) { wx.readBLECharacteristicValue({ deviceId : deviceId, serviceId : serviceId, characteristicId : item.uuid, }) } if (item.properties.write && itemUUID == writeUUID) { console .log("写 特征值 -----------------------" + item.uuid); _deviceId = deviceId _serviceId = serviceId _characteristicId = item.uuid if (flagFromTypes == 1 || flagFromTypes == 2 ) { handleTimeToHex(); } } if (notifyUUID == itemUUID) { if (item.properties.notify || item.properties.indicate) { console .log('调用notifyBLECharacteristicValueChange前' , item.uuid); wx.notifyBLECharacteristicValueChange({ deviceId : deviceId, serviceId : serviceId, characteristicId : item.uuid, state : true , success (res ) { console .log('notification通知数据' , res); status = true ; }, fail (res ) { console .log('notifyBLECharacteristicValueChange fali' , res); } }) } } } }, fail : (res ) => { console .log('getBLEDeviceCharacteristics fail' , res) asddErrorCallback(res.errCode, "" ); } }) wx.onBLECharacteristicValueChange(function (res ) { console .log(`characteristic ${res.characteristicId} has changed, now is ${res.value} ` ) console .log("操作类型:" + action_type); var resData = ab2hex(res.value); console .log("设备返回数据--->" , resData); if (flagFromTypes == 1 ) { console .log('开始调用 血压计=====》处理返回的数据' ); bloodPressureObj.filterStr(resData); } }) }
8. 写入数据
1 wx.writeBLECharacteristicValue(Object object)
接收hex
参数【下发指令数据】,向设备写入二进制数据。注意:
注意:必须 设备的特征值支持 write
才可以成功调用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 function writeData (hex, action = '' ) { if (!status) { return ; } if (!_deviceId) { asddWriteErrors('w' ); return ; } setTimeout (() => { var enDataBuf = new Uint8Array (hex); var buffer1 = enDataBuf.buffer console .log("发送内容长度:" , buffer1.byteLength) console .log('写入的数据:' + _deviceId + '服务serviceId---》' + _serviceId + '特征characteristicId---》' + _characteristicId); wx.writeBLECharacteristicValue({ deviceId : _deviceId, serviceId : _serviceId, characteristicId : _characteristicId, value : buffer1, success : (res ) => { wx.hideLoading(); console .log("写数据返回结果" , res.errMsg); if (action == 'lastZero' ) { console .log('最后一次写入00需执行回调========》' ); eyeCareObj.eyeCareCallback(); } }, fail (res ) { console .log("写数据失败.." , res); asddErrorCallback(res.errCode, "" ); } }) }, 1000 ) }
9. 断开蓝牙设备的连接
注意:
断开蓝牙设备连接 同时还要关闭蓝牙模块 , 否则安卓设备下
再次无法搜索到设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 function closeBLEConnection ( ) { stopBluetoothDevicesDiscovery(); console .log("断开与低功耗蓝牙设备的连接。" , deviceId); if (deviceId) { wx.closeBLEConnection({ deviceId : deviceId, success : function (res ) { console .log("closeBLEConnection。success" , res); }, fail : function (res ) { console .log("closeBLEConnection。fail" , res); }, complete : function ( ) { status = false ; } }) wx.closeBluetoothAdapter({ success : function (res ) { console .log("closeBluetoothAdapter ==>res:" , res); }, fail : function (error ) { console .log("closeBluetoothAdapter ==>error:" , error); } }) } _discoveryStarted = false ; isnotExist = true ; _deviceId = '' ; deviceId = '' ; }
10. 错误码判断
10006
错误码我单独处理, 自动重连操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 function bluetoothStatus (errorType ) { switch (errorType) { case 10001 : wx.showModal({ title : '提示' , content : '请检查手机蓝牙是否打开' , showCancel : false }) break ; case 10002 : wx.showToast({ title : '没有找到指定设备' , icon : 'none' }) break ; case 10003 : wx.showToast({ title : '连接失败' , icon : 'none' }) closeBLEConnection(); break ; case 10004 : wx.showToast({ title : '没有找到指定服务' , icon : 'none' }) closeBLEConnection(); break ; case 10005 : wx.showToast({ title : '没有找到指定特征值' , icon : 'none' }) closeBLEConnection(); break ; case 10007 : case 10008 : case 10013 : wx.showToast({ title : '设备启动失败,请重试' , icon : 'none' }) break ; case 10009 : wx.showModal({ title : '提示' , content : '当前系统版本过低,请更新版本体验' , showCancel : false }) break ; case 10012 : wx.showToast({ title : '连接超时' , icon : 'none' }) break ; } }
处理数据方法 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 function getNameMac (macAddress, len, name ) { let clearColonMac = clearSymbol(macAddress); let lastFourMac = clearColonMac.substring(clearColonMac.length - len); let strName = name.toUpperCase(); strName = strName + lastFourMac.toUpperCase(); console .log('拼接后的' + strName); return strName } function clearSymbol (str ) { str = str.replace(/:/g , "" ); return str; } function ab2hex (buffer ) { var hexArr = Array .prototype.map.call( new Uint8Array (buffer), function (bit ) { return ('00' + bit.toString(16 )).slice(-2 ) } ) return hexArr.join('' ); }
关于下篇内容 在实际中使用的案例。
———————————————— 版权声明:本文为CSDN博主「Smile_ping」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/Smile_ping/article/details/102938322