当前位置: 首页 > news >正文

uni-app 蓝牙传输

https://www.cnblogs.com/ckfuture/p/16450418.html

https://www.cnblogs.com/yangxiaobai123/p/16021058.html

字符串转base64:https://www.cnblogs.com/sunny3158/p/17312158.html 

将 ArrayBuffer 对象转成 Base64 字符串:基础 - uni.arrayBufferToBase64 - 《uni-app API 文档》 - 书栈网 · BookStack 

ArrayBuffer:https://zhuanlan.zhihu.com/p/655456833 

最近在做一个项目,要求app通过蓝牙连接设备并将报文传输至设备中,在这个过程踩过了几个坑,总结如下:

根据uni-app官网API主要涉及到“蓝牙”和“低功耗蓝牙”两个部分。

主要步骤:

步骤1:初始化蓝牙模块 openBluetoothAdapter

            $openBluetoothAdapter(){uni.openBluetoothAdapter({success: (res) => {//初始化成功,搜索设备console.log('openBluetoothAdapter success', res);uni.showLoading({title: '搜索设备中'});setTimeout(()=>{this.baseList=[];//每次扫码清空设备列表,不然会导致重复this.$startBluetoothDevicesDiscovery();//扫码蓝牙设备},100);//定时关闭搜索设备setTimeout(()=>{this.$stopBluetoothDevicesDiscovery();uni.hideLoading();},10*1000);},fail: (res) => {uni.showToast({title: '请打开蓝牙',duration: 1000});if (res.errCode === 10001) {//监听蓝牙适配器状态变化事件uni.onBluetoothAdapterStateChange(function(res){console.log('onBluetoothAdapterStateChange', res);if (res.available) {//开始扫描this.$startBluetoothDevicesDiscovery()}})}}})},

步骤2:搜索附近的蓝牙外围设备 startBluetoothDevicesDiscovery

            //2.搜索附近的蓝牙外围设备$startBluetoothDevicesDiscovery(){if (this._discoveryStarted) {return;}this._discoveryStarted = true;//开始搜寻附近的蓝牙外围设备uni.startBluetoothDevicesDiscovery({allowDuplicatesKey: true,success: (res) => {console.log('startBluetoothDevicesDiscovery success', res);//监听寻找到新设备的事件this.$onBluetoothDeviceFound()},fail:err=>{console.error("startBluetoothDevicesDiscoveryErr",err);uni.showToast({icon:'none',duration:2000,title:"请检查蓝牙状态",});}})},

步骤3:监听寻找到新设备 onBluetoothDeviceFound

            $onBluetoothDeviceFound(){let that =this;//监听寻找到新设备的事件uni.onBluetoothDeviceFound(function(res){res.devices.forEach(device => {if (!device.name && !device.localName) {return;}//添加蓝牙设备列表let oneBluetooth={deviceId: device.deviceId,name: device.name,RSSI:device.RSSI,localName:device.localName}            //判断是否存在if(that.bluetoothIndex.indexOf(device.deviceId) ==-1){that.baseList.push(oneBluetooth);that.bluetoothIndex.push(device.deviceId);}//如果名字相同连接设备//if(device.name == devicename){//$createBLEConnection(device.deviceId);//}})})},

步骤4:创建连接蓝牙事件  createBLEConnection

            $createBLEConnection(deviceId){let that=this;//1)判断设备是否处于连接状态if(that.Connecting){uni.showToast({icon:'none',duration:2000,title:"设备已连接",});return} //2)创建连接uni.showLoading({title: '设备连接中',mask:true,});uni.createBLEConnection({deviceId:deviceId,success: (res) => {that._deviceId = deviceId;//不延迟造成获取不到服务!!!!,我走过的坑!!!setTimeout(function() {//获取设备的蓝牙服务that.$getBLEDeviceServices(deviceId);//关闭等待提示setTimeout(function () {uni.hideLoading();}, 100);}, 7000);},fail: (err) =>{console.log(err);}});//3)设置MTU,否则传输报文不全,默认是23bytes,但是蓝牙本身是需要3bytes,故而只能传输20bytessetTimeout(()=>{console.log('deviceId>>>',deviceId);uni.setBLEMTU({deviceId:deviceId,mtu:255,success:(res)=>{console.log('设置MTU最大值成功',res);},fail:(res)=>{console.log('设置MTU最大值失败',res);}});},9000);//4)关闭搜索this.$stopBluetoothDevicesDiscovery();},

步骤5:获取蓝牙设备的所有服务 getBLEDeviceServices

            $getBLEDeviceServices(deviceId){//获取蓝牙设备所有服务(service)uni.getBLEDeviceServices({deviceId,success: (res) => {console.log('250res.services>>>',res.services);for (let i = 0; i < res.services.length; i++) {if (res.services[i].isPrimary) {this.$getBLEDeviceCharacteristics(deviceId, res.services[i].uuid);return;}}}});},

步骤6:获取蓝牙设备某个服务中所有特征值(characteristic)getBLEDeviceCharacteristics

            $getBLEDeviceCharacteristics(deviceId,serviceId){let that = this;//获取蓝牙设备某个服务中所有特征值(characteristic)。uni.getBLEDeviceCharacteristics({deviceId,serviceId,success: (res) => {console.log('288getBLEDeviceCharacteristics success', res.characteristics);for (let i = 0; i < res.characteristics.length; i++) {let item = res.characteristics[i]//if (item.properties.read) {//读取低功耗蓝牙设备的特征值的二进制数据值。1uni.readBLECharacteristicValue({deviceId,serviceId,characteristicId: item.uuid,})//}if (item.properties.write) {this._deviceId = deviceId;this._serviceId = serviceId;this._characteristicId = item.uuid;//写入请求数据this.$writeBLECharacteristicValue();                                }//if (item.properties.notify || item.properties.indicate) {//启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值。uni.notifyBLECharacteristicValueChange({deviceId,serviceId,characteristicId: item.uuid,state: true,success(res) {// console.log('notifyBLECharacteristicValueChange success:' + res.errMsg);// console.log(JSON.stringify(res));uni.onBLECharacteristicValueChange(characteristic => {console.log('监听低功耗蓝牙设备的特征值变化事件成功>>');//将字节转换成16进制字符串var data = ab2hex(characteristic.value)//将16进制转成字符串let newdataStr = Buffer.from(data,'hex');//先把数据存在buf里面//that.btvalue=newdataStr.toString("utf-8");//使用toString函数就能转换成字符串//设备返回SNthat.SN=newdataStr.toString("utf-8");console.log('设备返回SN>>>',that.SN);//根据返回的数据处理设备类型和显示的输入区域-----------------that.getEquType(that.SN);});}});//}}},fail(res) {console.error('getBLEDeviceCharacteristics', res)}})},

步骤7:向蓝牙设备发送一个16进制数据

            $writeBLECharacteristicValue(){let buffer = new ArrayBuffer(1)let dataView = new DataView(buffer);dataView.setUint8(0, 0);//0x61 | 0uni.writeBLECharacteristicValue({deviceId: this._deviceId,serviceId: this._serviceId,//"0000FE61-0000-1000-8000-00805F9B34FB",characteristicId: this._characteristicId,value: buffer,success: function(res){console.log('350',res);},fail: function(res){console.log(res);}})},

步骤8:向蓝牙设备发送字符串数据 writeBLECharacteristicValueString

            $writeBLECharacteristicValueString(str){// 发送方式一let buffer = new ArrayBuffer(str.length);let dataView = new DataView(buffer);for (let i in str) {dataView.setUint8(i, str[i].charCodeAt() | 0);    //打印二进制字节//console.log('dataView.getUint8(i)>>',dataView.getUint8(i));}//延迟发送指令setTimeout(()=>{uni.writeBLECharacteristicValue({deviceId: this._deviceId,serviceId: this._serviceId,characteristicId: this._characteristicId,//"0000FE61-0000-1000-8000-00805F9B34FB",//,value: buffer,success: function(res){console.log("命令写入成功",res); },fail: function(res){console.error("命令写入失败",res);}});},2000);},

步骤9:关闭搜索  stopBluetoothDevicesDiscovery

            $stopBluetoothDevicesDiscovery(){//关闭搜索uni.stopBluetoothDevicesDiscovery({success(res) {this._discoveryStarted=false;}})},

步骤10:断开蓝牙设备连接 closeBLEConnect

            $closeBLEConnect(deviceId){uni.closeBLEConnection({deviceId,success:res=>{this.deviceId = "";console.log("断开成功",res);},fail:err=>{console.error("断开错误",err);}})},

需要注意的是:

1)和蓝牙设备通讯不能太频繁。

2)写入数据时候要注意特性值UUID。

3)写入数据超过20bytes时候需要设置MTU。否则传输的内容将被截取,造成传输信息不完整。

相关文章:

uni-app 蓝牙传输

https://www.cnblogs.com/ckfuture/p/16450418.html https://www.cnblogs.com/yangxiaobai123/p/16021058.html 字符串转base64&#xff1a;https://www.cnblogs.com/sunny3158/p/17312158.html 将 ArrayBuffer 对象转成 Base64 字符串&#xff1a;基础 - uni.arrayBufferT…...

MBR10200CT-ASEMI智能AI应用MBR10200CT

编辑&#xff1a;ll MBR10200CT-ASEMI智能AI应用MBR10200CT 型号&#xff1a;MBR10200CT 品牌&#xff1a;ASEMI 封装&#xff1a;TO-220 批号&#xff1a;最新 恢复时间&#xff1a;35ns 最大平均正向电流&#xff08;IF&#xff09;&#xff1a;10A 最大循环峰值反向…...

力扣 爬楼梯

动态规划算法基础篇。 class Solution {public int climbStairs(int n) {int[] f new int[n 1];f[0] 1;f[1] 1;//当爬到n阶楼梯时&#xff0c;可知是由n-1阶或n-2阶楼梯而来for(int i 2; i < n; i) {f[i] f[i - 1] f[i - 2];//后面的每一阶种数由前两个状态得到}ret…...

java设计模式之:策略模式+工厂模式整合案例实战(一)

本文介绍项目中常用的策略模式工厂模式的案例&#xff0c;该案例是针对策略类比较少的情况&#xff1b;下一篇会讲解策略类比较多的案例&#xff0c;下面直接开始&#xff1a; 案例1&#xff1a;项目中对系统中的客户和销售进行事件通知(短信、邮件、钉钉) 首先要有通知的策略…...

国内Ubuntu安装 stable-diffusion教程,换成国内镜像

安装依赖&#xff1a; 首先更新系统并安装Python 3.10和pip&#xff1a; sudo apt update sudo apt install python3.10 python3-pip 设置Python虚拟环境&#xff08;可选&#xff09;&#xff1a; 安装Python虚拟环境管理工具&#xff0c;并创建激活虚拟环境&#xff1a; su…...

JAVA final详细介绍

一、介绍 final 中文意思: 最后的,最终的. final 可以修饰类、属性、方法和局部变量, 在某些情况下,程序员可能有以下需求&#xff0c;就会使用到final&#xff1a; 1&#xff09;当不希望类被继承时,可以用final修饰。 //如果我们要求A类不能被其他类继承 //可以使用fin…...

45、tomcat+课后实验

tomcat 1、tomcat tomcat和php一样&#xff0c;都是用来处理动态页面的。 tomcat也可以作为web应用服务器&#xff0c;开源的。 php .php tomcat .jsp nginx .html tomcat 是用Java代码写的程序&#xff0c;运行的是Java的web应用程序。 tomcat的特点和功能&#xff1a…...

设计模式的七大原则

1.单一职责原则 单一职责原则(Single responsibility principle)&#xff0c;即一个类应该只负责一项职责。如类A负责两个不同职责&#xff1a;职责1&#xff0c;职责2。当职责1需求变更而改变A时&#xff0c;可能造成职责2执行错误&#xff0c;所以需要将类A的粒度分解为A1、…...

ThreeJS-3D教学十五:ShaderMaterial(noise、random)

ThreeJS-3D教学十四:ShaderMaterial(length、fract、step) 上面这篇主要是操作 fragmentShader 片元着色器,实现对物体颜色的修改,这次咱们来看下修改 vertexShader 顶点着色器,这个其实就是位移各个顶点的位置。 接下来我们先介绍下 noise 噪声函数(Perlin Noise、Sim…...

LeetCode 2974.最小数字游戏:排序+交换奇偶位

【LetMeFly】2974.最小数字游戏&#xff1a;排序交换奇偶位 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-number-game/ 你有一个下标从 0 开始、长度为 偶数 的整数数组 nums &#xff0c;同时还有一个空数组 arr 。Alice 和 Bob 决定玩一个游戏&#xff…...

使用vllIm部署大语言模型

使用vllm部署大语言模型一般需要以下步骤&#xff1a; 一、准备工作 1. 系统要求 - 操作系统&#xff1a;常见的 Linux 发行版&#xff08;如 Ubuntu、CentOS&#xff09;或 Windows&#xff08;通过 WSL&#xff09;。 - GPU 支持&#xff1a;NVIDIA GPU 并安装了适当的驱动程…...

静态搜索iOS动态链接函数的调用位置

静态搜索iOS动态链接函数的调用位置 可执行文件格式mach-O,是在苹果的操作系统 macOS 和 iOS 上使用的一种二进制文件格式。 在一些iOS安全扫描中&#xff0c;可能存在需要获取函数具体调用位置的需求&#xff0c;能指导用户更精确的定位漏洞。 现在以NSLog函数为例&#xff…...

【鸿蒙学习笔记】尺寸设置・layoutWeight・对子组件进行重新布局

官方文档&#xff1a;尺寸设置 目录标题 layoutWeight&#xff1a;对子组件进行重新布局 layoutWeight&#xff1a;对子组件进行重新布局 设置了layoutWeight属性的子元素与兄弟元素占主轴尺寸按照权重进行分配&#xff0c;忽略元素本身尺寸设置。 // 引入包名 import { http…...

vue实现表单输入框数字类型校验功能

vue实现表单输入框数字类型校验功能 1. 样式代码 <el-form-item label"订单总价"><el-input size"small" v-model"form.totalPrice" placeholder"请输入订单总价 正整数或者2位数小数" input"check(form.totalPric…...

JS登录页源码 —— 可一键复制抱走

前期回顾 https://blog.csdn.net/m0_57904695/article/details/139838176?spm1001.2014.3001.5501https://blog.csdn.net/m0_57904695/article/details/139838176?spm1001.2014.3001.5501 登录页预览效果 <!DOCTYPE html> <html lang"en"><head…...

Kithara与OpenCV (一)

Kithara使用 OpenCV 库 目录 Kithara使用 OpenCV 库简介需求和支持的环境构建 OpenCV 库使用 CMake 进行配置以与 Kithara 一起工作 使用 OpenCV 库设置项目运行 OpenCV 代码图像采集和 OpenCV自动并行化限制和局限性1.系统建议2.实时限制3.不支持的功能和缺失的功能4.显示 Ope…...

什么是软件定义安全SDSec

一、软件定义安全SDSec产生的背景 软件定义安全&#xff08;Software Defined Security&#xff0c;SDSec&#xff09;的产生背景主要源于传统网络安全防护方法在面对复杂网络环境时的不适应性&#xff0c;以及软件定义网络&#xff08;SDN&#xff09;技术的发展和应用。 SD…...

【C语言】C语言可以做什么?

目录 1. 操作系统开发1.1 操作系统内核1.2 设备驱动程序1.3 系统工具和实用程序 2. 嵌入式系统2.1 微控制器编程2.2 传感器和执行器控制2.3 消费电子产品 3. 应用程序开发3.1 图形用户界面应用3.2 游戏开发3.3 多媒体处理 4. 网络编程4.1 网络协议实现4.2 服务器和客户端程序4.…...

WordPress 主题技巧:给文章页增加“谁来过”模块。

模块功能&#xff1a; 我个人目前在做一个电影类的网站&#xff0c;在开发文章页的模版时候&#xff0c;突然觉得给文章页增加一个“谁对本电影感兴趣”的功能模块可能会比较有趣&#xff0c;这个功能有点类似于‘足迹’的感觉&#xff0c;用户可以通过这个功能&#xff0c;发…...

【vue组件库搭建07】Vitest单元测试

vitest官网 vue-test-utils 我们的测试框架选择的是 Vitest 和 vue-test-utils。两者的关系为&#xff1a; Vitest 提供测试方法&#xff1a;断言、Mock 、SpyOn 等方法。vue-test-utils: 挂载和渲染组件&#xff1a; Vue Test Utils 允许您在隔离中挂载组件&#xff0c;这意…...

vLLM-v0.17.1与卷积神经网络(CNN)结合:多模态推理架构探索

vLLM-v0.17.1与卷积神经网络结合&#xff1a;多模态推理架构探索 1. 前沿技术融合带来的突破 当视觉理解遇上语言推理&#xff0c;会产生怎样的化学反应&#xff1f;我们最近尝试将vLLM-v0.17.1大语言模型与卷积神经网络&#xff08;CNN&#xff09;图像编码器相结合&#xf…...

wan2.1-vae开源模型价值:相比闭源方案节省90%图像生成API调用成本

wan2.1-vae开源模型价值&#xff1a;相比闭源方案节省90%图像生成API调用成本 你有没有算过&#xff0c;每个月花在AI图像生成上的钱有多少&#xff1f; 如果你是内容创作者、电商运营、设计师&#xff0c;或者任何需要大量图片素材的人&#xff0c;可能已经习惯了这样的场景…...

避开这些坑!用MATLAB做QPSK调制解调仿真时,你的成形滤波和匹配滤波设置对了吗?

QPSK仿真中的成形滤波与匹配滤波陷阱&#xff1a;MATLAB实战避坑指南 在数字通信系统的设计与验证过程中&#xff0c;MATLAB仿真扮演着至关重要的角色。许多工程师和研究人员在QPSK调制解调仿真中&#xff0c;常常遇到性能不达预期或结果与理论不符的情况。本文将深入剖析成形滤…...

HLAE高效创作指南:释放Source引擎电影级视觉潜能

HLAE高效创作指南&#xff1a;释放Source引擎电影级视觉潜能 【免费下载链接】advancedfx Half-Life Advanced Effects (HLAE) is a tool to enrich Source (mainly CS:GO) engine based movie making. 项目地址: https://gitcode.com/gh_mirrors/ad/advancedfx 一、核心…...

RocketMQ Topic队列配置实战指南:从原理到最佳实践

1. RocketMQ Topic队列配置的核心原理 第一次接触RocketMQ的Topic配置时&#xff0c;我也曾被那些专业术语搞得一头雾水。直到有一次线上系统因为队列配置不当导致消息积压&#xff0c;我才真正理解这些参数的重要性。现在回想起来&#xff0c;其实Topic队列配置就像高速公路的…...

CLIP-GmP-ViT-L-14多场景:新闻图解自动配文与虚假信息识别联动

CLIP-GmP-ViT-L-14多场景&#xff1a;新闻图解自动配文与虚假信息识别联动 你有没有想过&#xff0c;当你在新闻网站上看到一张图片时&#xff0c;旁边的文字描述是怎么来的&#xff1f;是编辑手动写的&#xff0c;还是机器自动生成的&#xff1f;更关键的是&#xff0c;你怎么…...

学术探险家的秘密武器:书匠策AI,解锁课程论文新宇宙!

在学术的浩瀚星空中&#xff0c;每一位学子都是勇敢的探险家&#xff0c;怀揣着对知识的渴望&#xff0c;踏上探索未知的征途。而课程论文&#xff0c;则是这场探险中不可或缺的“星际导航图”&#xff0c;指引着我们穿越知识的迷雾&#xff0c;抵达真理的彼岸。但你是否曾遇到…...

基于DAMOYOLO-S与计算机网络技术:构建分布式视频分析集群

基于DAMOYOLO-S与计算机网络技术&#xff1a;构建分布式视频分析集群 想象一下&#xff0c;一个大型物流园区&#xff0c;上百个摄像头日夜不停地运转&#xff0c;管理者需要实时知道&#xff1a;哪条通道拥堵了&#xff1f;哪个区域有异常人员闯入&#xff1f;传统的监控方式…...

终极视频硬字幕提取指南:本地OCR识别87种语言的完整解决方案

终极视频硬字幕提取指南&#xff1a;本地OCR识别87种语言的完整解决方案 【免费下载链接】video-subtitle-extractor 视频硬字幕提取&#xff0c;生成srt文件。无需申请第三方API&#xff0c;本地实现文本识别。基于深度学习的视频字幕提取框架&#xff0c;包含字幕区域检测、字…...

TSDoc贡献指南:如何为开源文档标准做出贡献的完整教程

TSDoc贡献指南&#xff1a;如何为开源文档标准做出贡献的完整教程 【免费下载链接】tsdoc A doc comment standard for TypeScript 项目地址: https://gitcode.com/gh_mirrors/ts/tsdoc TSDoc是一个为TypeScript设计的文档注释标准&#xff0c;旨在为不同的工具提供统一…...