Skip to content

Commit fc08918

Browse files
committed
Add a timeout mechanism during device scanning and connection to avoid lagging issues caused by slow or unresponsive devices.
1 parent 2e71e39 commit fc08918

File tree

5 files changed

+202
-67
lines changed

5 files changed

+202
-67
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mcblekit",
3-
"version": "1.0.6",
3+
"version": "1.0.9",
44
"description": "该微信小程序开源代码库用于管理微信小程序中的蓝牙功能。支持初始化蓝牙适配器、扫描和连接蓝牙设备、获取设备服务和特征、监听特征值变化、读写特征值以及断开连接等操作。通过设置不同的监听器,可灵活处理蓝牙连接状态变化、设备发现、服务和特征发现等事件,适用于需要与蓝牙设备进行数据交互的微信小程序开发场景。This WeChat mini program open-source code library is used to manage the Bluetooth function in WeChat mini programs. Support initialization of Bluetooth adapters, scanning and connecting Bluetooth devices, obtaining device services and features, monitoring feature value changes, reading and writing feature values, and disconnecting. By setting different listeners, it is possible to flexibly handle events such as changes in Bluetooth connection status, device discovery, service and feature discovery, which is suitable for WeChat mini program development scenarios that require data interaction with Bluetooth devices. ",
55
"main": "src/MCBleKit.js",
66
"scripts": {

src/MCBleKit.js

Lines changed: 88 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
/**
2+
* MCBleKit.js.
3+
* MCBleKit
4+
*
5+
* Created by Morgan Chen on 2025/4/8.
6+
* https://github.com/Json031
7+
*/
8+
19
var util = require('./MCUtil.js');
210
var mcrssi = require('./MCrssi.js');
11+
var mcTimeout = require('./MCTimeout.js');
12+
13+
let ScanDeviceTimeout = 35000;//扫描蓝牙超时时间,单位毫秒
14+
let ConnectDeviceTimeout = 60000;//连接蓝牙超时时间,单位毫秒
315

416
var __instance = (function () {
517
var instance;
@@ -207,17 +219,24 @@ MCBleKit.prototype.getBluetoothAdapterState = function () {
207219

208220
// 开始扫描
209221
MCBleKit.prototype.startBluetoothDevicesDiscovery = function () {
222+
mcTimeout.withTimeout(this.startScan(), ScanDeviceTimeout, '设备扫描超时')
223+
};
224+
MCBleKit.prototype.startScan = function () {
225+
return new Promise((resolve, reject) => {
210226
if (util.isEmptyStr(this.blueName)) {
227+
reject;
211228
return;
212229
}
213230
var that = this;
214231
wx.startBluetoothDevicesDiscovery({
215232
success: function (res) {
233+
resolve;
216234
console.log('🔍 开始扫描设备', res)
217235
that.onBluetoothDeviceFound();
218236
that.startDiscoverListener();
219237
},
220238
fail: function (res) {
239+
reject;
221240
console.log('❌ 扫描设备失败', res)
222241
if (res.errCode === 10004) {
223242
wx.showToast({
@@ -228,8 +247,8 @@ MCBleKit.prototype.startBluetoothDevicesDiscovery = function () {
228247
console.log('startBluetoothDevicesDiscovery fail' + res.errMsg);
229248
}
230249
});
250+
})
231251
};
232-
233252
//连接设备
234253
// 获取所有已发现的设备
235254
MCBleKit.prototype.onBluetoothDeviceFound = function () {
@@ -266,71 +285,80 @@ MCBleKit.prototype.stopBluetoothDevicesDiscovery = function () {
266285
};
267286

268287
MCBleKit.prototype.connectToBluetoothDevice = function () {
269-
if (util.isNullObject(this.bleDevice)) {
270-
return;
271-
}
272-
if (this.connected) {
273-
return;
274-
}
275-
if (this.connecting) {
276-
return;
277-
}
278-
this.connecting = true;
279-
// 连接外设
280-
var that = this;
281-
wx.createBLEConnection({
282-
deviceId: this.bleDevice.deviceId,
283-
success: function (res) {
284-
console.log('连接设备成功', res);
285-
that.connected = true;
286-
wx.setBLEMTU({
287-
deviceId: that.bleDevice.deviceId,
288-
mtu: that.bleMTU,
289-
success: function (res) {
290-
console.log('setBLEMTU succ');
291-
},
292-
fail: function (err) {
293-
that.errorOccurListener(err);
294-
console.log('setBLEMTU fail' + JSON.stringify(err));
295-
}
296-
});
297-
that.getBLEDeviceServices();
298-
that.getRssi();
299-
},
300-
fail: function (res) {
301-
console.log('❌ 连接设备失败', res)
302-
if (res.errno == 1509001 && res.errCode == 10003 && util.containsIgnoreCase(res.errMsg, 'status:133')) {
303-
wx.openBluetoothAdapter({
288+
mcTimeout.withTimeout(this.connectDeviceWithTimeout(), ConnectDeviceTimeout, '连接设备超时')
289+
};
290+
MCBleKit.prototype.connectDeviceWithTimeout = function () {
291+
return new Promise((resolve, reject) => {
292+
if (util.isNullObject(this.bleDevice)) {
293+
reject;
294+
return;
295+
}
296+
if (this.connected) {
297+
reject;
298+
return;
299+
}
300+
if (this.connecting) {
301+
reject;
302+
return;
303+
}
304+
this.connecting = true;
305+
// 连接外设
306+
var that = this;
307+
wx.createBLEConnection({
308+
deviceId: this.bleDevice.deviceId,
309+
success: function (res) {
310+
resolve;
311+
console.log('连接设备成功', res);
312+
that.connected = true;
313+
wx.setBLEMTU({
314+
deviceId: that.bleDevice.deviceId,
315+
mtu: that.bleMTU,
304316
success: function (res) {
305-
console.log('初始化蓝牙成功', res);
306-
var coTimer = setInterval(function () {
307-
that.connectToBluetoothDevice();
308-
clearInterval(coTimer);
309-
}, 1000);
317+
console.log('setBLEMTU succ');
310318
},
311-
fail: function (res) {
312-
that.errorOccurListener(res);
313-
console.log('初始化蓝牙失败', res);
319+
fail: function (err) {
320+
that.errorOccurListener(err);
321+
console.log('setBLEMTU fail' + JSON.stringify(err));
314322
}
315323
});
316-
return;
317-
}
318-
if (res.errno == 1509007) {
319324
that.getBLEDeviceServices();
325+
that.getRssi();
326+
},
327+
fail: function (res) {
328+
reject;
329+
console.log('❌ 连接设备失败', res)
330+
if (res.errno == 1509001 && res.errCode == 10003 && util.containsIgnoreCase(res.errMsg, 'status:133')) {
331+
wx.openBluetoothAdapter({
332+
success: function (res) {
333+
console.log('初始化蓝牙成功', res);
334+
var coTimer = setInterval(function () {
335+
that.connectToBluetoothDevice();
336+
clearInterval(coTimer);
337+
}, 1000);
338+
},
339+
fail: function (res) {
340+
that.errorOccurListener(res);
341+
console.log('初始化蓝牙失败', res);
342+
}
343+
});
344+
return;
345+
}
346+
if (res.errno == 1509007) {
347+
that.getBLEDeviceServices();
348+
}
349+
console.log('连接失败', res);
350+
//超时情况不提示
351+
if (!util.containsIgnoreCase(res.errMsg, 'connect time out')) {
352+
that.errorOccurListener(res);
353+
wx.showToast({
354+
title: '连接失败:' + res.errno,
355+
icon: 'none'
356+
});
357+
}
320358
}
321-
console.log('连接失败', res);
322-
//超时情况不提示
323-
if (!util.containsIgnoreCase(res.errMsg, 'connect time out')) {
324-
that.errorOccurListener(res);
325-
wx.showToast({
326-
title: '连接失败:' + res.errno,
327-
icon: 'none'
328-
});
329-
}
330-
}
331-
});
332-
};
333-
359+
});
360+
});
361+
}
334362
/**
335363
* 获取信号强度
336364
*/

src/MCTimeout.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* MCTimeout.js.
3+
* MCBleKit
4+
*
5+
* Created by Morgan Chen on 2025/4/17.
6+
* https://github.com/Json031
7+
*/
8+
9+
/**
10+
* Creates a timeout for function's promise.
11+
*
12+
* @param {function} promise function's promise.
13+
*
14+
* @param {timeoutMs} timeoutMs timeout milliseconds.
15+
*
16+
* @param {string} timeoutMessage timeout message.
17+
*
18+
* @return {Promise} new Promise
19+
*
20+
*/
21+
function withTimeout(promise, timeoutMs, timeoutMessage = '操作超时') {
22+
return new Promise((resolve, reject) => {
23+
const timer = setTimeout(() => {
24+
reject(new Error(timeoutMessage))
25+
}, timeoutMs)
26+
27+
promise
28+
.then((res) => {
29+
clearTimeout(timer)
30+
resolve(res)
31+
})
32+
.catch((err) => {
33+
clearTimeout(timer)
34+
reject(err)
35+
})
36+
})
37+
}
38+
39+
module.exports = {
40+
withTimeout: withTimeout
41+
};

src/MCUtil.js

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,44 @@
1-
// 空字符串
1+
/**
2+
* MCUtil.js.
3+
* MCBleKit
4+
*
5+
* Created by Morgan Chen on 2025/4/8.
6+
* https://github.com/Json031
7+
*/
8+
9+
/**
10+
* Determine if it is an empty string
11+
*
12+
* @param {string} str determine object
13+
*
14+
* @return {Boolean} true/false
15+
*
16+
*/
217
function isEmptyStr(str) {
318
return str === null || str === undefined || str === "";
419
}
520

6-
// 空对象
21+
/**
22+
* Determine if it is an empty object
23+
*
24+
* @param {object} object determine object
25+
*
26+
* @return {Boolean} true/false
27+
*
28+
*/
729
function isNullObject(object) {
830
return object === null || object === undefined;
931
}
1032

11-
// 含有子字符串
33+
/**
34+
* Determine if there are substrings present
35+
*
36+
* @param {string} str determine object
37+
* @param {string} subStr substrings
38+
*
39+
* @return {Boolean} true/false
40+
*
41+
*/
1242
function contains(str, subStr) {
1343
if (isEmptyStr(str)) {
1444
return false;
@@ -19,12 +49,28 @@ function contains(str, subStr) {
1949
return str.indexOf(subStr) >= 0;
2050
}
2151

22-
// 忽略大小写敏感判断是否含有子字符串
52+
/**
53+
* Ignore case sensitivity to determine if there are substrings
54+
*
55+
* @param {string} str determine object
56+
* @param {string} subStr substrings
57+
*
58+
* @return {Boolean} true/false
59+
*
60+
*/
2361
function containsIgnoreCase(str, subStr) {
2462
return contains(str.toLowerCase(), subStr.toLowerCase());
2563
}
2664

27-
// 忽略大小写敏感对比字符串
65+
/**
66+
* Ignore case sensitive comparison strings
67+
*
68+
* @param {string} str1 determine object
69+
* @param {string} sub2 determine object
70+
*
71+
* @return {Boolean} true/false
72+
*
73+
*/
2874
function isEqualIgnoreCase(str1, str2) {
2975
if (isEmptyStr(str1)) {
3076
return false;
@@ -35,6 +81,12 @@ function isEqualIgnoreCase(str1, str2) {
3581
return str1.toUpperCase() === str2.toUpperCase();
3682
}
3783

84+
/**
85+
* handle Bluetooth Error
86+
*
87+
* @param {object} err Bluetooth Error
88+
*
89+
*/
3890
function handleBluetoothError(err) {
3991
const code = err.errCode
4092
let message = '发生未知错误'

src/MCrssi.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
1-
// MCrssi.js
1+
/**
2+
* MCrssi.js.
3+
* MCBleKit
4+
*
5+
* Created by Morgan Chen on 2025/4/17.
6+
* https://github.com/Json031
7+
*/
8+
9+
/**
10+
* get Bluetooth Device RSSI
11+
*
12+
* @param {string} deviceId Bluetooth device id
13+
*
14+
* @return {number} RSSI value
15+
*/
216
function getDeviceRSSI(deviceId) {
317
return new Promise((resolve, reject) => {
418
wx.getBLEDeviceRSSI({

0 commit comments

Comments
 (0)