微信小程序蓝牙控制开门

小程序低功耗蓝牙控制开门

整体流程

  1. 初始化蓝牙模块openBluetoothAdapter
  2. 获取本机蓝牙适配器状态getBluetoothAdapterState
  3. 搜索外围蓝牙设备startBluetoothDevicesDiscovery
  4. 监听寻找到新设备onBluetoothDeviceFound
  5. 连接蓝牙createBLEConnection
  6. 获取蓝牙设备的服务getBLEDeviceServices
  7. 获取服务中的特征值getBLEDeviceCharacteristics
  8. 启用特征值变化时的notify功能notifyBLECharacteristicValueChange
  9. 向蓝牙设备写入数据writeBLECharacteristicValue
  10. 关闭蓝牙模块closeBluetoothAdapter

1. 初始化蓝牙模块

  • 初始化蓝牙模块使用的是:wx.openBluetoothAdapter,初始化之前对蓝牙功能做一个判断,看手机微信版本是否支持此功能
  • 初始化之前需要关闭蓝牙模块:wx.closeBluetoothAdapter,否则容易搜索失败
var _this = this
if (!wx.openBluetoothAdapter) {
  wx.showModal({
    title: '提示',
    showCancel: false,
    content: '当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试',
  })
} else {
  wx.closeBluetoothAdapter({
    success: res => {
      wx.openBluetoothAdapter({ // 初始化蓝牙模块
        success: res => {
          console.log('初始化蓝牙成功')
          _this.getBluetoothAdapterState()
        },
        fail: err => {
          console.log(err)
        }
      })
    },
  })
}

2. 获取本机蓝牙适配器状态

  • 获取本机蓝牙适配器状态使用的是wx.getBluetoothAdapterState,调用成功后,会返回两个参数
    • discovering判断是否正在搜索设备
    • available判断蓝牙适配器是否可用
getBluetoothAdapterState: function(){
  var _this = this
  wx.getBluetoothAdapterState({
    success: res => {
      if (res.available == false) {
        wx.showToast({
          title: '设备无法开启蓝牙连接',
          icon: 'none',
          duration: 2000
        })
        wx.closeBluetoothAdapter()
      } else if (res.discovering == false) {
        _this.startBluetoothDevicesDiscovery() // 开启搜索外围设备
      } else if (res.available){
        _this.startBluetoothDevicesDiscovery() // 蓝牙适配器正常,去执行搜索外围设备
      }
    }
  })
}

3. 搜索外围蓝牙设备

  • 搜索外围蓝牙设备使用的是wx.startBluetoothDevicesDiscovery,连接设备后一定要使用wx.stopBluetoothDevicesDiscovery停止搜索
startBluetoothDevicesDiscovery: function(){
    var _this = this
    wx.startBluetoothDevicesDiscovery({
      allowDuplicatesKey: false,
      success: res => {
        if(!res.isDiscovering){ // 是否在搜索设备
          _this.getBluetoothAdapterState()
        }else{
          _this.onBluetoothDeviceFound() // 搜索成功后,执行监听设备的api
        }
      },
      fail: err => {
        console.log("蓝牙搜寻失败")
        wx.stopBluetoothDevicesDiscovery() // 没有搜索到设备
        wx.closeBluetoothAdapter() // 关闭蓝牙模块
      }
    })
}

4. 监听寻找到新设备

  • 监听寻找到新设备使用的是wx.onBluetoothDeviceFound,每搜到一个新设备就会触发一次,然后返回一个搜索到的设备列表,包含了设备名称和mac地址,一般都是使用设备名称和mac地址来匹配设备的
    • 安卓和IOS返回的deviceId不一样,安卓返回的是mac地址,IOS返回的是UUID,如果想通过mac地址来匹配设备,可以让mac地址存储在advertisData数据段中,然后解析这个数据段得到mac地址
    • 我使用的是通过设备名称来进行匹配
onBluetoothDeviceFound: function(){
  var _this = this
  wx.onBluetoothDeviceFound(res => {
    for(let i=0; i<res.devices.length; i++){
      if(res.devices[i].name == "设备名称" || res.devices[i].localName == "设备名称"){
        _this.setData({
          deviceId: res.devices[i].deviceId // 把匹配设备的deviceId存到data中
        })
        wx.stopBluetoothDevicesDiscovery() // 匹配到设备后关闭搜索
        _this.createBLEConnection() // 连接蓝牙
      }
    }
  })
}

5. 连接蓝牙

  • 连接蓝牙使用的是wx.createBLEConnection,连接蓝牙是通过deviceId连接,deviceId是通过wx.onBluetoothDeviceFound获取的
  • 连接蓝牙容易失败,所以可以定一个变量count用来计算连接的次数,如果超出特定的次数就判断为连接失败,关闭蓝牙模块
createBLEConnection: function () { // 连接低功耗蓝牙
  var _this = this
  wx.createBLEConnection({
    deviceId: _this.data.deviceId,
    success: res => {
      _this.getBLEDeviceServices()
    },
    fail: err => {
      console.log("连接失败")
      if( count < 6 ){
        count++
        _this.createBLEConnection()
      }else{
        wx.closeBluetoothAdapter() // 连接失败关闭蓝牙模块
      }
    }
  })
}

