node-switchbot 3.0.2-beta.2 → 3.0.2-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/advertising.js +1 -1
- package/dist/advertising.js.map +1 -1
- package/dist/device/woblindtilt.d.ts +5 -2
- package/dist/device/woblindtilt.d.ts.map +1 -1
- package/dist/device/woblindtilt.js +6 -6
- package/dist/device/woblindtilt.js.map +1 -1
- package/dist/device/wobulb.d.ts +5 -2
- package/dist/device/wobulb.d.ts.map +1 -1
- package/dist/device/wobulb.js +14 -12
- package/dist/device/wobulb.js.map +1 -1
- package/dist/device/woceilinglight.d.ts +7 -4
- package/dist/device/woceilinglight.d.ts.map +1 -1
- package/dist/device/woceilinglight.js +15 -14
- package/dist/device/woceilinglight.js.map +1 -1
- package/dist/device/wocontact.d.ts +5 -2
- package/dist/device/wocontact.d.ts.map +1 -1
- package/dist/device/wocontact.js +6 -2
- package/dist/device/wocontact.js.map +1 -1
- package/dist/device/wocurtain.d.ts +5 -2
- package/dist/device/wocurtain.d.ts.map +1 -1
- package/dist/device/wocurtain.js +34 -20
- package/dist/device/wocurtain.js.map +1 -1
- package/dist/device/wohand.d.ts +6 -3
- package/dist/device/wohand.d.ts.map +1 -1
- package/dist/device/wohand.js +13 -14
- package/dist/device/wohand.js.map +1 -1
- package/dist/device/wohub2.d.ts +5 -2
- package/dist/device/wohub2.d.ts.map +1 -1
- package/dist/device/wohub2.js +6 -2
- package/dist/device/wohub2.js.map +1 -1
- package/dist/device/wohumi.d.ts +5 -2
- package/dist/device/wohumi.d.ts.map +1 -1
- package/dist/device/wohumi.js +6 -6
- package/dist/device/wohumi.js.map +1 -1
- package/dist/device/woiosensorth.d.ts +5 -2
- package/dist/device/woiosensorth.d.ts.map +1 -1
- package/dist/device/woiosensorth.js +6 -2
- package/dist/device/woiosensorth.js.map +1 -1
- package/dist/device/woplugmini.d.ts +8 -5
- package/dist/device/woplugmini.d.ts.map +1 -1
- package/dist/device/woplugmini.js +10 -10
- package/dist/device/woplugmini.js.map +1 -1
- package/dist/device/wopresence.d.ts +2 -0
- package/dist/device/wopresence.d.ts.map +1 -1
- package/dist/device/wopresence.js +3 -0
- package/dist/device/wopresence.js.map +1 -1
- package/dist/device/wosensorth.d.ts +2 -0
- package/dist/device/wosensorth.d.ts.map +1 -1
- package/dist/device/wosensorth.js +3 -0
- package/dist/device/wosensorth.js.map +1 -1
- package/dist/device/wostrip.d.ts +2 -0
- package/dist/device/wostrip.d.ts.map +1 -1
- package/dist/device/wostrip.js +3 -0
- package/dist/device/wostrip.js.map +1 -1
- package/dist/device.d.ts +33 -31
- package/dist/device.d.ts.map +1 -1
- package/dist/device.js +94 -90
- package/dist/device.js.map +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/switchbot-ble.d.ts +22 -14
- package/dist/switchbot-ble.d.ts.map +1 -1
- package/dist/switchbot-ble.js +155 -289
- package/dist/switchbot-ble.js.map +1 -1
- package/dist/switchbot-openapi.d.ts +3 -2
- package/dist/switchbot-openapi.d.ts.map +1 -1
- package/dist/switchbot-openapi.js +4 -3
- package/dist/switchbot-openapi.js.map +1 -1
- package/dist/test/switchbot-ble.test.d.ts +2 -0
- package/dist/test/switchbot-ble.test.d.ts.map +1 -0
- package/dist/test/switchbot-ble.test.js +45 -0
- package/dist/test/switchbot-ble.test.js.map +1 -0
- package/dist/types/bledevicestatus.d.ts +5 -3
- package/dist/types/bledevicestatus.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/test/switchbot.test.d.ts +0 -2
- package/dist/test/switchbot.test.d.ts.map +0 -1
- package/dist/test/switchbot.test.js +0 -106
- package/dist/test/switchbot.test.js.map +0 -1
package/dist/switchbot-ble.d.ts
CHANGED
|
@@ -3,10 +3,10 @@ import { EventEmitter } from 'node:events';
|
|
|
3
3
|
import * as Noble from '@stoprocent/noble';
|
|
4
4
|
import { SwitchbotDevice } from './device.js';
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* SwitchBotBLE class to interact with SwitchBot devices.
|
|
7
7
|
*/
|
|
8
8
|
export declare class SwitchBotBLE extends EventEmitter {
|
|
9
|
-
|
|
9
|
+
ready: Promise<void>;
|
|
10
10
|
noble: typeof Noble;
|
|
11
11
|
ondiscover?: (device: SwitchbotDevice) => Promise<void> | void;
|
|
12
12
|
onadvertisement?: (ad: Ad) => Promise<void> | void;
|
|
@@ -22,45 +22,53 @@ export declare class SwitchBotBLE extends EventEmitter {
|
|
|
22
22
|
* @param level - The severity level of the log (e.g., 'info', 'warn', 'error').
|
|
23
23
|
* @param message - The log message to be emitted.
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
log(level: string, message: string): Promise<void>;
|
|
26
26
|
/**
|
|
27
27
|
* Initializes the noble object.
|
|
28
28
|
*
|
|
29
29
|
* @param {Params} [params] - Optional parameters
|
|
30
30
|
* @returns {Promise<void>} - Resolves when initialization is complete
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
private initialize;
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
34
|
+
* Validates the parameters.
|
|
35
35
|
*
|
|
36
|
-
* @param {Params} params - The parameters
|
|
37
|
-
* @
|
|
36
|
+
* @param {Params} params - The parameters to validate.
|
|
37
|
+
* @param {Record<string, unknown>} schema - The schema to validate against.
|
|
38
|
+
* @returns {Promise<void>} - Resolves if parameters are valid, otherwise throws an error.
|
|
38
39
|
*/
|
|
39
|
-
|
|
40
|
+
validate(params: Params, schema: Record<string, unknown>): Promise<void>;
|
|
40
41
|
/**
|
|
41
|
-
*
|
|
42
|
+
* Waits for the noble object to be powered on.
|
|
42
43
|
*
|
|
43
44
|
* @returns {Promise<void>} - Resolves when the noble object is powered on.
|
|
44
45
|
*/
|
|
45
|
-
|
|
46
|
+
private waitForPowerOn;
|
|
47
|
+
/**
|
|
48
|
+
* Discover SwitchBot devices based on the provided parameters.
|
|
49
|
+
*
|
|
50
|
+
* @param {Params} params - The parameters for discovery.
|
|
51
|
+
* @returns {Promise<SwitchbotDevice[]>} - A promise that resolves with a list of discovered devices.
|
|
52
|
+
*/
|
|
53
|
+
discover(params?: Params): Promise<SwitchbotDevice[]>;
|
|
46
54
|
/**
|
|
47
|
-
*
|
|
55
|
+
* Creates a device object based on the peripheral, id, and model.
|
|
48
56
|
*
|
|
49
57
|
* @param {Noble.Peripheral} peripheral - The peripheral object.
|
|
50
58
|
* @param {string} id - The device id.
|
|
51
59
|
* @param {string} model - The device model.
|
|
52
60
|
* @returns {Promise<SwitchbotDevice | null>} - The device object or null.
|
|
53
61
|
*/
|
|
54
|
-
|
|
62
|
+
private createDevice;
|
|
55
63
|
/**
|
|
56
64
|
* Filters advertising data based on id and model.
|
|
57
65
|
*
|
|
58
66
|
* @param {Ad} ad - The advertising data.
|
|
59
67
|
* @param {string} id - The device id.
|
|
60
68
|
* @param {string} model - The device model.
|
|
61
|
-
* @returns {boolean} - True if the advertising data matches the id and model, false otherwise.
|
|
69
|
+
* @returns {Promise<boolean>} - True if the advertising data matches the id and model, false otherwise.
|
|
62
70
|
*/
|
|
63
|
-
|
|
71
|
+
private filterAd;
|
|
64
72
|
/**
|
|
65
73
|
* Starts scanning for SwitchBot devices.
|
|
66
74
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"switchbot-ble.d.ts","sourceRoot":"","sources":["../src/switchbot-ble.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"switchbot-ble.d.ts","sourceRoot":"","sources":["../src/switchbot-ble.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,EAAQ,MAAM,kBAAkB,CAAA;AAExD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,OAAO,KAAK,KAAK,MAAM,mBAAmB,CAAA;AAG1C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAoB7C;;GAEG;AACH,qBAAa,YAAa,SAAQ,YAAY;IACrC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IACpB,KAAK,EAAG,OAAO,KAAK,CAAA;IAC3B,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC9D,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAElD;;;;OAIG;gBACS,MAAM,CAAC,EAAE,MAAM;IAK3B;;;;;OAKG;IACU,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI/D;;;;;OAKG;YACW,UAAU;IAIxB;;;;;;OAMG;IACU,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAQrF;;;;OAIG;YACW,cAAc;IA4B5B;;;;;OAKG;IACU,QAAQ,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA+DtE;;;;;;;OAOG;YACW,YAAY;IA6B1B;;;;;;;OAOG;YACW,QAAQ;IAatB;;;;;OAKG;IACU,SAAS,CAAC,MAAM,GAAE,MAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAgC1D;;;;OAIG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IActC;;;;;OAKG;IACU,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAO/C;AAED,OAAO,EAAE,eAAe,EAAE,CAAA"}
|
package/dist/switchbot-ble.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
/* Copyright(C) 2024, donavanbecker (https://github.com/donavanbecker). All rights reserved.
|
|
3
|
-
*
|
|
4
|
-
* switchbot.ts: Switchbot BLE API registration.
|
|
5
|
-
*/
|
|
6
2
|
import * as Noble from '@stoprocent/noble';
|
|
7
3
|
import { Advertising } from './advertising.js';
|
|
8
4
|
import { SwitchbotDevice } from './device.js';
|
|
@@ -25,7 +21,7 @@ import { parameterChecker } from './parameter-checker.js';
|
|
|
25
21
|
import { DEFAULT_DISCOVERY_DURATION, PRIMARY_SERVICE_UUID_LIST } from './settings.js';
|
|
26
22
|
import { SwitchBotBLEModel } from './types/types.js';
|
|
27
23
|
/**
|
|
28
|
-
*
|
|
24
|
+
* SwitchBotBLE class to interact with SwitchBot devices.
|
|
29
25
|
*/
|
|
30
26
|
export class SwitchBotBLE extends EventEmitter {
|
|
31
27
|
ready;
|
|
@@ -39,7 +35,7 @@ export class SwitchBotBLE extends EventEmitter {
|
|
|
39
35
|
*/
|
|
40
36
|
constructor(params) {
|
|
41
37
|
super();
|
|
42
|
-
this.ready = this.
|
|
38
|
+
this.ready = this.initialize(params);
|
|
43
39
|
}
|
|
44
40
|
/**
|
|
45
41
|
* Emits a log event with the specified log level and message.
|
|
@@ -47,7 +43,7 @@ export class SwitchBotBLE extends EventEmitter {
|
|
|
47
43
|
* @param level - The severity level of the log (e.g., 'info', 'warn', 'error').
|
|
48
44
|
* @param message - The log message to be emitted.
|
|
49
45
|
*/
|
|
50
|
-
async
|
|
46
|
+
async log(level, message) {
|
|
51
47
|
this.emit('log', { level, message });
|
|
52
48
|
}
|
|
53
49
|
/**
|
|
@@ -56,222 +52,150 @@ export class SwitchBotBLE extends EventEmitter {
|
|
|
56
52
|
* @param {Params} [params] - Optional parameters
|
|
57
53
|
* @returns {Promise<void>} - Resolves when initialization is complete
|
|
58
54
|
*/
|
|
59
|
-
async
|
|
60
|
-
this.noble = params
|
|
55
|
+
async initialize(params) {
|
|
56
|
+
this.noble = params?.noble ?? Noble.default;
|
|
61
57
|
}
|
|
62
58
|
/**
|
|
63
|
-
*
|
|
59
|
+
* Validates the parameters.
|
|
64
60
|
*
|
|
65
|
-
* @param {Params} params - The parameters
|
|
66
|
-
* @
|
|
61
|
+
* @param {Params} params - The parameters to validate.
|
|
62
|
+
* @param {Record<string, unknown>} schema - The schema to validate against.
|
|
63
|
+
* @returns {Promise<void>} - Resolves if parameters are valid, otherwise throws an error.
|
|
67
64
|
*/
|
|
68
|
-
async
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
required: false,
|
|
75
|
-
type: 'string',
|
|
76
|
-
enum: [
|
|
77
|
-
SwitchBotBLEModel.Bot,
|
|
78
|
-
SwitchBotBLEModel.Curtain,
|
|
79
|
-
SwitchBotBLEModel.Curtain3,
|
|
80
|
-
SwitchBotBLEModel.Humidifier,
|
|
81
|
-
SwitchBotBLEModel.Meter,
|
|
82
|
-
SwitchBotBLEModel.MeterPlus,
|
|
83
|
-
SwitchBotBLEModel.Hub2,
|
|
84
|
-
SwitchBotBLEModel.OutdoorMeter,
|
|
85
|
-
SwitchBotBLEModel.MotionSensor,
|
|
86
|
-
SwitchBotBLEModel.ContactSensor,
|
|
87
|
-
SwitchBotBLEModel.ColorBulb,
|
|
88
|
-
SwitchBotBLEModel.CeilingLight,
|
|
89
|
-
SwitchBotBLEModel.CeilingLightPro,
|
|
90
|
-
SwitchBotBLEModel.StripLight,
|
|
91
|
-
SwitchBotBLEModel.PlugMiniUS,
|
|
92
|
-
SwitchBotBLEModel.PlugMiniJP,
|
|
93
|
-
SwitchBotBLEModel.Lock,
|
|
94
|
-
SwitchBotBLEModel.LockPro,
|
|
95
|
-
SwitchBotBLEModel.BlindTilt,
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
99
|
-
quick: { required: false, type: 'boolean' },
|
|
100
|
-
}, false);
|
|
101
|
-
if (!valid) {
|
|
102
|
-
this.emitLog('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
|
|
103
|
-
reject(new Error(parameterChecker.error.message));
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (!params) {
|
|
107
|
-
params = {};
|
|
108
|
-
}
|
|
109
|
-
// Determine the values of the parameters
|
|
110
|
-
const p = {
|
|
111
|
-
duration: params.duration ?? DEFAULT_DISCOVERY_DURATION,
|
|
112
|
-
model: params.model ?? '',
|
|
113
|
-
id: params.id ?? '',
|
|
114
|
-
quick: !!params.quick,
|
|
115
|
-
};
|
|
116
|
-
// Initialize the noble object
|
|
117
|
-
this._init()
|
|
118
|
-
.then(() => {
|
|
119
|
-
if (this.noble === null) {
|
|
120
|
-
return reject(new Error('noble failed to initialize'));
|
|
121
|
-
}
|
|
122
|
-
const peripherals = {};
|
|
123
|
-
let timer = setTimeout(() => { }, 0);
|
|
124
|
-
const finishDiscovery = () => {
|
|
125
|
-
if (timer) {
|
|
126
|
-
clearTimeout(timer);
|
|
127
|
-
}
|
|
128
|
-
this.noble.removeAllListeners('discover');
|
|
129
|
-
this.noble.stopScanningAsync();
|
|
130
|
-
const device_list = [];
|
|
131
|
-
for (const addr in peripherals) {
|
|
132
|
-
device_list.push(peripherals[addr]);
|
|
133
|
-
}
|
|
134
|
-
resolve(device_list);
|
|
135
|
-
};
|
|
136
|
-
// Set a handler for the 'discover' event
|
|
137
|
-
this.noble.on('discover', async (peripheral) => {
|
|
138
|
-
const device = await this.getDeviceObject(peripheral, p.id, p.model);
|
|
139
|
-
if (!device) {
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
const id = device.id;
|
|
143
|
-
peripherals[id] = device;
|
|
144
|
-
if (this.ondiscover && typeof this.ondiscover === 'function') {
|
|
145
|
-
this.ondiscover(device);
|
|
146
|
-
}
|
|
147
|
-
if (p.quick) {
|
|
148
|
-
finishDiscovery();
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
// Start scanning
|
|
152
|
-
this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, false).then(() => {
|
|
153
|
-
timer = setTimeout(() => {
|
|
154
|
-
finishDiscovery();
|
|
155
|
-
}, p.duration);
|
|
156
|
-
}).catch((error) => {
|
|
157
|
-
reject(error);
|
|
158
|
-
});
|
|
159
|
-
})
|
|
160
|
-
.catch((error) => {
|
|
161
|
-
reject(error);
|
|
162
|
-
});
|
|
163
|
-
});
|
|
164
|
-
return promise;
|
|
65
|
+
async validate(params, schema) {
|
|
66
|
+
const valid = parameterChecker.check(params, schema, false);
|
|
67
|
+
if (!valid) {
|
|
68
|
+
this.log('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
|
|
69
|
+
throw new Error(parameterChecker.error.message);
|
|
70
|
+
}
|
|
165
71
|
}
|
|
166
72
|
/**
|
|
167
|
-
*
|
|
73
|
+
* Waits for the noble object to be powered on.
|
|
168
74
|
*
|
|
169
75
|
* @returns {Promise<void>} - Resolves when the noble object is powered on.
|
|
170
76
|
*/
|
|
171
|
-
async
|
|
77
|
+
async waitForPowerOn() {
|
|
172
78
|
await this.ready;
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
79
|
+
if (this.noble._state === 'poweredOn') {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
178
83
|
this.noble.once('stateChange', (state) => {
|
|
179
84
|
switch (state) {
|
|
180
85
|
case 'unsupported':
|
|
181
86
|
case 'unauthorized':
|
|
182
87
|
case 'poweredOff':
|
|
183
|
-
reject(new Error(`Failed to initialize the Noble object: ${
|
|
184
|
-
|
|
88
|
+
reject(new Error(`Failed to initialize the Noble object: ${state}`));
|
|
89
|
+
break;
|
|
185
90
|
case 'resetting':
|
|
186
91
|
case 'unknown':
|
|
187
|
-
reject(new Error(`Adapter is not ready: ${
|
|
188
|
-
|
|
92
|
+
reject(new Error(`Adapter is not ready: ${state}`));
|
|
93
|
+
break;
|
|
189
94
|
case 'poweredOn':
|
|
190
95
|
resolve();
|
|
191
|
-
|
|
96
|
+
break;
|
|
192
97
|
default:
|
|
193
|
-
reject(new Error(`Unknown state: ${
|
|
98
|
+
reject(new Error(`Unknown state: ${state}`));
|
|
194
99
|
}
|
|
195
100
|
});
|
|
196
101
|
});
|
|
197
|
-
return promise;
|
|
198
102
|
}
|
|
199
103
|
/**
|
|
200
|
-
*
|
|
104
|
+
* Discover SwitchBot devices based on the provided parameters.
|
|
105
|
+
*
|
|
106
|
+
* @param {Params} params - The parameters for discovery.
|
|
107
|
+
* @returns {Promise<SwitchbotDevice[]>} - A promise that resolves with a list of discovered devices.
|
|
108
|
+
*/
|
|
109
|
+
async discover(params = {}) {
|
|
110
|
+
await this.ready;
|
|
111
|
+
await this.validate(params, {
|
|
112
|
+
duration: { required: false, type: 'integer', min: 1, max: 60000 },
|
|
113
|
+
model: { required: false, type: 'string', enum: Object.values(SwitchBotBLEModel) },
|
|
114
|
+
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
115
|
+
quick: { required: false, type: 'boolean' },
|
|
116
|
+
});
|
|
117
|
+
await this.waitForPowerOn();
|
|
118
|
+
if (!this.noble) {
|
|
119
|
+
throw new Error('noble failed to initialize');
|
|
120
|
+
}
|
|
121
|
+
const p = {
|
|
122
|
+
duration: params.duration ?? DEFAULT_DISCOVERY_DURATION,
|
|
123
|
+
model: params.model ?? '',
|
|
124
|
+
id: params.id ?? '',
|
|
125
|
+
quick: !!params.quick,
|
|
126
|
+
};
|
|
127
|
+
const peripherals = {};
|
|
128
|
+
let timer;
|
|
129
|
+
const finishDiscovery = async () => {
|
|
130
|
+
if (timer) {
|
|
131
|
+
clearTimeout(timer);
|
|
132
|
+
}
|
|
133
|
+
this.noble.removeAllListeners('discover');
|
|
134
|
+
try {
|
|
135
|
+
await this.noble.stopScanningAsync();
|
|
136
|
+
this.log('info', 'Stopped Scanning for SwitchBot BLE devices.');
|
|
137
|
+
}
|
|
138
|
+
catch (e) {
|
|
139
|
+
this.log('error', `discover stopScanningAsync error: ${JSON.stringify(e.message ?? e)}`);
|
|
140
|
+
}
|
|
141
|
+
return Object.values(peripherals);
|
|
142
|
+
};
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
this.noble.on('discover', async (peripheral) => {
|
|
145
|
+
const device = await this.createDevice(peripheral, p.id, p.model);
|
|
146
|
+
if (!device) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
peripherals[device.id] = device;
|
|
150
|
+
if (this.ondiscover) {
|
|
151
|
+
this.ondiscover(device);
|
|
152
|
+
}
|
|
153
|
+
if (p.quick) {
|
|
154
|
+
resolve(await finishDiscovery());
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, false)
|
|
158
|
+
.then(() => {
|
|
159
|
+
timer = setTimeout(async () => resolve(await finishDiscovery()), p.duration);
|
|
160
|
+
})
|
|
161
|
+
.catch(reject);
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Creates a device object based on the peripheral, id, and model.
|
|
201
166
|
*
|
|
202
167
|
* @param {Noble.Peripheral} peripheral - The peripheral object.
|
|
203
168
|
* @param {string} id - The device id.
|
|
204
169
|
* @param {string} model - The device model.
|
|
205
170
|
* @returns {Promise<SwitchbotDevice | null>} - The device object or null.
|
|
206
171
|
*/
|
|
207
|
-
async
|
|
208
|
-
const ad = await Advertising.parse(peripheral, this.
|
|
209
|
-
if (ad && await this.
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
break;
|
|
232
|
-
case SwitchBotBLEModel.OutdoorMeter:
|
|
233
|
-
device = new WoIOSensorTH(peripheral, this.noble);
|
|
234
|
-
break;
|
|
235
|
-
case SwitchBotBLEModel.MotionSensor:
|
|
236
|
-
device = new WoPresence(peripheral, this.noble);
|
|
237
|
-
break;
|
|
238
|
-
case SwitchBotBLEModel.ContactSensor:
|
|
239
|
-
device = new WoContact(peripheral, this.noble);
|
|
240
|
-
break;
|
|
241
|
-
case SwitchBotBLEModel.ColorBulb:
|
|
242
|
-
device = new WoBulb(peripheral, this.noble);
|
|
243
|
-
break;
|
|
244
|
-
case SwitchBotBLEModel.CeilingLight:
|
|
245
|
-
device = new WoCeilingLight(peripheral, this.noble);
|
|
246
|
-
break;
|
|
247
|
-
case SwitchBotBLEModel.CeilingLightPro:
|
|
248
|
-
device = new WoCeilingLight(peripheral, this.noble);
|
|
249
|
-
break;
|
|
250
|
-
case SwitchBotBLEModel.StripLight:
|
|
251
|
-
device = new WoStrip(peripheral, this.noble);
|
|
252
|
-
break;
|
|
253
|
-
case SwitchBotBLEModel.PlugMiniUS:
|
|
254
|
-
case SwitchBotBLEModel.PlugMiniJP:
|
|
255
|
-
device = new WoPlugMini(peripheral, this.noble);
|
|
256
|
-
break;
|
|
257
|
-
case SwitchBotBLEModel.Lock:
|
|
258
|
-
device = new WoSmartLock(peripheral, this.noble);
|
|
259
|
-
break;
|
|
260
|
-
case SwitchBotBLEModel.LockPro:
|
|
261
|
-
device = new WoSmartLockPro(peripheral, this.noble);
|
|
262
|
-
break;
|
|
263
|
-
case SwitchBotBLEModel.BlindTilt:
|
|
264
|
-
device = new WoBlindTilt(peripheral, this.noble);
|
|
265
|
-
break;
|
|
266
|
-
default: // 'resetting', 'unknown'
|
|
267
|
-
device = new SwitchbotDevice(peripheral, this.noble);
|
|
268
|
-
}
|
|
172
|
+
async createDevice(peripheral, id, model) {
|
|
173
|
+
const ad = await Advertising.parse(peripheral, this.log.bind(this));
|
|
174
|
+
if (ad && await this.filterAd(ad, id, model)) {
|
|
175
|
+
switch (ad.serviceData.model) {
|
|
176
|
+
case SwitchBotBLEModel.Bot: return new WoHand(peripheral, this.noble);
|
|
177
|
+
case SwitchBotBLEModel.Curtain:
|
|
178
|
+
case SwitchBotBLEModel.Curtain3: return new WoCurtain(peripheral, this.noble);
|
|
179
|
+
case SwitchBotBLEModel.Humidifier: return new WoHumi(peripheral, this.noble);
|
|
180
|
+
case SwitchBotBLEModel.Meter:
|
|
181
|
+
case SwitchBotBLEModel.MeterPlus: return new WoSensorTH(peripheral, this.noble);
|
|
182
|
+
case SwitchBotBLEModel.Hub2: return new WoHub2(peripheral, this.noble);
|
|
183
|
+
case SwitchBotBLEModel.OutdoorMeter: return new WoIOSensorTH(peripheral, this.noble);
|
|
184
|
+
case SwitchBotBLEModel.MotionSensor: return new WoPresence(peripheral, this.noble);
|
|
185
|
+
case SwitchBotBLEModel.ContactSensor: return new WoContact(peripheral, this.noble);
|
|
186
|
+
case SwitchBotBLEModel.ColorBulb: return new WoBulb(peripheral, this.noble);
|
|
187
|
+
case SwitchBotBLEModel.CeilingLight:
|
|
188
|
+
case SwitchBotBLEModel.CeilingLightPro: return new WoCeilingLight(peripheral, this.noble);
|
|
189
|
+
case SwitchBotBLEModel.StripLight: return new WoStrip(peripheral, this.noble);
|
|
190
|
+
case SwitchBotBLEModel.PlugMiniUS:
|
|
191
|
+
case SwitchBotBLEModel.PlugMiniJP: return new WoPlugMini(peripheral, this.noble);
|
|
192
|
+
case SwitchBotBLEModel.Lock: return new WoSmartLock(peripheral, this.noble);
|
|
193
|
+
case SwitchBotBLEModel.LockPro: return new WoSmartLockPro(peripheral, this.noble);
|
|
194
|
+
case SwitchBotBLEModel.BlindTilt: return new WoBlindTilt(peripheral, this.noble);
|
|
195
|
+
default: return new SwitchbotDevice(peripheral, this.noble);
|
|
269
196
|
}
|
|
270
|
-
return device || null;
|
|
271
|
-
}
|
|
272
|
-
else {
|
|
273
|
-
return null;
|
|
274
197
|
}
|
|
198
|
+
return null;
|
|
275
199
|
}
|
|
276
200
|
/**
|
|
277
201
|
* Filters advertising data based on id and model.
|
|
@@ -279,23 +203,17 @@ export class SwitchBotBLE extends EventEmitter {
|
|
|
279
203
|
* @param {Ad} ad - The advertising data.
|
|
280
204
|
* @param {string} id - The device id.
|
|
281
205
|
* @param {string} model - The device model.
|
|
282
|
-
* @returns {boolean} - True if the advertising data matches the id and model, false otherwise.
|
|
206
|
+
* @returns {Promise<boolean>} - True if the advertising data matches the id and model, false otherwise.
|
|
283
207
|
*/
|
|
284
|
-
async
|
|
208
|
+
async filterAd(ad, id, model) {
|
|
285
209
|
if (!ad) {
|
|
286
210
|
return false;
|
|
287
211
|
}
|
|
288
|
-
if (id) {
|
|
289
|
-
|
|
290
|
-
const ad_id = ad.address.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
291
|
-
if (ad_id !== id) {
|
|
292
|
-
return false;
|
|
293
|
-
}
|
|
212
|
+
if (id && ad.address.toLowerCase().replace(/[^a-z0-9]/g, '') !== id.toLowerCase().replace(/:/g, '')) {
|
|
213
|
+
return false;
|
|
294
214
|
}
|
|
295
|
-
if (model) {
|
|
296
|
-
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
215
|
+
if (model && ad.serviceData.model !== model) {
|
|
216
|
+
return false;
|
|
299
217
|
}
|
|
300
218
|
return true;
|
|
301
219
|
}
|
|
@@ -306,77 +224,31 @@ export class SwitchBotBLE extends EventEmitter {
|
|
|
306
224
|
* @returns {Promise<void>} - Resolves when scanning starts successfully.
|
|
307
225
|
*/
|
|
308
226
|
async startScan(params = {}) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
SwitchBotBLEModel.MotionSensor,
|
|
325
|
-
SwitchBotBLEModel.ContactSensor,
|
|
326
|
-
SwitchBotBLEModel.ColorBulb,
|
|
327
|
-
SwitchBotBLEModel.CeilingLight,
|
|
328
|
-
SwitchBotBLEModel.CeilingLightPro,
|
|
329
|
-
SwitchBotBLEModel.StripLight,
|
|
330
|
-
SwitchBotBLEModel.PlugMiniUS,
|
|
331
|
-
SwitchBotBLEModel.PlugMiniJP,
|
|
332
|
-
SwitchBotBLEModel.Lock,
|
|
333
|
-
SwitchBotBLEModel.LockPro,
|
|
334
|
-
SwitchBotBLEModel.BlindTilt,
|
|
335
|
-
],
|
|
336
|
-
},
|
|
337
|
-
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
338
|
-
}, false);
|
|
339
|
-
if (!valid) {
|
|
340
|
-
this.emitLog('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
|
|
341
|
-
reject(new Error(parameterChecker.error.message));
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
// Initialize the noble object
|
|
345
|
-
this._init()
|
|
346
|
-
.then(() => {
|
|
347
|
-
if (this.noble === null) {
|
|
348
|
-
return reject(new Error('noble object failed to initialize'));
|
|
227
|
+
await this.ready;
|
|
228
|
+
await this.validate(params, {
|
|
229
|
+
model: { required: false, type: 'string', enum: Object.values(SwitchBotBLEModel) },
|
|
230
|
+
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
231
|
+
});
|
|
232
|
+
await this.waitForPowerOn();
|
|
233
|
+
if (!this.noble) {
|
|
234
|
+
throw new Error('noble object failed to initialize');
|
|
235
|
+
}
|
|
236
|
+
const p = { model: params.model || '', id: params.id || '' };
|
|
237
|
+
this.noble.on('discover', async (peripheral) => {
|
|
238
|
+
const ad = await Advertising.parse(peripheral, this.log.bind(this));
|
|
239
|
+
if (ad && await this.filterAd(ad, p.id, p.model)) {
|
|
240
|
+
if (this.onadvertisement) {
|
|
241
|
+
this.onadvertisement(ad);
|
|
349
242
|
}
|
|
350
|
-
|
|
351
|
-
const p = {
|
|
352
|
-
model: params.model || '',
|
|
353
|
-
id: params.id || '',
|
|
354
|
-
};
|
|
355
|
-
// Set a handler for the 'discover' event
|
|
356
|
-
this.noble.on('discover', async (peripheral) => {
|
|
357
|
-
const ad = await Advertising.parse(peripheral, this.emitLog.bind(this));
|
|
358
|
-
if (ad && await this.filterAdvertising(ad, p.id, p.model)) {
|
|
359
|
-
if (this.onadvertisement
|
|
360
|
-
&& typeof this.onadvertisement === 'function') {
|
|
361
|
-
this.onadvertisement(ad);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
});
|
|
365
|
-
// Start scanning
|
|
366
|
-
this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, true).then(() => {
|
|
367
|
-
this.emitLog('info', 'Started Scanning for SwitchBot BLE devices.');
|
|
368
|
-
resolve();
|
|
369
|
-
}).catch((error) => {
|
|
370
|
-
this.emitLog('error', `startScanning error: ${JSON.stringify(error.message)}`);
|
|
371
|
-
reject(error);
|
|
372
|
-
});
|
|
373
|
-
})
|
|
374
|
-
.catch((error) => {
|
|
375
|
-
this.emitLog('error', `startScanning error: ${JSON.stringify(error.message)}`);
|
|
376
|
-
reject(error);
|
|
377
|
-
});
|
|
243
|
+
}
|
|
378
244
|
});
|
|
379
|
-
|
|
245
|
+
try {
|
|
246
|
+
await this.noble.startScanningAsync(PRIMARY_SERVICE_UUID_LIST, true);
|
|
247
|
+
this.log('info', 'Started Scanning for SwitchBot BLE devices.');
|
|
248
|
+
}
|
|
249
|
+
catch (e) {
|
|
250
|
+
this.log('error', `startScanningAsync error: ${JSON.stringify(e.message ?? e)}`);
|
|
251
|
+
}
|
|
380
252
|
}
|
|
381
253
|
/**
|
|
382
254
|
* Stops scanning for SwitchBot devices.
|
|
@@ -384,12 +256,17 @@ export class SwitchBotBLE extends EventEmitter {
|
|
|
384
256
|
* @returns {Promise<void>} - Resolves when scanning stops successfully.
|
|
385
257
|
*/
|
|
386
258
|
async stopScan() {
|
|
387
|
-
if (this.noble
|
|
259
|
+
if (!this.noble) {
|
|
388
260
|
return;
|
|
389
261
|
}
|
|
390
262
|
this.noble.removeAllListeners('discover');
|
|
391
|
-
|
|
392
|
-
|
|
263
|
+
try {
|
|
264
|
+
await this.noble.stopScanningAsync();
|
|
265
|
+
this.log('info', 'Stopped Scanning for SwitchBot BLE devices.');
|
|
266
|
+
}
|
|
267
|
+
catch (e) {
|
|
268
|
+
this.log('error', `stopScanningAsync error: ${JSON.stringify(e.message ?? e)}`);
|
|
269
|
+
}
|
|
393
270
|
}
|
|
394
271
|
/**
|
|
395
272
|
* Waits for the specified time.
|
|
@@ -398,21 +275,10 @@ export class SwitchBotBLE extends EventEmitter {
|
|
|
398
275
|
* @returns {Promise<void>} - Resolves after the specified time.
|
|
399
276
|
*/
|
|
400
277
|
async wait(msec) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
}, {
|
|
406
|
-
msec: { required: true, type: 'integer', min: 0 },
|
|
407
|
-
}, true);
|
|
408
|
-
if (!valid) {
|
|
409
|
-
this.emitLog('error', `parameterChecker: ${JSON.stringify(parameterChecker.error.message)}`);
|
|
410
|
-
reject(new Error(parameterChecker.error.message));
|
|
411
|
-
return;
|
|
412
|
-
}
|
|
413
|
-
// Set a timer
|
|
414
|
-
setTimeout(resolve, msec);
|
|
415
|
-
});
|
|
278
|
+
if (typeof msec !== 'number' || msec < 0) {
|
|
279
|
+
throw new Error('Invalid parameter: msec must be a non-negative integer.');
|
|
280
|
+
}
|
|
281
|
+
return new Promise(resolve => setTimeout(resolve, msec));
|
|
416
282
|
}
|
|
417
283
|
}
|
|
418
284
|
export { SwitchbotDevice };
|