uniapp连接蓝牙操作(蓝牙设备地锁)

news2024/12/21 1:55:08

 介绍:

本文采用uni-app框架来创建一个简单的用户界面,用于搜索、连接和发送命令给蓝牙设备。

1.打开蓝牙适配器 

function openBluetooth() {
	  uni.openBluetoothAdapter({
	    success() {
	      uni.offBluetoothDeviceFound();
	      
	      // 监听新设备发现事件
	      uni.onBluetoothDeviceFound((res) => {
	        res.devices.forEach(device => {
	          if (device.name && device.name.startsWith('one-parking')) {
	            const existingDevice = devicesInfo.value.find(d => d.deviceId === device.deviceId);
	            if (!existingDevice) {
	              devicesInfo.value.push(device);
	            }
	          }
	        });
	      });
	
	      // 开始搜索蓝牙设备
	      uni.startBluetoothDevicesDiscovery({
	        success() {
	          console.log('开始搜索蓝牙设备...');
	          // 设置一个定时器,在一定时间后停止搜索
	          setTimeout(stopDiscovery, 10000);
	        },
	        fail(err) {
	          console.error('开始搜索失败', err);
	        }
	      });
	    },
	    fail() {
	      uni.showToast({
	        title: '请打开蓝牙',
	        icon: 'none'
	      });
	    }
	  });
	}
	

2.连接蓝牙

function connectBluetooth( data : any ) {
		bluetoothInfo.value = data;
		bluetoothInfo.value.deviceId = data.deviceId;
		uni.createBLEConnection({
		  deviceId : data.deviceId,
		  success() {
			// 判断连接的状态和断开重新连接
			checkSttusOrReconnect(data);
			// 获取蓝牙的服务ServiceID
		    uni.getBLEDeviceServices({
			  deviceId : data.deviceId,
			  success(servicesRes : any) {
				if(servicesRes.services.length > 0) {
					bluetoothInfo.value.serviceId = servicesRes.services[0].uuid;
					// 获取蓝牙的特征值characteristicId
					uni.getBLEDeviceCharacteristics({
					  deviceId : data.deviceId,
					  serviceId : servicesRes.services[0].uuid,
					  success(resCharacter) {
						if(resCharacter.characteristics.length > 0) {
							bluetoothInfo.value.characteristics = resCharacter.characteristics;
							// 接受通知
							notify();
							let macAddress = data.name.split('-')[1];
							let password = calculatePassword(macAddress);
							let bondCommand = `phbond${password}`;
							sendMsg(bondCommand);
						}
					  }
					})
				}
			  }
			});
		  }
		})
	}

提示:这里根据蓝牙的设备id连接后,一起获取了服务和特征id,用于方便后面蓝牙进行通信,其中的特征值是一个重点,不同的特征值id会对应不同的操作,不然就会操作不了其他的api,比如uni.notifyBLECharacteristicValueChange(OBJECT)这个就需要notify 或者 indicate 才可以成功调用

3.监听蓝牙的通知

    // 接收蓝牙端发送的通知
	function notify() {
		uni.notifyBLECharacteristicValueChange({
		  state: true,
		  // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
		  deviceId : bluetoothInfo.value.deviceId,
		  serviceId: bluetoothInfo.value.serviceId,
		  characteristicId : bluetoothInfo.value.characteristics.find(item => item.properties.notify).uuid,
		  success() {
			monitorMsg();
		  },
		  fail(res) {
		  	console.log('不支持这个notify' + JSON.stringify(res))
		  }
		})
	}
	
	function monitorMsg() {
		uni.onBLECharacteristicValueChange((res : any) => {
			console.log("发送过来的数据---------", res);
			let resHex = ab2ascii(res.value)
			console.log("转换后的简易数据----------",resHex);
		});
	}

 提示: 刚刚在上面说到的点就是特征值id有多个,需要有对应的特征权限

 4.发送数据

    // 向蓝牙写数据
	function sendMsg( msg : string ) {
		uni.writeBLECharacteristicValue({
			 deviceId : bluetoothInfo.value.deviceId,
			 serviceId: bluetoothInfo.value.serviceId,
			 characteristicId : bluetoothInfo.value.characteristics.find(item => item.properties.write).uuid,
			 value: asciiToArrayBuffer(msg) as any,
			 writeType: 'write',
			 success(res) {
				console.log('消息发送成功', res)
			},
			fail(res) {
				console.log('消息发送失败', res)
			}
		});
	}

