微信小程序连接蓝牙

准备工作:

复制代码
1:需要一个蓝牙板子和串口软件(卖蓝牙板子的商家会提供),手机上需要蓝牙调试助手(为了测试蓝牙是否正常连接)
2:蓝牙板通过usb插入到电脑端
3:安装好串口调试工具并打开连接上蓝牙
4:打开手机蓝牙调试助手,连接上后进行读写操作,确认已正常连接通信
准备工作完结!

直接上代码

第一步:初始化蓝牙设备, onShow里面调用或者onLoad里面调用都可,看你的需求场景

复制代码
initBlue () {
    wx.openBluetoothAdapter({
      success: (res) => {
        wx.showToast({
          title: '正在搜索蓝牙设备...',
          icon: 'loading'
        })
        this.findBlue()
      },
      fail: (error) => {
        wx.showToast({
          title: '请开启蓝牙',
          icon: 'fails',
          duration: 1000
        })
        this.setData({ isTrigger: false })
      }
    })
  },

第二步:搜索蓝牙设备

复制代码
findBlue(){
    wx.startBluetoothDevicesDiscovery({
      allowDuplicatesKey: true,
      interval: 0,
      powerLevel: 'high',
      success: (res) => {
        this.getBlue()//3.0
      },
      complete: () => {
        this.setData({ isTrigger: false })
      }
    })
  },

第三步:拿到需要的蓝牙设备进行列表渲染

复制代码
getBlue () {
    wx.onBluetoothDeviceFound((devices) => {
      if (devices.devices[0].name.includes('demo')) {
        console.log(devices.devices[0].name, 'devices.devices[0].name')
        // 添加有名字的蓝牙设备,并去重处理
        this.setData({ bluetoolList: [...this.data.bluetoolList, devices.devices[0]].filter((obj, index, self) =>
          index === self.findIndex((t) => (
              t.name === obj.name
          ))) })
        wx.stopBluetoothDevicesDiscovery() // 停止搜索
      }
    })
  },

第四步:点击某个蓝牙设备进行连接

复制代码
connetBluetooth(evt) {
    wx.showToast({
      title: '正在连接...',
      icon: 'loading'
    })
    console.log(evt.currentTarget.dataset, '=========')
    const { row } = evt.currentTarget.dataset
    this.setData({ currentDeviceid: row.deviceId })
    wx.setStorageSync('deviceId', row.deviceId)
    wx.createBLEConnection({
      deviceId: row.deviceId,
      timeout: 5000,
      success: (res) => {
        console.log('connet success: ', res)
        wx.stopBluetoothDevicesDiscovery()
        this.getServiceUUid() // 连接的收就获取服务ID 用于后面获取特征值id(特征值id可以用来进行读、写、监听蓝牙操作)
      },
      fail: (error) => {
        console.log('createBLEConnection error: ', error)
        if (error.errCode === -1) { // 表示已经连接, 直接跳转到对应页面即可
          wx.navigateTo({ url: '/pages/xxx/xxx' })
        } else {
          wx.showToast({
            title: '连接失败',
            icon: 'error',
            timeout: 500,
            complete: () => {
            }
          })
        }
      }
    })
  },

第五步:获取服务id,不同蓝牙设备,不同机型,获取的服务值不一样,根据你自己的蓝牙板子和机型来获取,一定要获取准确,错了就读写不了蓝牙设备

复制代码
getServiceUUid() {
    console.log('=====================getServiceUUid=======================')
    let _this = this
    wx.getBLEDeviceServices({
      // 这里的 deviceid 需要已经通过 createBLEConnection 与对应设备建立链接
      deviceId: _this.data.currentDeviceid,
      success: async (res) => {
        console.log('res.services: ', res.services)
        if (wx.getStorageSync('platform') === 'ios') {
          // read
          await _this.setData({ readServiceId: res.services[0].uuid })
          await wx.setStorageSync('readServiceId', res.services[0].uuid)

          // write true
          await _this.setData({ writeServiceId: res.services[1].uuid })
          await wx.setStorageSync('writeServiceId', res.services[1].uuid)

          // notify
          await _this.setData({ notifyServiceId: res.services[1].uuid })
          await wx.setStorageSync('notifyServiceId', res.services[1].uuid)

          await _this.getReadCharacteIdIos()
          await _this.getWriteCharacteIdIos()

        } else {
          // read true
          // _this.setData({ readServiceId: res.services[0].uuid })
          await _this.setData({ readServiceId: res.services[2].uuid })
          await wx.setStorageSync('readServiceId', res.services[2].uuid)
  
          // 第一个 write: true;第二个 notify: true
          await _this.setData({ writeServiceId: res.services[1].uuid })
          await wx.setStorageSync('writeServiceId', res.services[1].uuid)

          await _this.setData({ notifyServiceId: res.services[1].uuid })
          await wx.setStorageSync('notifyServiceId', res.services[1].uuid)
  
          // read true
          // await _this.setData({ readServiceId: res.services[2].uuid })
          // await wx.setStorageSync('readServiceId', res.services[2].uuid)
          
          // indicate 安卓端监听不到蓝牙发送过来的回调
          // await _this.setData({ notifyServiceId: res.services[3].uuid })
          // await wx.setStorageSync('notifyServiceId', res.services[3].uuid)
  
          await _this.getReadCharacteId()
          // await _this.getNotifyCharacteId()
          await _this.getWriteCharacteId()
        }
      }
    })
  },

