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

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

 介绍:

本文采用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.kler.cn/a/443653.html

相关文章:

  • 使用Python开发高级游戏:实现一个3D射击游戏
  • 前端工作中问题点拆分
  • 操作系统导论读书笔记
  • MarkItDown的使用(将Word、Excel、PDF等转换为Markdown格式)
  • 探索多模态大语言模型(MLLMs)的推理能力
  • 一键打断线(根据相交点打断)——CAD c# 二次开发
  • 授权模型DAC
  • PostgreSQL 常用运维SQL整理
  • 3.zabbix中文设置
  • 洛谷 B3836 [GESP202303 二级] 百鸡问题
  • day-21 内核链表以及栈
  • CSS系列(17)-- 工具与生态系统详解
  • 【实用技能】如何在 Unity3D 中将网页内容渲染为纹理
  • ChatGPT与领域特定语言的集成
  • [手机Linux] 六,ubuntu18.04私有网盘(NextCloud)安装
  • MFC扩展库BCGControlBar Pro v36.0 - 工具栏 对话框组件升级
  • SQL Server 中对网络数据库文件的支持说明
  • @pathvariable什么作用
  • Vue3+Vite 环境变量和模式配置详解
  • C语言编程1.26判断八进制数字字符
  • ISP代理提供商及其作用
  • 详解负载均衡
  • 远程连接:构建智能家居舒适生活
  • 案例:Spark/Hive中‘String=数值类型’丢失精度问题
  • 电子应用设计方案-61:智能沙发系统方案设计
  • Unity常用面试问题