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

news/2024/12/19 9:06:29/

 介绍:

本文采用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);// 获取蓝牙的服务ServiceIDuni.getBLEDeviceServices({deviceId : data.deviceId,success(servicesRes : any) {if(servicesRes.services.length > 0) {bluetoothInfo.value.serviceId = servicesRes.services[0].uuid;// 获取蓝牙的特征值characteristicIduni.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);// 获取蓝牙的服务ServiceIDuni.getBLEDeviceServices({deviceId : data.deviceId,success(servicesRes : any) {if(servicesRes.services.length > 0) {bluetoothInfo.value.serviceId = servicesRes.services[0].uuid;// 获取蓝牙的特征值characteristicIduni.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.ppmy.cn/news/1556349.html

相关文章

在 Mac M1 上使用 Docker 运行 Jenkins

在 Mac M1 上使用 Docker 运行 Jenkins&#xff0c;你需要注意以下几点&#xff1a; 1. 安装 Docker Desktop 首先&#xff0c;确保你已在 Mac M1 上安装并配置了 Docker Desktop。你可以从 Docker 官方网站 下载并安装适用于 Apple Silicon&#xff08;M1&#xff09;的版本…

数据结构(Java版)第六期:LinkedList与链表(一)

目录 一、链表 1.1. 链表的概念及结构 1.2. 链表的实现 专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 一、链表 1.1. 链表的概念及结构 链表是⼀种物理存储结构上⾮连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引⽤链接次序实现的。与火车…

如何发挥网络爬虫利器phpSpider最大功效

要发挥网络爬虫利器phpSpider的最大功效&#xff0c;可以从以下几个方面入手&#xff1a; 一、基础配置与优化 安装与配置&#xff1a; 确保PHP环境已正确安装&#xff0c;并通过Composer等工具安装phpSpider及其依赖。根据目标网站的特点&#xff0c;合理设置phpSpider的配置…

夜成都APP前端代码模板开源-供学习交流-不限制商用-夜成都视频交友生活交流APP开源-优雅草2024年12月14日

夜成都APP前端代码模板开源-供学习交流-不限制商用-夜成都视频交友生活交流APP开源-优雅草2024年12月14日 介绍 夜成都APP-成都夜生活–是一款展示成都丰富多彩夜生活的APP&#xff0c;城市的灯光星星点点地亮起&#xff0c;成都人的夜生活就在灯光璀璨中蔓延开来&#xff0c…

wrk如何测试post请求

wrk git地址 https://github.com/wg/wrk wrk 默认是针对 GET 请求的&#xff0c;但它也可以通过添加自定义的 HTTP 请求体和 头部信息来进行 POST 请求的压测。以下是详细的步骤&#xff1a; wrk -t4 -c100 -d30s -s post.lua http://example.com-t4&#xff1a;使用 4 个线…

面试小札:闪电五连鞭_7

1. 为什么非公平锁的吞吐量大于公平锁&#xff1f; 公平锁&#xff1a;公平锁的获取遵循先来先服务的原则。线程在获取锁时&#xff0c;如果锁被其他线程占用&#xff0c;它会进入队列等待&#xff0c;当锁可用时&#xff0c;队列中的第一个线程会获取到锁。这种机制保证了每个…

【SpringBoot 调度任务】

在 Spring Boot 中实现调度任务&#xff08;Scheduled Tasks&#xff09;&#xff0c;通过使用 EnableScheduling 和 Scheduled 注解来完成。 添加依赖启用调度任务支持创建调度任务运行应用程序 添加依赖 pom.xml 文件中有以下依赖项&#xff1a; <dependency><gro…

sylar:日志管理

参照 log4j 先写一个日志系统 以下代码均在同一文件sylar/log.h 开头两行&#xff1a; #ifndef __SYLAR_LOG_H__ #define __SYLAR_LOG_H__#endif#ifndef 是 “if not defined” 的缩写&#xff0c;它是一个预处理指令&#xff0c;去检查在当前的编译阶段&#xff0c;SYLAR_L…