(二)小程序蓝牙和设备通讯

(一)蓝牙需要知道的几个名词

1、profile

profile可以理解为一种规范,一个标准的通信协议,它存在于从机中。蓝牙组织规定了一些标准的profile,例如 HID OVER GATT ,防丢器 ,心率计等。每个profile中会包含多个service,每个service代表从机的一种能力。

2、service

service可以理解为一个服务,在ble从机中,通过有多个服务,例如电量信息服务、系统信息服务等,每个service中又包含多个characteristic特征值。每个具体的characteristic特征值才是ble通信的主题。比如当前的电量是80%,所以会通过电量的characteristic特征值存在从机的profile里,这样主机就可以通过这个characteristic来读取80%这个数据

3、characteristic

characteristic特征值,ble主从机的通信均是通过characteristic来实现,可以理解为一个标签,通过这个标签可以获取或者写入想要的内容。

4、UUID

UUID,统一识别码,我们刚才提到的service和characteristic,都需要一个唯一的uuid来标识

整理一下,每个从机都会有一个叫做profile的东西存在,不管是上面的自定义的simpleprofile,还是标准的防丢器profile,他们都是由一些列service组成,然后每个service又包含了多个characteristic,主机和从机之间的通信,均是通过characteristic来实现。

(二)流程图

微信文档总结的蓝牙通讯流程图

这里写图片描述

我觉得你看一遍微信的官方文档,按照我这个流程基本上就可以调通蓝牙。

(三)微信小程序蓝牙通讯相关代码

1.搜索附近的设备

 /* 初始化蓝牙适配器 */
        wx.openBluetoothAdapter({
          success: function (res) {
            //  console.log('初始化蓝牙适配器成功');
            wx.startBluetoothDevicesDiscovery({
              services: [],
              allowDuplicatesKey: false,
              success: function (res) {

                // console.log('这里是开始搜索附近设备', res);

                wx.onBluetoothDeviceFound(function (res) {
                  console.log("成功", res);


                  /* 获取设备信号,判断信号强度 */
                  var device_RSSI_1 = res.devices[0].RSSI;
                  //Number将不同的对象转换成数字
                  var device_RSSI_2 = Number(device_RSSI_1);
                  //Math.abs获取绝对值
                  var device_RSSI = Math.abs(device_RSSI_2);


                  if (device_RSSI <= 60) {

                    var img = "../../images/signal4.png"

                  } else if (device_RSSI > 60 && device_RSSI <= 70) {
                    var img = "../../images/signal3.png"

                  } else if (device_RSSI > 70 && device_RSSI <= 80) {

                    var img = "../../images/signal2.png"

                  } else if (device_RSSI > 80) {

                    var img = "../../images/signal1.png"

                  }


                  if (res.devices[0].name == "") {
                    var temp = {
                      ID: res.devices[0].deviceId,
                      name: "",
                      RSSI: res.devices[0].RSSI,
                      img: img
                    }
                  } else {
                    var temp = {
                      ID: res.devices[0].deviceId,
                      name: res.devices[0].name,
                      RSSI: res.devices[0].RSSI,
                      img: img
                    }

                  }
                  var tempName = temp.name;
                  console.log('name', tempName)
                   //这里我直接把没有名字的设备过滤掉了
                  if (tempName != "") {
                    console.log('tempName', tempName)
                    devices.push(temp);//我定义的一个设备数组用于保存搜索到的设备

                    that.setData({
                      deviceArray: devices,
                      isShow: true
                    });
                  }
                });
              },
            });
          },

          fail: function (res) {
            wx.showLoading({
              title: '请打开蓝牙',
            });
          }
        })
      }
    })
  },

2.连接设备

我这里的逻辑是:用户点击搜索到的设备后,跳转到另一个界面进行相应的操作。

