小程序蓝牙亲身总结

2023-10-30

问题:

最近做了一个涉及到蓝牙模块小程序,做一下总结,为自己的成长做一份记录,如果能帮到大家的话是再好不过的了;

1.小程序蓝牙搜索能不能搜到手机设备
2.如何判断蓝牙是否打开
3.搜索指定设备
4.开发者工具和 Android 上获取到的deviceId为设备 MAC 地址,iOS 上则为设备 uuid。因此deviceId不能硬编码到代码中,
如何连接蓝牙
5.设备服务所有 service(服务) 如何去选择
6.设备characteristic(特征值)干嘛的,怎么用
7.开启notify
8.写入数据

1.小程序蓝牙搜索能不能搜到手机设备

搜不到!!!
小程序蓝牙只支持BLE低功耗蓝牙
什么是低功耗蓝牙设备呢?百度一下,你就知道(^__^) 嘻嘻


2.如何判断蓝牙是否打开

利用wx.openBluetoothAdapter(OBJECT)判断蓝牙是否可用
在用户蓝牙开关未开启或者手机不支持蓝牙功能的情况下,调用wx.openBluetoothAdapter会返回错误,表示手机蓝牙功能不可用;

wx.openBluetoothAdapter({
  success: function (res) {
    console.log(res)
  },
  fail: function (res) {
      wx.showModal({
           content: '请开启手机蓝牙后再试'
       })
   }
})

注意:建议wx.openBluetoothAdapter(OBJECT)和wx.closeBluetoothAdapter(OBJECT)成对使用
wx.closeBluetoothAdapter:关闭蓝牙模块,使其进入未初始化状态。调用该方法将断开所有已建立的链接并释放系统资源;


3.搜索指定设备

wx.startBluetoothDevicesDiscovery(OBJECT)开始搜寻附近的蓝牙外围设备
wx.getBluetoothDevices(OBJECT)获取在小程序蓝牙模块生效期间所有已发现的蓝牙设备
wx.onBluetoothDeviceFound(CALLBACK) 监听寻找到新设备的事件

注意:搜索蓝牙wx.startBluetoothDevicesDiscovery(OBJECT)操作比较耗费系统资源,在搜索并连接到设备后调用 wx.stopBluetoothDevicesDiscovery(OBJECT) 方法停止搜索

//开始搜索蓝牙
    wx.startBluetoothDevicesDiscovery({
        success: function (res) {
            console.log('search', res)
        }
    })
//发现设备
      wx.getBluetoothDevices({
         success: function (res) {
            console.log('发现设备', res)
            if (res.devices[0]) { 
                console.log(that.ab2hext(res.devices[0].advertisData))                                      
            }
            //5s内未搜索到设备,关闭搜索,关闭蓝牙模块
            setTimeout(function(){
                  if (!that.data.deviceId){
                      wx.hideLoading()
                      app.showToast('搜索设备超时','none');
                      //关闭搜索
                      that.stopBluetoothDevicesDiscovery();
                      //关闭蓝牙
                      that.closeBluetoothAdapter();
                  }
             },5000)
         }
      })
    //监听发现设备
    wx.onBluetoothDeviceFound(function (devices) {
        console.log('发现设备:', devices.devices)
        for (let i = 0; i < devices.devices.length; i++) {
            //检索指定设备
            if (devices.devices[i].name == '设备name') {
                that.setData({
                    deviceId: devices.devices[i].deviceId
                })
                //关闭搜索
                that.stopBluetoothDevicesDiscovery();
                console.log('已找到指定设备:', devices.devices[i].deviceId);  
             }
          }
     })
     ab2hext: function(buffer) {
            var hexArr = Array.prototype.map.call(
                new Uint8Array(buffer),
                function (bit) {
                    return ('00' + bit.toString(16)).slice(-2)
                }
            )
            return hexArr.join('');
       }

这段代码是通过设备名name去匹配配对设备,若5s内未搜到指定设备则关闭搜索,关闭蓝牙模块;
设备名是已发现的蓝牙设备device 对象中的name
这里写图片描述

4.开发者工具和 Android 上获取到的deviceId为设备 MAC 地址,iOS 上则为设备 uuid。因此deviceId不能硬编码到代码中,如何连接蓝牙

搜索我们可以拿到了设备的deviceId,通过deviceId去连接蓝牙
Android 上获取到的deviceId为设备 MAC 地址iOS 上获取到的deviceId则为设备 uuid,因此deviceId不能硬编码到代码中
那么可能就有机智的小伙伴说了,设置两个变量,一个为设备MAC,一个为设备uuid
在连接设备的之前判断下机型,ios设备deviceId取:设备uuidandroid设备deviceId:MAC地址!!!
我原本也是这样想的,因为我们做的这个小程序是扫码连接指定设备(就好像共享单车一样),所以本来是想在二维码中直接放入mac和uuid然后连接的时候去根据机型去取对应值
但是!!!但是!!!但是!!!
在实现过程中发现,ios不同手机搜索到的设备deviceId还是不同的.
所以还是乖乖通过设备name(广播名),去获取deviceId去连接
这里写图片描述
这里写图片描述
只怪自己经验不足,还总想走捷径
正确的流程是
初始化蓝牙wx.openBluetoothAdapter(OBJECT)