注意:其中写数据需要向设备写的是二进制,所以需要转换一下

    // 二进制转化工具
	function ab2ascii(buffer : ArrayBuffer) {
		var str = Array.prototype.map.call(
			new Uint8Array(buffer),
			function(bit : any) {
				return String.fromCharCode(bit);
			}
		)
		return str.join('');
	}
	
	
	function asciiToArrayBuffer(str : string) {
		if (!str) {
			return new ArrayBuffer(0);
		}
		var buffer = new ArrayBuffer(str.length);
		var bufView = new Uint8Array(buffer);
		for (var i = 0, strLen = str.length; i < strLen; i++) {
			bufView[i] = str.charCodeAt(i);
		}
		return buffer;
	 }

5.监听蓝牙的状态并发现断开重连

function checkSttusOrReconnect( data : any ) {
		uni.onBLEConnectionStateChange(function (state) {
			if (!state.connected) {
			  console.warn('与设备' + data.name + '的连接已断开');
			  if(breakCount.value < 2) {
				  reconnectionTimer = setTimeout(()=>{
				  	  connectBluetooth(bluetoothInfo.value);
				  },3000);
			  }
			  breakCount.value += 1;
			} else {
			  console.log('与设备 ' + data.name + ' 的连接已建立');
			  if(reconnectionTimer) { clearTimeout(reconnectionTimer) }
			  breakCount.value = 0;
			}
		});
}

6.完整的demo代码(设备是车辆地锁)

<template>
	<view class="pageBox">
		<view style="font-size: 22px;text-align: center;margin-top: 32px;">
			蓝牙测试用例
		</view>
		<view style="margin: 12px;display: flex;flex-direction: column;">
			<radio-group style="margin: 12px;gap: 26px;display: flex;flex-wrap: wrap;padding: 6px;">
				<radio value="phup" @click="cmdText = 'phup'">phup(升)</radio>
				<radio value="phdown" @click="cmdText = 'phdown'">phdown(降)</radio>
				<radio value="phstatus" @click=" cmdText = 'phstatus'">phstatus(状态)</radio>
			</radio-group>
			<button @click="sendControllCmd()" style="background-color: #564DD6;color: #fff;border-radius: 26px;margin: 12px;">发送指令</button>
		</view>
		<view style="margin: 22px;font-size: 18px;font-weight: bold;color: royalblue;">蓝牙设置信息:</view>
		<view v-for="devices in devicesInfo">
			<view style="justify-content: space-between;border-radius: 8px;display: flex;margin: 12px;margin:12px 22px;background-color: #fff;border: 2px dashed #564DD6;padding: 12px;">
				<view style="display: flex;flex-direction: column;gap: 6px;">
					<view>设备名称:{{devices.name}}</view>
					<view>ID: {{devices.deviceId}}</view>
				</view>
				<view><button style="margin: 6px;border-radius: 6px;background-color: #9A2CD7;color: #fff;" size="mini" @click="connectBluetooth(devices)">连接</button></view>
			</view>
		</view>
		
	</view>
</template>

