小程序蓝牙通信

蓝牙通信能力封装

一开始是根据uniapp提供的蓝牙api写的蓝牙方法,之后发现复用性,以及一些状态的监听存在缺陷,之后整理成了类。这样复用性以及状态监听的问题就解决了。

蓝牙组件

创建蓝牙组件的类

在这里插入图片描述

单例模式是为了保证蓝牙长连接,只有一个蓝牙实例

// 单例模式if (Bluetooth.instance) {return Bluetooth.instance;}Bluetooth.instance = this;

根据需求定义变量
const serviceUUID = “”; // 主服务的UUID
const notifyUUID = “”; // 读
const writeUUID = “”; // 写
这一部分,连接蓝牙uuid是必须的,可以考虑接受参数的形式,或者在类里面写好,两种方式

根据需要传入相应的回调方法
successLinkFn:蓝牙连接成功的回调
dataChangeFn:成功接收蓝牙指令的回调
blueToothLinkStatusFn :监听蓝牙状态的回调

export class Bluetooth {constructor(params) {// 单例模式if (Bluetooth.instance) {return Bluetooth.instance;}this.bundleData = null; // 需要拼包的数据this.BLTdeviceId = ""; // 设备的 idthis.deviceId = params.deviceId; // 设备号(设备序列号)this.serviceUUID = params.serviceUUID || serviceUUID;this.notifyUUID = params.notifyUUID || notifyUUID;this.writeUUID = params.writeUUID || writeUUID;this.successLinkFn = params.successLinkFn; // 蓝牙连接成功this.dataChangeFn = params.dataChangeFn; // 接收蓝牙指令this.blueToothLinkStatusFn = params.blueToothLinkStatusFn; // 蓝牙连接状态this.initBluetooth();Bluetooth.instance = this;}}

初始化蓝牙

initBluetooth() {let _this = this;uni.openBluetoothAdapter({success(res) {console.log("初始化蓝牙成功", res);_this.getBluetoothAdapterState();},fail(error) {console.log(error);},});}

判断手机蓝牙标识是否打开的状态

  // 判断手机蓝牙标识是否打开的状态getBluetoothAdapterState() {const _this = this;uni.getBluetoothAdapterState({success(res) {//如果res.avaliable==false 说明没打开蓝牙 反之则打开if (res.available) {// 蓝牙打开-----开始搜寻附近蓝牙_this.startBluetoothDevicesDiscovery();} else {uni.showModal({content:"当前手机蓝牙关闭,请在手机设置中开启蓝牙,并允许微信获取您的蓝牙权限",confirmColor: "#4AC596",confirmText: "确定",showCancel: false,success(res) {},fail() {// TODO 蓝牙打开失败// 页面返回uni.navigateBack({delta: 1, //返回层数,2则上上页});},});}},});}

搜寻附近的蓝牙外围设备

  // 搜寻附近的蓝牙外围设备// 此操作比较耗费系统资源,请在搜索并连接到设备后调用 uni.stopBluetoothDevicesDiscovery 方法停止搜索。startBluetoothDevicesDiscovery() {let _this = this;uni.startBluetoothDevicesDiscovery({success(res) {console.log(res);_this.onBluetoothDeviceFound();},fail: function(res) {uni.showToast({title: "搜寻附近的蓝牙外围设备失败",icon: "none",duration: 1000,});console.log("搜寻附近的蓝牙外围设备失败");},});}

发现蓝牙设备(匹配要连接的蓝牙设备)

根据传入的设备序列号(设备号)进行匹配

