小程序蓝牙连接低功耗设备(BLE)记录

第一步 查询是否授权蓝牙 授权后初始化蓝牙 获取本机蓝牙状态 开启监听蓝牙开启关闭事件 若不调用openBluetoothAdapter方法 下面无法进行

代码中bluetooth 为封装的一些公共方法 会写在最下面

bluetooth.getBluetoothSetting().then(() => {
      //已授权 初始化蓝牙模块
      wx.openBluetoothAdapter({
        success: () => {},
        fail: err => bluetooth.errorCodeToStr(err),
        complete: () => {
          wx.hideLoading()
          this.setData({
            bluetoothInit: true
          })
          // 获取本机蓝牙适配器状态。
          wx.getBluetoothAdapterState().then(res => {
            this.setData({
              bluetoothAvailable: res.available,
            })
          }).catch(err => bluetooth.errorCodeToStr(err))
          // 监听蓝牙适配器状态变化事件 是否开启蓝牙
          wx.onBluetoothAdapterStateChange((res) => {
            let page = getCurrentPages()
            if (page[page.length - 1].route != 'pages/index/index') return
            wx.showToast({
              title: '蓝牙已' + (res.available ? '开启' : '关闭'),
              icon: 'none'
            })
            this.setData({
              bluetoothAvailable: res.available,
            })
          })
        }
      })
    }).catch(err => {
      wx.showToast({
        title: err,
        icon: 'none'
      })
    })

第二步 搜索低功耗蓝牙设备 和停止搜索 搜索到的设备添加到列表 点击列表选择想要连接的蓝牙设备 (列表点击事件没写 自己写就行)

let timer=null  
// 开始搜索蓝牙设备 10秒后自动停止 也可以手动停止搜索
  starSearch() {
    wx.hideLoading()
    wx.startBluetoothDevicesDiscovery({
      allowDuplicatesKey: false
    }).then(res => {
      this.setData({
        status: 1
      })
      // 定时结束搜索
      timer = setTimeout(() => {
        this.stopSearch()
      }, 10000)
    }).catch(err => bluetooth.errorCodeToStr(err))
    // 监听搜索到新设备的事件 添加到列表
    wx.onBluetoothDeviceFound((res) => {
      var devices = res.devices[0];
      if (devices.name) {
        this.setData({
          list: [...this.data.list, devices]
        })
      }
    })
  },
  // 停止搜索(可手动调用)
  stopSearch() {
    wx.hideLoading()
   //清除计时器
    clearTimeout(timer)
   //取消监听寻找到新设备的事件
    wx.offBluetoothDeviceFound()
    //停止搜寻附近的蓝牙外围设备 判断设备数量做出提示
    wx.stopBluetoothDevicesDiscovery().then(res => {
      let status = (this.data.list.length < 1 ? 2 : 3)
      this.setData({
        status: status
      })
      if (status == 2) {
        wx.showModal({
          title: '提示',
          content: '未检测到设备,请打开设备重试~',
          showCancel: false
        })
      }
    }).catch(err => bluetooth.errorCodeToStr(err))
  },

第三步  创建蓝牙连接获取所需要deviceId(搜索到设备时获取) serviceId(isPrimary=true的那个uuid),characteristicId(这个是需要characteristics中 write为true时 为写入时需要用到的uuid 若需要监听上报信息 需要选择notify为true的uuid)就是个概念 具体参考官方文档结合自己控制台打印的去判断

当蓝牙连接成功后可以把蓝牙设备的数据 存到缓存或者别的位置 方便下次直接试用

原文:

createBLEConnection 连接蓝牙低功耗设备。

若小程序在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需再次进行搜索操作。

