微信小程序:蓝牙通讯,搜索、发送与接收

需求背景

使用微信小程序,通过蓝牙与硬件设备产品进行交互

参考文档

微信小程序蓝牙通讯

开始

1.初始化蓝牙

initBlue: function () {
    var that = this
    wx.openBluetoothAdapter({
      success: function (res) {
        that.findBlue()
      },
      fail: function (res) {
        wx.showToast({
          title: '请打开手机蓝牙!',
          icon: 'none',
          duration: 2000
        })
      }
    })
  }

2.查找蓝牙

findBlue() {
    var that = this
    wx.startBluetoothDevicesDiscovery({
      allowDuplicatesKey: false,
      interval: 0,
      success: function (res) {
        that.getBlue()
      }
    })
  },

  getBlue() {
    var that = this
    var searchResult = false
    var index = 0

    wx.showLoading({
      title: '搜索设备...',
    })

    //定时搜索
    var interval = setInterval(function () {
      wx.getBluetoothDevices({
        success: function (res) {
          index = index + 1
          if (!searchResult) {
            for (var i = 0; i < res.devices.length; i++) {
              //根据设备名称匹配   这里的meterId是需要匹配的设备名称
              if ((res.devices[i].name + "").substr(0, 16) == that.data.meterId ||
                (res.devices[i].localName + "").substr(0, 16) == that.data.meterId) {
                that.setData({
                  //获取蓝牙设备的deviceId
                  deviceId: res.devices[i].deviceId,
                })

                searchResult = true
                if (searchResult) {
                  clearInterval(interval)
                }
                //连接蓝牙
                that.connetBlue(res.devices[i].deviceId)
                return
              }
            }
          }

          if (index > 20) {
            clearInterval(interval)
            wx.hideLoading()
            wx.showToast({
              title: '未找到设备,请重试!',
              icon: 'none',
              duration: 2000
            })
            wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
          }
        }
      })
    }, 500)
  }

3.连接蓝牙设备

connetBlue(deviceId) {
    var that = this

    wx.hideLoading()
    wx.showLoading({
      title: '连接设备...',
    })

    wx.createBLEConnection({
      deviceId: deviceId,
      success: function (res) {
        wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
        that.getServiceId() //获取服务ID
      },
      fail: function () {
        wx.hideLoading()
        wx.showToast({
          title: '连接设备失败!',
          icon: 'none',
          duration: 2000
        })
        wx.stopBluetoothDevicesDiscovery() //关闭蓝牙搜索
      }
    })
  },

  getServiceId() {
    var that = this
    wx.getBLEDeviceServices({
      deviceId: that.data.deviceId,
      success: function (res) {
        var model = res.services[0]
        that.setData({
          serviceId: model.uuid
        })
        that.getCharacteId()
      }
    })
  },

  getCharacteId() {
    var that = this

    wx.getBLEDeviceCharacteristics({
      deviceId: that.data.deviceId,
      serviceId: that.data.serviceId,
      success: function (res) {
        for (var i = 0; i < res.characteristics.length; i++) {
          var model = res.characteristics[i]
          if (model.properties.notify == true) {
            that.setData({
              notifyId: model.uuid
            })

            //重点:开启监听服务。监听设备数据变化
            that.startNotice(model.uuid)
          }
          if (model.properties.write == true) {
            that.setData({
              writeId: model.uuid
            })
          }
        }

        //有可写权限
        if (that.data.writeId != '') {
          wx.hideLoading()
          wx.showLoading({
            title: '通讯中...',
          })

          //这里可以完成需要下发到设备上的指令的生成
          that.sendCmd(value)
        } else {
          wx.showToast({
            title: '失败: 设备无写入权限!',
            icon: 'none',
            duration: 2000
          })
        }
      }
    })
  }

