uni-app使用蓝牙

news2025/1/23 3:07:04

目录

前言   

 连接蓝牙

开启蓝牙适配器

 发现蓝牙

连接蓝牙

收发蓝牙数据

 获取服务ID

获取特征值

读取蓝牙数据

写蓝牙数据

遇到的坑

获取serviceId的坑

  特征值不支持读写

 notify成功后立刻写蓝牙数据

工具方法


前言   

        原因是公司要搞个共享单车给内部员工使用,所以需要用手机连接锁蓝牙,然后扫码开锁。这个时候就要看看uni-app的蓝牙模块了。

   uni-app的蓝牙模块看起来只支持低功耗蓝牙,即ble蓝牙。

         然后公司就找了个厂商,这个厂商就给了我一份文档,如下图所示,

         这份文档呢有一些指令,指令如下图,可以看到这些指令呢都是一些16进制的数据,即发送给蓝牙的数据为,0xfe 0x66 0x00 0x21 0x00 (app->车锁的模块)

最后的CRC是将前面的数据加密。

最后车锁会返回给APP数据,即 车锁->app模块。

        厂家的蓝牙锁就是市面上常见的,如下图,有一个二维码,扫一下二维码开锁就是需要实现的逻辑。

 连接蓝牙

        首先需要开启蓝牙适配器,发现蓝牙,然后连接蓝牙。

   对应模块分别为,

开启蓝牙适配器

 发现蓝牙

 

 当startBluetoothDevicesDiscovery调用后,搜索到的蓝牙就会在onBluetoothDeviceFound中被搜索到,

devices返回的数据如下,而本次的目标就是name:BleLock。

{
    "devices": [
        {
            "deviceId": "2A:40:6F:28:24:90",
            "name": "",
            "RSSI": -53,
            "localName": "",
            .......
        }
    ]
}

{
    "devices": [
        {
            "deviceId": "32:71:0D:BF:43:FA",
            "name": "",
            "RSSI": -57,
            "localName": "",
            .......
        }
    ]
}

{
    "devices": [
        {
            "deviceId": "ED:C0:93:EF:0D:C5",
            "name": "BleLock",
            "RSSI": -45,
            .......
        }
    ]
}


 

连接蓝牙

        与上面方法对应的还有,停止搜索,关闭蓝牙连接,关闭蓝牙适配器,在Uni-app的API中蓝牙栏目都有对应方法。

        当发现到目标蓝牙后,一般就调用停止搜索方法,连接上蓝牙完成任务后就关闭蓝牙连接,关闭蓝牙适配器。

     即调用顺序为: 打开蓝牙适配器--> 监听搜索--> 开始搜索--> (发现目标蓝牙后) 关闭搜索-->

连接蓝牙--> 发送蓝牙指令 --> 断开蓝牙--> 关闭蓝牙适配器

    当然,打开蓝牙适配器只需要在onLoad中执行即可,不需要多次执行,但在我实际操作中,我发现有时候打开蓝牙适配器成功后,依旧无法连接蓝牙。

      所以我每次在扫码时都是按照上述顺序来操作一遍,扫一次码走一遍流程,大不了失败后多扫码几次。

收发蓝牙数据

        当连接上蓝牙后,需要收发蓝牙数据,收发蓝牙数据需要先获取服务ID,再获取特征值,即下图中的serviceId和characteristicId。

 

 获取服务ID

 调用此方法后,发现会输出如下数据,此处的uuid就是serviceId

[
    {
        "uuid": "00001800-0000-1000-8000-00805F9B34FB",
        "isPrimary": true
    },
    {
        "uuid": "00001801-0000-1000-8000-00805F9B34FB",
        "isPrimary": true
    },
    {
        "uuid": "6E400001-E6AC-A7E7-B1B3-E699BAE8D000",
        "isPrimary": true
    }
]

         此时需要循环遍历每个serviceId获取到特征值,但是在厂商中只有6e4开头获取到的特征值才能操作蓝牙,所以就只需要提取此处6e4开头的serviceId即可。