// 创建蓝牙连接
  createMachineLink() {
    // 连接前 断开与其他蓝牙低功耗设备的连接
    wx.showLoading({
      title: '连接中...',
      mask: true
    })
    // 监听断开连接
    wx.onBLEConnectionStateChange((res) => {
      if (!res.connected)
        this.setData({
          isLink: res.connected,
        })
    })

    wx.createBLEConnection({
      deviceId: this.data.deviceId,
      timeout: 5000,
    }).then(() => {
      // 获取蓝牙低功耗设备所有服务 (service)
      wx.getBLEDeviceServices({
        deviceId: this.data.deviceId
      }).then(servicesData => {
        this.setData({
          serviceId: servicesData.services[0].uuid
        }, () => {
          // 获取蓝牙低功耗设备某个服务中所有特征 (characteristic)
          wx.getBLEDeviceCharacteristics({
            deviceId: this.data.deviceId,
            serviceId: this.data.serviceId,
          }).then(res => {
            wx.setStorageSync('leaveStatus', 'link')
            wx.showToast({
              title: '连接成功',
            })
            this.setData({
              isLink: true,
              writeCharacteristicId: res.characteristics.find(item => item.properties.write == true).uuid,
              notifyCharacteristicId: res.characteristics.find(item => item.properties.notify == true).uuid
            }, () => this.notifyBluetoothListener())
          }).catch(err => bluetooth.errorCodeToStr(err))
        })
      }).catch(err => bluetooth.errorCodeToStr(err))
    }).catch(err => bluetooth.errorCodeToStr(err))
  },

第四步   写入数据 我这里直接封装的方法 可以参考(这个是需要传入10字节 的16进制字符串)我这个只是参考

bluetooth.writeData(this.data.deviceId, this.data.serviceId, this.data.writeCharacteristicId, '044000')

//封装
  // 写入数据
  writeData(deviceId, serviceId, characteristicId, value) {
    wx.writeBLECharacteristicValue({
      deviceId,
      serviceId,
      characteristicId,
      value: this.createBuffer(value),
    }).then(res => {
      setTimeout(() => {
        wx.hideLoading()
      }, 700)
    }).catch(err => this.errorCodeToStr(err))
  },
  // 创建10位 0x00 16进制数据
  createBuffer(num) {
    let buffer = new ArrayBuffer(10);
    let dataView = new DataView(buffer);
    // 固定头
    dataView.setUint8(0, 0x0D);
    dataView.setUint8(1, 0x02);
    // 固定头尾
    dataView.setUint8(8, 0x0D);
    dataView.setUint8(9, 0x03);
    for (let i in num) {
      dataView.setUint8(parseInt(i) + 2, ('0x' + num[i].charCodeAt().toString(16)));
    }
    return dataView.buffer
  },

第五步 监听蓝牙上报信息 解码并做出相应处理

// 监听 设备上报
  notifyBluetoothListener() {
    wx.showLoading({
      title: '获取状态中...',
      mask: true
    })
    //  启用蓝牙低功耗设备特征值变化时的 notify 功能
    wx.notifyBLECharacteristicValueChange({
      state: true,
      deviceId: this.data.deviceId,
      serviceId: this.data.serviceId,
      characteristicId: this.data.notifyCharacteristicId,
    }).then(res => {
      // 启用成功 下发指令 获取 设备状态
      bluetooth.writeData(this.data.deviceId, this.data.serviceId, this.data.writeCharacteristicId, '018000')
    }).catch(err => bluetooth.errorCodeToStr(err))

    // 必须先启用 wx.notifyBLECharacteristicValueChange 才能监听到设备 characteristicValueChange 事件
    wx.onBLECharacteristicValueChange((res) => {
      setTimeout(() => {
        this.setData({
          writeType: false
        })
      }, 1000)

      if (res.value.length >= 11) {
        bluetooth.closeBLEConnection(this.data.deviceId)
        wx.showToast({
          title: '未知错误',
        })
        return
      }
      this.handleValueChange(bluetooth.ab2hex(res.value))
    })
  },
  // 上报结果处理
  handleValueChange(str) {
    // 去除固定头固定尾
    let hex = str.substring(4,str.length-4)
    hex = bluetooth.hexCharCodeToStr(hex)
    if (!hex) {
      wx.showToast({
        title: '未知错误',
      })
      return
    }
    let status = Number('0x' + (hex.substring(0, 2)))

    if (!status) {
      bluetooth.closeBLEConnection(this.data.deviceId)
      wx.showToast({
        title: '未知错误',
      })
      return
    }

    this.setData({
      isRun: (status >> 6) & 1, //是否运行中
      isHot: (status & 1), //加热
      speed: (status >> 2) & 3, //速度
      mode: (status >> 4) & 3, //模式
    })
  },

这里 封装的上面代码中所用的的方法