4.发送数据

 sendCmd(cmdValue) {
    var that = this

    if (cmdValue != '' && cmdValue != null && cmdValue != undefined) {
      that.writeCharacterToDevice(util.stringToArrayBuffer(cmdValue))
    } else {
      wx.showToast({
        title: '获取设备指令失败',
        icon: 'none',
        duration: 2000
      })
    }
  }

 writeCharacterToDevice(buffer) {
    var that = this

    wx.writeBLECharacteristicValue({
      deviceId: that.data.deviceId,
      serviceId: that.data.serviceId,
      characteristicId: that.data.writeId,
      value: buffer,
      fail: function () {
        wx.showToast({
          title: '写入设备数据失败!',
          icon: 'none',
          duration: 2000
        })

      },
      success: function () {
        wx.showLoading({
          title: '指令发送成功',
          duration: 2000
        })
      }
    })
  }

5.工具函数


  function stringToArrayBuffer(str) {
  var bytes = new Array();
  var len, c;
  len = str.length;
  for (var i = 0; i < len; i++) {
    c = str.charCodeAt(i);
    if (c >= 0x010000 && c <= 0x10FFFF) {
      bytes.push(((c >> 18) & 0x07) | 0xF0);
      bytes.push(((c >> 12) & 0x3F) | 0x80);
      bytes.push(((c >> 6) & 0x3F) | 0x80);
      bytes.push((c & 0x3F) | 0x80);
    } else if (c >= 0x000800 && c <= 0x00FFFF) {
      bytes.push(((c >> 12) & 0x0F) | 0xE0);
      bytes.push(((c >> 6) & 0x3F) | 0x80);
      bytes.push((c & 0x3F) | 0x80);
    } else if (c >= 0x000080 && c <= 0x0007FF) {
      bytes.push(((c >> 6) & 0x1F) | 0xC0);
      bytes.push((c & 0x3F) | 0x80);
    } else {
      bytes.push(c & 0xFF);
    }
  }
  var array = new Int8Array(bytes.length);
  for (var i in bytes) {
    array[i] = bytes[i];
  }
  return array.buffer;
}

function arrayBufferToString(arr) {
  if (typeof arr === 'string') {
    return arr;
  }
  var dataview = new DataView(arr);
  var ints = new Uint8Array(arr.byteLength);
  for (var i = 0; i < ints.length; i++) {
    ints[i] = dataview.getUint8(i);
  }
  arr = ints;
  var str = '',
    _arr = arr;
  for (var i = 0; i < _arr.length; i++) {
    var one = _arr[i].toString(2),
      v = one.match(/^1+?(?=0)/);
    if (v && one.length == 8) {
      var bytesLength = v[0].length;
      var store = _arr[i].toString(2).slice(7 - bytesLength);
      for (var st = 1; st < bytesLength; st++) {
        store += _arr[st + i].toString(2).slice(2);
      }
      str += String.fromCharCode(parseInt(store, 2));
      i += bytesLength - 1;
    } else {
      str += String.fromCharCode(_arr[i]);
    }
  }
  return str;
}

6.开启事件监听

  /**
   * 监听水表数据变化
   * @param {水表ID} uuid 
   */
  startNotice(uuid) {
    var that = this

    wx.notifyBLECharacteristicValueChange({
      state: true, // 启用 notify 功能
      deviceId: that.data.deviceId,
      serviceId: that.data.serviceId,
      characteristicId: uuid,
      success: function (res) {
        var deviceResult = ''
        //特征数据变化
        wx.onBLECharacteristicValueChange(function (res) {
          deviceResult = deviceResult + util.arrayBufferToString(res.value) //应答数据比较长,会触发多次
          //如果应答帧总长度大于数据包长度,并且包含“16”,则说明是完整的应答帧
          if (deviceResult.lastIndexOf('16') >= (deviceResult.length - 8) && deviceResult.indexOf('68') >= 0) {
            //解析应答帧  这里开始对设备应答数据进行处理了
            
            deviceResult = ''
          }
        })
      }
    })
  },

设备应答数据也可以发送到后台服务进行处理,根据具体业务而定

上一篇:统计学习方法-感知机+手写代码


下一篇:GUI信息收集