小程序开发中的蓝牙使用

1|0前言

公司项目,一个在鸿蒙的华为运动健康,一个在微信小程序,外接我们的产品,经过两个项目的洗礼,也算是对蓝牙连接有了一些理解,在此记录(以微信小程序为例,总体流程是基本一样的,只是调的api会不同,一些细节可能又略微不同)

2|0整体流程梳理

  1. 初始化蓝牙适配器、获取本机蓝牙状态
  2. 搜索设备、监听发现新设备
  3. 建立连接
  4. 初始化已连接的设备的蓝牙事件
    4.1 注册连接状态改变的回调
    4.2 注册适配器状态改变的回调
    4.3 启用notify开始监听
  5. 操作设备,发送指令
  6. 在回调中监听蓝牙设备对接收到的指令的应答处理
  7. 蓝牙协议中服务UUID和特征值UUID的说明

3|0初始化

  • 初始化蓝牙适配器:什么是蓝牙适配器?它其实是一个硬件,在短距离无线通信中,作为接口转换器,像我们日常用的无线鼠标和无线键盘,其实现技术就有wifi和蓝牙还有ZigBee这些,其中蓝牙无线鼠标不都有一个USB接口的东西嘛,那个其实就是一个简易的蓝牙适配器,通常情况,台式电脑是不会自带蓝牙适配器的,笔记本有些会自带,就因为没有蓝牙适配器,所以在电脑上跑代码的时候,就一般都无法连蓝牙,而且是直接在初始化蓝牙适配器这第一步就报错。
  • 所以初始化蓝牙适配器可以理解为检测当前设备是否有蓝牙适配器,必须有,才能进行后续操作,所以在小程序中,必须在调用了wx.openBluetoothAdapter()并成功之后,才能调用其他api
  • 获取本机蓝牙状态,初始化蓝牙适配器成功后,也就是检测到当前设备支持蓝牙了,然后就要获取本机的蓝牙是否打开,毕竟要打开蓝牙才能连接设备嘛
    const that = this wx.getBluetoothAdapterState({ success: function (res) { console.log("本机蓝牙适配器状态:" + res.available) that.setData({ adapterState: res.available // 蓝牙可用状态存起来 }) }, fail:function(err){ console.log("提醒用户打开蓝牙") } })
  • 好了,基本的准备工作就这两个了,所以就是两个api,wx.openBluetoothAdapterwx.getBluetoothAdapterState调一下,成功了就可以进行后续了

4|0搜索设备

  • 当一个蓝牙设备没有被连接时,它就会持续的向外界发送信号,告诉外界它正空闲,快去连它,但是如果它连了设备,就不会被其他设备发现了。
  • 所以搜索设备就是打开一个雷达,去找附近正在“求救”的设备,调用wx.startBluetoothDevicesDiscovery打开雷达,wx.onBluetoothDeviceFound处理雷达里出现的设备
    const that = this wx.startBluetoothDevicesDiscovery({ success: function (res) { //成功启动后开始监听新设备发现 wx.onBluetoothDeviceFound((res) => { that.setData({ devicesDiscovered: that.data.devicesDiscovered.concat(res.devices.filter(item => { // 这里我们可以过滤一下不想查看的设备,只留下设备名里带‘test’,且未在已发现设备列表中的 return item.name.match(/(test)/) && that.isInDevicesDiscovered(item) })) }) }) } })
  • 在连接设备之前,别忘了还要停止搜索,并停止监听新设备的发现,调用wx.stopBluetoothDevicesDiscovery关闭雷达,wx.offBluetoothDeviceFound停止发现新设备
    wx.stopBluetoothDevicesDiscovery({ success: function (res) { wx.offBluetoothDeviceFound() } })

5|0连接设备

  • 首先在上面发现的设备中,设备信息中都是包含有deviceId的,也就是设备的sn号,连接设备就是通过sn号进行连接。
  • 然后调wx.createBLEConnection建立连接
    const that = this wx.showLoading({ title: "正在连接...", mask: true }) wx.createBLEConnection({ // targetIndex是目标连接设备在devicesDiscovered中的index deviceId: that.data.devicesDiscovered[targetIndex].deviceId, success: function (res) { console.log(res) that.setData({ device_sn: that.data.devicesDiscovered[e.currentTarget.id].deviceId }) //连接成功后初始化蓝牙事件 that.initBleListeners() }, fail: function () { wx.showToast({ title: '连接失败', duration: 1500, icon: "error" }) }, complete: function(){ wx.hideLoading() } })

6|0监听蓝牙事件

  • 上面设备连接成功之后,就开始初始化蓝牙事件that.initBleListeners(),但是蓝牙事件的初始化也是分步骤的
  • 需要先注册事件回调,然后再启用notify功能,就开始监听了
    initBleListeners() { //注册连接状态改变的回调 wx.onBLEConnectionStateChange(this.bleConnectionStateCallback) //注册适配器状态改变的回调 wx.onBluetoothAdapterStateChange(this.bluetoothAdapterStateCallback) //启用notify功能 that.enableNotifyAndIndicate() }, //启用蓝牙低功耗设备特征值变化时的 notify 功能,订阅特征 enableNotifyAndIndicate() { let that = this wx.notifyBLECharacteristicValueChange({ deviceId: that.data.macAddress, serviceId: globalData.SERVICE_ID, characteristicId: globalData.NOTIFY_CHARACTERISTIC_ID, state: true, // 表示是否启用notify,传true success: () => { console.log('Enable notify and indicate success!') }, fail: (code, err) => { console.log("notify failed! code:" + code) console.log(err) //重新启用 that.enableNotifyAndIndicate() } }) }
  • 这里传的参数serviceId和characteristicId什么意思呢?文章最后说明
  • 有些时候启用会失败,至于为什么会失败,笔者没有搞明白,所以只能尝试重新启用,就一般就能启用成功了

7|0蓝牙指令

  • 启用了蓝牙事件监听之后,就能对设备发送指令,与设备进行通讯了。notify是“通知”的意思,所以启用notify功能可以理解位让设备进入服务应答状态
  • 至于发送指令的形式就是根据自己公司设备的蓝牙协议来定了。这里笔者只简单讲下发送指令的流程
    • 首先根据蓝牙协议确认指令,你得先知道你想要进行的操作对应的是哪个设备型号的哪个指令,指令格式、指令参数等信息,这些协议里肯定都有,只是需要你去确认
    • 然后就是生成指令包,let cmd = BTSDK.sendCommand("f1", this.data.type, []),一般协议里都会规定包头、指令类型、data段、校验码等指令格式,按着来就行
    • 指令cmd生成好了,就可以写入指令了BTSDK.writeCharacter(cmd, this.data.macAddress),这里需要根据蓝牙协议规定的是字节流还是比特流进行数据传输来给cmd转一下格式,而在小程序中,在调wx.writeBLECharacteristicValue接口写入的时候都需要用string2buffer()再转一下才能正常写入,这也是小程序与鸿蒙那边的不同,鸿蒙是不用转二进制的
      writeCharacter(cmd, deviceId){ let value = cmd let that = this if(cmd.substr(0,2)!='A5'){ value = parseInt(cmd,16) } // wx.writeBLECharacteristicValue和其他不同的地方在于,它的value是ArrayBuffer型变量,所以要把value从16进制转换为二进制 wx.onBLECharacteristicValueChange(this.bleCharacteristicChangeCallback) wx.writeBLECharacteristicValue({ deviceId: deviceId, serviceId: globalData.SERVICE_ID, characteristicId: globalData.WRITE_CHARACTERISTIC_ID, value: string2buffer(value), // 写入的指令特征值 success: function(e){ console.log("success,errorCode:", + e.errCode + "," + e.errMsg) }, error(e){ console.log("success,errorCode:", + e.errCode + "," + e.errMsg) } }) }
    • 注意,在写入特征值之前,还要先注册特征值变化的监听回调wx.onBLECharacteristicValueChange(this.bleCharacteristicChangeCallback)
  • 写入了特征值即指令之后,最后就要处理监听到的设备接收到指令后的应答了

8|0监听设备应答

  • 由于肯定是有很多种指令的,但是每个指令我们都是通过同样的封装发给设备的,所以在监听到后,返回的数据包里是应该包含该数据包是应答哪个指令的说明的,这个在协议里会说明,所以在BTSDK里我们要做的就是根据数据包说明的指令类型进行分类处理。
  • 而分类处理的重点就是对数据流的解码处理,同样根据协议而来,比如数据流的第 i 到 i+2 个字节表示什么,一段数据包的头标志,每个数据包的最长长度是多少等等。

9|0额外说明

  • 什么是UUID
    • 简单来说就是国际标准组织定义的,用来标识蓝牙硬件设备服务类型和特征值的一个属性值。至于这个值的由来、唯一性、对应什么服务等信息,可自行查找
  • 服务UUID和特征UUID的区别
    • 服务是指一个蓝牙设备能够提供的服务种类,是比较大的一个面,如:拨号网络服务、蓝牙串口服务、文件读写服务等等,更像是在说明这个设备具备哪些能力,而这些能力具体怎么使用,就需要结合特征UUID
    • 特征值是指对蓝牙设备的某个参数的读、写、通知等操作,比如设备的电量、温度等基本信息就是对应了不同的特征值,但是这种基本信息其实可以归为一类,所以服务也可以理解为特征值的一个类,即服务包含特征值。

__EOF__

本文作者Mizuki
本文链接https://www.cnblogs.com/mizuki-vone/p/16409282.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Mizuki-Vone  阅读(1963)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· [翻译] 为什么 Tracebit 用 C# 开发
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 刚刚!百度搜索“换脑”引爆AI圈,正式接入DeepSeek R1满血版
点击右上角即可分享
微信分享提示