开始搜索蓝牙 wx.startBluetoothDevicesDiscovery(OBJECT)

所有已发现的蓝牙设备wx.getBluetoothDevices(OBJECT)

监听寻找到新设备的事件wx.onBluetoothDeviceFound(CALLBACK)

连接低功耗蓝牙设备wx.createBLEConnection(OBJECT)

获取蓝牙设备所有 service(服务) wx.getBLEDeviceServices(OBJECT)

获取蓝牙设备某个服务中的所有 characteristic(特征值)wx.getBLEDeviceCharacteristics(OBJECT)

启用低功耗蓝牙设备特征值变化时的 notify 功能wx.notifyBLECharacteristicValueChange(OBJECT)

写入wx.writeBLECharacteristicValue(OBJECT)

在搜索到设备后通过拿到的设备的deviceId去连接设备

wx.createBLEConnection({
    deviceId: that.data.deviceId,//搜索设备获得的蓝牙设备 id
    success: function (res) {
        console.log('连接蓝牙:', res.errMsg);
    },
    fail: function (res) {
        app.showToast('连接超时,请重试或更换车辆', 'none');
        that.closeBluetoothAdapter();
    }
})

5.serviceId如何去选择

连接成功以后就可以去获取设备的服务列表,我这边拿的是FEE7的服务ID

wx.getBLEDeviceServices({
  deviceId: that.data.deviceId,//搜索设备获得的蓝牙设备 id
  success: function (res) {        
    let service_id = "";
    for(let i = 0;i<res.services.length;i++){
      if(services[i].uuid.toUpperCase().indexOf("FEE7") != -1){
        service_id = services[i].uuid;
        break;
      }
    }
     console.log('fee7-service_id:', that.data.service_id);
  },
  fail(res){
    console.log(res);
  }
})

6.characteristic(特征值)干嘛的,怎么用

服务特征值是干嘛的:每个服务都包含了一组特征值用来描述服务的一些属性,获取是否可读,是否可写,是否可以开启notify通知等,当你跟蓝牙通信时需要这些特征值ID来传递数据。
服务特征值怎么用

//获取特征值
wx.getBLEDeviceCharacteristics({
    deviceId: that.data.deviceId,//搜索设备获得的蓝牙设备 id
    serviceId: that.data.service_id,//服务ID
    success: function (res) {
        console.log('device特征值:', res.characteristics)
        for (let i = 0; i < res.characteristics.length; i++) {
            let charc = res.characteristics[i];
            if (charc.properties.indicate) {
                that.setData({indicate_id: charc.uuid});
                console.log('indicate_id:', that.data.indicate_id);
            }
            if (charc.properties.write) {
                that.setData({write_id: charc.uuid});
                console.log('写write_id:', that.data.write_id);
            }
            if (charc.properties.read) {
                that.setData({read_id: charc.uuid});
                console.log('读read_id:', that.data.read_id);
            }
        }
   }
});

筛选出你所需要的服务特征值
在得到对应特征值后可以在执行相关操作时使用
例如:
开启notify:必须设备的特征值支持notify或者indicate才可以成功调用
支不支持notify或者indicate就是我们上面筛选出来的对应值

 if (charc.properties.indicate) {
     that.setData({indicate_id: charc.uuid});
     console.log('indicate_id:', that.data.indicate_id);
 }

7.开启notify

开启notify后可以监听低功耗蓝牙设备的特征值变化。必须先启用notify接口才能接收到设备推送的notification

//开启notify
wx.notifyBLECharacteristicValueChange({
    state: true, // 启用 notify 功能
    deviceId: that.data.deviceId,//蓝牙设备id
    serviceId: that.data.service_id,//服务id
    characteristicId: that.data.indicate_id,//服务特征值indicate
    success: function (res) {
        console.log('开启notify', res.errMsg)
        //监听低功耗蓝牙设备的特征值变化
        wx.onBLECharacteristicValueChange(function (res) {
            console.log('特征值变化', that.arrayBufferToHexString(res.value));
        })
        //写入数据

    }
});

8.如何写入数据