module.exports = {
  // 创建10位 0x00 16进制数据
  createBuffer(num) {
    let buffer = new ArrayBuffer(10);
    let dataView = new DataView(buffer);
    // 固定头
    dataView.setUint8(0, 0x0D);
    dataView.setUint8(1, 0x02);
    // 固定头尾
    dataView.setUint8(8, 0x0D);
    dataView.setUint8(9, 0x03);
    for (let i in num) {
      dataView.setUint8(parseInt(i) + 2, ('0x' + num[i].charCodeAt().toString(16)));
    }
    return dataView.buffer
  },
  // 写入数据
  writeData(deviceId, serviceId, characteristicId, value) {
    wx.writeBLECharacteristicValue({
      deviceId,
      serviceId,
      characteristicId,
      value: this.createBuffer(value),
    }).then(res => {
      setTimeout(() => {
        wx.hideLoading()
      }, 700)
    }).catch(err => this.errorCodeToStr(err))
  },
  // 断开蓝牙连接
  closeBLEConnection(deviceId, type) {
    wx.closeBLEConnection({
      deviceId: deviceId,
      success: () => {
        if (type)
          wx.showToast({
            title: '断开连接',
            icon: 'none'
          })
      },
      fail: err => this.errorCodeToStr(err, type)
    })
  },
  //蓝牙授权查询
  getBluetoothSetting() {
    return new Promise((resolve, reject) => {
      wx.getSetting().then(res => {
        if (!res.authSetting['scope.bluetooth']) {
          this.scopeBluetooth().then(data => {
            resolve(data)
          }).catch(err => reject(err))
        } else {
          resolve(res.authSetting)
        }
      }).catch(err => reject('getSetting error'))
    })
  },
  //申请蓝牙授权
  scopeBluetooth() {
    return new Promise((resolve, reject) => {
      wx.authorize({
        scope: 'scope.bluetooth',
        success(res) {
          resolve(res)
        },
        fail(err) {
          wx.showModal({
            title: '提示',
            content: '请授权蓝牙,以便使用设备',
            success(res) {
              if (res.cancel) {
                reject('未授权蓝牙')
                return
              }
              wx.openSetting({
                success(data) {
                  if (data.authSetting['scope.bluetooth']) {
                    resolve(data.authSetting)
                  } else {
                    reject('未授权蓝牙')
                  }
                }
              })
            }
          })
        }
      })
    })
  },
  // 蓝牙错误统一处理
  errorCodeToStr(err, type) {
    console.log(err)

    if (!err.errCode) {
      console.log(err.errMsg)
      return
    }
    if (type) return
    wx.showToast({
      title: this.codeToStr[err.errCode],
      icon: 'none'
    })
  },
  codeToStr: {
    "0": "正常",
    "-1": "已连接",
    "10000": "未初始化蓝牙适配器",
    "10001": "当前蓝牙适配器不可用",
    "10002": "没有找到指定设备",
    "10003": "连接失败",
    "10004": "没有找到指定服务",
    "10005": "没有找到指定特征",
    "10006": "当前连接已断开",
    "10007": "当前特征不支持此操作",
    "10008": "其余所有系统上报的异常",
    "10009": "Android 系统特有,系统版本低于 4.3 不支持 BLE",
    "10012": "连接超时",
    "10013": "连接 deviceId 为空或者是格式不正确",
  },
  // ArrayBuffer转16进制字符串
  ab2hex(buffer) {
    let hexArr = Array.prototype.map.call(
      new Uint8Array(buffer),
      function (bit) {
        return ('00' + bit.toString(16)).slice(-2)
      }
    )
    return hexArr.join('');
  },
  // ArrayBuffer转16进制字符串转16进制数字
  hexCharCodeToStr(hexCharCodeStr) {
    var trimedStr = hexCharCodeStr.trim();
    var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
    var len = rawStr.length;
    if (len % 2 !== 0) {
      alert("存在非法字符!");
      return "";
    }
    var curCharCode;
    var resultStr = [];
    for (var i = 0; i < len; i = i + 2) {
      curCharCode = parseInt(rawStr.substr(i, 2), 16);
      resultStr.push(String.fromCharCode(curCharCode));
    }
    return resultStr.join("");
  },
}

此文章 只是大概记录  以便再次遇到类似项目能有些经验  希望能给看到这篇文章的人提供一些帮助 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

招来红月

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值