335 lines
10 KiB
JavaScript
335 lines
10 KiB
JavaScript
import Taro from "@tarojs/taro";
|
||
import { handshake1, handshake2 } from "./sendOrder";
|
||
import TASK from "./taskQueue";
|
||
|
||
const errMsg = {
|
||
0: "正常",
|
||
10000: "未初始化蓝牙适配器",
|
||
10001: "请检查手机蓝牙是否打开或微信是否授权蓝牙",
|
||
10002: "没有找到指定设备",
|
||
10003: "连接失败",
|
||
10004: "没有找到指定服务",
|
||
10005: "没有找到指定特征",
|
||
10006: "当前连接已断开",
|
||
10007: "当前特征不支持此操作",
|
||
10008: "其余所有系统上报的异常",
|
||
10009: "Android系统版本低于4.3不支持蓝牙功能",
|
||
10012: "连接超时",
|
||
10013: "连接超时",
|
||
1509008: "请检查手机定位是否打开或微信是否授权定位",
|
||
};
|
||
|
||
class Bluetooth {
|
||
config = {
|
||
serviceId: "4E31BF4A-8507-3A2B-7344-C7EDACD38104", //设备服务id
|
||
NotifyUUID: "4E31BF4B-8507-3A2B-7344-C7EDACD38104",
|
||
WriteUUID: "4E31BF4C-8507-3A2B-7344-C7EDACD38104",
|
||
|
||
// serviceId: 'C7E6FAE0-E966-1000-8000-BEF9C723DF6A', //设备服务id
|
||
// NotifyUUID: 'C7E6FAE1-E966-1000-8000-BEF9C723DF6A',
|
||
// WriteUUID: 'C7E6FAE2-E966-1000-8000-BEF9C723DF6A',
|
||
};
|
||
|
||
// 连接状态
|
||
linkFlag = false;
|
||
// 蓝牙是否可用
|
||
available = true;
|
||
// 蓝牙初始化
|
||
isInit = false;
|
||
|
||
timeout = null;
|
||
timeout1 = null;
|
||
|
||
// 判断是否搜索到设备
|
||
isFindBt = null;
|
||
|
||
platform = Taro.getSystemInfoSync().platform;
|
||
appAuthorize = Taro.getAppAuthorizeSetting();
|
||
deviceInfo = {}
|
||
callBack = () => { };
|
||
searchBack = () => { };
|
||
|
||
constructor() {
|
||
this.onBluetoothAdapterStateChange();
|
||
this.onBLEConnectionStateChange();
|
||
this.onBluetoothDeviceFound();
|
||
}
|
||
// 错误
|
||
fail(res) {
|
||
this.linkFlag = false;
|
||
if (!res.errCode) return;
|
||
let starIde = res.errMsg.indexOf("fail") + 5;
|
||
Taro.showToast({ title: errMsg[res.errCode] || errMsg[res.errno] || res.errMsg.substring(starIde), icon: "none", duration: 3000 });
|
||
}
|
||
|
||
// 监测手机蓝牙状态
|
||
onBluetoothAdapterStateChange() {
|
||
Taro.onBluetoothAdapterStateChange(({ available, discovering }) => {
|
||
this.available = available;
|
||
// 手机蓝牙开启
|
||
if (this.available && !this.isInit) {
|
||
Taro.closeBluetoothAdapter({
|
||
success: (res) => {
|
||
this.openBluetoothAdapter();
|
||
},
|
||
});
|
||
console.log("手机蓝牙开启");
|
||
}
|
||
// 手机蓝牙关闭
|
||
if (!available) {
|
||
this.isInit = false;
|
||
this.deviceInfo.state = false;
|
||
this.linkFlag = false;
|
||
this.callBack(this.deviceInfo);
|
||
console.log("手机蓝牙关闭");
|
||
}
|
||
});
|
||
}
|
||
// 初始化蓝牙模块
|
||
openBluetoothAdapter() {
|
||
return Taro.openBluetoothAdapter({
|
||
success: () => {
|
||
console.log("初始化蓝牙模块");
|
||
this.isInit = true;
|
||
this.deviceInfo = Taro.getStorageSync('deviceInfo') || {}
|
||
if (this.deviceInfo.name) {
|
||
this.createBleConnection()
|
||
}
|
||
},
|
||
fail: (err) => {
|
||
this.isInit = false;
|
||
this.fail(err);
|
||
},
|
||
});
|
||
}
|
||
|
||
// 开始搜寻附近的蓝牙外围设备
|
||
startBluetoothDevicesDiscovery() {
|
||
console.log("搜索蓝牙");
|
||
if (this.appAuthorize.locationAuthorized != "authorized" && this.platform == "android")
|
||
return Taro.showToast({ title: "请打开微信定位权限", icon: "none", duration: 3000 });
|
||
Taro.startBluetoothDevicesDiscovery({
|
||
// allowDuplicatesKey: true,
|
||
powerLevel: "high",
|
||
success: (res) => {
|
||
this.isFindBt = setTimeout(() => {
|
||
if (this.platform == "android") {
|
||
this.stopBluetoothDevicesDiscovery();
|
||
Taro.showModal({
|
||
title: "未搜索到设备",
|
||
content: "1、请检查设备是否在附近,或者设备是否被其他应用连接。2、请检查手机微信应用权限中的‘附近的设备权限’是否打开。",
|
||
showCancel: false,
|
||
success: () => {
|
||
const pages = Taro.getCurrentPages();
|
||
if (pages?.length > 1) {
|
||
Taro.navigateBack();
|
||
}
|
||
},
|
||
});
|
||
}
|
||
console.log("未搜索到设备");
|
||
this.isFindBt && this.clearTimeoutFn("isFindBt");
|
||
}, 6000);
|
||
},
|
||
fail: (err) => {
|
||
this.fail(err);
|
||
this.stopBluetoothDevicesDiscovery();
|
||
},
|
||
});
|
||
}
|
||
|
||
// 监听搜索到新设备的事件
|
||
// 定义一个方法用于处理蓝牙设备发现事件
|
||
onBluetoothDeviceFound(fn) {
|
||
Taro.onBluetoothDeviceFound((res) => {
|
||
const devices = res.devices[0];
|
||
const advertisData = this.ab2hex(devices.advertisData);
|
||
const mac = this.strInsert(String(advertisData).substring(4, 16)).toLocaleUpperCase();
|
||
// 判断是否有搜索到设备
|
||
this.isFindBt && this.clearTimeoutFn("isFindBt");
|
||
// if (devices.name && devices.name == "W53A") {
|
||
if (devices.name && devices.name == "LE-AB2020") {
|
||
console.log(JSON.stringify(res), "搜索到设备");
|
||
const item = {
|
||
deviceId: devices.deviceId,
|
||
mac: mac,
|
||
name: devices.name,
|
||
};
|
||
fn && fn(item)
|
||
}
|
||
});
|
||
}
|
||
|
||
// 蓝牙连接
|
||
createBleConnection() {
|
||
if (!this.available || this.linkFlag || !this.deviceInfo.deviceId) return;
|
||
this.linkFlag = true;
|
||
Taro.setStorageSync("deviceInfo", this.deviceInfo);
|
||
console.log("正在连接设备");
|
||
Taro.createBLEConnection({
|
||
timeout: 3000,
|
||
deviceId: this.deviceInfo.deviceId,
|
||
success: () => {
|
||
this.deviceInfo.state = true;
|
||
this.getBLEDeviceServices();
|
||
},
|
||
fail: (res) => {
|
||
this.linkFlag = false;
|
||
console.log(res, this.deviceInfo, "连接错误");
|
||
this.callBack({ ...this.deviceInfo, errCode: 10003 });
|
||
if (res.errno == "1509007") {
|
||
this.closeBluetoothAdapter();
|
||
} else {
|
||
this.timeoutBleConnection()
|
||
}
|
||
},
|
||
});
|
||
}
|
||
|
||
// 获取蓝牙多个service
|
||
getBLEDeviceServices() {
|
||
Taro.getBLEDeviceServices({
|
||
deviceId: this.deviceInfo.deviceId,
|
||
success: () => {
|
||
this.getBLEDeviceCharacteristics();
|
||
},
|
||
fail: (err) => this.fail(err),
|
||
});
|
||
}
|
||
// 获取蓝牙低功耗设备某个服务中所有特征
|
||
getBLEDeviceCharacteristics() {
|
||
Taro.getBLEDeviceCharacteristics({
|
||
deviceId: this.deviceInfo.deviceId,
|
||
serviceId: this.config.serviceId,
|
||
success: (res) => {
|
||
this.notifyBLECharacteristicValueChange();
|
||
},
|
||
fail: (err) => this.fail(err),
|
||
});
|
||
}
|
||
|
||
// 启用蓝牙低功耗设备特征值变化时的 notify 功能
|
||
notifyBLECharacteristicValueChange() {
|
||
Taro.notifyBLECharacteristicValueChange({
|
||
deviceId: this.deviceInfo.deviceId,
|
||
serviceId: this.config.serviceId,
|
||
characteristicId: this.config.NotifyUUID,
|
||
state: true,
|
||
success: (res) => {
|
||
console.log("连接成功");
|
||
Taro.setStorageSync("deviceInfo", { ...this.deviceInfo, state: false });
|
||
// handshake1()
|
||
this.callBack(this.deviceInfo);
|
||
},
|
||
fail: (err) => this.fail(err),
|
||
});
|
||
}
|
||
//监听设备返回的数据
|
||
onBLECharacteristicValueChange(fn) {
|
||
Taro.onBLECharacteristicValueChange((data) => {
|
||
let bytes = new Uint8Array(data.value);
|
||
let value = String(this.ab2hex(bytes)).toLocaleUpperCase();
|
||
|
||
// 第二次握手
|
||
// if (bytes[2] == 0xea && bytes[3] == 0x01) {
|
||
// handshake2()
|
||
// }
|
||
console.log(`设备回复====>${value}`);
|
||
TASK.executeTask();
|
||
fn && fn(bytes, value);
|
||
});
|
||
}
|
||
// 向蓝牙写入数据
|
||
writeBleValue(value) {
|
||
console.log("发送指令====>" + String(this.ab2hex(value)).toLocaleUpperCase());
|
||
if (!this.deviceInfo.state) {
|
||
// console.log("蓝牙未连接")
|
||
return
|
||
}
|
||
return Taro.writeBLECharacteristicValue({
|
||
deviceId: this.deviceInfo.deviceId,
|
||
serviceId: this.config.serviceId,
|
||
characteristicId: this.config.WriteUUID,
|
||
writeType: "writeNoResponse",
|
||
value: value,
|
||
});
|
||
}
|
||
|
||
//蓝牙断开
|
||
onBLEConnectionStateChange() {
|
||
Taro.onBLEConnectionStateChange((res) => {
|
||
if (!res.connected) {
|
||
console.log(res, "蓝牙断开");
|
||
this.deviceInfo.state = res.connected;
|
||
this.callBack(this.deviceInfo);
|
||
this.timeoutBleConnection()
|
||
}
|
||
});
|
||
}
|
||
timeoutBleConnection() {
|
||
this.linkFlag = false;
|
||
if (!this.available || !this.isInit || !this.deviceInfo.deviceId) return;
|
||
this.timeout = setTimeout(() => {
|
||
this.timeout && this.clearTimeoutFn("timeout");
|
||
this.createBleConnection();
|
||
}, 3000);
|
||
}
|
||
//停止搜寻附近的蓝牙外围设备
|
||
stopBluetoothDevicesDiscovery() {
|
||
Taro.stopBluetoothDevicesDiscovery();
|
||
this.isFindBt && this.clearTimeoutFn("isFindBt");
|
||
console.log("停止搜寻");
|
||
}
|
||
// 断开与蓝牙低功耗设备的连接
|
||
closeBluetoothAdapter() {
|
||
this.linkFlag = false;
|
||
this.deviceInfo = { state: false };
|
||
Taro.removeStorageSync("deviceInfo");
|
||
Taro.closeBluetoothAdapter({
|
||
success: (res) => {
|
||
console.log(this.deviceInfo, '解绑1');
|
||
this.callBack(this.deviceInfo);
|
||
this.openBluetoothAdapter()
|
||
},
|
||
});
|
||
}
|
||
// 设备响应回调
|
||
deviceCallBack(fn) {
|
||
this.callBack = fn;
|
||
}
|
||
// 转换二进制数据
|
||
ab2hex(buffer) {
|
||
if (!buffer) return;
|
||
const hexArr = Array.prototype.map.call(new Uint8Array(buffer), function (bit) {
|
||
return ("00" + bit.toString(16)).slice(-2);
|
||
});
|
||
return hexArr.join("").toLocaleLowerCase();
|
||
}
|
||
// unBindDevice() {
|
||
// this.deviceInfo = {}
|
||
// Taro.removeStorageSync('deviceInfo')
|
||
// this.closeBluetoothAdapter()
|
||
// }
|
||
/**
|
||
* 字符串插入字符
|
||
* @param {*} str 字符串
|
||
* @param {*} length 间隔多少个插入
|
||
* @param {*} fmt 插入符号
|
||
* @returns
|
||
*/
|
||
strInsert(str, length = 2, fmt = ":") {
|
||
if (!str || !str.length) return "";
|
||
var reg = new RegExp("\\w{1," + length + "}", "g");
|
||
let ma = str.match(reg);
|
||
return ma.join(fmt).toLocaleLowerCase();
|
||
}
|
||
|
||
// 清除计时器
|
||
clearTimeoutFn(name) {
|
||
clearTimeout(this[name]);
|
||
this[name] = null;
|
||
}
|
||
}
|
||
|
||
export default new Bluetooth();
|