如何写入数据呢,通过获取到的write特征值write_id
注意:必须设备的特征值支持write才可以成功调用

 let buffer = that.hexStringToArrayBuffer(ArrayBuffer);
 //写入数据
 wx.writeBLECharacteristicValue({
     deviceId: that.data.deviceId,//设备deviceId
     serviceId: that.data.service_id,//设备service_id
     characteristicId: that.data.write_id,//设备write特征值
     value: buffer,//写入数据
     success: function (res) {
         console.log('发送数据:', res.errMsg)
     }
 });
 hexStringToArrayBuffer:function (str) {
        if(!str) {
            return new ArrayBuffer(0);
        }
        var buffer = new ArrayBuffer(str.length);
        let dataView = new DataView(buffer)
        let ind = 0;
        for (var i = 0, len = str.length; i < len; i += 2) {
            let code = parseInt(str.substr(i, 2), 16)
            dataView.setUint8(ind, code)
            ind++
        }
        return buffer;
 }

总结:有几点特别需要注意,快拿出小本本
1.IOS里面蓝牙状态变化以后不能马上开始搜索,否则会搜索不到设备,必须要等待2秒以上
2.开启notify以后并不能马上发送消息,蓝牙设备有个准备的过程,需要在setTimeout中延迟1秒以上才能发送,否则会发送失败

setTimeout(function () {
   wx.writeBLECharacteristicValue({
     deviceId: that.data.deviceId,
     serviceId: that.data.service_id,
     characteristicId: that.data.write_id,
     value: buffer,
     success: function (res) {
         console.log('发送数据:', res.errMsg)
     }
 });
}, 1100);

3.搜索到设备后记得释放资源stopBluetoothDevicesDiscovery
4.不需要使用蓝牙的时候一定要关闭蓝牙.wx.openBluetoothAdapter(OBJECT)和wx.closeBluetoothAdapter(OBJECT)成对使用

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

小程序蓝牙亲身总结 的相关文章

  • Python数据库SQLite中的fetchone()、fetchMany()、fetchall()函数

    今天在练习python数据库的查询操作时 使用fetchone fetchMany fetchall 函数 出现了一些奇怪的现象 现在做如下记录 我想在同一个代码块中 使用fetchone 查询一条信息 使用fetchmany 3 查询3条
  • SQL Server中的登录名和用户名映射关系

    SQL Server 1 SQL Server 中 一个登录名可以映射多个数据库用户名 但是一个数据库用户名不能同时被两个数据库登录名映射 可以分别被A映射完 再被B映射 否则会干掉其中的一个 2 guest 用户是一个数据库用户名 是一个
  • oracle中的几种分区方式

    1 列表分区 1 1 分区技术实质可以把数据分摊到不同的物理位置 增加I O负载 提高检索效率 可用性 分区表可以跨越表空间 而普通表则不然 好处就是如果表的一个分区损坏 其他分区不会受到影响我们只需要修复损坏的分区即 可 1 2 创建li
  • 牛顿迭代法解非线性方程组(附C++代码)

    目录 一 公式介绍 二 应用环境 三 C 代码 实例说明 C 编译环境 C 代码 运行结果 特别注意 解决方法 一 公式介绍 牛顿迭代法基本公式 迭代出 面对非线性方程组问题 将上式变形 其中为 注 这里面的不再时代表一个值 而是代表关于变
  • SpringBoot---@DeleteMapping

    DeleteMapping 在编写代码时引用了 DeleteMapping 注解 DeleteMapping value remove courseNo public String remove PathVariable courseNo