第六步:获取特征值id,并保证在了本地(也可以挂在全局,方便另一个页面获取),跳转到对应页面,这里你可以封装一下,我这里做demo就没封装,五个方法,分别获取IOS端和安卓端的对应读写和监听的特征值,一定要根据蓝牙的板子获取对应正确的特征值(为true的才能进行后面的连接和读写操作),慢慢调试

复制代码
 // readServiceId
  getReadCharacteId() {
    let _this = this
    wx.getBLEDeviceCharacteristics({
      deviceId: _this.data.currentDeviceid,
      serviceId: _this.data.readServiceId,
      success: (res) => {
        console.log('res.haracteristics read: ', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
          let characteristic = res.characteristics[i]
          // 检查特征值是否具有 read 属性为 false
          if (characteristic.properties.read) {
            // 当找到 read 属性为 false 的特征值时,设置 writeId 为该特征值的 UUID
            _this.setData({ characteReadId: characteristic.uuid })
            wx.setStorageSync('characteReadId', characteristic.uuid)
            // break // 找到符合条件的特征值后,结束循环
          }
        }
      },
      fail: (error) => {
        console.log('get read CharacteId error: ', error)
      }
    })
  },
  // use bluetool deviceId and uuid get characteId (特征值) writeServiceId
  getWriteCharacteId () {
    let _this = this
    wx.getBLEDeviceCharacteristics({
      deviceId: _this.data.currentDeviceid,
      serviceId: _this.data.writeServiceId,
      success: (res) => {
        // 遍历特征值列表
        console.log('res.characteristics write : ', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
          let characteristic = res.characteristics[i]
          // 检查特征值是否具有 read 属性为 false
          if (characteristic.properties.write) {
            // 当找到 read 属性为 false 的特征值时,设置 writeId 为该特征值的 UUID
            _this.setData({
              characteWriteId: characteristic.uuid
            })
            wx.setStorageSync('characteWriteId', characteristic.uuid)
            // break // 找到符合条件的特征值后,结束循环
          }
          if (characteristic.properties.notify) {
            _this.setData({ characteNotifyId: characteristic.uuid })
            wx.setStorageSync('characteNotifyId', characteristic.uuid)
          }
        }
        console.log('currentDeviceid: ', _this.data.currentDeviceid)
        console.log('----------------------read--------------------')
        console.log('readServiceId: ', _this.data.readServiceId)
        console.log('characteReadId: ', _this.data.characteReadId)
        console.log('----------------------write--------------------')
        console.log('writeServiceId: ', _this.data.writeServiceId)
        console.log('characteWriteId: ', _this.data.characteWriteId)
        wx.navigateTo({
          url: '/pages/action/action'
        })
        wx.hideToast()
      },
      fail: function (error) {
        console.log("error reason: ", error)
      }
    })
  },
  // notifyServiceId
  getNotifyCharacteId() {
    let _this = this
    wx.getBLEDeviceCharacteristics({
      deviceId: _this.data.currentDeviceid,
      serviceId: _this.data.notifyServiceId,
      success: (res) => {
        console.log('res.characteristics notify: ', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
          let characteristic = res.characteristics[i]
          // 检查特征值是否具有 read 属性为 false
          if (characteristic.properties.indicate) {
            // 当找到 read 属性为 false 的特征值时,设置 writeId 为该特征值的 UUID
            _this.setData({ characteNotifyId: characteristic.uuid })
            wx.setStorageSync('characteNotifyId', characteristic.uuid)
            break // 找到符合条件的特征值后,结束循环
          }
        }
      },
      fail: (error) => {
        console.log('get notify CharacteId error: ', error)
      }
    })
  },

  // ios read characteId
  getReadCharacteIdIos() {
    wx.getBLEDeviceCharacteristics({
      deviceId: this.data.currentDeviceid,
      serviceId: this.data.readServiceId,
      success: (res) => {
        // 遍历特征值列表
        console.log('res.characteristics read : ', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
          let characteristic = res.characteristics[i]
          // 检查特征值是否具有 read 属性为 false
          if (characteristic.properties.read) {
            // 当找到 read 属性为 false 的特征值时,设置 writeId 为该特征值的 UUID
            this.setData({
              characteReadId: characteristic.uuid
            })
            wx.setStorageSync('characteReadId', characteristic.uuid)
            break // 找到符合条件的特征值后,结束循环
          }
        }
      }
    })
  },
  // ios write characteId
  getWriteCharacteIdIos() {
    wx.getBLEDeviceCharacteristics({
      deviceId: this.data.currentDeviceid,
      serviceId: this.data.writeServiceId,
      success: (res) => {
        // 遍历特征值列表
        console.log('res.characteristics write : ', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
          let characteristic = res.characteristics[i]
          // 检查特征值是否具有 read 属性为 false
          if (characteristic.properties.write) {
            // 当找到 read 属性为 false 的特征值时,设置 writeId 为该特征值的 UUID
            this.setData({
              characteWriteId: characteristic.uuid
            })
            wx.setStorageSync('characteWriteId', characteristic.uuid)
            // break // 找到符合条件的特征值后,结束循环
          }
          if (characteristic.properties.notify) {
            // 当找到 read 属性为 false 的特征值时,设置 writeId 为该特征值的 UUID
            this.setData({
              characteNotifyId: characteristic.uuid
            })
            wx.setStorageSync('characteNotifyId', characteristic.uuid)
          }
          wx.navigateTo({
            url: '/pages/xxx/xxx'
          })
          wx.hideToast()
        }
      }
    })
  },

