最近的项目是做一个通过蓝牙控制开关的小程序,看了很多写的很详细全面的博客,不过自己还是有点混混沌沌的。现在自己总结一下小程序运行代码的大致流程,也能整理一下思路。

一、蓝牙的介绍:

蓝牙的类型

  小程序提供的API都是针对“BLE低功耗蓝牙 ”,这种蓝牙有区别与我们手机的蓝牙功能,特点是特点就是耗电极低、传输速度更快,常用在对续航要求较高且只需小数据量传输的各种智能电子产品中。

蓝牙的工作模式

  根据低功耗蓝牙协议为设备定义了若干角色,比较重要的角色便是“外围设备”和“中心设备”。

外围设备是用来提供数据,通过不停的向外广播数据,使中心设备在扫描的时候能够发现自己并连接。中心设备扫描到外围设备可以与之建立连接,然后使用外围设备提供的服务(Service),利用外围设备提供的数据进行处理或展示等。而我们用到的小程序接口默认设定手机为中心设备。

通信协议

  两个蓝牙设备建立连接后,双方的数据交互式基于一个叫做GTAA(Generic Attribute Profile)的规范,根据该规范可以定义出不同的配置文件(Profile)描述该蓝牙设备提供的服务。

  配置文件(Profile)、服务(Service)、特性(ChriCharacteristic)是通信过程中比较重要的三个概念:

  Profile是被蓝牙标准预先定义的一些Service的集合,一个蓝牙可以支持多种Profile,当两个蓝牙设备支持相同的Profile,便能兼容。

  Service是一个功能的合集,一个设备可以提供多个服务,而每一个service都有一个16bit或128bit的UUID作为唯一识别。蓝牙的UUID共用了一个基本的UUID:0x0000xxxx-0000-1000-8000-00805F9B34FB。所以16 bit 的 UUID 实际上是 128 bit 的缩短版,代替xxxx部分,接收方收到后会补上蓝牙的 UUID 基数,目的是为了提高传输效率。

  Characteristic是存在于Service中的独立数据项,由一个 value 和多个描述特性的 Desciptor 组成。同样有一个16bit或128bit的UUID作为标识。而设备之间的交互便是通过对value的读写完成的。我们通过蓝牙发送给数据给外围设备就是往Characteristic的value字段写入数据;外围设备发送数据给手机就是监听这些 Charateristic 中的 Value 字段有没有变化,如果发生了变化,手机的接口就会收到一个监听的回调。

二、搜索设备

检查蓝牙是否打开

  首先利用wx.openBluetoothAdapter(OBJECT)初始化蓝牙模块,在用户蓝牙开关未开启或者手机不支持蓝牙功能的情况下,调用wx.openBluetoothAdapter会返回错误,表示手机蓝牙功能不可用;

  在数据传输后调用wx.closeBluetoothAdapter(OBJECT)来使关闭蓝牙模块使其处于未初始化的状态,断开所有已经建立的连接并释放系统资源。

  可以用wx.onBluetoothAdapterStateChange接口看蓝牙适配器的状态,avavaliable属性是表示蓝牙适配器是否可用,discovering属性是表示蓝牙适配器是否处在搜索状态。

wx.openBluetoothAdapter({
        success: function (res) {
          console.log("初始化蓝牙适配器成功")
          wx.onBluetoothAdapterStateChange(function (res) {
            console.log("蓝牙适配器状态变化", res)
            })
          })

 

开启蓝牙搜索

  调用wx.startBluetoothDevicesDiscovery接口开始搜索附近的蓝牙外围设备。

  该操作比较耗费系统资源,在搜索并连接设备后应该调用wx.stopBluetoothDevicesDiscovery接口停止搜索。

wx.startBluetoothDevicesDiscovery({
        success: function (res) {
          console.log("开始搜索附近蓝牙设备")
          console.log(res)
        }
      })

  wx.onBluetoothDeviceFound接口用来监听寻找到新设备的事件,可以在此做一些过滤,比如根据设备名字或者设备的UUID来寻找指定的设备。在此我将所有找到的设备放在一个数组中方便调用数组在界面展示找到的设备。

wx.onBluetoothDeviceFound(function (res) {
            var devices = res.devices;
            console.log(devices)
            temp = temp.concat(devices)
            console.log("temp:", temp);
            that.setData({
              devices: temp
            })
            console.log('发现新蓝牙设备')
            console.log('设备id' + devices[0].deviceId)
            console.log('设备name' + devices[0].name)
          })

三、连接设备

  调用wx.createBLEConnection接口通过传入deviceId连接设备

wx.createBLEConnection({
        deviceId: id,
        success: function (res) {
          wx.hideLoading()
          wx.showToast({
            title: '连接成功',
            icon: 'success',
            duration: 1000
          })
})

四、数据交互

连接后就可以调用wx.getBLEDeviceServices获取设备的服务列表和wx.getBLEDeviceCharacteristics获取特征值

wx.getBLEDeviceServices({
            deviceId:id,//传入连接设备的ID
            success(res) {
              console.log('device services:', res.services);
              var services = res.services;
              for(var i=0;i<services.length;i++){
                var service = services[i];
                wx.getBLEDeviceCharacteristics({
                  deviceId:  id,
                  serviceId: service.uuid,
                  success: function(res) {
                    console.log(service,res);
                  },
                })
              }
            }
          })

用支持notify的设备特征值调用wx.notifyBLECharacteristicValueChange接口,接收设备推送的notification。

wx.notifyBLECharacteristicValueChanged({
            deviceId: that.data.connectedDeviceId,
            serviceId: serviceId,
            characteristicId: characteristicId,
            success: function (res) {
              console.log("启用notify");
              callback('open');
            },
            fail: (res) =>{
              console.log("启用notify失败:",res);
            }
          })

用支持write的设备特征值调用wx.writeBLECharacteristicValue接口写入数据。

wx.writeBLECharacteristicValue({
      deviceId: id,
      serviceId: serviceId,
      characteristicId: characteristicId,
      value: data,//写入数据
      success: function(res) {
        console.log(res);
        console.log('writeBLECharacteristicValue success', res.errMsg);
      },
      fail: function(res) {
        console.log(res);
      }
    })