获取特征值

        下面的uuid就是特征值,其实都写数据只需要write:true和notify:true的特征值即可。

        read:true表示支持读取蓝牙数据,

        write:true表示支持向蓝牙写数据,

        notify:true 表示支持监听蓝牙返回的数据,

[
    {
        "uuid": "6E400003-E6AC-A7E7-B1B3-E699BAE8D000",
        "properties": {
            "read": false,
            "write": false,
            "notify": true,
            "indicate": false
        }
    },
    {
        "uuid": "6E400002-E6AC-A7E7-B1B3-E699BAE8D000",
        "properties": {
            "read": false,
            "write": true,
            "notify": false,
            "indicate": false
        }
    }

读取蓝牙数据

        一般是在连接蓝牙成功后就需要调用如下方法,在notify方法成功后就需要调用onBLECharacteristicValueChange方法,监听返回。

uni.notifyBLECharacteristicValueChange({
	state: true, // 启用 notify 功能
	// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
	deviceId: ths.deviceInfo.deviceId,
	// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
	serviceId: serviceId,
	// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
	characteristicId: characteristicId,
	success(res) {
		// 必须在这里的回调才能获取
		uni.onBLECharacteristicValueChange(function(res) {
			var receiveValue = ths.ab2hex(res.value) //2进制数据转为16进制字符串
			console.log("蓝牙返回数据为:"+receiveValue)
			
		})

		//获取key  此处一定要延迟,要等Notify成功后才能发送
		setTimeout(function(){
			ths.unlock();//开锁
		},2000);

	},
	fail(res) {
		console.log(res)
		ths.startNotify = false;
	},
})

// ArrayBuffer转16进度字符串示例
function ab2hex(buffer) {
  const hexArr = Array.prototype.map.call(
    new Uint8Array(buffer),
    function (bit) {
      return ('00' + bit.toString(16)).slice(-2)
    }
  )
  return hexArr.join('')
}

         蓝牙返回的数据是二进制的,是无法打印出来,所以需要转换为字符串

写蓝牙数据

        向蓝牙写入的是二进制数据,所以需要转为二进制,

        根据厂商文档需要开锁,那么需要写入 0xfe 0x66 0x00 0x21 0x00

// 向蓝牙设备发送一个0x00的16进制数据
const buffer = new ArrayBuffer(6)
const dataView = new DataView(buffer)
dataView.setUint8(0,0xFE);//STX
dataView.setUint8(1,0x66);//NUM
dataView.setUint8(2,0x00);//通信秘钥 Key
dataView.setUint8(3,0x21);//CMd
dataView.setUint8(4,0x00);//LEN

dataView.setUint8(5,0xB4);//CRC
dataView.setUint8(6,0xF6);

uni.writeBLECharacteristicValue({
	// 这里的 deviceId 需要在 getBluetoothDevices 或 onBluetoothDeviceFound 接口中获取
	deviceId:deviceIdValue,
	// 这里的 serviceId 需要在 getBLEDeviceServices 接口中获取
	serviceId:serviceIdValue,
	// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
	characteristicId:characteristicIdValue,
	// 这里的value是ArrayBuffer类型
	value: buffer,
	success(res) {
	  console.log('writeBLECharacteristicValue success', res)
	},
	fail(res) {
		console.log(res)
	},
})

        注意此处的success返回,只是告诉你蓝牙写成功否,并不是蓝牙的返回数据,蓝牙的返回数据在 onBLECharacteristicValueChange 中。

        此时到这里应该是能操作蓝牙了,但是uni-app中还遇到一些坑。

遇到的坑

获取serviceId的坑

        刚连接蓝牙成功时就调用getBLEDeviceServices获取,结果一直报蓝牙未连接,解决的方式是加个setTimeout,如果延迟后还获取不到serviceId,那么用户就重新扫码吧。

connectBle() {
	var ths = this; 
	uni.createBLEConnection({
		// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
		deviceId:ths.deviceInfo.deviceId,
		success(res) {
			//此处也需要延迟,刚连接上时,无法获取到特征值
			setTimeout(function(){
				ths.getServices();
			},2000)
		},
		fail(res) {
			ths.showModalInfo("连接蓝牙失败");
		},
		complete(res) { //无论有没有连上蓝牙,都要停止搜索
			ths.stopFindBluetooth(); //停止搜索蓝牙
		}
	})
},

  特征值不支持读写

        可以看到获取到了如下特征值,有write:true的(00002A00-0000-1000-8000-00805F9B34FB),但是用这个特征值写数据,你会发现就是写不了,会报特征值不支持写入。

        原因是厂商设置了只支持6e4开头的特征值,麻蛋的,当时我以为是uni-app获取特征值数据错了呢!

[
    {
        "uuid": "00002A00-0000-1000-8000-00805F9B34FB",
        "properties": {
            "read": true,
            "write": true,
            "notify": false,
            "indicate": false
        }
    },
    {
        "uuid": "00002A01-0000-1000-8000-00805F9B34FB",
        "properties": {
            "read": true,
            "write": false,
            "notify": false,
            "indicate": false
        }
    },
    {
        "uuid": "00002A04-0000-1000-8000-00805F9B34FB",
        "properties": {
            "read": true,
            "write": false,
            "notify": false,
            "indicate": false
        }
    }
]

 notify成功后立刻写蓝牙数据

         如下图可以看到,在notify成功后,我当时是立刻调用解锁方法,结果一直没有蓝牙数据返回,甚至写数据还报特征值不支持写入,no connection等,

        这个鬼原因我也不知道,后面加个延迟解决了,推测应该是success调用应该不是真正的成功,需要等一会,

        但不得不说,这个延迟就是定时炸弹,谁也不知道需要延迟多久。        

        可以看到在连接蓝牙成功后获取serviceId,Notify后发送指令都是需要延迟,明明给出success了,结果还是无法去调用。

          针对这个问题,去看了官网,好像也没啥回应,大部分人也是延迟一下。 

工具方法

/**
 * 将一个比如abcd的字符串转为16进制数据
 * @param {Object} str
 */
function stringToHex(str) {
	var hexArray = [];
	for (var i = 0; i < str.length; i++) {
		var hexStr = str.charCodeAt(i).toString(16);
		hexArray.push(str16(hexStr));
	}
	return hexArray;
}

var str = "yOTmK50z"
var dataArray = stringToHex("yOTmK50z"); //返回16进制的数组 0x79, 0x4f, 0x54, 0x6d, 0x4b, 0x35, 0x30,0x7a


/**
 * 将字符串变为16进制数据
 * @param {Object} str  16进制的字符串样式,不能是随便的字符串
 */
function str16(str) {
	return parseInt(str, 16);
}

var hexStr = "0c"; //对应16进制,对应10进制12
var num = str16(str);//返回12,也可以是0x0c,两者一样


/**
 * 将一个十进制的数变为十六进制的字符串
 * @param {Object} value
 */
function int2HexStr(value) {
	return value.toString(16);
}

var num = 12;
var hexStr = int2HexStr(num) //返回 0c


/**
 * 字符串分割为数组,2位一个
 * @param {Object} str
 */
function str2intArray(str) {
	var length = str.length / 2;
	var data = [];
	for (var i = 0; i < length; i++) {
		data[i] = str16(str.substring(i * 2, (i + 1) * 2));
	}
	return data;
}

//0x79, 0x4f, 0x54, 0x6d, 0x4b, 0x35, 0x30,0x7a
var hexStr = "794f546d4b35307a"
var dataArray = str2intArray(hexStr) //变为一个数组,里面保存16进制的数



/**
 * 时间戳变为  yyyy-MM-dd HH:mm:ss格式的时间
 * @param {Object} timestamp
 */
function timestamp2YYYYMMDDHHmmSS(timestamp){
  var n=new Date(timestamp)
  return n.toLocaleDateString().replace(/\//g, "-") + " " + n.toTimeString().substr(0, 8)
}


//获取时间戳
var timestampNum = Math.round(new Date() / 1000)  // 返回秒级别的时间戳,1673248864
var hexStr = int2HexStr(timestampNum); // 1673248864 转换为16进制  63bbc060
var timestamp16Array = str2intArray(hexStr); // 将 63bbc060 变为 0x63 0xbb 0xc0 0x60的数组

//产生随机数
Math.round(Math.random() * 100); //[0,100)

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

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

相关文章

32位浮点数表示方法

今天开始给大家介绍计算机组成原理课程&#xff0c;本文主要内容是32位浮点数表示方法。 一、32位浮点数构成 32位浮点数是计算机中常见的一种数据类型&#xff0c;该数占据32bit空间&#xff0c;可以表示较大范围内的整数和小数。32位浮点数由三部分组成&#xff0c;分别是符…

Java集合List、Set、Map底层源码解析

目录集合介绍MapHashMapLinkedHashMapHashTablePropertiesCollectionListArrayListVectorLinkedListSetHashSetLinkedHashSetTreeSet集合介绍 为什么使用集合&#xff1f; 当我们想要保存一组数据时&#xff0c;可以使用到的变量类型有集合和数组。那么就像说一下数组的局限性…

1.9

完善案例 ​ this.$nextTick(function () {this.$refs.input.focus()})}​ //点击编辑直接获取焦点 this.$refs.input.focus() //但是这种写法 由于input是用v-show控制的 所以执行了上面代码 改变了isEdit值 但是不会立马去重新解析模板 input框还没有出来 //将handleedit回调…

springboot+xxl-job初体验

在日常开发中经常遇到任务调度的需求&#xff0c;下面体验一下分布式调度xxl-job。 1、常见定时任务的实现方式 Java自带的java.util.Timer类ScheduledExcutorServiceSpringboot自带的EnableScheduling注解Quartz框架Elastic-job框架XXL-JOB框架 下面对xxl-job实现任务调度尝…

【TypeScript】TS进阶-函数重载(七)

&#x1f431;个人主页&#xff1a;不叫猫先生 &#x1f64b;‍♂️作者简介&#xff1a;前端领域新星创作者、华为云享专家、阿里云专家博主&#xff0c;专注于前端各领域技术&#xff0c;共同学习共同进步&#xff0c;一起加油呀&#xff01; &#x1f4ab;系列专栏&#xff…

一文读懂电商数字员工究竟是什么?| RPA铺第1期

百度的曦灵&#xff0c;中核的核小智、万科集团数字员工“崔筱盼”都曾在2022年度爆火&#xff0c;数字员工一夜之间成为众多行业追捧的对象&#xff0c;那么&#xff0c;他/她们究竟代表着什么&#xff0c;对企业而言&#xff0c;是噱头大于收益&#xff0c;还是收益大于噱头呢…

简单的客户端服务器(多线程)基于json通信

这是一个客户端和服务器通信的小项目&#xff0c;小编自己手写了一个json工具&#xff0c;测试比jsoncpp&#xff0c;protobuf "效率更高"&#xff08;浅拷贝&#xff09;&#xff0c;改写成深拷贝效率会急剧下降&#xff08;小编能力有限&#xff0c;知识点&#xf…

技术分享 | Spring Boot 异常处理

说到异常处理&#xff0c;我们都知道使用 try-catch 可以捕捉异常&#xff0c;可以 throws 抛出异常。那么在 Spring Boot 中我们如何处理异常&#xff0c;如何更优雅的处理异常&#xff0c;如何全局处理异常。是本章讨论解决的问题。Java 异常类首先让我们简单了解或重新学习下…

Android开发-AS学习(一)

完整项目最精简流程&#xff1a;Android <-> 接口 <-> 数据库Android开发工具&#xff1a;Android Studio项目目录信息&#xff1a;一、控件1.1 TextView基础属性描述layout_width组件的宽度layout_height组件的高度id为TextView设置一个组件idtext设置显示的文本内…

Linux 学习笔记(借鉴黑马程序员Linux课程)

Linux视频课程 简介 Linux诞生于1991年&#xff0c;由林纳斯托瓦兹在21岁时完成。此后成为最为流行的服务器操作系统之一。 Linux内核和系统发行版 由Linux系统内核和系统级应用程序两部分组成。 内核提供系统最核心的功能&#xff0c;如&#xff1a;调度CPU、调度内存、调…

【笑小枫的按步照搬系列】Redis多系统安装(Windows、Linux、Ubuntu)

笑小枫&#x1f495; 欢迎来到笑小枫的世界&#xff0c;喜欢的朋友关注一下我呦&#xff0c;大伙的支持&#xff0c;就是我坚持写下去的动力。 微信公众号&#xff1a;笑小枫 笑小枫个人博客&#xff1a;https://www.xiaoxiaofeng.com Windows 下安装 方式一&#xff1a;https…

HCL(新华三模拟器)如何连接CRT及改界面颜色

我使用的HCL版本是2.1.1官网下载连接&#xff1a;https://www.h3c.com/cn/Service/Document_Software/Software_Download/Other_Product/H3C_Cloud_Lab/Catalog/HCL/&#xff0c;一键直达下载官网这个版本可以适配virtualbox的5.2.44的版本&#xff0c;同时支持华为的ensp模拟器…

Spring Security 表单配置(一)

Spring Security 表单配置&#xff08;一&#xff09;工具版本及环境参考资源配置详细说明工具版本及环境 工具&#xff1a; IDEA 2021.3 Maven 3.8.6 JDK 8 Spring Boot 2.7.7 Spring Securiity 5.7.6 参考资源 Spring Security官网: https://docs.spring.io/spring-security…

javaEE 初阶 — 常见的锁策略

文章目录1. 乐观锁 vs 悲观锁2. 互斥锁 vs 读写锁3. 重量级锁 vs 轻量级锁4. 自旋锁 vs 挂起等待锁5. 公平锁 vs 非公平锁6. 可重入锁 vs 不可重入锁7. synchronized 是哪种锁8. 相关面试题1. 乐观锁 vs 悲观锁 乐观锁 指的是预测锁竞争不是很激烈&#xff0c;也就是指这里做的…

排列组合两个列表中的元素 product(a,b)

【小白从小学Python、C、Java】【计算机等级考试500强双证书】【Python-数据分析】排列组合两个列表中的元素product(a,b)关于以下python代码表述错误的一项是?from itertools import producta [1,2,3]b [4,5,6]print("【显示】a",a)print("【显示】b",…

修改Keil开发环境背景(修改为黑色主题)

修改Keil开发背景&#xff08;修改为黑色主题&#xff09;引言步骤总结引言 我们平时在Keil uVision5下开发单片机/嵌入式程序的时候&#xff0c;如果始终用的是官方的主题背景&#xff0c;往往会因为背景太白了&#xff0c;而导致视疲劳。我们使用VSCode往往不会有这种困扰&a…

Python处理字符串 中文(汉字)编码示例

在实际开发中&#xff0c;发现打印Python打印经常出现乱码&#xff0c;大部分都是编码引起&#xff0c;这里只是简单说一下utf-8/ gbk/ unicode编码之间的相互转换问题&#xff1a; utf-8是Unix下的一种通用编码&#xff0c;gbk是win环境下的一种汉字编码&#xff0c;unicode是…

计算机组成原理_总线仲裁

计算机组成原理总目录总线仲裁 由于总线连接着多个设备&#xff0c;那么在同一时刻多个设备想要占用总线时&#xff0c;就会发生冲突问题 为了解决冲突问题&#xff0c;就需要规定好所有设备使用设备的优先权&#xff0c;仲裁也就是判断设备占用总线的优先权 例如设备A的任务比…

Docker--安装mysql8--方法/步骤

原文网址&#xff1a;Docker--安装mysql8--方法/步骤_IT利刃出鞘的博客-CSDN博客 简介 本文介绍如何使用docker安装mysql8。 查看mysql版本 https://hub.docker.com/_/mysql/tags 我选择8.0&#xff0c;点击右侧箭头处直接复制命令。 拉取镜像 拉取镜像的命令 docker pul…

RADIANT:一种全新的雷达图像关联网络用于3D目标检测

RADIANT&#xff1a;一种全新的雷达图像关联网络用于3D目标检测 论文地址&#xff1a;RADIANT: Radar-Image Association Network for 3D Object Detection 源码&#xff1a;https://github.com/longyunf/radiant 单位&#xff1a;密歇根大学、福特 动机 作为一种能够直接…