<script setup lang="ts">
	
	
	import { onReady } from "@dcloudio/uni-app";
	import { ref } from "vue";
	
	onReady(()=>{
		openBluetooth();
	});
	
	
	
	let devicesInfo = ref([]);
	let reconnectionTimer : any;
	let breakCount = ref<number>(0);
	
	
	function openBluetooth() {
	  uni.openBluetoothAdapter({
	    success() {
	      uni.offBluetoothDeviceFound();
	      
	      // 监听新设备发现事件
	      uni.onBluetoothDeviceFound((res) => {
	        res.devices.forEach(device => {
	          if (device.name && device.name.startsWith('one-parking')) {
	            const existingDevice = devicesInfo.value.find(d => d.deviceId === device.deviceId);
	            if (!existingDevice) {
	              devicesInfo.value.push(device);
	            }
	          }
	        });
	      });
	
	      // 开始搜索蓝牙设备
	      uni.startBluetoothDevicesDiscovery({
	        success() {
	          console.log('开始搜索蓝牙设备...');
	          // 设置一个定时器,在一定时间后停止搜索
	          setTimeout(stopDiscovery, 10000);
	        },
	        fail(err) {
	          console.error('开始搜索失败', err);
	        }
	      });
	    },
	    fail() {
	      uni.showToast({
	        title: '请打开蓝牙',
	        icon: 'none'
	      });
	    }
	  });
	}
	
	function stopDiscovery() {
	  uni.stopBluetoothDevicesDiscovery({
	    success() {
	      console.log('停止蓝牙嗅探成功');
	    },
	    fail(err) {
	      console.error('停止蓝牙嗅探失败', err);
	    }
	  });
	}

    
	
	
	// 地锁密码获取: 提取MAC地址的最后6位转换为十进制 , 加上520168 , 取结果的最后六位
	function calculatePassword(mac : string) {
	  let lastSixHex = mac.slice(-6);
	  let hexToInt = parseInt(lastSixHex, 16);
	  let sum = hexToInt + 520168;
	  let finalPassword = ('000000' + sum).slice(-6);
	  return finalPassword;
	}
	
	
	let bluetoothInfo = ref({
		deviceId: '',
		serviceId: '',
		characteristics: [],
		devicesInfo: {} // 连接的蓝牙设备
	});
	function connectBluetooth( data : any ) {
		bluetoothInfo.value = data;
		bluetoothInfo.value.deviceId = data.deviceId;
		uni.createBLEConnection({
		  deviceId : data.deviceId,
		  success() {
			// 判断连接的状态和断开重新连接
			checkSttusOrReconnect(data);
			// 获取蓝牙的服务ServiceID
		    uni.getBLEDeviceServices({
			  deviceId : data.deviceId,
			  success(servicesRes : any) {
				if(servicesRes.services.length > 0) {
					bluetoothInfo.value.serviceId = servicesRes.services[0].uuid;
					// 获取蓝牙的特征值characteristicId
					uni.getBLEDeviceCharacteristics({
					  deviceId : data.deviceId,
					  serviceId : servicesRes.services[0].uuid,
					  success(resCharacter) {
						if(resCharacter.characteristics.length > 0) {
							bluetoothInfo.value.characteristics = resCharacter.characteristics;
							// 接受通知
							notify();
							let macAddress = data.name.split('-')[1];
							let password = calculatePassword(macAddress);
							let bondCommand = `phbond${password}`;
							sendMsg(bondCommand);
						}
					  }
					})
				}
			  }
			});
		  }
		})
	}
	
	
	// 检查设备并重连
	function checkSttusOrReconnect( data : any ) {
		uni.onBLEConnectionStateChange(function (state) {
			if (!state.connected) {
			  console.warn('与设备' + data.name + '的连接已断开');
			  if(breakCount.value < 2) {
				  reconnectionTimer = setTimeout(()=>{
				  	  connectBluetooth(bluetoothInfo.value);
				  },3000);
			  }
			  breakCount.value += 1;
			} else {
			  console.log('与设备 ' + data.name + ' 的连接已建立');
			  if(reconnectionTimer) { clearTimeout(reconnectionTimer) }
			  breakCount.value = 0;
			}
		});
	}
	
	
	// 接收蓝牙端发送的通知
	function notify() {
		uni.notifyBLECharacteristicValueChange({
		  state: true,
		  // 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
		  deviceId : bluetoothInfo.value.deviceId,
		  serviceId: bluetoothInfo.value.serviceId,
		  characteristicId : bluetoothInfo.value.characteristics.find(item => item.properties.notify).uuid,
		  success() {
			monitorMsg();
		  },
		  fail(res) {
		  	console.log('不支持这个notify' + JSON.stringify(res))
		  }
		})
	}
	
	function monitorMsg() {
		uni.onBLECharacteristicValueChange((res : any) => {
			console.log("发送过来的数据---------", res);
			let resHex = ab2ascii(res.value)
			console.log("转换后的简易数据----------",resHex);
		});
	}
	
	
	let cmdText = ref('');
	function sendControllCmd() {
		console.log('发送的指令:' + cmdText.value);
		sendMsg(cmdText.value);
	}
	
	// 向蓝牙写数据
	function sendMsg( msg : string ) {
		uni.writeBLECharacteristicValue({
			 deviceId : bluetoothInfo.value.deviceId,
			 serviceId: bluetoothInfo.value.serviceId,
			 characteristicId : bluetoothInfo.value.characteristics.find(item => item.properties.write).uuid,
			 value: asciiToArrayBuffer(msg) as any,
			 writeType: 'write',
			 success(res) {
				console.log('消息发送成功', res)
			},
			fail(res) {
				console.log('消息发送失败', res)
			}
		});
	}
	
	
	// 二进制转化工具
	function ab2ascii(buffer : ArrayBuffer) {
		var str = Array.prototype.map.call(
			new Uint8Array(buffer),
			function(bit : any) {
				return String.fromCharCode(bit);
			}
		)
		return str.join('');
	}
	
	
	function asciiToArrayBuffer(str : string) {
		if (!str) {
			return new ArrayBuffer(0);
		}
		var buffer = new ArrayBuffer(str.length);
		var bufView = new Uint8Array(buffer);
		for (var i = 0, strLen = str.length; i < strLen; i++) {
			bufView[i] = str.charCodeAt(i);
		}
		return buffer;
	 }
	
