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:https://www.cnblogs.com/sunny3158/p/17312158.html 将 ArrayBuffer 对象转成 Base64 字符串:基础 - uni.arrayBufferT…...
MBR10200CT-ASEMI智能AI应用MBR10200CT
编辑:ll MBR10200CT-ASEMI智能AI应用MBR10200CT 型号:MBR10200CT 品牌:ASEMI 封装:TO-220 批号:最新 恢复时间:35ns 最大平均正向电流(IF):10A 最大循环峰值反向…...
力扣 爬楼梯
动态规划算法基础篇。 class Solution {public int climbStairs(int n) {int[] f new int[n 1];f[0] 1;f[1] 1;//当爬到n阶楼梯时,可知是由n-1阶或n-2阶楼梯而来for(int i 2; i < n; i) {f[i] f[i - 1] f[i - 2];//后面的每一阶种数由前两个状态得到}ret…...
java设计模式之:策略模式+工厂模式整合案例实战(一)
本文介绍项目中常用的策略模式工厂模式的案例,该案例是针对策略类比较少的情况;下一篇会讲解策略类比较多的案例,下面直接开始: 案例1:项目中对系统中的客户和销售进行事件通知(短信、邮件、钉钉) 首先要有通知的策略…...
国内Ubuntu安装 stable-diffusion教程,换成国内镜像
安装依赖: 首先更新系统并安装Python 3.10和pip: sudo apt update sudo apt install python3.10 python3-pip 设置Python虚拟环境(可选): 安装Python虚拟环境管理工具,并创建激活虚拟环境: su…...
JAVA final详细介绍
一、介绍 final 中文意思: 最后的,最终的. final 可以修饰类、属性、方法和局部变量, 在某些情况下,程序员可能有以下需求,就会使用到final: 1)当不希望类被继承时,可以用final修饰。 //如果我们要求A类不能被其他类继承 //可以使用fin…...
45、tomcat+课后实验
tomcat 1、tomcat tomcat和php一样,都是用来处理动态页面的。 tomcat也可以作为web应用服务器,开源的。 php .php tomcat .jsp nginx .html tomcat 是用Java代码写的程序,运行的是Java的web应用程序。 tomcat的特点和功能:…...
设计模式的七大原则
1.单一职责原则 单一职责原则(Single responsibility principle),即一个类应该只负责一项职责。如类A负责两个不同职责:职责1,职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1、…...
ThreeJS-3D教学十五:ShaderMaterial(noise、random)
ThreeJS-3D教学十四:ShaderMaterial(length、fract、step) 上面这篇主要是操作 fragmentShader 片元着色器,实现对物体颜色的修改,这次咱们来看下修改 vertexShader 顶点着色器,这个其实就是位移各个顶点的位置。 接下来我们先介绍下 noise 噪声函数(Perlin Noise、Sim…...
LeetCode 2974.最小数字游戏:排序+交换奇偶位
【LetMeFly】2974.最小数字游戏:排序交换奇偶位 力扣题目链接:https://leetcode.cn/problems/minimum-number-game/ 你有一个下标从 0 开始、长度为 偶数 的整数数组 nums ,同时还有一个空数组 arr 。Alice 和 Bob 决定玩一个游戏ÿ…...
使用vllIm部署大语言模型
使用vllm部署大语言模型一般需要以下步骤: 一、准备工作 1. 系统要求 - 操作系统:常见的 Linux 发行版(如 Ubuntu、CentOS)或 Windows(通过 WSL)。 - GPU 支持:NVIDIA GPU 并安装了适当的驱动程…...
静态搜索iOS动态链接函数的调用位置
静态搜索iOS动态链接函数的调用位置 可执行文件格式mach-O,是在苹果的操作系统 macOS 和 iOS 上使用的一种二进制文件格式。 在一些iOS安全扫描中,可能存在需要获取函数具体调用位置的需求,能指导用户更精确的定位漏洞。 现在以NSLog函数为例ÿ…...
【鸿蒙学习笔记】尺寸设置・layoutWeight・对子组件进行重新布局
官方文档:尺寸设置 目录标题 layoutWeight:对子组件进行重新布局 layoutWeight:对子组件进行重新布局 设置了layoutWeight属性的子元素与兄弟元素占主轴尺寸按照权重进行分配,忽略元素本身尺寸设置。 // 引入包名 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产生的背景 软件定义安全(Software Defined Security,SDSec)的产生背景主要源于传统网络安全防护方法在面对复杂网络环境时的不适应性,以及软件定义网络(SDN)技术的发展和应用。 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 主题技巧:给文章页增加“谁来过”模块。
模块功能: 我个人目前在做一个电影类的网站,在开发文章页的模版时候,突然觉得给文章页增加一个“谁对本电影感兴趣”的功能模块可能会比较有趣,这个功能有点类似于‘足迹’的感觉,用户可以通过这个功能,发…...
【vue组件库搭建07】Vitest单元测试
vitest官网 vue-test-utils 我们的测试框架选择的是 Vitest 和 vue-test-utils。两者的关系为: Vitest 提供测试方法:断言、Mock 、SpyOn 等方法。vue-test-utils: 挂载和渲染组件: Vue Test Utils 允许您在隔离中挂载组件,这意…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
【JVM】Java虚拟机(二)——垃圾回收
目录 一、如何判断对象可以回收 (一)引用计数法 (二)可达性分析算法 二、垃圾回收算法 (一)标记清除 (二)标记整理 (三)复制 (四ÿ…...
PostgreSQL——环境搭建
一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在࿰…...
Golang——7、包与接口详解
包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...
系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...
论文阅读:LLM4Drive: A Survey of Large Language Models for Autonomous Driving
地址:LLM4Drive: A Survey of Large Language Models for Autonomous Driving 摘要翻译 自动驾驶技术作为推动交通和城市出行变革的催化剂,正从基于规则的系统向数据驱动策略转变。传统的模块化系统受限于级联模块间的累积误差和缺乏灵活性的预设规则。…...
