记录微信小程序与蓝牙设备的通信

1,034 阅读6分钟

不取花里胡哨的标题了,到时候搜索关键词找不到该找的。开门见山

领导:“我们要做一个蓝牙经络仪的小程序,很急,你们搞一下”,急急国王都没这么急,不懂为什么每次项目都催得那么急。 项目具体是个什么情况呢?6月5号开始说起项目,6月30号之前要完成,一个微信小程序、一个后台管理系统,后台系统比较简单,只有数据的增删改查。难点都在小程序,后端4人,人均4个接口;前端2人,人均一个系统🙂;我单人通关小程序,等到我可以正式开始做了是6月12号,设计图基本完成。算了下日子,还有13天,好家伙一个月周期,真正开发的时间13天,中间指定害得出岔子。

行了不废话了,主要是记录下中间的步骤以及踩的坑。 1、首先自然是蓝牙的初始化,需要小程序获取蓝牙授权的过程wx.getSetting(),回调中判断是否有'scope.bluetooth'属性,'scope.bluetooth'属性存在,且为false则需要调用授权引导用户打开小程序蓝牙,如果存在则后续不再弹窗。

image.png

image.png

2、第二步正式进入蓝牙对接环节,建议先查看微信官方的文档,因为他们经常改动。首先需要调用 wx.openBluetoothAdapter() 初始化,同意需要进行判断,手机蓝牙是否开启,如果开启直接调用下一步开始搜索,如果未开启,需要手动开启,安卓手机能直接调用手机蓝牙开关,苹果不能,所以全部采用引导的方式打开蓝牙,回到页面我采用的是下拉刷新重新初始化判断是否成功。tips:在这一步就可以思考是否应该记住上次连接的设备,下次初始化后直接连接不用搜索,于是留了一手,将deviceId存了下来,有就不搜索了,自动连接,没有就重新搜索。

3、蓝牙搜索 wx.startBluetoothDevicesDiscovery() ,(搜索比较耗费系统资源,需要在搜索到之后调用停止搜索wx.stopBluetoothDevicesDiscovery())。 wx.startBluetoothDevicesDiscovery() 接收 services、allowDuplicatesKey、interval、powerLevel、success等几个主要是参数,全部都不是必填,大家可以对着看啥意思,反正我就写了个success回调(doge),在搜索过程中需要调用 wx.onBluetoothDeviceFound() 监听搜索到的设备,大概率会搜到很多不带名称的设备,我的做法是直接忽略不带名字的设备 if (!device.name && !device.localName) return ;带名字的全都push进数组在弹框中展示。这步也可以做个筛选,设置uuid参数,则只搜索广播包有对应 UUID 的主服务的蓝牙设备,可以跟设备工程师对接。

4、蓝牙连接 wx.createBLEConnection(),终于到了激动人心的一步了,要连上了!两个主要参数:deviceId(之前搜索到的设备中会返回deviceId),与success回调。一次成功,就这?后来发现坑在这,因为第一次对接蓝牙通信不懂,设备id是唯一的,但是!通过不同手机搜索到的同一个蓝牙设备返回的deviceId居然不同,之前完全没想到。在下一步之前需要判断该蓝牙设备与用户绑定的关系,我不得不在此就与蓝牙建立通信,获取设备信息。(下一步展示)。别急还有,当你连接设备成功后,返回上一个页面再回到此页面又会发现奇妙的现象,重新调用蓝牙初始化,直接报错了,为什么?因为你之前没有断开连接,你又接着连,能不报错🐎,行吧,断就断呗。onUnload中调用 wx.closeBLEConnection(),完事。

5、蓝牙通信

image.png

先上图,看到头都大了,先理一下思路。我需要先建立与蓝牙设备之前的通信,然后... 然后我该从哪里切入...麻了。 从建立通信开始吧, 1、wx.getBLEDeviceServices() 通过deviceId获取蓝牙特征对应服务的 UUID(serviceId), 2、wx.getBLEDeviceCharacteristics(),通过deviceId和serviceId获取characteristicId, 3、wx.notifyBLECharacteristicValueChange,通过deviceId、serviceId和characteristicId开启监听。

好家伙,套娃呢。还不止套娃这么简单,获取serviceID时,大概率会返回多个带uuid的数组,选哪个呢?你问我我问谁?看了许多官方的问答才知道,这步需要问设备工程师是哪个uuid,而且安卓可能会自带1800 1801 180A 1802(uuid的第4-8位)编号的uuid,筛除掉这些就行了,一堆人在问答区提问说为什么安卓比苹果的返回的多,只有一个回答说到点了,得亏我提前看到了。

数据长这样 { "services": [{ "uuid": "00001800-0000-1000-8000-00805F9B34FB", "isPrimary": true }, { "uuid": "00001801-0000-1000-8000-00805F9B34FB", "isPrimary": true }, { "uuid": "0000180A-0000-1000-8000-00805F9B34FB", "isPrimary": true }, { "uuid": "0000FFF0-0000-1000-8000-00805F9B34FB", "isPrimary": true }, { "uuid": "0000FFE0-0000-1000-8000-00805F9B34FB", "isPrimary": true }], "errMsg": "getBLEDeviceServices:ok" }

同样获取characteristicId也会返回多个,查看其中,notify或者indicate为true的characteristicId就能实现监听,注意是监听,后续如果想要给蓝牙设备发信息,需要write为ture的那一组characteristicId。

数据长这样 { "characteristics": [{ "uuid": "0000FFE1-0000-1000-8000-00805F9B34FB", "properties": { "read": true, "write": true, "notify": true, "indicate": false } }], "errMsg": "getBLEDeviceCharacteristics:ok" }

监听实现了,还需要在监听成功后调用 wx.onBLECharacteristicValueChange(),所有蓝牙设备的广播,都只能在这个方法的回调中接收。把监听蓝牙设备状态也一起整上 wx.onBLEConnectionStateChange()

到这一步了,怎么告诉蓝牙我需要数据呢? wx.writeBLECharacteristicValue()wx.readBLECharacteristicValue() 前端需要传值,后者只需要读取蓝牙设备广播的值,我这里需要传值给设备,所以调用writeBLECharacteristicValue,必传参数为deviceId、serviceId、characteristicId、value,这里characteristicId需要write属性为true的那一组!如果没有,需要跟设备方沟通。value是传给蓝牙设备的值,设备方给我提供了指令,不同穴位有不同的指令,全部为16进制数据,这里value只能传Arraybuffer类的数据,所以需要将16进制转成Arraybuffer,官方有示例。

当你传过去成功了,设备不一定收到了,检查设备是否有反应,如果没反应,还是那句,再问问设备方,大概率是传输数据不对。成功后在 wx.onBLECharacteristicValueChange() 会调用,我这里会返回10次数据,我取了最后一次的,接收数据时传过来的也是Arraybuffer,需要转成16进制数据,然后读取,设备方会告诉你数据格式。16进制再转成10进制就能看懂了。 用进度条的方式告诉用户此次检测已完成。如果是自动检测,则继续下一次通信。手动则每次都是点击开始检测就发送指令。

到此整个蓝牙通信已完成。踩了很多坑,分享记录一下,以前没有记录的习惯,写完就忘。

废话很多,写的不好或者遗漏、错误的地方望指正,互相学习!