/**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
   var that = this;
    wx.stopBluetoothDevicesDiscovery({
      success: function (res) {
        console.log('停止搜索设备', res)
        that.setData({
          connect: false
        })
      }
    })
    console.log(options);
    this.setData({
      deviceId: options.id,
      deviceName: options.name,
      num: options.num,
      deviceType: options.type

    });
    console.log('设备的ID', this.data.deviceId);
    console.log('设备的号', this.data.num);
  },

/**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

    var that = this;
    /* 连接中动画 */
    wx.showLoading({
      title: '连接中...',
    });
    //开始连接蓝牙设备 
    wx.createBLEConnection({
      deviceId: that.data.deviceId,
      success: function (res) {
        console.log('连接成功', res);

        /* 获取设备的服务UUID */
        wx.getBLEDeviceServices({
          deviceId: that.data.deviceId,
          success: function (service) {
            var all_UUID = service.services;    //取出所有的服务
            console.log('所有的服务', all_UUID);
            var UUID_lenght = all_UUID.length;  //获取到服务数组的长度
            /* 遍历服务数组 */
            for (var index = 0; index < UUID_lenght; index++) {
              var ergodic_UUID = all_UUID[index].uuid;    //取出服务里面的UUID
              var UUID_slice = ergodic_UUID.slice(4, 8);   //截取4到8位
              /* 判断是否是我们需要的FEE0 */
              if (UUID_slice == 'FEE0' || UUID_slice == 'fee0') {
                var index_uuid = index;
                that.setData({
                  serviceId: all_UUID[index_uuid].uuid    //确定需要的服务UUID
                });
              };
            };
            console.log('需要的服务UUID', that.data.serviceId)
            that.Characteristics();     //调用获取特征值函数
          },
        });
        that.setData({
          connect: true
        })
      },
      complete: function (res) {
        console.log('打印出>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', res);
      }
    })
  },


 Characteristics: function () {
    var that = this;
    var device_characteristics = [];
    var characteristics_uuid = {};
    wx.getBLEDeviceCharacteristics({
      deviceId: that.data.deviceId,
      serviceId: that.data.serviceId,
      success: function (res) {
        var characteristics = res.characteristics;      //获取到所有特征值
        var characteristics_length = characteristics.length;    //获取到特征值数组的长度
        console.log('获取到特征值', characteristics);
        console.log('获取到特征值数组长度', characteristics_length);
        /* 遍历数组获取notycharacteristicsId */
        for (var index = 0; index < characteristics_length; index++) {
          var noty_characteristics_UUID = characteristics[index].uuid;    //取出特征值里面的UUID
          var characteristics_slice = noty_characteristics_UUID.slice(4, 8);   //截取4到8位
          /* 判断是否是我们需要的FEE1 */
          if (characteristics_slice == 'FEE1' || characteristics_slice == 'fee1') {
            var index_uuid = index;
            that.setData({
              notycharacteristicsId: characteristics[index_uuid].uuid,    //需确定要的使能UUID
              characteristicsId: characteristics[index_uuid].uuid         //暂时确定的写入UUID
            });
            /* 遍历获取characteristicsId */
            for (var index = 0; index < characteristics_length; index++) {
              var characteristics_UUID = characteristics[index].uuid;    //取出特征值里面的UUID
              var characteristics_slice = characteristics_UUID.slice(4, 8);   //截取4到8位
              /* 判断是否是我们需要的FEE2 */
              if (characteristics_slice == 'FEE2' || characteristics_slice == 'fee2') {
                var index_uuid = index;
                that.setData({
                  characteristicsId: characteristics[index_uuid].uuid         //确定的写入UUID
                });
              };
            };
          };
        };
        console.log('使能characteristicsId', that.data.notycharacteristicsId);
        console.log('写入characteristicsId', that.data.characteristicsId);
        that.notycharacteristicsId();       //使能事件
      },
    })
  },

  /* 使能函数 */
  notycharacteristicsId: function () {
    var that = this;

    var recve_value = "";

    wx.notifyBLECharacteristicValueChange({
      deviceId: that.data.deviceId,
      serviceId: that.data.serviceId,
      characteristicId: that.data.notycharacteristicsId,
      state: true,
      success: function (res) {
        console.log('使能成功', res);
        wx.hideLoading();
         if (that.data.isTest) {

          console.log(res);
          console.log('this>>>>>>>>>>>>>>>>>>>',this);
          setTimeout(function () { 
          that.SendTap()  

          }, 2000);  
        console.log('that>>>>>>>>>>>>>>>>>>>', that);
        } 

        /* 设备返回值 */
        wx.onBLECharacteristicValueChange(function (res) {
          var length_hex = [];
          var turn_back = "";
          var result = res.value;
          var hex = that.buf2hex(result);

          recve_value = recve_value + hex;
          console.log('设备>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>返回的值', recve_value);
      },
      fail: function (res) {
        wx.showToast({
          title: '通讯异常',
        })
        console.log('使能失败', res);
      },
      complete:function(res){
        console.log('使能', res);
      }
    })
  },

3.发送数据

注意:蓝牙最多一次发送20个字节,所以大于20个字节时,需要分段发送.

var value_initial_1 = "你要发的数据";
 var write_array = [];//用于发送数据的数组。
 /* 判断是否存在空格 */
    if (value_initial_1.indexOf(' ') > 0) {
      var value_initial = that.splitStr(value_initial_1, ' ');    //存在空格时
      console.log('删除掉空格', value_initial);
    } else {
      var value_initial = value_initial_1;    //不存在空格时
    }

    /* 判断字节是否超过20字节 */
    if (value_initial.length > 20) {

      //当字节超过20的时候,采用分段发送

        //选择16进制发送时
        var value_initial_exceed = value_initial;
        //将输入框的值取过来,方便循环
        var value_initial_average = Math.ceil(value_initial_exceed.length / 20);        //将value_initial_exceed的长度除以20,余数再向上取一,确定循环几次
        console.log('需要循环的次数', value_initial_average);
        for (var i = 0; i < value_initial_average; i++) {

          if (value_initial_exceed.length > 20) {
            var value_initial_send = value_initial_exceed.slice(0, 20);      //截取前20个字节
            console.log('截取到的值', value_initial_send);
            value_initial_exceed = value_initial_exceed.substring(20);      //value_initial_exceed替换为取掉前20字节后的数据
            write_array.push(value_initial_send);       //将所有截取的值放在一个数组
          } else {
            write_array.push(value_initial_exceed);
          }

        }
        console.log('write_array数组', write_array);
        write_array.map(function (val, index) {
          setTimeout(function () {
            var value_set = val;
            console.log('value_set', value_set);
            var write_function = that.write(value_set);       //调用数据发送函数
          }, index * 100)
        });
    } else {                   
    //当字节不超过20的时候,直接发送
        var value = value_initial;
      var write_function = that.write(value);     //调用数据发送函数
    }
  },

  //写入数据
  write: function (str) {
    var that = this;
    var value = str;
    console.log('value', value);
    /* 将数值转为ArrayBuffer类型数据 */
    var typedArray = new Uint8Array(value.match(/[\da-f]{2}/gi).map(function (h) {
      return parseInt(h, 16)
    }));
    var buffer = typedArray.buffer;
    wx.writeBLECharacteristicValue({
      deviceId: that.data.deviceId,
      serviceId: that.data.serviceId,
      characteristicId: that.data.characteristicsId,
      value: buffer,
      success: function (res) {
        console.log('数据发送成功', res);
      },
      fail: function (res) {
        console.log('调用失败', res);
        /* 调用失败时,再次调用 */
        wx.writeBLECharacteristicValue({
          deviceId: that.data.deviceId,
          serviceId: that.data.serviceId,
          characteristicId: that.data.characteristicsId,
          value: buffer,
          success: function (res) {
            console.log('第2次数据发送成功', res);
          },
          fail: function (res) {
            console.log('第2次调用失败', res);
            /* 调用失败时,再次调用 */
            wx.writeBLECharacteristicValue({
              deviceId: that.data.deviceId,
              serviceId: that.data.serviceId,
              characteristicId: that.data.characteristicsId,
              value: buffer,
              success: function (res) {
                console.log('第3次数据发送成功', res);
              },
              fail: function (res) {
                console.log('第3次调用失败', res);
              }
            });
          }
        });
      }
    });
  },

(四)相关的转换方法

  /* ArrayBuffer类型数据转为16进制字符串 */
  buf2hex: function (buffer) { // buffer is an ArrayBuffer
    return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + x.toString(16)).slice(-2)).join('');
  },


  /* 去除输入框输入的值中的空格 */
  splitStr: function (str, s) {
    var newStr = "";
    var strArray = str.split(s);
    for (var i = 0; i < strArray.length; i++) {
      newStr += strArray[i];
    }
    return newStr;
  },

Demo下载地址

此demo包含了微信小程序充值和蓝牙通讯的功能。希望能帮您节省一定的时间,快速上手。如果有问题留言,我看到会回复您的。

  • 8
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值