</script> 

<style scoped lang="scss">
	.pageBox {
		height: 100%;
		width: 100%;
		position: fixed;
	}
</style>
ui界面
UI操作界面

操作台连接和蓝牙通知日志

最后官方文档地址:
Uniapp蓝牙连接文档icon-default.png?t=O83Ahttps://uniapp.dcloud.net.cn/api/system/bluetooth.html

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

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

相关文章

谁说C比C++快?

看到这个问题&#xff0c;我我得说&#xff1a;这事儿没有那么简单。 1. 先把最大的误区打破 "C永远比C快" —— 某位1990年代的程序员 这种说法就像"自行车永远比汽车省油"一样荒谬。我们来看个例子&#xff1a; // C风格 char* str (char*)malloc(100…

宝塔SSL证书申请失败,报错:申请SSL证书错误 module ‘OpenSSL.crypto‘ has no attribute ‘sign‘(已解决)

刚安装宝塔申请SSL就报错&#xff1a;申请SSL证书错误 module OpenSSL.crypto has no attribute sign 面板、插件版本&#xff1a;9.2.0 系统版本&#xff1a;Alibaba Cloud Linux 3.2104 LTS 问题&#xff1a;申请SSL证书错误 module OpenSSL.crypto has no attribute sign…

华为OD-计算正方形数量