随机推荐

  • linux中shell脚本命令使用详解

    文章目录 一 普通用户和超级用户 二 关于系统的操作 三 关于文件操作 3 1 ls显示文件 3 2 cd进出目录 3 3 mkdir创建目录 3 4 touch创建文件 3 5 cp复制命令 3 6 rm删除命令 3 7 cat命令 3
  • 注意力机制:CA - Coordinate Attention for Efficient Mobile Network Design(文末附代码)

    注意力机制 CA Coordinate Attention for Efficient Mobile Network Design 摘要 引言 具体而言 优势 相关工作 Mobile Network 架构 注意力机制 Coordinate
  • java 正则表达式 检测数学公式是否正确_java 正则表达式 检测数学公式是否正

    java 正则表达式 检测数学公式是否正 2021 02 05 13 33 36 简介 java中正则表达式基本用法的使用 1 Test01 java 使用正则表达式使代码变得非常简洁 2 TestMatcher01 java Matche
  • IBM近期扩充Watson认知API服务

    本文转载至 http www infoq com cn news 2016 03 watson cognitive apis 近期 IBM对Watson认知API服务进行了扩充 新增了情绪和语调分析API的测试版本 Watson的情绪分析A
  • Flutter 组件抽取:验证码输入功能(CodeInputContainer)

    简介 验证码输入框 可选需要输入的验证码个数 输入达指定个数后自动回调 效果 范例 class TestPageState extends State
  • 【通信原理】七、数字带通传输系统

    文章目录 一 2ASK振幅键控 2ASK振幅键控原理 2ASK包络检波 2ASK相干解调法 二 2FSK频移键控 过零点检测解调法 三 2PSK相移键控 四 2DPSK差分相移键控 差分相干解调 相位比较法 五 已调信号功率谱密度 六 抗噪
  • VB.Net正则表达式大全(3)

    深入浅出之正则表达式 注 JanGoyvaerts为RegexBuddy写的教程的译文 前言 半年前我对正则表达式产生了兴趣 在网上查找过不少资料 看过不少的教程 最后在使用一个正则表达式工具RegexBuddy时发现他的教程写的非常好 可
  • IDEA插件之输入法自动切换【Smart Input Source】

    MAC系统推荐快捷键 针对输入切换无需快捷键 但是在某些场景下比如Git Diff的时候可能存在自动跳转到源文件的情况 这种时候需要手动关闭自动切换功能 给作者提了个建议对这种场景进行优化 建议使用的快捷键 C代表关闭 O代表打开 介绍 解
  • 量子云计算:实现自我验证!

    量子云计算 实现自我验证 背景 即使对于世界上最强大的经典计算机来说 有些极度复杂的计算仍然需要花费漫长的时间 可是 从理论上说 量子计算机却可以完全胜任非常复杂的计算任务 原因是 不同于经典计算机的比特位 量子计算机拥有 量子位 经典二进
  • 人工智能讲师专家老师叶梓人工智能讲师之机器学习与深度学习-34

    接上一篇 系列博文 人工智能讲师叶梓关于人机器学习与深度学习入门课程课件 为系列博文 更多课程 及老师资料可点击 个人主页 最小二乘法的示意图 R语言实现的一元线性回归 一元回归的PYTHON实现 IMPORT PANDAS AS PD f
  • 前端实现csv文件的解析预览、上传、下载

    最近遇到了一些关于csv文件的上传 下载 解析预览 删除的需求 因为之前没有做过 尤其是关于csv的解析并预览 于是记录一下 上传 关于上传 绝大部分的选择都是通过第三方的OSS进行存储 比如阿里云的 这个其实没什么难度 有文档可以看 对于
  • ServiceLoader SPI的简单认知

    写了这么长时间的代码 竟然没有用过jdk SPI的ServiceLoader 深表遗憾 为什么写这个 因为在看Sentinel配置代码的时候 看到了这个 挺好用的 用法 在jar包中 resources 中建立 META INF servi
  • Java客户端连接不了安装在CentOS7上的redis解决方案

    今天初试了使用Java Redisson 客户端连接安装在CentOS上的redis 发现一直连接不了 报错信息如下 Exception in thread main com lambdaworks redis RedisException
  • HTML教程

    文章目录 HTML 1 HTML 概述 2 第一个 HTML 代码 3 HTML 标签分类 4 HTML基本标签 4 1 结构标签 4 2 排版标签 4 3 块标签和行内标签 4 4 文本标签 已过时 4 5 文本格式标签 4 6 标题标签
  • mybatis TypeHandler详解

    1 TypeHandler概念 TypeHandler 类型转换器 在mybatis中用于实现java类型和JDBC类型的相互转换 mybatis使用prepareStatement来进行参数设置的时候 需要通过typeHandler将传入
  • 简单的LVGL按键例程

    以下是一个简单的LVGL按键例程 使用LVGL的按键事件来处理按钮的单击和长按操作 include lvgl lvgl h void btn click action lv obj t obj 处理按钮单击事件 void btn long
  • ASP.NET -- WebForm -- ScriptManager 类

    ASP NET WebForm ScriptManager 类 通过 ScriptManager 可注册随后将作为页面一部分呈现的脚本 1 注册并立即执行脚本 RegisterStartupScript 方法 例 在ASP NET中实现和
  • 构建Java Web应用实验

    1 创建负责下载WAR文件的镜像 1 创建一个目录fetcher 保存相关的配置信息和内容 在 后输入mkdir fetcher cd fetcher命令 然后按Enter键 创建fetcher目录并进入该目录 示例代码如下 root xi
  • 知识追踪实战:lstm+ Multi-head Attention注意力机制的学生做题成绩预测实战

    项目视频讲解 知识追踪实战 lstm Multi head Attention注意力机制的学生做题成绩预测实战 哔哩哔哩 bilibili from collections import Counter import torch from
  • 小程序蓝牙亲身总结

    问题 1 小程序蓝牙搜索能不能搜到手机设备 2 如何判断蓝牙是否打开 3 搜索指定设备 4 开发者工具和 Android 上获取到的deviceId为设备 MAC 地址 iOS 上则为设备 uuid 因此deviceId不能硬编码到代码中