6. 获取蓝牙设备的服务

  • 获取蓝牙设备的服务列表使用的是wx.getBLEDeviceServices
  getBLEDeviceServices: function () {
    var _this = this
    wx.getBLEDeviceServices({
      deviceId: _this.data.deviceId,
      success: res => {
        for(let i=0; i<res.services.length; i++){
          // 如果提前得知可以直接判断,如果不知道可以用蓝牙工具看一下服务所需的功能
          if(res.services[i].uuid == _this.data.service){
            _this.setData({
              serviceId: res.services[i].uuid
            })
            _this.getBLEDeviceCharacteristics()
          }   
        }
      },
      fail: err => {
        console.log("获取服务失败")
        wx.closeBluetoothAdapter() // 关闭蓝牙模块
      }
    })
  },

7. 获取服务中的特征值

  • 获取服务中的特征值使用的是wx.getBLEDeviceCharacteristics
  getBLEDeviceCharacteristics: function () { // 获取服务中的特征值
    var _this = this
    wx.getBLEDeviceCharacteristics({
      deviceId: _this.data.deviceId,
      serviceId: _this.data.serviceId,
      success: res => {
        for(let i=0; i<res.characteristics.length; i++){
          let model = res.characteristics[i]
          if ((model.properties.notify || model.properties.indicate) && (model.properties.read && model.properties.write)){
            _this.setData({
              characteristicId: model.uuid
            })
            _this.notifyBLECharacteristicValueChange()
          }
        }
      },
      fail: err => {
        console.log("获取服务中的特征值失败")
        wx.closeBluetoothAdapter() // 关闭蓝牙模块
      }
    })
  },

8. 启用特征值变化时的notify功能

  • 启用特征值变化时的notify功能使用的是wx.notifyBLECharacteristicValueChange
notifyBLECharacteristicValueChange: function () { // 启用蓝牙特征值变化时的notify功能
    var _this = this
    wx.notifyBLECharacteristicValueChange({
      deviceId: _this.data.deviceId,
      serviceId: _this.data.serviceId,
      characteristicId: _thisa.characteristicId,
      state: true,
      success: res => {
        wx.onBLECharacteristicValueChange(res => {
            console.log(如果要打印需要从arraybuffer格式转为字符串或16进制)
        })
        _this.writeBLECharacteristicValue() // 向蓝牙设备写入数据
      },
      fail: err => {
        console.log("启用BLE蓝牙特征值变化时的notify功能错误")
        wx.closeBluetoothAdapter() // 关闭蓝牙模块
      }
    })

9. 向蓝牙设备写入数据

  • 向蓝牙设备写入数据wx.writeBLECharacteristicValue,这时候就是输入提前设定好的指令
  writeBLECharacteristicValue: function () { // 向蓝牙设备写入数据
    var _this = this
    wx.writeBLECharacteristicValue({
      deviceId: _this.data.deviceId,
      serviceId: _this.data.serviceId,
      characteristicId: _this.data.characteristicId,
      value: buffer, // 这个输入的指令,需要转换成ArrayBuffer
      success: res => {
        console.log("成功")
        wx.closeBluetoothAdapter() // 关闭蓝牙模块
      },
      fail: err => {
        console.log("输入指令失败")
        wx.closeBluetoothAdapter() // 关闭蓝牙模块
      }
    })
  }

转换格式

  • 字符串转为arraybuffer
string2buffer: function (str) {
    // 首先将字符串转为16进制
    let val = ""
    for (let i = 0; i < str.length; i++) {
      if (val === '') {
        val = str.charCodeAt(i).toString(16)
      } else {
        val += ',' + str.charCodeAt(i).toString(16)
      }
    }
    // 将16进制转化为ArrayBuffer
    return new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {
      return parseInt(h, 16)
    })).buffer
}
  • arraybuffer转为字符串
function ab2str(u,f) {
   var b = new Blob([u]);
   var r = new FileReader();
    r.readAsText(b, 'utf-8');
    r.onload = function (){if(f)f.call(null,r.result)}
}

蓝牙遇见的坑

  • 1.苹果手机有时候输入指令会显示发送成功,但是设备并没有反应
    • 解决方法:把需要输入的指令改成每10毫秒输入一个字节
    • 如果改成每10毫秒输入一个字节,安卓手机就会频繁出现10008错误
    • 针对这个问题我用了一个不太好的方法,我判断了一下手机的类型,如果是ios的就分10毫秒输入,如果是安卓的就一次性输入
  • 2.在调用wx.onBluetoothDeviceFound这个api时ios会监听两次,然后就会导致最后设备会有两次指令输入
    • 解决方法:我在搜索蓝牙设备之前做了一个定时器,然后用getBluetoothDevices来查看所有已搜索到的蓝牙,在这个里面做判断来连接蓝牙设备
  • 我上面的步骤没有把这些坑的解决步骤加上,如果碰见此类问题,可以自己在合适的位置修改一下

二维码

我自己做了一个小程序的蓝牙调试器,下面是小程序码,欢迎大家体验
在这里插入图片描述

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值