华为OD-计算正方形数量 题目解题思路源码实现 题目 解题思路 由于是构成正方形 再结合用例1 很容易直接写出第一行代码 const pointCount await readline();if (pointCount < 4) {console.log(0);return;}然后就是典型的数学题,什么才能构成正方形(这题题主不会,看了解析之…

使用 rvest 包快速抓取网页数据:从入门到精通

介绍 随着大数据和数据科学的迅速发展&#xff0c;互联网数据的抓取已经成为重要的信息获取手段之一。网页抓取&#xff08;Web Scraping&#xff09;可以帮助我们自动化地从网页中提取有价值的数据&#xff0c;应用广泛&#xff0c;包括新闻热点分析、金融数据采集等。在本篇…

【机器学习】【集成学习——决策树、随机森林】从零起步:掌握决策树、随机森林与GBDT的机器学习之旅

这里写目录标题 一、引言机器学习中集成学习的重要性 二、决策树 (Decision Tree)2.1 基本概念2.2 组成元素2.3 工作原理分裂准则 2.4 决策树的构建过程2.5 决策树的优缺点&#xff08;1&#xff09;决策树的优点&#xff08;2&#xff09;决策树的缺点&#xff08;3&#xff0…

【Rust自学】4.2. 所有权规则、内存与分配

4.2.0 写在正文之前 在学习了Rust的通用编程概念后&#xff0c;就来到了整个Rust的重中之重——所有权&#xff0c;它跟其他语言都不太一样&#xff0c;很多初学者觉得学起来很难。这个章节就旨在让初学者能够完全掌握这个特性。 本章有三小节&#xff1a; 所有权&#xff1…

Mamba安装环境和使用,anaconda环境打包

什么是mamba Mamba是一个极速版本的conda&#xff0c;它是conda的C重新实现&#xff0c;使用多线程并行处理来加速包和依赖项的下载。 Mamba旨在提高安装、更新和卸载Python包的速度&#xff0c;同时保持与conda相同的兼容性和命令行接口。 Mamba的核心部分使用C实现&#xff…

Vue前端开发-数据缓存

完成全局性的axios实例对象配置后&#xff0c;则可以在任意一个组件中直接调用这个对象&#xff0c;发送异步请求&#xff0c;获取服务端返回的数据&#xff0c;同时&#xff0c;针对那些不经常变化的数据&#xff0c;可以在请求过程中&#xff0c;进行数据缓存&#xff0c;并根…

Composer指定php版本执行(windows)

✔️指定php版本执行&#xff08;windows&#xff09; 正常用法如下 /usr/bin/php7.1 /usr/local/bin/composer require xxxx 通过alias 简化指定PHP版本的路径 alias .php7_composer‘/d/application/phpstudy_pro/Extensions/php/php7.3.4nts/php /d/application/phpstudy_pr…

搭建私有链

文章目录 1. 准备工作2. 创建创世区块配置文件2.1 创建数据目录2.2 创建创世区块配置文件1. “config”部分2. “alloc”部分3. “coinbase”4. “difficulty”5. “extraData”6. “gasLimit”7. “nonce”8. “mixhash”9. “parentHash”10. “timestamp” 3. 初始化&#x…

游戏AI实现-寻路算法(BFS)

广度优先搜索算法&#xff08;英语&#xff1a;Breadth-first search&#xff0c;缩写&#xff1a;BFS&#xff09;&#xff0c;又译作宽度优先搜索&#xff0c;或横向优先搜索&#xff0c;是一种图形搜索算法。 寻路地图搭建&#xff1a; 游戏AI实现-寻路地图搭建-CSDN博客 …

k-均值聚类(k-Means Clustering)详解

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

复合机器人为生产提供精准的建议和决策支持

在现代化生产的浪潮中&#xff0c;智能复合机器人以其卓越的性能和高度智能化特点&#xff0c;正成为保障生产安全与可靠性的重要力量。 智能复合机器人具备精确的感知、判断和决策能力&#xff0c;能够在复杂的生产环境中自主导航、精确操作&#xff0c;避免了人为因素可能导致…

AI前沿分析:Github Copilot 推出免费版本,AI + 编程更高效!

名人说&#xff1a;莫听穿林打叶声&#xff0c;何妨吟啸且徐行。—— 苏轼 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、GitHub Copilot&#xff1a;AI编程的“革命性”助力二、免费版本上线&#xff1a;AI编程的普及时代&…

git使用教程(超详细)-透彻理解git

一.核心基础 核心概念有六个 首先请把与svn有关的一切概念暂时从你的脑海中移除掉&#xff0c;我们要重新认识本文所讲述的所有概念。这非常重要。 1.worktree worktree是一个目录&#xff0c;你在这里对文件进行增加、删除、修改。也就是我们常说的工作区。在git中worktree…

【优选算法---分治】快速排序三路划分(颜色分类、快速排序、数组第K大的元素、数组中最小的K个元素)

一、颜色分类 题目链接: 75. 颜色分类 - 力扣&#xff08;LeetCode&#xff09; 题目介绍&#xff1a; 给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums &#xff0c;原地 对它们进行排序&#xff0c;使得相同颜色的元素相邻&#xff0c;并按照红色、白色、蓝色顺序…

第六周作业

完成的作业&#xff1a; 1、自建yum仓库&#xff0c;分别为网络源和本地源 执行步骤&#xff1a;将光盘挂载到目录设置为本地源。 再将光盘挂载到http目录下实现ip访问&#xff0c;实现网络源。 编辑/etc/yum.repos.d/rocky.repo修改源 [base] namecd baseurlfile:///mnt/cd/…

PHP木马编写

一、最简单的一句话木马 <?php eval($_REQUEST[cmd]); ?> 1. <?php 和 ?> <?php 和 ?> 是 PHP 代码的开始和结束标记&#xff0c;表示 PHP 代码块的范围。 2. eval() eval() 是 PHP 中的一个内建函数&#xff0c;用来执行字符串类型的 PHP 代码。…

面试题整理3----nc命令的常见用法

面试题整理3----nc命令的常见用法 1. NC是什么2. NC的常用参数2.1 开启指定端口TCP监听(-l小写的L)2.2 测试端口是否能访问(-v)2.3 开启指定端口UDP监听(-u)2.4 端口扫描(-z)2.5 指定超时时间(-w)2.6 指定本地端口号连接(-p)2.7 指定的命令(-e) 1. NC是什么 nc&#xff08;Net…

智源大模型通用算子库FlagGems四大能力升级 持续赋能AI系统开源生态

FlagGems是由智源研究院于2024年6月推出的面向多种AI芯片的开源大模型通用算子库。FlagGems使用Triton语言开发&#xff0c;在Triton生态开源开放的基础上&#xff0c;为多种AI芯片提供开源、统一、高效的算子层生态接入方案。FlagGems沿着统一的中间语言、统一的算子接口和统一…