第七步:这时候已经跳转到对应页面了,在页面onLoad里开启监听,后面蓝牙发送设备到小程序可以实时监听到值

复制代码
async onLoad(options) {
    // 监听蓝牙发送到小程序的数据
    await wx.onBLECharacteristicValueChange((res) => {
      console.log('characteristicis: ', res.value)
      console.log('转换后的值: ', this.ab2hex(res.value))
      this.setData({ fromBlueToolsData: this.ab2hex(res.value) })
      // this.setData({ fromBlueToolsData: res.value })
    })

    await wx.readBLECharacteristicValue({
      deviceId: wx.getStorageSync('deviceId'),
      serviceId: wx.getStorageSync('readServiceId'),
      characteristicId: wx.getStorageSync('characteReadId'),
      success: (res) => {
        console.log('read data is: ', res)
      },
      fail: (error) => {
        console.log('read error, error message is: ', error)
      }
    })

    await wx.notifyBLECharacteristicValueChange({
      state: true,
      type: 'notification', // 根据你蓝牙的特征值来选择类型
      deviceId: wx.getStorageSync('deviceId'),
      serviceId: wx.getStorageSync('notifyServiceId'),
      characteristicId: wx.getStorageSync('characteNotifyId'),
      success: (res) => {
        console.log('notify success, success message is: ', res)
      },
      fail: (error) => {
        console.log('notify error, error message is: ', error)
        this.setData({ fromBlueToolsData: '' })
      }
    })
  },

  // 16 进制到 10进制
  ab2hex(buffer) {
    let hexArr = Array.prototype.map.call(
      new Uint8Array(buffer),
      function(bit) {
        return ('00' + bit.toString(16)).slice(-2)
      }
    )
    return hexArr.join('');
  },

第八步:测试读写,看蓝牙串口与小程序是否有通信

复制代码
// 写入数据
writeTap() {
    console.log('-----------------start write action----------------------------')
    console.log('inputValue: ', this.data.inputValue)
    let data = this.data.inputValue
    if (data.length === 0) {
      wx.showModal({ title: '提示', content: '请输入要发送的数据' })
      return
  }
    wx.writeBLECharacteristicValue({
      deviceId: wx.getStorageSync('deviceId'),
      serviceId: wx.getStorageSync('writeServiceId'),
      characteristicId: wx.getStorageSync('characteWriteId'),
      value: this.string2buffer(data), // 数据转换发送
      success (res) {
        console.log('writeBLECharacteristicValue success', res)
        this.setData({ inputValue: '' })
      },
      fail: (error) => {
        console.log('write error, error message is: ', error)
      }
    })
  },
  string2buffer(hexString) {
    hexString = hexString.replace(/^0x/, '');
    const bytes = new Uint8Array(hexString.length / 2);
    for (let i = 0; i < hexString.length; i += 2) {
        bytes[i / 2] = parseInt(hexString.substring(i, i + 2), 16);
    }
    console.log('写入的buffer:', bytes.buffer)
    return bytes.buffer;
  },
  // input输入值
  onWriteInput(evt) {
    const { value } = evt.detail
    this.setData({ inputValue: value })
  },

最终测试后在ios与安卓上能够与蓝牙串口进行正常通信,完结!

相关推荐
诗书画唱3 分钟前
【前端面试题】JavaScript 核心知识点解析(第二十二题到第六十一题)
开发语言·前端·javascript
excel10 分钟前
前端必备:从能力检测到 UA-CH,浏览器客户端检测的完整指南
前端
前端小巷子17 分钟前
Vue 3全面提速剖析
前端·vue.js·面试
悟空聊架构23 分钟前
我的网站被攻击了,被干掉了 120G 流量,还在持续攻击中...
java·前端·架构
CodeSheep25 分钟前
国内 IT 公司时薪排行榜。
前端·后端·程序员
尖椒土豆sss29 分钟前
踩坑vue项目中使用 iframe 嵌套子系统无法登录,不报错问题!
前端·vue.js
遗悲风29 分钟前
html二次作业
前端·html
江城开朗的豌豆33 分钟前
React输入框优化:如何精准获取用户输入完成后的最终值?
前端·javascript·全栈
CF14年老兵33 分钟前
从卡顿到飞驰:我是如何用WebAssembly引爆React性能的
前端·react.js·trae
画月的亮36 分钟前
前端处理导出PDF。Vue导出pdf
前端·vue.js·pdf