  onBluetoothDeviceFound() {let _this = this;uni.onBluetoothDeviceFound(function(res) {res.devices.forEach(function(device) {let deviceName = device.localName || device.name;if (_this.deviceId == deviceName) { //根据传入的设备序列号(设备号)进行匹配console.log("发现蓝牙设备", device);_this.BLTdeviceId = device.deviceId;_this.startBluetoothDevicesDiscovery();_this.connectDevice();}});});}

连接蓝牙

  //连接蓝牙connectDevice() {let _this = this;uni.createBLEConnection({deviceId: _this.BLTdeviceId,timeout: 3000,success: function(res) {uni.showToast({icon: "success",title: "蓝牙连接成功",mask: true,duration: 3000,});console.log("蓝牙连接成功");_this.getBLEDeviceServices();// 监听蓝牙状态_this.blueToothLinkChange();},fail: function(res) {console.log("连接失败" + JSON.stringify(res));uni.showToast({icon: "none",title: "未成功连接设备,请重新搜索",mask: true,duration: 3000,});},});}

监听蓝牙状态

  // 监听蓝牙状态blueToothLinkChange() {const _this = this;uni.onBLEConnectionStateChange(function(res) {// 该方法回调中可以用于处理连接意外断开等异常情况console.log(`device ${res.deviceId} state has changed, connected: ${res.connected}`);_this.blueToothLinkStatusFn && _this.blueToothLinkStatusFn(res);});}

获取服务

  // 获取服务getBLEDeviceServices() {uni.showToast({icon: "none",title: "数据处理中,请稍后",duration: 3000,mask: true,});let _this = this;uni.getBLEDeviceServices({deviceId: _this.BLTdeviceId,success: function(res) {for (let i = 0; i < res.services.length; i++) {if (res.services[i].uuid == _this.serviceUUID) {console.log("获取serviceId成功", res);_this.getBLEDeviceCharacteristics();break;}}},fail: function(res) {console.log("获取serviceId失败", res);uni.showToast({icon: "none",title: "未成功连接设备,请重新搜索",mask: true,duration: 3000,});},});}

获取特征值

  // 获取特征值getBLEDeviceCharacteristics() {let _this = this;// 如果是自动链接的话,wx.getBLEDeviceCharacteristics方法建议使用setTimeout延迟1秒后再执行wx.getBLEDeviceCharacteristics({deviceId: _this.BLTdeviceId,serviceId: _this.serviceUUID,success(res) {console.log("获取特征值成功: ", res); // 可以在此判断特征值是否支持读写等操作,特征值其实也需要提前向硬件佬索取的_this.notify();},fail(err) {console.error(err);_this.closeBLEConnection();uni.showToast({title: "获取特征值失败",icon: "error",});},});}

开启消息监听(只使用一次)

  // 开启消息监听,只使用一次notify() {let _this = this;uni.notifyBLECharacteristicValueChange({state: true,deviceId: _this.BLTdeviceId, // 设备idserviceId: _this.serviceUUID, // 监听指定的服务characteristicId: _this.notifyUUID, // 监听对应的特征值type: "notification",success(res) {console.log("已开启监听: ", res);_this.successLinkFn && _this.successLinkFn("success");},fail(err) {console.error(err);_this.closeBLEConnection();uni.showToast({title: "监听失败",icon: "error",});console.log("监听失败");},});}

发送数据,只要有指令发送就会使用

根据蓝牙协议处理需要发送的数据,处理数据属于业务代码,处理好了直接调用send方法即可。

  // 发送数据,只要有指令发送就会使用send(data) {// 向蓝牙设备发送const _this = this;let buffer = Util.string2buffer(data);const BLTdeviceId = wx.getStorageSync("BLTdeviceId");wx.writeBLECharacteristicValue({deviceId: _this.BLTdeviceId,serviceId: _this.serviceUUID,characteristicId: _this.writeUUID,value: buffer,writeType: "writeNoResponse",success(res) {console.log("指令发送成功:", res);setTimeout(() => {_this.listenValueChange();}, 500);},fail(err) {console.error(err);_this.closeBLEConnection();},});}

监听消息变化

  // 监听消息变化listenValueChange() {const _this = this;uni.onBLECharacteristicValueChange((res) => {const data = Util.ab2hex(res.value);console.log("监听消息变化:", data);// 返回的数据有拆包的情况,所以需要判断data是否有帧头与帧尾,如无则需要拼接// 作为业务代码在回调方法中处理数据_this.dataChangeFn && _this.dataChangeFn(data, res);});}

蓝牙设备停止搜索

stopBluetoothDevicesDiscovery() {wx.stopBluetoothDevicesDiscovery({success(res) {console.log("蓝牙设备停止搜索:", res);},});}

断开蓝牙

// 断开蓝牙连接closeBLEConnection() {uni.closeBLEConnection({deviceId: _this.deviceId,});uni.closeBluetoothAdapter();}

使用蓝牙组件

在需要连接蓝牙的页面,调用Bluetooth的类,根据需要传入参数以及回调方式即可,可以在回调函数里面处理蓝牙数据,监听蓝牙连接状态

// 蓝牙连接handleBlueToothLink() {let _this = thislet params = {deviceId: _this.deviceId,serviceUUID: "", // 主服务的UUIDnotifyUUID: "", // 读writeUUID: "", // 写successLinkFn: function(res) {_this.successLinkFn(res);},dataChangeFn: function(data, res) {_this.dataChangeFn(data, res);},blueToothLinkStatusFn: function(res) {_this.blueToothStatusChange(res);},};_this.blueTooth = new Bluetooth(params);},

发送蓝牙指令

在页面上点击按钮,发送对应的蓝牙指令,需要将指令处理为蓝牙协议需要的数据格式。

handlerClick(instruct, dataLen, data) {this.blueTooth.send(Util.instructData(instruct, dataLen, data));
},

由于处理蓝牙协议使用的方法很多 ,单独写在了util.js方法中进行调用,包含进制转换,帧头和帧尾的处理,补零,数据处理等方法。(本文中提供ArrayBuffer转换的方法,有需要的话,再提供)。

蓝牙传输需要ArrayBuffer格式的数据

// 将字符串转换成ArrayBufer
string2buffer(str) {let val = ""if(!str) return;let length = str.length;let index = 0;let array = []while(index < length){array.push(str.substring(index,index+2));index = index + 2;}val = array.join(",");// 将16进制转化为ArrayBufferreturn new Uint8Array(val.match(/[\da-f]{2}/gi).map(function (h) {return parseInt(h, 16)})).buffer
},// 将ArrayBuffer转换成字符串
ab2hex(buffer) {var hexArr = Array.prototype.map.call(new Uint8Array(buffer),function (bit) {return ('00' + bit.toString(16)).slice(-2)})return hexArr.join('');
},// ArrayBuffer转字符串arrayBufferToString(buffer) {return String.fromCharCode.apply(null, new Uint8Array(buffer));},

总结

蓝牙方法都是调用的uniapp提供的蓝牙api,按照文档来编写的。
类的封装是为了代码的复用性和组件化。以后再遇到蓝牙需求,可以直接使用BlueTooth的类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/16007.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(22)LED灯(外部)

文章目录 前言 22.1 带有I2C连接的RGB LEDs/显示器 22.2 串行连接的设备 22.3 NTF LED的含义 前言 外部 LED 或 LED 显示屏可以通过连接到自动驾驶仪的 I2C 端口&#xff0c;或者在 4.0 及以后的版本中&#xff0c;如果是串行编程的设备&#xff0c;可以通过输出使用 SERV…

Image Sensor的FSIN/VSYNC

本文介绍Image Sensor的FSIN/VSYNC。 产品开发过程(比如3D成像)中&#xff0c;有时会遇到需要2个及以上的Image Sensor同步采集&#xff0c;因此&#xff0c;Image Sensor厂家对于他们的产品都提供了同步功能&#xff0c;也就是我们经常所见的FSIN/VSYNC(OV),XVS(Sony IMX3系列…

gen1-视频生成论文阅读

文章目录 摘要贡献算法3.1 LDM3.2 时空隐空间扩散3.3表征内容及结构内容表征结构表征条件机制采样 3.4优化过程 实验结果结论 论文&#xff1a; 《Structure and Content-Guided Video Synthesis with Diffusion Models》 官网&#xff1a; https://research.runwayml.com/ge…

大象机器人myCobot 280 2023版全新功能展示

引言 机械臂是一种可编程的、自动化的机械系统&#xff0c;它可以模拟人类的动作&#xff0c;完成各种任务&#xff0c;例如装配、喷涂、包装、搬运、焊接、研磨等。由于其高度灵活性和多功能性&#xff0c;机械臂在现代社会中已经得到了广泛的应用。 myCobot 280 M5Stack 202…

Spring Boot 中的 SockJS

Spring Boot 中的 SockJS 在 Spring Boot 中&#xff0c;SockJS 是一个用于实现 WebSocket 的兼容性解决方案。本文将介绍 SockJS 的原理、使用方法和示例代码。 什么是 SockJS SockJS 是一种浏览器与服务器之间的通信协议&#xff0c;它可以在浏览器和服务器之间建立一个基于…

论文阅读:Segment Anything之阅读笔记

目录 引言整体结构介绍论文问答代码仓库中&#xff0c;模型哪部分转换为了ONNX格式&#xff1f;以及如何转的&#xff1f;Mask decoder部分 Transformer decoder block?如何整合image_embedding&#xff0c;image_pe, sparse_prompt_embedding和dense_prompt_embedding的&…

将OxyPlot封装成用户控件后在WPF中的应用

1、文件架构 2、加载依赖项 Newtonsoft.Json OxyPlot.Wpf 3、NotifyBase.cs namespace Accurate.Common {public class NotifyBase : INotifyPropertyChanged{public event PropertyChangedEventHandler? PropertyChanged;public void DoNotify([CallerMemberName] string p…

XR-FRAME 开始

目录 新建一个XR组件在页面中使用这个组件添加一个物体来点颜色和灯光有点寡淡&#xff0c;加上图像让场景更丰富&#xff0c;环境数据动起来&#xff0c;加入动画还是不够&#xff0c;放个模型再来点交互组件通信&#xff0c;加上HUD虚拟 x 现实&#xff0c;追加AR能力识别人脸…

抖音seo矩阵系统源码开发部署-开源分享(二)

目录 市场背景分析 一、 抖音seo矩阵系统开发部署流程 二、 源码开发功能构思 三、 抖音seo源码开发部署注意事项 四、 部分开发代码展示 市场背景分析 账号矩阵是通过不同平台不同账号之间建立联系&#xff0c;通过将同一品牌下不同平台不同账号的粉丝流量进行账号互通&a…

网络安全 log4j漏洞复现

前言&#xff1a; log4j被爆出“史诗级”漏洞。其危害非常大&#xff0c;影响非常广。该漏洞非常容易利用&#xff0c;可以执行任意代码。这个漏洞的影响可谓是重量级的。 漏洞描述&#xff1a; 由于Apache Log4j存在递归解析功能&#xff0c;未取得身份认证的用户&#xff…

每次装完 homebrew,ohmyzsh 就会报错:Insecure completion-dependent directories detected:

参考:https://zhuanlan.zhihu.com/p/313037188 这是因为在big sur安装homebrew后&#xff0c;会在/usr/local/share/生成一个zsh文件夹&#xff0c;里面包含了 因此&#xff0c;zsh文件默认设置的权限是775&#xff0c;也就是group user有writer的权利&#xff0c;zsh认为这是…

【笔记】数字电路基础1 - 门电路

目录 数字电路基础与门电路数电基础基本门电路复合门电路TTL 门电路CMOS 门电路 数字电路基础与门电路 数电基础 数字电路中常将 0 &#xff5e; 1V 范围的电压称为低电平&#xff0c;用“0”表示&#xff1b;而将 3 &#xff5e; 5V 范围的电压称为高电平&#xff0c;用“1”…