1
0
forked from dyf/APP
Files
APP/utils/BleHelper.js
2025-10-23 10:42:30 +08:00

1787 lines
42 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import receivTool from "@/utils/BleReceive.js"
var recei = null;
const serviceDic = [ //合作供应商的蓝牙主服务
{
"serviceId": "0000FFE0-0000-1000-8000-00805F9B34FB",
"writeId": "0000FFE1-0000-1000-8000-00805F9B34FB",
"notifyId": "0000FFE2-0000-1000-8000-00805F9B34FB"
},
{
"serviceId": "0000AE30-0000-1000-8000-00805F9B34FB",
"writeId": "0000AE03-0000-1000-8000-00805F9B34FB",
"notifyId": "0000AE02-0000-1000-8000-00805F9B34FB"
}
];
class BleHelper {
constructor() {
this.StorageKey = "linkedDevices";
recei = receivTool.getBleReceive();
this.init();
}
init() {
var store = uni.getStorageInfoSync();
var f = store.keys.includes(this.StorageKey);
var linkedDevices = [];
if (f) {
linkedDevices = uni.getStorageSync(this.StorageKey);
}
if (linkedDevices && linkedDevices.length && linkedDevices.length > 0) {
// console.log("111111", linkedDevices);
linkedDevices = linkedDevices.filter((v) => {
v.Linked = false;
v.notifyState = false;
return true;
});
}
setTimeout(() => {
this.OpenBlue().then(() => {
this.linkAllDevices();
});
}, 10);
this.data = {
isOpenBlue: false, //蓝牙模块是否开启
available: false, //蓝牙状态是否可用
discovering: false, //蓝牙是否正在搜索
searchList: [], //已搜索到的设备列表,
isSubscribe: false, //是否开启了订阅
LinkedList: linkedDevices //已连接的设备列表
}
this.cfg = {
onDeviceFound: [], //发现新设备的事件
receivDataCallback: [], //接收到数据的事件
bleDisposeCallback: [], //蓝牙断开连接的事件
recoveryCallback: [], //蓝牙连接恢复的事件
stateRecoveryCallback: [], //蓝牙适配器恢复可用事件
stateBreakCallback: [] //蓝牙适配器不可用事件
}
// this.addReceiveCallback((a, b, c) => {
// recei.ReceiveData(a, b, c);
// }, "BleReceiveData");
this.dic = {
errRemarks: [{
key: '10000',
remark: '未初始化蓝牙适配器'
},
{
key: '10001',
remark: '当前蓝牙适配器不可用'
},
{
key: '10002',
remark: '没有找到指定设备'
},
{
key: '10003',
remark: '蓝牙设备连接失败'
},
{
key: '10004',
remark: '蓝牙设备没有找到指定服务'
},
{
key: '10005',
remark: '蓝牙设备没有找到指定特征值'
},
{
key: '10006',
remark: '蓝牙连接已断开'
},
{
key: '10007',
remark: '蓝牙设备当前特征值不支持此操作'
},
{
key: '10008',
remark: '其余所有系统上报的异常'
},
{
key: '10009',
remark: '蓝牙设备不支持BLE低功耗蓝牙'
},
{
key: '10010',
remark: '已连接'
},
{
key: '10011',
remark: '蓝牙设备配对设备需要配对码'
},
{
key: '10012',
remark: '蓝牙设备连接超时'
},
{
key: '10013',
remark: '连接 deviceId 为空或者是格式不正确'
}
]
}
}
//从缓存中删除某个设备bleId蓝牙iddeviceId数据库中的设备id
DropDevice(bleId, deviceId) {
let flag = false;
for (var i = 0; i < this.data.LinkedList.length; i++) {
let item = this.data.LinkedList[i];
if (deviceId && item.device) {
if (item.device.id == deviceId) {
console.log("找到要删除的设备", item);
this.data.LinkedList.splice(i, 1);
this.disconnectDevice(item.deviceId);
flag = true;
break;
}
} else {
if (bleId && item.deviceId == bleId) {
console.log("找到要删除的设备1,", item)
this.data.LinkedList.splice(i, 1);
this.disconnectDevice(item.deviceId);
flag = true;
break;
}
}
}
if (flag) {
this.updateCache();
}
}
//更新缓存
updateCache() {
uni.setStorageSync(this.StorageKey, this.data.LinkedList);
}
//连接所有已连接过的设备
linkAllDevices() {
// console.log("模块启动时,自动连接已连接过的设备", this.data.LinkedList);
if (this.data.LinkedList && this.data.LinkedList.length > 0) {
let flag = false;
for (var i = 0; i < this.data.LinkedList.length; i++) {
let device = this.data.LinkedList[i];
// console.log("自动连接绑定过的设备:" + device.deviceId);
if (device.macAddress && device.device && device.device.id) {
this.LinkBlue(device.deviceId, device.writeServiceId, device.wirteCharactId, device
.notifyCharactId);
flag = true;
}
}
if (!flag) {
this.updateCache();
}
} else {
// console.log("蓝牙未连接过任何设备");
this.updateCache();
}
}
//获取当前页面栈
getCurrentPagePath() {
const pages = getCurrentPages();
if (pages.length === 0) {
return "";
}
const currentPage = pages[pages.length - 1];
// console.log("currentPage=", currentPage.route);
return currentPage.route;
}
//添加事件回调
addCallback(callback, currKey, type) {
if (!type) {
return;
}
let key = currKey ? currKey : this.getCurrentPagePath();
if (!key) {
key = new Date().getTime();
}
if (key) {
// console.log("key=" + key);
let f = this.cfg[type].findIndex((v) => {
return v.key == key;
});
if (f > -1) {
this.cfg[type][f].callback = callback;
return;
}
this.cfg[type].push({
key: key,
callback: callback
});
}
}
//移除事件回调
removeCallback(currKey, type) {
if (!type) {
return;
}
let key = currKey ? currKey : this.getCurrentPagePath();
if (key) {
// console.log("key=" + key);
let f = this.cfg[type].findIndex((v) => {
return v.key == key;
});
if (f > -1) {
this.cfg[type].splice(f, 1);
}
} else {
if (this.cfg[type].length > 0) {
this.cfg[type].splice(this.cfg[type].length - 1, 1);
}
}
}
//设置蓝牙恢复连接的回调
addRecoveryCallback(callback, currKey) {
this.addCallback(callback, currKey, 'recoveryCallback');
}
//移除蓝牙恢复连接的回调
removeRecoveryCallback(currKey) {
this.removeCallback(currKey, 'recoveryCallback');
}
//设置蓝牙断开连接的回调
addDisposeCallback(callback, currKey) {
this.addCallback(callback, currKey, 'bleDisposeCallback');
}
//移除蓝牙断开连接的回调
removeDisposeCallback(currKey) {
this.removeCallback(currKey, 'bleDisposeCallback');
}
//设置发现新设备的回调
addDeviceFound(callback, currKey) {
this.addCallback(callback, currKey, 'onDeviceFound');
}
//移除发现新设备的回调
removeDeviceFound(currKey) {
this.removeCallback(currKey, 'onDeviceFound');
}
//添加接收到数据的回调
addReceiveCallback(callback, currKey) {
this.addCallback(callback, currKey, 'receivDataCallback');
}
//移除接收到数据的回调
removeReceiveCallback(currKey) {
this.removeCallback(currKey, 'receivDataCallback');
}
//添加蓝牙不可用的回调
addStateBreakCallback(callback, currKey) {
this.addCallback(callback, currKey, 'stateBreakCallback');
}
//移除蓝牙不可用的回调
removeStateBreakCallback(currKey) {
this.removeCallback(currKey, 'stateBreakCallback');
}
//设置蓝牙适配器恢复可用的回调
addStateRecoveryCallback(callback, currKey) {
this.addCallback(callback, currKey, 'stateRecoveryCallback');
}
//移除蓝牙适配器恢复的回调
removeStateRecoveryCallback(currKey) {
this.removeCallback(currKey, 'stateRecoveryCallback');
}
//清除所有事件回调
removeAllCallback(currKey) {
this.removeDeviceFound(currKey)
this.removeDisposeCallback(currKey);
this.removeReceiveCallback(currKey);
this.removeRecoveryCallback(currKey);
this.removeStateRecoveryCallback(currKey);
this.removeStateBreakCallback(currKey);
}
getError(ex) {
let code = ex.code;
ex.msg = "未知的异常"
let f = this.dic.errRemarks.find((v) => {
return v.key == code;
});
if (f) {
ex.msg = f.remark;
}
return ex;
}
//引导到设置中打开蓝牙
showBlueSetting(showTip) {
let platform = process.env.UNI_PLATFORM;
var openBlueSetting = function() {
// 判断平台类型
if (platform === 'mp-weixin') {
uni.openSetting();
} else if (platform === 'app-plus' || platform === 'app') {
//----------------------------------------------------------------
const osName = plus.os.name;
if (osName === 'iOS') {
// iOS 平台打开蓝牙设置
plus.runtime.openURL('App-Prefs:root=Bluetooth', function() {
////console.log('成功打开蓝牙设置');
}, function(err) {
console.error('打开蓝牙设置失败:' + err.message);
uni.showModal({
title: '提示',
content: '无法自动打开蓝牙设置,请手动前往设置 > 蓝牙 进行操作。',
showCancel: false
});
});
} else if (osName === 'Android') {
// Android 平台打开蓝牙设置
try {
const Intent = plus.android.importClass('android.content.Intent');
const Settings = plus.android.importClass('android.provider.Settings');
const main = plus.android.runtimeMainActivity();
const intent = new Intent(Settings.ACTION_BLUETOOTH_SETTINGS);
main.startActivity(intent);
} catch (e) {
console.error('打开蓝牙设置失败:' + e.message);
// 尝试使用通用设置页面作为备选方案
plus.runtime.openURL('settings://', function() {
////console.log('打开系统设置成功,请手动找到蓝牙选项');
}, function() {
uni.showModal({
title: '提示',
content: '无法自动打开蓝牙设置,请手动前往设置页面开启蓝牙。',
showCancel: false
});
});
}
} else {
uni.showModal({
title: '提示',
content: '当前系统不支持自动打开蓝牙设置,请手动操作。',
showCancel: false
});
}
//--------------------------------------------------------------------
} else if (platform === 'mp-alipay') {
uni.openSetting();
}
}
if (showTip !== undefined) {
openBlueSetting();
return;
}
if (platform === 'mp-weixin' || platform === 'app-plus' ||
platform === 'mp-alipay' || platform === 'app') {
uni.showModal({
title: '蓝牙未开启',
content: '请在系统设置中打开蓝牙以使用此功能',
success: (res) => {
if (res.confirm) {
openBlueSetting();
}
}
});
} else {
////console.log("当前平台不支持打开系统设置" + platform);
}
}
//获取蓝牙适配器状态
CheckBlue() {
return new Promise((resolve, reject) => {
if (this.data.available) {
// console.log("蓝牙模块是可用状态");
resolve({
available: this.data.available,
discovering: this.data.discovering
});
return;
}
if (!this.data.isOpenBlue) {
console.error("蓝牙模块未打开");
resolve({
available: false,
discovering: false
});
return;
}
uni.getBluetoothAdapterState({
success: (info) => {
// console.log("蓝牙状态获取成功,", info)
this.data.available = info.available;
this.data.discovering = info.discovering;
resolve(info);
},
fail: (ex1) => {
console.error("蓝牙状态获取失败", ex1);
let res1 = {
available: false,
discovering: false
}
resolve(res1);
}
});
});
}
//打开蓝牙适配器
OpenBlue() {
var init = () => {
return new Promise((resolve, reject) => {
if (this.data.isOpenBlue) {
// console.log("蓝牙状态已可用,提前返回");
resolve(false);
return;
}
uni.openBluetoothAdapter({
success: (args) => {
// console.log("蓝牙初始化成功:" + JSON.stringify(args));
this.data.isOpenBlue = true;
this.data.available = true;
resolve(true);
if (this.data.isSubscribe) { //整个App生命周期只订阅一次
return;
}
console.log("开始订阅各类变化消息");
this.data.isSubscribe = true;
// 保存每个设备的连接状态
let bleDeviceStates = {};
var bytesToHexString = (bytes) => {
return bytes.map(byte => byte.toString(16).padStart(2,
'0'));
}
uni.onBluetoothAdapterStateChange((state) => {
// console.log('蓝牙状态发生变化:' + JSON.stringify(state));
if (this.data.available !== state.available) {
this.data.available = state.available;
this.data.discovering = state.discovering;
if (this.data.available && this.data
.isOpenBlue) { //蓝牙状态再次可用,重连所有设备
if (this.cfg.stateRecoveryCallback.length > 0) {
this.cfg.stateRecoveryCallback.forEach(
c => {
try {
c.callback();
} catch (error) {
console.error(
"蓝牙适配器已恢复,但回调函数发生错误",
error);
}
})
}
}
}
if (!state.available) { //蓝牙状态不可用了,将所有设备标记为断开连接
this.data.LinkedList.filter((v) => {
v.Linked = false;
v.notifyState = false;
return true;
});
let keys = Object.keys(bleDeviceStates)
keys.filter(v => {
bleDeviceStates[v] = false;
});
this.cfg.stateBreakCallback.forEach(f => {
try {
f.callback();
} catch (error) {
console.error("蓝牙状态不可用了,执行回调异常",
error)
}
})
this.updateCache();
}
});
uni.onBLEConnectionStateChange((res) => {
console.log("蓝牙连接状态变化了", res);
// 检查状态是否真的发生了变化
if (bleDeviceStates[res.deviceId] === res.connected) {
console.error('专业给Uniapp填坑,连接状态重复回调');
return;
}
// 更新状态记录
bleDeviceStates[res.deviceId] = res.connected;
setTimeout(() => {
if (!res.connected) {
console.error("蓝牙已断开", res);
let f = this.data.LinkedList.find((
v) => {
if (v.deviceId == res
.deviceId) {
v.Linked = false;
v.notifyState = false;
return true;
}
return false;
});
this.updateCache();
if (f && f.device && f.device.id) {
console.log("尝试5次恢复连接,", f
.deviceId);
this.LinkBlue(res.deviceId, f
.writeServiceId, f
.wirteCharactId, f
.notifyCharactId, 5);
}
if (this.cfg.bleDisposeCallback.length >
0) {
this.cfg.bleDisposeCallback.forEach(
(c) => {
try {
c.callback(res);
} catch (error) {
console.error(
"执行蓝牙断开连接的回调出现异常,",
error)
}
});
}
} else {
console.log("蓝牙连接已恢复,", res);
if (this.cfg.recoveryCallback.length >
0) {
this.cfg.recoveryCallback.forEach((
c) => {
try {
c.callback(res);
} catch (error) {
console.error(
"执行蓝牙恢复连接的回调出现异常,",
error)
}
});
}
}
}, 0);
});
uni.onBluetoothDeviceFound((res) => {
// console.log("发现新设备:" + JSON.stringify(devices));
let arr = [];
for (var i = 0; i < res.devices.length; i++) {
let item = res.devices[i];
let f = serviceDic.find(v => {
return item.advertisServiceUUIDs
.includes(v.serviceId);
});
if (f) {
console.log("发现新设备:", item);
arr.push(item);
}
}
if (arr.length === 0) {
// console.error("发现了设备,但不是想要的设备", res);
return;
}
res.devices = arr;
this.data.searchList = this.data.searchList.concat(
res);
if (this.cfg.onDeviceFound) {
if (this.cfg.onDeviceFound.length > 0) {
this.cfg.onDeviceFound.forEach((found) => {
try {
found.callback(res);
} catch (error) {
console.error("处理发现设备的回调出现异常,",
error);
}
});
}
}
});
uni.onBLECharacteristicValueChange((receive) => {
//订阅消息
console.log("收到订阅消息", receive);
let f = this.data.LinkedList.find((v) => {
return v.deviceId == receive.deviceId;
})
let dataView = new DataView(receive.value);
// 转换为字节数组
let bytes = [];
for (let i = 0; i < dataView.byteLength; i++) {
bytes.push(dataView.getUint8(i));
}
let hexs = bytesToHexString(bytes);
let str = '';
try {
let uint8Array = new Uint8Array(receive.value);
for (let i = 0; i < uint8Array.length; i++) {
// 将每个字节转换为对应的字符
str += String.fromCharCode(uint8Array[i]);
}
let header = "mac address:";
if (str.indexOf(header) == 0) { //650以文本传输mac
console.log("str=", str);
this.data.LinkedList.find((v) => {
if (v.deviceId == receive
.deviceId) {
let macStr = str.replace(
header, "");
if (macStr.includes(':')) {
v.macAddress = macStr;
} else {
v.macAddress = macStr
.replace(
/(.{2})/g, '$1:')
.slice(0, -1)
}
str = header + v.macAddress;
console.log("收到mac地址:", v
.macAddress)
}
});
this.updateCache();
}
if (str.indexOf('imei:') == 0) {
let imei = str.split(':')[1];
this.data.LinkedList.find((v) => {
if (v.deviceId == receive
.deviceId) {
v.imei = imei;
}
});
this.updateCache();
}
if (bytes[0] == 0xFC) { //6155以0xFC开头代表mac地址
console.log("收到mac地址:", bytes)
if (bytes.length >= 7) {
console.log("hexs=", hexs);
let mac = hexs.slice(1, 7).join(":")
.toUpperCase();
this.data.LinkedList.find((v) => {
if (v.deviceId == receive
.deviceId) {
v.macAddress = mac;
// console.log("收到mac地址:", str)
}
});
this.updateCache();
}
}
console.log("str=", str);
} catch (ex) {
console.error("将数据转文本失败", ex);
}
try {
let recData = {
deviceId: receive.deviceId,
serviceId: receive.serviceId,
characteristicId: receive.characteristicId,
bytes: bytes,
str: str,
hexs: hexs
};
console.log("监听到特征值:" + JSON.stringify(recData));
if (this.cfg.receivDataCallback) {
if (this.cfg.receivDataCallback.length > 0) {
let path = this.getCurrentPagePath();
// console.log("有人订阅消息")
this.cfg.receivDataCallback.forEach((
rec) => {
// console.log("有人订阅消息111", )
if (rec.callback) {
try {
rec.callback(recData, f,
path, this.cfg
.receivDataCallback
);
} catch (err) {
console.error(
"订阅消息出现异常",
err);
}
}
})
} else {
// console.log("无人订阅消息");
}
} else {
// console.log("无人订阅receivDataCallback,不处理数据");
}
} catch (ex) {
console.error("处理订阅消息失败,ex=", ex);
}
});
},
fail: (ex2) => {
console.error("蓝牙模块启动失败", ex2);
reject(this.getError(ex2));
}
});
});
}
return new Promise((resolve, reject) => {
if (this.data.isOpenBlue) {
resolve();
return;
}
this.CheckBlue().then((res) => {
// console.log("res=", res)
return init();
}).then(resolve).catch((ex) => {
console.error("异常:", ex);
reject(ex);
});
});
}
//关闭蓝牙适配器
CloseBlue() {
return new Promise((resolve, reject) => {
this.data.available = false;
this.data.discovering = false;
this.data.isOpenBlue = false;
this.data.searchList = [];
this.StopSearch();
this.disconnectDevice();
uni.closeBluetoothAdapter({
success: () => {
// console.log("蓝牙模块已关闭");
},
fail: (ex) => {
console.error('无法关闭蓝牙模块:', ex);
ex = this.getError(ex);
},
complete: () => {
resolve();
}
});
});
}
//开始搜索新设备
StartSearch() {
this.data.searchList = [];
var these = this;
//开始搜索
var Search = () => {
//只搜索合作供应商的服务id
let serviceIds = serviceDic.map(v => {
return v.serviceId
});
//搜索一个服务id的设备循环调用
let RunSearch = (serviceId) => {
return new Promise((resolve, reject) => {
uni.startBluetoothDevicesDiscovery({
services: serviceId ? [serviceId] : [],
allowDuplicatesKey: true,
success: (res) => {
//console.log('开始搜索蓝牙设备成功');
resolve(res);
},
fail: (err) => {
console.error(`搜索蓝牙设备失败:`, err);
reject(this.getError(err));
}
});
});
}
return new Promise((resolve, reject) => {
let promises = [];
// for (let i = 0; i < serviceIds.length; i++) {
// promises.push(RunSearch(serviceIds[i]));
// }
promises.push(RunSearch());
Promise.all(promises).then(resolve).catch(reject);
});
}
return this.OpenBlue().then((res) => {
// console.log("蓝牙适配器状态", res)
return Search();
});
}
//停止搜索
StopSearch() {
let p1 = new Promise((resolve, reject) => {
uni.stopBluetoothDevicesDiscovery({
success: (res) => {
// console.log("停止搜索蓝牙设备成功");
resolve();
},
fail: (ex) => {
console.error("无法停止蓝牙搜索");
reject(this.getError(ex));
}
});
});
let p2 = new Promise((succ, err) => {
setTimeout(() => {
err({
code: -1
});
}, 100);
});
return new Promise((resolve, reject) => {
Promise.race([p1, p2]).then(resolve).catch(ex => {
if (ex.code == -1) {
console.error('专业给Uniapp填坑,停止搜索永无回调处理');
resolve();
return;
}
reject(ex);
});
});
}
//获取已连接的设备
getLinkBlue(callback) {
return new Promise((resolve, reject) => {
uni.getConnectedBluetoothDevices({
success: (res) => {
resolve(res);
},
fail: (ex) => {
////console.log("获取已连接设备异常", ex);
reject({
devices: []
});
}
});
});
}
//订阅消息
subScribe(deviceId, state) {
// console.log("开始订阅消息", state);
return new Promise((resolve, reject) => {
setTimeout(() => {
let c = this.data.LinkedList.find((v) => {
return v.deviceId == deviceId;
});
if (!deviceId) {
console.error('deviceId无效')
reject({
code: 404,
msg: 'deviceId无效'
});
return;
}
if (!c) {
console.error("已找不到该设备");
reject({
code: 404,
msg: '已找不到该设备'
});
return;
}
if (state) {
if (c.notifyState) {
resolve();
return;
}
}
let startSubScribe = (id, serviceId, characteristicId) => {
// console.log("serviceId=", serviceId);
// console.log("characteristicId=", characteristicId);
let p1 = new Promise((succ, err) => {
uni.notifyBLECharacteristicValueChange({
deviceId: id,
serviceId: serviceId,
characteristicId: characteristicId,
state: state,
success: (res) => {
if (state) {
// console.log("订阅消息成功", res);
} else {
// console.log("取消订阅成功", res);
}
this.data.LinkedList.find((v) => {
if (v.deviceId == deviceId) {
v.notifyState = state;
}
});
// console.log("success SubScribe");
succ(
res
); //见了鬼了有时候执行了succ但promise永远pending了
},
fail: (ex) => {
err(this.getError(ex));
}
});
});
let p2 = new Promise((succ, err) => {
setTimeout(() => {
err({
code: -1
});
}, 50);
});
return new Promise((succ, err) => {
Promise.race([p1, p2]).then(succ).catch(ex => {
// console.error("异常了:",ex);
if (ex.code == -1) {
console.error('专业给Uniapp填坑,订阅消息永无回调了');
succ();
return;
}
err(ex);
})
});
}
let serv = serviceDic.find(v => {
return v.serviceId == c.writeServiceId;
});
let promies = new Array();
if (c.notifyServiceid && c.notifyCharactId) {
promies.push(startSubScribe(c.deviceId, c.notifyServiceid, c.notifyCharactId));
} else if (serv) {
promies.push(startSubScribe(c.deviceId, serv.serviceId, serv.notifyId));
} else if (c.Characteristics && c.Characteristics.length) {
for (var i = 0; i < c.Characteristics.length; i++) {
let item = c.Characteristics[i];
let serviceId = item.serviceId;
let characteristicId = item.uuid;
if (item.properties.notify) {
promies.push(startSubScribe(deviceId, serviceId, characteristicId));
}
}
} else {
// console.log("c=", c);
// console.log("serv=", serv);
reject({
code: 403,
msg: "出现错误,找不到任何通知特征"
});
return;
}
if (promies.length > 0) {
Promise.allSettled(promies).then((results) => {
results.forEach((result, index) => {
if (result.status === "fulfilled") {
// console.log(`操作${index + 1}成功:`, result.value);
} else {
// console.log(`操作${index + 1}失败:`, result.reason
// .message);
}
});
// console.log("订阅消息成功");
resolve();
}).catch((ex) => {
console.error("异常,ex=", ex);
reject(ex);
}).finally(() => {
// console.log("finally")
});
} else {
console.error("没有特征需要订阅");
resolve();
}
}, 800);
});
}
//获取服务
getService(id, targetServiceId, writeCharId, notifyCharId) {
if (!targetServiceId) {
targetServiceId = "xx"; // "FFE0";
}
return new Promise((resolve, reject) => {
var repeatCnt = 0;
var startgetService = () => {
uni.getBLEDeviceServices({
deviceId: id,
success: (res) => {
if (res.services && res.services.length > 0) {
// console.log("获取到服务:" + JSON.stringify(res));
this.data.LinkedList.find((v) => {
if (v.deviceId == id) {
v.services = res.services;
}
});
//this.updateCache();
var promises = [];
let s = null;
let se = res.services.find((v) => {
s = serviceDic.find(k => {
return k.serviceId == v.uuid;
})
if (s) {
return true;
}
return false;
// return v.uuid.indexOf(targetServiceId) > -1;
});
if (se) {
// console.log("合作供应商的", s)
this.data.LinkedList.find((v) => {
if (v.deviceId == id) {
v.writeServiceId = s.serviceId;
v.wirteCharactId = s.writeId;
v.notifyServiceid = s.serviceId;
v.notifyCharactId = s.notifyId;
}
});
this.updateCache();
//合作供应商的设备,直接订阅消息,不走发现特征了
promises.push(this.subScribe(id, true));
// promises.push(this.getFeatrus(id, se.uuid, writeCharId,
// notifyCharId));
} else {
console.error("预设的蓝牙服务和特征中找不到");
for (var i = 0; i < res.services.length; i++) {
let service = res.services[i];
promises.push(this.getFeatrus(id, service.uuid,
writeCharId, notifyCharId));
}
}
if (promises.length == 0) {
console.error("未找到主服务");
reject({
msg: "未找到主服务",
code: -1
});
} else {
Promise.all(promises)
.then(results => {
if (!s) {
//非指定供应商的设备,走订阅消息
return this.subScribe(id, true);
} else {
//指定供应商的设备已经订阅过了
return Promise.resolve();
}
})
.then((res) => {
// console.log('设备连接成功,初始化完成', this.data
// .LinkedList);
resolve();
})
.catch(error => {
console.error("errrr=", error);
reject(error);
});
}
} else {
repeatCnt++;
if (repeatCnt > 5) {
reject({
msg: "获取设备服务失败",
code: -1
});
return;
}
setTimeout(function() {
startgetService(id);
}, 100+repeatCnt*300);
}
},
fail: (ex) => {
reject(this.getError(ex));
}
})
}
setTimeout(function() {
startgetService(id);
}, 100);
});
}
//获取特征
getFeatrus(id, serviceId, writeCharId, notifyCharId) {
var promise = new Promise((resolve, reject) => {
uni.getBLEDeviceCharacteristics({
deviceId: id,
serviceId: serviceId,
success: (res) => {
// console.log("获取到特征:" + JSON.stringify(res));
// res.characteristics.forEach((v) => {
// v.serviceId = serviceId;
// });
//写特征
let writeChar = res.characteristics.find(char => {
let fe = serviceDic.find(v => {
return v.serviceId == serviceId && v.writeId == char
.uuid;
})
// return char.uuid.indexOf(writeCharId) > -1
if (fe) {
return true;
}
return false;
});
// if (!writeChar) {
// writeChar = res.characteristics.find(char => {
// return char.properties.write;
// });
// }
//通知特征
let notiChar = res.characteristics.find(char => {
let fe = serviceDic.find(v => {
return v.serviceId == serviceId && v.notifyId ==
char.uuid;
})
// return char.uuid.indexOf(writeCharId) > -1
if (fe) {
return true;
}
return false;
// return char.uuid.indexOf(notifyCharId) > -1;
});
// if (!notiChar) {
// notiChar = res.characteristics.find(char => {
// return char.properties.notify;
// });
// }
this.data.LinkedList.find(function(v) {
if (v.deviceId == id) {
if (!v.Characteristics) {
v.Characteristics = [];
}
for (var i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
let flag = false;
for (var j = 0; j < v.Characteristics.length; j++) {
let charact = v.Characteristics[j];
if (charact.uuid == item.uuid) {
flag = true;
break;
}
}
if (!flag) {
v.Characteristics.push(item);
}
}
if (writeChar) {
v.writeServiceId = serviceId;
v.wirteCharactId = writeChar.uuid;
}
if (notiChar) {
v.notifyServiceid = serviceId;
v.notifyCharactId = notiChar.uuid;
}
return true;
}
return false;
});
this.updateCache();
resolve(res);
},
fail: (ex) => {
////console.log("获取特征出现异常:" + JSON.stringify(ex));
reject(ex);
}
});
});
return promise;
}
//连接某个设备
LinkBlue(deviceId, targetServiceId, writeCharId, notifyCharId, maxRetries) {
if (maxRetries === undefined) {
maxRetries = 0; // 最大重试次数
}
if (!writeCharId) {
writeCharId = "xxxx"; // "FFE1";
}
if (!notifyCharId) {
notifyCharId = "xxxxx"; // "FFE2";
}
let fIndex = -1;
let f = this.data.LinkedList.find((v, index) => {
if (v.deviceId == deviceId) {
fIndex = index;
return true;
}
return false;
});
////console.log("findex=" + fIndex);
var these = this;
//连接设备
var linkDevice = () => {
// 添加重试次数限制
let retryCount = 0;
const connect = () => {
return new Promise((resolve, reject) => {
if (fIndex > -1 && f?.Linked) {
// console.log("当前已连接,跳过其他步骤");
resolve(false);
return;
}
if (!this.data.available) {
reject(this.getError({
code: 10001
}));
return;
}
// console.log("正在连接" + deviceId);
uni.createBLEConnection({
deviceId: deviceId,
timeout: 30000,
success: (info) => {
// console.log("新连接成功", this.data.LinkedList);
this.getLinkBlue().then((arr) => {
let cr = arr.devices.find(c => {
if (c.deviceId == deviceId) {
c.Linked = true;
return true;
}
return false;
});
if (fIndex > -1) {
this.data.LinkedList[fIndex].Linked = true;
} else {
this.data.LinkedList.push(cr);
}
this.updateCache();
// console.log("LinkedList=", this.data
// .LinkedList);
// 处理 MTU 设置
if (plus.os.name === 'Android') {
this.setMtu(deviceId);
}
resolve(true);
}).catch((ex) => {
reject(this.getError(ex));
});
},
fail: (ex) => {
ex = this.getError(ex);
console.error("蓝牙" + deviceId + "连接失败" + JSON.stringify(
ex));
// 连接超时后自动重试
if (ex.code === 10012 && retryCount < maxRetries) {
retryCount++;
console.log(`重试连接 (${retryCount}/${maxRetries})`);
// 使用 setTimeout 避免递归调用栈溢出
setTimeout(() => {
connect().then(resolve).catch(reject);
}, 1000); // 延迟1秒后重试
} else {
reject(ex);
}
}
});
});
};
return connect();
};
return new Promise((resolve, reject) => {
this.OpenBlue().then((res) => {
////console.log("2222222");
return linkDevice(deviceId);
}).then((res) => {
if (res) { //新连接
// console.log("11111111");
if (fIndex == -1) {
// console.log("开始获取服务", targetServiceId)
return this.getService(deviceId, targetServiceId, writeCharId,
notifyCharId); //获取服务
} else {
if (f.wirteCharactId && f.notifyCharactId) {
if (!f.notifyState) {
// console.log("开始订阅特征");
this.subScribe(deviceId, true);
} else {
console.log("不订阅消息");
}
return Promise.resolve(true);
} else {
console.log("开始获取服务", targetServiceId)
return this.getService(deviceId, targetServiceId, writeCharId,
notifyCharId);
}
}
} else { //已连接过,直接订阅消息
// console.log("11111111");
if (fIndex > -1 && f && !f.notifyState) {
this.subScribe(deviceId, true);
}
return Promise.resolve(true); //已连接过的设备无需获取服务
}
}).then(() => {
// console.log("then.....");
setTimeout(() => {
resolve();
}, 500);
}).catch((ex) => {
console.error("出现异常", ex);
reject(ex);
});
});
}
setMtu(deviceId){
let prom=new Promise((_succ,_err)=>{
uni.setBLEMTU({
deviceId: deviceId,
mtu: 512,
success: (mtuRes) => {
console.log("mtu约定成功");
_succ(mtuRes);
},
fail: (ex) => {
console.error(
"mtu设置失败",ex);
ex=this.getError(ex);
_err(
ex
); // MTU设置失败不影响连接成功
},complete(){
console.log("设置mtu完毕");
}
});
});
return prom;
}
//断开连接
disconnectDevice(deviceId) {
var disconnect = (id) => {
return new Promise((resolve, reject) => {
uni.closeBLEConnection({
deviceId: id,
success: (res) => {
console.log("用户主动断开了蓝牙:" + id);
this.subScribe(id, false);
resolve();
},
fail: (ex) => {
console.error("无法断开蓝牙连接", ex);
reject(this.getError(ex));
}
});
});
}
if (deviceId) {
disconnect(deviceId);
this.data.LinkedList.find(v => {
if (v.deviceId === deviceId) {
return true;
}
return false;
});
return;
}
if (this.data.LinkedList.length > 0) {
let arr = [];
for (var i = 0; i < this.data.LinkedList.length; i++) {
let item = this.data.LinkedList[i];
if (item.Linked) {
arr.push(disconnect(item.deviceId));
}
}
if (arr.length == 0) {
return;
}
Promise.allSettled(arr).then((results) => {
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
////console.log(`第${index + 1}个Promise成功:`, result.value);
} else {
////console.log(`第${index + 1}个Promise失败:`, result.reason.message);
}
});
});
} else {
////console.log("无已连接设备");
}
}
//向蓝牙设备发送一个字符串的ASCII码
sendString(deviceid, str, writeServiceId, wirteCharactId, ms) {
if (str && str.length) {
let buffer = new ArrayBuffer(str.length);
let dataView = new DataView(buffer);
// 2. 将字符串转换为 ASCII 码并写入 DataView
for (let i = 0; i < str.length; i++) {
dataView.setUint8(i, str.charCodeAt(i));
}
return this.sendData(deviceid, buffer, writeServiceId, wirteCharactId, ms);
} else {
return Promise.resolve({
code: 200,
msg: "没有数据要发送"
})
}
}
//向蓝牙设备发送一个16进制的数组数据
sendHexs(deviceid, array, writeServiceId, wirteCharactId, ms) {
if (array && array.length) {
let bufferSize = array.length;
let buffer = new ArrayBuffer(bufferSize);
let dataView = new DataView(buffer);
for (let i = 0; i < array.length; i++) {
dataView.setUint8(i, array);
}
return this.sendData(deviceid, buffer, writeServiceId, wirteCharactId, ms);
} else {
return Promise.resolve({
code: 200,
msg: "没有数据要发送"
})
}
}
//向蓝牙设备发送数据,如果没连接将自动连接后再发
sendData(deviceid, buffer, writeServiceId, wirteCharactId, ms) {
// console.log("deviceid=" + deviceid + ",writeServiceId=" + writeServiceId + ",wirteCharactId=" +
// wirteCharactId + ",timeout=" + ms)
if (ms === undefined) {
ms = 50;
}
let c = this.data.LinkedList.find((v) => {
return v.deviceId == deviceid;
});
let device = {
deviceId: deviceid,
writeServiceId: null,
wirteCharactId: null
};
if (writeServiceId) {
device.writeServiceId = writeServiceId;
}
if (wirteCharactId) {
device.wirteCharactId = wirteCharactId;
}
if (!device.writeServiceId || !device.wirteCharactId) {
//console.log("从已连接中找设备")
if (c) {
device = c;
}
}
let sendBuffer = () => {
return new Promise(async (resolve, reject) => {
var promise = new Promise((succ, err) => {
if (!c) {
err(this.getError({
code: 10002
})); //没有找到指定设备
return;
}
// console.log("device=", device);
uni.writeBLECharacteristicValue({
deviceId: device.deviceId,
serviceId: device.writeServiceId,
characteristicId: device.wirteCharactId,
value: buffer,
success: () => {
// console.log("发送数据成功");
succ();
},
fail: (ex) => {
ex = this.getError(ex);
console.error("发送数据失败", ex);
err(ex);
}
});
});
if (plus.os.name == 'iOS') {
function timeOut(ms) {
return new Promise((_, err) => {
setTimeout(() => {
err({
code: -1,
errMsg: '超时了'
})
}, ms);
});
}
Promise.race([timeOut(ms), promise]).then(resolve).catch((ex) => {
// console.error("ex=", ex);
if (ex.code == -1) {
console.error('专业给Uniapp填坑,发送消息永无回调');
resolve(ex);
} else {
reject(ex);
}
}).finally(() => {
//console.log("完成了")
});
} else {
promise.then(resolve).catch(reject);
}
});
}
if (c.Linked) {
// console.log("蓝牙已连接,直接发送");
return sendBuffer();
} else {
// console.log("先连接蓝牙再发送");
return new Promise((resolve, reject) => {
let f = this.data.LinkedList.find((v) => {
return v.deviceId == deviceid;
});
if (!f) {
reject({
code: '-9',
msg: '蓝牙未连接过此设备,请重新使用蓝牙添加该设备'
});
retrn;
}
this.LinkBlue(f.deviceId, f.writeServiceId, f.wirteCharactId, f.notifyCharactId).then((
res) => {
console.log("连接成功");
return sendBuffer();
}).then(() => {
//console.log("发送成功")
resolve();
}).catch((ex) => {
console.error("出现异常", ex);
reject(this.getError(ex));
});
});
}
}
//将点阵数据转换成RGB565
convertToRGB565(pixels, type) {
if (!type) {
type = 'rgb';
}
const result = new Uint16Array(pixels.length / 4);
let index = 0;
for (let i = 0; i < pixels.length; i += 4) {
let r = pixels[i];
let g = pixels[i + 1];
let b = pixels[i + 2];
let a = pixels[i + 3];
if (type == 'bgr') {
result[index++] = ((b & 0xF8) << 8) | ((g & 0xFC) << 3) | (r >> 3);
} else {
result[index++] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
}
return result;
}
}
let instance = null;
export default {
getBleTool: function(found, receive) {
if (!instance) {
instance = new BleHelper();
} else {
////console.log("调用现有实例");
}
return instance;
}
}