import { BluetoothLE } from "@ionic-native/bluetooth-le";
|
import { ref, onMounted } from "vue";
|
|
import { Buffer } from "buffer";
|
|
import CRC from "crc";
|
|
/**
|
* 要求开锁前先请求后台鉴权
|
* 有权限后 先连蓝牙 再读数据 计算密钥 写数据开锁 开锁成功或失败 都断开连接
|
*/
|
// MAC 为蓝牙设备的MAC地址 :分隔的六个字节 全部要大小
|
export default (MAC) => {
|
MAC = MAC.toUpperCase();
|
const service = ref("00FF");
|
const characteristic = ref("FF01");
|
|
// 请求蓝牙权限
|
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 () => {
|
return BluetoothLE.connect(
|
{
|
address: MAC,
|
},
|
(device) => {
|
console.log("连接成功", device);
|
},
|
(error) => {
|
console.log("连接失败", error);
|
}
|
).subscribe({
|
next: (device) => {
|
console.log("连接 next", device);
|
if (device.status === "connected") {
|
// connected.value = true;
|
// getServer();
|
}
|
},
|
error: (error) => {
|
console.error("连接失败2", error);
|
},
|
complete: () => {
|
console.log("连接完成");
|
},
|
});
|
};
|
|
const disconnect = async () => {
|
try {
|
await BluetoothLE.disconnect({
|
address: MAC,
|
});
|
console.log("断开成功");
|
// connected.value = false;
|
} catch (error) {
|
console.log("断开失败", error);
|
}
|
};
|
|
const scan = async () => {
|
try {
|
await BluetoothLE.startScan().subscribe({
|
next: (device) => {
|
console.log("发现设备", device);
|
if (device.address.toUperCase() === MAC) {
|
BluetoothLE.stopScan();
|
connect();
|
}
|
},
|
error: (error) => {
|
console.error("扫描设备失败", error);
|
},
|
complete: () => {
|
console.log("扫描设备完成");
|
},
|
});
|
} catch (error) {
|
console.log("扫描失败", error);
|
}
|
};
|
|
// 发现服务和 发现特征
|
function getServer() {
|
console.log("getServer", "发现服务", "=============");
|
|
BluetoothLE.discover({
|
address: MAC,
|
})
|
.then((res) => {
|
console.log("res", res, "=============");
|
|
const { services } = res;
|
console.log("发现服务", services, JSON.stringify(services));
|
})
|
.catch((error) => {
|
console.log("发现服务失败", error);
|
});
|
}
|
|
// 读取数据
|
async function read() {
|
console.log("read", service.value, characteristic.value, "=============");
|
return BluetoothLE.read({
|
address: MAC,
|
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() {
|
console.log(
|
"write",
|
service.value,
|
characteristic.value,
|
"=============",
|
key.value
|
);
|
|
return BluetoothLE.write({
|
address: MAC,
|
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() {
|
BluetoothLE.close({
|
address: MAC,
|
});
|
}
|
|
async function open() {
|
// TODO 鉴权
|
|
let connected = await connect();
|
console.log('connected', connected, '=============');
|
await read();
|
let writeRes = await write();
|
console.log('writeRes', writeRes, '=============');
|
disconnect();
|
close();
|
}
|
|
onMounted(() => {
|
_initBL();
|
});
|
|
return { read, write, close, scan, connect, disconnect, open };
|
};
|