| | |
| | | import { ref, onMounted, inject, watch, reactive } from "vue"; |
| | | import { useRouter } from "vue-router"; |
| | | |
| | | import { BluetoothLE } from "@ionic-native/bluetooth-le"; |
| | | |
| | | import { Buffer } from "buffer"; |
| | | |
| | | import CRC from "crc"; |
| | | |
| | | |
| | | const router = useRouter(); |
| | | const service = ref("00FF"); |
| | | const characteristic = ref("FF01"); |
| | | const key = ref([]); |
| | | const MAC = ref('A0:DD:6C:23:26:16'); |
| | | |
| | | function setMac(mac) { |
| | | MAC.value = mac.toUpperCase(); |
| | | } |
| | | |
| | | // 请求蓝牙权限 |
| | | function _initBL() { |
| | | BluetoothLE.hasPermission().then( |
| | | (hasPermission) => { |
| | | console.log("hasPermission", hasPermission); |
| | | if (!hasPermission.isEnabled) { |
| | | BluetoothLE.requestPermission().then( |
| | | () => { |
| | | console.log("蓝牙权限已授予"); |
| | | initBL(); |
| | | }, |
| | | (error) => { |
| | | console.log("蓝牙权限未授予", error); |
| | | } |
| | | ); |
| | | } else { |
| | | console.log("蓝牙权限已授予"); |
| | | initBL(); |
| | | } |
| | | }, |
| | | (error) => { |
| | | console.log("蓝牙权限未授予", error); |
| | | } |
| | | ); |
| | | } |
| | | |
| | | // 计算开锁密钥 data 从蓝牙读取到的数据 数组 8个字节 |
| | | function calcKey(data) { |
| | | // 计算出crc 校验码 结果要低字节在前 |
| | | // let res = CRC.crc16modbus(data).toString(16).split(""); |
| | | // let _res = ["0X" + (res[2] + res[3]), "0X" + (res[0] + res[1])]; |
| | | |
| | | let res = CRC.crc16modbus(data); |
| | | let _res = [res & 0xff, (res >> 8) & 0xff]; |
| | | // console.log("res", res, CRC.crc16modbus(data), _res, "============="); |
| | | let __res = [..._res, data[6], data[7]]; |
| | | // 遇到0 变成128 |
| | | // 然后再前两字节相乘 结果高字节放前 后两字节相乘 高字节在前 |
| | | // console.log("__res", __res, "============="); |
| | | __res = __res.map((v) => (v > 0 ? v : 128)); |
| | | let a = __res[0] * __res[1]; |
| | | let b = __res[2] * __res[3]; |
| | | // console.log("a, b", a, b, "============="); |
| | | |
| | | return [a >> 8, a & 0xff, b >> 8, b & 0xff]; |
| | | } |
| | | |
| | | // 检查蓝牙是否可用 |
| | | async function checkBluetoothEnabled() { |
| | | try { |
| | | const isEnabled = await BluetoothLE.isEnabled(); |
| | | console.log("蓝牙是否可用", isEnabled, "============="); |
| | | |
| | | if (!isEnabled.isEnabled) { |
| | | console.log("蓝牙不可用 请求开启", "============="); |
| | | } |
| | | console.log("return true", "============="); |
| | | |
| | | return true; |
| | | } catch (error) { |
| | | console.log("蓝牙不可用", error); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | // 初始化蓝牙 |
| | | async function initBL(params) { |
| | | const isBluetoothEnabled = await checkBluetoothEnabled(); |
| | | if (!isBluetoothEnabled) { |
| | | console.log("蓝牙不可用,无法初始化"); |
| | | return; |
| | | } |
| | | // 初始化蓝牙 |
| | | BluetoothLE.initialize().subscribe( |
| | | (result) => { |
| | | console.log("蓝牙初始化成功", result); |
| | | |
| | | // scan(); |
| | | }, |
| | | (error) => { |
| | | console.log("蓝牙初始化失败", error); |
| | | } |
| | | ); |
| | | } |
| | | |
| | | const connect = async () => { |
| | | if (!MAC.value) { |
| | | console.log("MAC 为空"); |
| | | return false; |
| | | } |
| | | // return new Promise((resolve, reject) => { |
| | | BluetoothLE.connect( |
| | | { |
| | | address: MAC.value, |
| | | }, |
| | | (device) => { |
| | | console.log("连接成功", device); |
| | | }, |
| | | (error) => { |
| | | console.log("连接失败", error); |
| | | } |
| | | ).subscribe({ |
| | | next: (device) => { |
| | | console.log("连接 next", device); |
| | | if (device.status === "connected") { |
| | | // connected.value = true; |
| | | getServer(); |
| | | // resolve(true); |
| | | // } else { |
| | | // resolve(false); |
| | | } |
| | | }, |
| | | error: (error) => { |
| | | console.error("连接失败2", error); |
| | | // resolve(false); |
| | | }, |
| | | complete: () => { |
| | | console.log("连接完成"); |
| | | // resolve(true); |
| | | }, |
| | | }); |
| | | // }); |
| | | }; |
| | | |
| | | const disconnect = async () => { |
| | | if (!MAC.value) { |
| | | console.log("MAC 为空"); |
| | | return false; |
| | | } |
| | | try { |
| | | await BluetoothLE.disconnect({ |
| | | address: MAC.value, |
| | | }); |
| | | console.log("断开成功"); |
| | | // connected.value = false; |
| | | } catch (error) { |
| | | console.log("断开失败", error); |
| | | } |
| | | }; |
| | | |
| | | const scan = async () => { |
| | | if (!MAC.value) { |
| | | console.log("MAC 为空"); |
| | | return false; |
| | | } |
| | | try { |
| | | await BluetoothLE.startScan().subscribe({ |
| | | next: (device) => { |
| | | console.log("发现设备", device); |
| | | if (device.address && device.address.toUpperCase() === MAC.value) { |
| | | BluetoothLE.stopScan(); |
| | | connect(); |
| | | } |
| | | }, |
| | | error: (error) => { |
| | | console.error("扫描设备失败", error); |
| | | }, |
| | | complete: () => { |
| | | console.log("扫描设备完成"); |
| | | }, |
| | | }); |
| | | } catch (error) { |
| | | console.log("扫描失败", error); |
| | | } |
| | | }; |
| | | |
| | | // 发现服务和 发现特征 |
| | | function getServer() { |
| | | if (!MAC.value) { |
| | | console.log("MAC 为空"); |
| | | return false; |
| | | } |
| | | console.log("getServer", "发现服务", "============="); |
| | | |
| | | BluetoothLE.discover({ |
| | | address: MAC.value, |
| | | }) |
| | | .then((res) => { |
| | | console.log("res", res, "============="); |
| | | |
| | | const { services } = res; |
| | | console.log("发现服务", services, JSON.stringify(services)); |
| | | }) |
| | | .catch((error) => { |
| | | console.log("发现服务失败", error); |
| | | }); |
| | | } |
| | | |
| | | // 读取数据 |
| | | async function read() { |
| | | if (!MAC.value) { |
| | | console.log("MAC 为空"); |
| | | return false; |
| | | } |
| | | console.log("read", service.value, characteristic.value, "============="); |
| | | return BluetoothLE.read({ |
| | | address: MAC.value, |
| | | service: service.value, |
| | | characteristic: characteristic.value, |
| | | }) |
| | | .then((data) => { |
| | | console.log("读取数据成功", data); |
| | | let str = data.value; |
| | | |
| | | let bytes = BluetoothLE.encodedStringToBytes(data.value); |
| | | let readStr = Array.from(bytes) |
| | | .map((v) => v.toString(16)) |
| | | .join(" "); |
| | | let res = calcKey(Array.from(bytes)); |
| | | key.value = res; |
| | | console.log( |
| | | "str:", |
| | | str, |
| | | "=======readStr:", |
| | | readStr, |
| | | "=======bytes:", |
| | | bytes, |
| | | "=======res:", |
| | | res, |
| | | "=============" |
| | | ); |
| | | }) |
| | | .catch((error) => { |
| | | console.log("读取数据失败", error); |
| | | }); |
| | | } |
| | | |
| | | // 写入数据 |
| | | function write() { |
| | | if (!MAC.value) { |
| | | console.log("MAC 为空"); |
| | | return false; |
| | | } |
| | | console.log( |
| | | "write", |
| | | service.value, |
| | | characteristic.value, |
| | | "=============", |
| | | key.value |
| | | ); |
| | | |
| | | return BluetoothLE.write({ |
| | | address: MAC.value, |
| | | service: service.value, |
| | | characteristic: characteristic.value, |
| | | // value: new Uint8Array([0xff, 0x05, 0x00, 0x01, 0xff, 0x00, 0xc8, 0x24]), |
| | | value: BluetoothLE.bytesToEncodedString(new Uint8Array(key.value)), |
| | | }) |
| | | .then(() => { |
| | | console.log("写入数据成功"); |
| | | }) |
| | | .catch((error) => { |
| | | console.log("写入数据失败", error); |
| | | }); |
| | | } |
| | | |
| | | function close() { |
| | | if (!MAC.value) { |
| | | console.log("MAC 为空"); |
| | | return false; |
| | | } |
| | | try { |
| | | BluetoothLE.close({ |
| | | address: MAC.value, |
| | | }); |
| | | console.log('close 成功', '============='); |
| | | |
| | | } catch (error) { |
| | | console.log('close 失败', error, '============='); |
| | | |
| | | } |
| | | } |
| | | onMounted(() => { |
| | | _initBL(); |
| | | }); |
| | | |
| | | </script> |
| | | |
| | |
| | | <div class=""> |
| | | <span>安全智能</span> |
| | | <span>操作便捷</span> |
| | | <el-button @click="scan">扫描</el-button> |
| | | <el-button @click="disconnect">断开</el-button> |
| | | <el-button @click="close">关闭</el-button> |
| | | <el-button @click="connect">连接</el-button> |
| | | <el-button @click="read">读取</el-button> |
| | | <el-button @click="write">写入</el-button> |
| | | </div> |
| | | <div class="">助力智慧化机房、机柜的安全管理</div> |
| | | <!-- 扫码 --> |