2025-04-16 18:15:18 +08:00
|
|
|
|
import Taro from "@tarojs/taro";
|
2025-04-18 09:09:09 +08:00
|
|
|
|
import { handshake1, handshake2 } from "./sendOrder";
|
2025-04-16 18:15:18 +08:00
|
|
|
|
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 = {
|
2025-04-21 18:27:42 +08:00
|
|
|
|
// 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',
|
2025-04-16 18:15:18 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 连接状态
|
|
|
|
|
linkFlag = false;
|
|
|
|
|
// 蓝牙是否可用
|
|
|
|
|
available = true;
|
|
|
|
|
// 蓝牙初始化
|
|
|
|
|
isInit = false;
|
|
|
|
|
|
|
|
|
|
timeout = null;
|
|
|
|
|
timeout1 = null;
|
|
|
|
|
|
|
|
|
|
// 判断是否搜索到设备
|
|
|
|
|
isFindBt = null;
|
|
|
|
|
|
|
|
|
|
platform = Taro.getSystemInfoSync().platform;
|
|
|
|
|
appAuthorize = Taro.getAppAuthorizeSetting();
|
2025-04-21 18:27:42 +08:00
|
|
|
|
deviceInfo = Taro.getStorageSync('deviceInfo') || {}
|
2025-04-16 18:15:18 +08:00
|
|
|
|
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;
|
|
|
|
|
},
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-04-18 09:09:09 +08:00
|
|
|
|
console.log("未搜索到设备");
|
2025-04-16 18:15:18 +08:00
|
|
|
|
this.isFindBt && this.clearTimeoutFn("isFindBt");
|
|
|
|
|
}, 6000);
|
|
|
|
|
},
|
|
|
|
|
fail: (err) => {
|
|
|
|
|
this.fail(err);
|
|
|
|
|
this.stopBluetoothDevicesDiscovery();
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 监听搜索到新设备的事件
|
|
|
|
|
// 定义一个方法用于处理蓝牙设备发现事件
|
2025-04-21 18:27:42 +08:00
|
|
|
|
onBluetoothDeviceFound(fn) {
|
2025-04-16 18:15:18 +08:00
|
|
|
|
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");
|
|
|
|
|
|
2025-04-21 18:27:42 +08:00
|
|
|
|
if (devices.name && devices.name == "W53A") {
|
|
|
|
|
// if (devices.name && devices.name == "LE-AB2020") {
|
2025-04-16 18:15:18 +08:00
|
|
|
|
const item = {
|
|
|
|
|
deviceId: devices.deviceId,
|
|
|
|
|
mac: mac,
|
|
|
|
|
name: devices.name,
|
|
|
|
|
};
|
|
|
|
|
|
2025-04-21 18:27:42 +08:00
|
|
|
|
// this.deviceInfo = { ...this.deviceInfo, ...item }
|
|
|
|
|
// this.stopBluetoothDevicesDiscovery();
|
|
|
|
|
// this.createBleConnection();
|
|
|
|
|
fn && fn(item)
|
2025-04-16 18:15:18 +08:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 蓝牙连接
|
|
|
|
|
createBleConnection() {
|
|
|
|
|
if (!this.available || this.linkFlag) return;
|
|
|
|
|
this.linkFlag = true;
|
|
|
|
|
Taro.setStorageSync("deviceInfo", this.deviceInfo);
|
|
|
|
|
console.log("正在连接设备");
|
|
|
|
|
Taro.createBLEConnection({
|
|
|
|
|
timeout: 8000,
|
|
|
|
|
deviceId: this.deviceInfo.deviceId,
|
|
|
|
|
success: () => {
|
|
|
|
|
this.deviceInfo.state = true;
|
|
|
|
|
this.getBLEDeviceServices();
|
|
|
|
|
// this.getBLEDeviceCharacteristics();
|
|
|
|
|
},
|
|
|
|
|
fail: (res) => {
|
|
|
|
|
this.linkFlag = false;
|
|
|
|
|
console.log(res, this.deviceInfo, "连接错误");
|
|
|
|
|
this.callBack({ ...this.deviceInfo, errCode: 10003 });
|
|
|
|
|
if (!this.deviceInfo.deviceId) return this.timeout && this.clearTimeoutFn("timeout");
|
|
|
|
|
if (this.timeout) return;
|
|
|
|
|
if (res.errno == "1509007") {
|
|
|
|
|
this.closeBluetoothAdapter();
|
|
|
|
|
} else {
|
|
|
|
|
this.timeout = setTimeout(() => {
|
|
|
|
|
this.timeout && this.clearTimeoutFn("timeout");
|
|
|
|
|
this.createBleConnection();
|
|
|
|
|
}, 10000);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取蓝牙多个service
|
|
|
|
|
getBLEDeviceServices() {
|
|
|
|
|
Taro.getBLEDeviceServices({
|
|
|
|
|
deviceId: this.deviceInfo.deviceId,
|
|
|
|
|
success: (res) => {
|
|
|
|
|
console.log(JSON.stringify(res), 'JSON.stringify(res)');
|
|
|
|
|
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("连接成功");
|
2025-04-21 18:27:42 +08:00
|
|
|
|
Taro.setStorageSync("deviceInfo", this.deviceInfo);
|
2025-04-18 09:09:09 +08:00
|
|
|
|
handshake1()
|
2025-04-16 18:15:18 +08:00
|
|
|
|
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));
|
2025-04-18 09:09:09 +08:00
|
|
|
|
|
|
|
|
|
// 第二次握手
|
|
|
|
|
if (bytes[2] == 0xea && bytes[3] == 0x01) {
|
|
|
|
|
handshake2()
|
2025-04-16 18:15:18 +08:00
|
|
|
|
}
|
2025-04-18 09:09:09 +08:00
|
|
|
|
console.log(`设备回复====>${value}`);
|
2025-04-16 18:15:18 +08:00
|
|
|
|
TASK.executeTask();
|
2025-04-18 09:09:09 +08:00
|
|
|
|
fn && fn(bytes, value);
|
2025-04-16 18:15:18 +08:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
// 向蓝牙写入数据
|
|
|
|
|
writeBleValue(value) {
|
2025-04-18 09:09:09 +08:00
|
|
|
|
if (!this.deviceInfo.state) {
|
|
|
|
|
console.log("蓝牙未连接")
|
|
|
|
|
return
|
|
|
|
|
}
|
2025-04-16 18:15:18 +08:00
|
|
|
|
console.log("发送指令====>" + String(this.ab2hex(value)).toLocaleUpperCase());
|
|
|
|
|
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.linkFlag = false;
|
|
|
|
|
if (!this.available || this.timeout || !this.isInit || !this.deviceInfo.deviceId) return;
|
|
|
|
|
this.timeout = setTimeout(() => {
|
|
|
|
|
this.timeout && this.clearTimeoutFn("timeout");
|
|
|
|
|
this.createBleConnection();
|
|
|
|
|
}, 1000);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
//停止搜寻附近的蓝牙外围设备
|
|
|
|
|
stopBluetoothDevicesDiscovery() {
|
|
|
|
|
Taro.stopBluetoothDevicesDiscovery();
|
2025-04-18 09:09:09 +08:00
|
|
|
|
this.isFindBt && this.clearTimeoutFn("isFindBt");
|
2025-04-16 18:15:18 +08:00
|
|
|
|
console.log("停止搜寻");
|
|
|
|
|
}
|
|
|
|
|
// 断开与蓝牙低功耗设备的连接
|
|
|
|
|
closeBluetoothAdapter() {
|
|
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
|
this.linkFlag = false;
|
|
|
|
|
this.deviceInfo = { state: false };
|
|
|
|
|
wx.removeStorageSync("deviceInfo");
|
|
|
|
|
this.callBack(this.deviceInfo);
|
|
|
|
|
Taro.closeBluetoothAdapter({
|
|
|
|
|
success: (res) => {
|
|
|
|
|
this.openBluetoothAdapter().then(resolve).catch(reject);
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
// 设备响应回调
|
|
|
|
|
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();
|
|
|
|
|
}
|
2025-04-21 18:27:42 +08:00
|
|
|
|
unBindDevice() {
|
|
|
|
|
this.deviceInfo = {}
|
|
|
|
|
wx.removeStorageSync('deviceInfo')
|
|
|
|
|
this.closeBluetoothAdapter()
|
|
|
|
|
}
|
2025-04-16 18:15:18 +08:00
|
|
|
|
/**
|
|
|
|
|
* 字符串插入字符
|
|
|
|
|
* @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();
|