uniapp小程序连接蓝牙设备

uniapp小程序连接蓝牙设备

      • 一、初始化蓝牙模块
      • 二、开始搜索
      • 三、连接蓝牙
      • 四、监听特征值变化
      • 五、调用示例
      • utils.js文件

一、初始化蓝牙模块

这一步是必须的,在开发项目过程中,初始化蓝牙模块之后,紧接着就要开启一些监听的api,供后续设备读写数据时监听变化。

initBLE(callback) {//提前定义变量,直接在uni的api中使用this是不可以的var self = this;// `第一步:初始化蓝牙模块`uni.openBluetoothAdapter({success: function (e) {utils.toast("初始化蓝牙适配器成功");},fail: function (e) {utils.toast("初始化蓝牙适配器失败 : " + JSON.stringify(e));},});// `检查蓝牙适配器状态变化`// `这一步主要是为了在连接成功蓝牙之后关闭蓝牙搜索,蓝牙搜索非常耗费性能`uni.onBluetoothAdapterStateChange(function (e) {self.bluetooth.available = e.available;if (!e.available) {utils.toast("蓝牙适配器不可用");if (self.bluetooth.startDiscovery) {self.bluetooth.startDiscovery = false;self.stopBluetoothDevicesDiscovery();}}});// `监听搜索到设备`uni.onBluetoothDeviceFound(function (e) {// `当搜索到设备后,可以在e.devices中获取到设备信息列表`if (!e.devices) return;for (var i = 0; i < e.devices.length; i++) {var device = e.devices[i];for (var j = 0; j < self.discoveryList.length; j++) {var item = self.discoveryList[j];// 去重if (item.deviceId === device.deviceId) {return;}}self.discoveryList.push(device);}});// `监听蓝牙设备连接变化`uni.onBLEConnectionStateChange(function (e) {// 该方法回调中可以用于处理连接意外断开等异常情况self.currentDeviceStatus = e.connected ? 1 : 2;// 在连续盘点过程中是不允许断开的,万一因为其他什么原因断开了,则尝试停止连续盘点if (!e.connected && self.inventoryLabelForm.looping) {self.sendStopLoopInventoryCmd(); //停止盘点}});// `读数据`uni.onBLECharacteristicValueChange(function (e) {if (e.deviceId != self.currentDevice.deviceId) return;var value = self.buffer2Hex(e.value);console.log(e); //查看是否有R20固定返回值utils.toast("读数据178:" + JSON.stringify(e));self.lastRcvData += value;self.doRcvData();});self.historyList = utils.getHistoryList();// 如果有cb回调函数,则需要停止下拉刷新if (callback) {// setTimeout这里等待一下上面的异步初始化setTimeout(() => {callback();}, 1000);}},

二、开始搜索

以上只是蓝牙的初始化操作,要想真正实现蓝牙连接从第二步开始

// 开启蓝牙搜索服务startBluetoothDevicesDiscovery() {var self = this;// 小程序环境需要等待一下,不然会报错setTimeout(() => {// 开始搜寻附近的蓝牙外围设备uni.startBluetoothDevicesDiscovery({allowDuplicatesKey: false,success: function (e) {self.bluetooth.discoverying = true;//开启搜索成功,此时初始化中定义的onBluetoothDeviceFound会自动执行},fail: function (e) {utils.toast("开始搜索蓝牙设备失败 : " + JSON.stringify(e));},});}, 1000);},

三、连接蓝牙

目前为止我们已经搜索到蓝牙设备了,下面要做的就是在蓝牙列表中选择对应的蓝牙设备进行连接

// 连接设备onConnectDevice(device) {// `device是选择的设备对象,在这可以取到设备的deviceId供后续使用`var self = this;this.onCloseDiscoveryDialog();this.onCloseHistoryDialog();this.currentDevice = device;this.currentDeviceStatus = 3;this.lastRcvData = "";// 创建一个BLE连接uni.createBLEConnection({deviceId: device.deviceId,//这里使用设备id来创建连接success: function (e) {// 创建完成后获取服务(这在ios中是必须的,否则会导致后面读取数据失败)uni.getBLEDeviceServices({// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接deviceId: device.deviceId,success(res) {// 获取特征值(这在ios中是必须的,否则会导致后面读取数据失败)uni.getBLEDeviceCharacteristics({// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接deviceId: device.deviceId,// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取serviceId: RX_SERVICE_UUID, //因为这里使用的是固定服务所以事先定义过常量了,这里直接使用success(res) {// 创建连接-获取服务-获取特征值之后就可以开启nofity功能了self.enableBleNotify(device);},fail() {},});},});// 开启nofity功能self.enableBleNotify(device);},fail: function (e) {utils.toast("连接蓝牙设备失败 : " + JSON.stringify(e));self.currentDeviceStatus = 2;},});// 保存设备到历史记录里var flag = true;for (var i = 0; i < this.historyList.length; i++) {var item = this.historyList[i];if (item.deviceId === device.deviceId) {this.historyList[i] = device;flag = false;}}if (flag) {this.historyList.push(device);}utils.saveHistoryList(this.historyList);},

四、监听特征值变化

 enableBleNotify(device) {// 这里监听时,ios测试需要有点延迟,安卓的话,只在测试机上测试过,不需要延迟// 这里延迟1秒兼容,反正差距不大setTimeout(function () {uni.notifyBLECharacteristicValueChange({state: true,deviceId: device.deviceId,serviceId: RX_SERVICE_UUID,characteristicId: R_UUID,success: function (e) {//到了此时蓝牙才算真正的连接成功},fail: function (e) {},});}, 1000);},

五、调用示例

这里以单次盘点为例

 // 单步盘点标签async  onOneStepInventory() {var self = this;if (!this.checkDeviceConnect()) return;this.inventoryLabelForm.startTime = utils.currentTimeMillis(); //获取盘点时间的// 单步盘点关闭enableRssithis.inventoryLabelForm.enableRssi = false;// 发送固定值await this.sendR20Hex(); //这里是定制需要没有可以省去var cmd = this.generateUHFProtocl(0x80, utils.number2Hex(5000, 2));self.sendData(cmd);},//发送固定值async sendR20Hex() {await this.sendData("A55A0029F011D75238EE46C3ECFFCE3B9AFC093ACC13F711A6ADF3FF76ACE59A8DF1BA704E22EC0D0A");},//写入操作(发送数据,连续存盘指令自行实现了,不调用该方法)async sendData(hexStr, serviceId, characteristicId) {if (utils.isBlank(hexStr)) return;serviceId = serviceId || RX_SERVICE_UUID;characteristicId = characteristicId || W_UUID;var self = this;var sendData;// ble发送数据时,需要分包,最多20字节if (hexStr.length > 40) {sendData = hexStr.substr(0, 40);hexStr = hexStr.substr(40, hexStr.length - 40);} else {sendData = hexStr;hexStr = null;}this.logSend(sendData);var buffer = new ArrayBuffer(sendData.length / 2);var bufView = new Uint8Array(buffer);for (var i = 0; i < sendData.length; i += 2) {bufView[i / 2] = parseInt(sendData.substr(i, 2), 16);}//这里写了一个promise是为了在执行正常操作之前,先执行固定值操作return new Promise((resolve, reject) => {uni.writeBLECharacteristicValue({deviceId: self.currentDevice.deviceId,serviceId: serviceId,characteristicId: characteristicId,value: buffer,success: async function (e) {if (hexStr) {//超过20字节 递归循环写入await self.sendData(hexStr);}console.log("写入数据成功391" + sendData);// 由于写字节限制,如果还有未发送完的数据,接着继续发送resolve();},fail: function (e) {},});});},

utils.js文件

这里主要存放一些转换方法,上面用到的utils.xx方法可以在此处查看

export default {alert: function (content, title = "提示") {uni.showModal({title,content,showCancel: false,success: function (res) {},});},confirm: function (content, title = "提示") {uni.showModal({title,content,success: function (res) {if (res.confirm) {console.log("用户点击确定");} else if (res.cancel) {console.log("用户点击取消");}},});},toast: function (title, duration = 1000) {uni.showToast({title,icon: "none",duration,});},showWaiting: function (title = "加载中") {uni.showLoading({title,});},closeWaiting: function () {uni.hideLoading();},actionSheet: function (itemList) {uni.showActionSheet({itemList,success: function (res) {console.log("选中了第" + (res.tapIndex + 1) + "个按钮");},fail: function (res) {console.log(res.errMsg);},});},saveHistoryList: function (list) {try {uni.setStorageSync("history_list", JSON.stringify(list));} catch (e) {// error}},getHistoryList: function () {try {const value = uni.getStorageSync("history_list");if (value) {return JSON.parse(value);} else {return [];}} catch (e) {// error}},clearHistoryList: function () {try {uni.removeStorageSync("history_list");} catch (e) {// error}},leftPad: function (value, length, fill) {while (length - value.length > 0) {value = fill + value;}return value;},number2Hex: function (value, byteLength) {value = parseInt(value);var hex = value.toString(16).toUpperCase();byteLength = byteLength || hex.length / 2 + (hex.length % 2);return this.leftPad(hex, byteLength * 2, "0");},bin2Hex: function (value, byteLength) {byteLength = byteLength || 1;byteLength = Math.max(value.length / 8 + (value.length % 8 > 0 ? 1 : 0),byteLength);value = this.leftPad(value, byteLength * 8, "0");var hex = "";for (var i = 0; i < value.length; i += 8) {hex += this.number2Hex(parseInt(value.substr(i, 8), 2), 1);}return hex;},isNull: function (value) {if (value == null) return true;if ("undefined" == typeof value) return true;return false;},isString: function (value) {return "[object String]" === Object.prototype.toString.call(value);},isBlank: function (value) {if (this.isNull(value)) return true;if (!this.isString(value)) return true;if (value.trim().length == 0) return true;return false;},str2Hex: function (str) {var hex = "";for (var i = 0; i < str.length; i++) {hex += this.number2Hex(str.charCodeAt(i), 1);}return hex;},currentTimeMillis: function () {return new Date().getTime();},hex2ByteArray: function (hex) {var result = [];for (var i = 0; i < hex.length; i += 2) {var value = parseInt(hex.substr(i, 2), 16);if (value > 127) {value -= 0x100;}result.push(value);}return result;},/*** hex转字符串* @param {Object} hex* @param {Object} charset	编码格式,默认为utf-8*/hex2Str: function (hex, charset = "utf-8") {var bytesArray = this.hex2ByteArray(hex);try {var str;// 创建一个TextDecoder对象,指定所需的编码格式const decoder = new TextDecoder(charset);// 将ByteArray转换为字符串str = decoder.decode(bytesArray);return str;} catch (e) {this.toast("错误的编码格式");}},
};

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

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

相关文章

redis查询慢,你们是如何查询优化?(运维篇3)

1、查看是否写入了bigkey 如果你查询慢日志发现&#xff0c;并不是复杂度过高的命令导致的&#xff0c;而都是 SET / DEL 这种简单命令出现在慢日志中&#xff0c;那么你就要怀疑你的实例否写入了 bigkey。 Redis 在写入数据时&#xff0c;需要为新的数据分配内存&#xff0c;相…

2024年公共文化与社会服务国际会议(ICPCSS 2024)

2024年公共文化与社会服务国际会议 2024 International Conference on Public Culture and Social Services 【1】会议简介 2024年公共文化与社会服务国际会议是一个集学术性、实践性和国际性于一体的盛会。我们期待与您共同探讨公共文化与社会服务的未来发展方向&#xff0c;为…

【linux】服务器设置所有用户创建虚拟环境到默认路径

【linux】服务器设置所有用户创建虚拟环境到默认路径 【创作不易&#xff0c;点点赞关注收藏】&#x1f600; 需要安装anaconda3的小伙伴可以看一下我前面的博文linux安装anaconda3 一、情况说明 我的anaconda3安装在"/public/apps/anaconda3/“&#xff0c;我希望所有…

C#实现最短路径算法

创建点集 double r 200 * 500;double width 1920;double height 1080;int col (int)(r / width);int row (int)(r / height);List<(double, double)> list1 new List<(double, double)>();for (int i 0; i < row; i){var y i * height;if (y < r){va…

好莱坞级别AI视频工具Odyssey亮相!AI世界动态回顾

好莱坞级别的视觉AI&#xff1a;Odyssey 首先&#xff0c;我们要提到的就是Odyssey——一款新晋AI视频工具&#xff0c;它以其好莱坞级别的视觉AI能力引起了广泛关注。奥德赛展示的一些片段令人印象深刻&#xff0c;包括精美的无人机镜头、风景画面以及专业级的B-roll素材。虽…

Snap Video:用于文本到视频合成的扩展时空变换器

图像生成模型的质量和多功能性的显著提升&#xff0c;研究界开始将其应用于视频生成领域。但是视频内容高度冗余&#xff0c;直接将图像模型技术应用于视频生成可能会降低运动的保真度和视觉质量&#xff0c;并影响可扩展性。来自 Snap 的研究团队及其合作者提出了 "Snap …

运算放大器(2)

&#xff08;1&#xff09;反向放大器 Vout(-R2/R1)*Vi 图一运放的同向端接地0V&#xff0c;反向端和同向端虚短&#xff0c;所以也是0V 反向输入端输入电阻很高&#xff0c;虚断&#xff0c;几乎没有电流注入和流出&#xff0c;那么R1和R2相当于是串联的&#xff0c;流过一个…

Nacos服务公网环境登陆报密码错误问题排查

作者&#xff1a;小丫 一、问题现象 nacos服务内网可以正常登录&#xff0c;如下&#xff1a; 走公网代理出来之后&#xff0c;无法正常登录&#xff0c;报错"用户名密码错误" 二、排查步骤 1、链路分析 首先确认公网代理的链路&#xff1a; 域名—>haprox…

Epson打印机日常问题和解决办法

1、打印过程中缺纸&#xff0c;重新放入纸张之后&#xff0c;打印机出错。 打开“控制面板”&#xff0c;进入“设备与打印机”&#xff1a; 选择你正在使用的打印机&#xff0c;最下面可以看到打印机状态&#xff08;我这边用完脱机了&#xff0c;所以显示脱机&#xff09;&a…

【Python实战因果推断】34_双重差分5

目录 Identification Assumptions Parallel Trends No Anticipation Assumption and SUTVA Identification Assumptions 您现在可能已经知道&#xff0c;因果推断是统计工具和假设之间的不断互动。在本文中&#xff0c;我选择从统计工具入手&#xff0c;展示 DID 如何利用单…

数据结构之单链表(赋源码)

数据结构之单链表 线性表 线性表的顺序存储结构&#xff0c;有着较大的缺陷 插入和删除操作需要移动大量元素。会耗费很多时间增容需要申请空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗即使是使用合理的增容策略&#xff0c;实际上还会浪费许多用不上的…

led灯什么牌子的质量好?口碑前五的led灯推荐

每每到开学季&#xff0c;学生们重返校园&#xff0c;各个家长和学生们也迎接新学期的前期准备工作&#xff0c;当然&#xff0c;用眼健康的考量也列位其中&#xff0c;国内的学习压力大一直是众所周知的&#xff0c;学生除了在学校长时间用眼外&#xff0c;短暂的户外休息时间…

为什么有些3d模型不能编辑?---模大狮模型网

在展览3D模型设计行业中&#xff0c;设计师们面临一个重要的技术挑战&#xff1a;为什么有些3D模型在某些情况下变得难以编辑?这一问题不仅关乎技术操作的复杂性&#xff0c;更深层次地影响着设计工作的效率和成果质量。本文将探讨这一问题的根本原因及其在实际工作中的具体表…

JSONObject和Map<String, Object>的转换

一、前言 Java开发中出参返回和入参传入更灵活的方法是使用Map<String, Object>入参或出参&#xff0c;或者使用JSONObject。 1、好处&#xff0c;参数可变&#xff0c;对接口扩展性很友好。 public ResponseData<WXModelDTO> getUserInfo(RequestBody Map<…

浏览器输入URL后的过程

总体流程&#xff1a; 1. 用户输入URL并按下回车 当用户在浏览器的地址栏中输入一个 URL 并按下回车&#xff0c;浏览器开始解析用户输入并判断这是一个合法的 URL。 2. DNS 解析 缓存查找&#xff1a;浏览器首先查看本地 DNS 缓存中是否有对应的 IP&#xff0c;如果有则直接…

九盾安防丨如何判断叉车是否超速?

在现代物流和生产流程中&#xff0c;叉车是提高效率和降低成本的关键工具。然而&#xff0c;叉车的高速行驶也带来了安全隐患&#xff0c;这就要求我们对其进行严格的安全管理。九盾安防&#xff0c;作为业界领先的安防专家&#xff0c;今天就为大家揭晓如何判断叉车是否超速&a…

Java高频面试基础知识点整理7

干货分享&#xff0c;感谢您的阅读&#xff01;背景​​​​​​高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09; 最全文章见&#xff1a;Java高频面试基础知识点整理 &#xff08;一&#xff09;Java基础高频知识考点 针对人员&#xff1a; 1.全部人员都…

SCI一区级 | Matlab实现NGO-CNN-LSTM-Mutilhead-Attention多变量时间序列预测

SCI一区级 | Matlab实现NGO-CNN-LSTM-Mutilhead-Attention多变量时间序列预测 目录 SCI一区级 | Matlab实现NGO-CNN-LSTM-Mutilhead-Attention多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matlab实现NGO-CNN-LSTM-Mutilhead-Attention北方苍鹰算…

【机器学习】Exam4

实现线性不可分logistic逻辑回归 我们目前所学的都是线性回归&#xff0c;例如 y w 1 x 1 w 2 x 2 b y w_1x_1w_2x_2b yw1​x1​w2​x2​b 用肉眼来看数据集的话不难发现&#xff0c;线性回归没有用了&#xff0c;那么根据课程所学&#xff0c;我们是不是可以增加 x 3 x…