node-switchbot 1.1.3-beta.4 → 1.1.3-beta.5
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/lib/parameter-checker.js +319 -317
- package/lib/switchbot-advertising.js +192 -190
- package/lib/switchbot-device-wocontact.js +3 -2
- package/lib/switchbot-device-wocurtain.js +52 -51
- package/lib/switchbot-device-wohand.js +38 -37
- package/lib/switchbot-device-wohumi.js +46 -60
- package/lib/switchbot-device-wopresence.js +3 -2
- package/lib/switchbot-device-wosensorth.js +3 -2
- package/lib/switchbot-device.js +438 -437
- package/lib/switchbot.js +238 -237
- package/package.json +3 -10
package/lib/switchbot.js
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
const parameterChecker = require('./parameter-checker.js');
|
|
3
|
+
const switchbotAdvertising = require('./switchbot-advertising.js');
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
const SwitchbotDevice = require('./switchbot-device.js');
|
|
6
|
+
const SwitchbotDeviceWoHand = require('./switchbot-device-wohand.js');
|
|
7
|
+
const SwitchbotDeviceWoCurtain = require('./switchbot-device-wocurtain.js');
|
|
8
|
+
const SwitchbotDeviceWoPresence = require('./switchbot-device-wopresence.js');
|
|
9
|
+
const SwitchbotDeviceWoContact = require('./switchbot-device-wocontact.js');
|
|
10
|
+
const SwitchbotDeviceWoSensorTH = require('./switchbot-device-wosensorth.js');
|
|
11
|
+
const SwitchbotDeviceWoHumi = require('./switchbot-device-wohumi.js');
|
|
11
12
|
|
|
12
13
|
class Switchbot {
|
|
13
|
-
|
|
14
|
+
/* ------------------------------------------------------------------
|
|
14
15
|
* Constructor
|
|
15
16
|
*
|
|
16
17
|
* [Arguments]
|
|
@@ -20,27 +21,27 @@ class Switchbot {
|
|
|
20
21
|
* | | | If you don't specify this parameter, this
|
|
21
22
|
* | | | module automatically creates it.
|
|
22
23
|
* ---------------------------------------------------------------- */
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
constructor(params) {
|
|
25
|
+
// Check parameters
|
|
26
|
+
let noble = null;
|
|
27
|
+
if (params && params.noble) {
|
|
28
|
+
noble = params.noble;
|
|
29
|
+
} else {
|
|
30
|
+
noble = require('@abandonware/noble');
|
|
31
|
+
}
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
// Plublic properties
|
|
34
|
+
this.noble = noble;
|
|
35
|
+
this.ondiscover = null;
|
|
36
|
+
this.onadvertisement = null;
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
38
|
+
// Private properties
|
|
39
|
+
this._scanning = false;
|
|
40
|
+
this._DEFAULT_DISCOVERY_DURATION = 5000
|
|
41
|
+
this._PRIMARY_SERVICE_UUID_LIST = ['cba20d00224d11e69fb80002a5d5c51b'];
|
|
42
|
+
};
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
/* ------------------------------------------------------------------
|
|
44
45
|
* discover([params])
|
|
45
46
|
* - Discover switchbot devices
|
|
46
47
|
*
|
|
@@ -72,162 +73,162 @@ class Switchbot {
|
|
|
72
73
|
* An array will be passed to the `resolve()`, which includes
|
|
73
74
|
* `SwitchbotDevice` objects representing the found devices.
|
|
74
75
|
* ---------------------------------------------------------------- */
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
76
|
+
discover(params = {}) {
|
|
77
|
+
let promise = new Promise((resolve, reject) => {
|
|
78
|
+
// Check the parameters
|
|
79
|
+
let valid = parameterChecker.check(params, {
|
|
80
|
+
duration: { required: false, type: 'integer', min: 1, max: 60000 },
|
|
81
|
+
model: { required: false, type: 'string', enum: ['H', 'T', 'e', 's', 'd', 'c'] },
|
|
82
|
+
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
83
|
+
quick: { required: false, type: 'boolean' }
|
|
84
|
+
}, false);
|
|
84
85
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
86
|
+
if (!valid) {
|
|
87
|
+
reject(new Error(parameterChecker.error.message));
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
89
90
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
if (!params) {
|
|
92
|
+
params = {};
|
|
93
|
+
}
|
|
93
94
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
// Determine the values of the parameters
|
|
96
|
+
let p = {
|
|
97
|
+
duration: params.duration || this._DEFAULT_DISCOVERY_DURATION,
|
|
98
|
+
model: params.model || '',
|
|
99
|
+
id: params.id || '',
|
|
100
|
+
quick: params.quick ? true : false
|
|
101
|
+
};
|
|
101
102
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
103
|
+
// Initialize the noble object
|
|
104
|
+
this._init().then(() => {
|
|
105
|
+
let peripherals = {};
|
|
106
|
+
let timer = null;
|
|
107
|
+
let finishDiscovery = () => {
|
|
108
|
+
if (timer) {
|
|
109
|
+
clearTimeout(timer);
|
|
110
|
+
}
|
|
111
|
+
this.noble.removeAllListeners('discover');
|
|
112
|
+
this.noble.stopScanning();
|
|
113
|
+
let device_list = [];
|
|
114
|
+
for (let addr in peripherals) {
|
|
115
|
+
device_list.push(peripherals[addr]);
|
|
116
|
+
}
|
|
117
|
+
resolve(device_list);
|
|
118
|
+
};
|
|
118
119
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
120
|
+
// Set an handler for the 'discover' event
|
|
121
|
+
this.noble.on('discover', (peripheral) => {
|
|
122
|
+
let device = this._getDeviceObject(peripheral, p.id, p.model);
|
|
123
|
+
if (!device) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
let id = device.id;
|
|
127
|
+
peripherals[id] = device;
|
|
127
128
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
129
|
+
if (this.ondiscover && typeof (this.ondiscover) === 'function') {
|
|
130
|
+
this.ondiscover(device);
|
|
131
|
+
}
|
|
131
132
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
if (p.quick) {
|
|
134
|
+
finishDiscovery();
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
137
138
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
139
|
+
// Start scaning
|
|
140
|
+
this.noble.startScanning(this._PRIMARY_SERVICE_UUID_LIST, false, (error) => {
|
|
141
|
+
if (error) {
|
|
142
|
+
reject(error);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
timer = setTimeout(() => {
|
|
146
|
+
finishDiscovery();
|
|
147
|
+
}, p.duration);
|
|
148
|
+
});
|
|
149
|
+
}).catch((error) => {
|
|
150
|
+
reject(error);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
return promise;
|
|
154
|
+
}
|
|
154
155
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
156
|
+
_init() {
|
|
157
|
+
let promise = new Promise((resolve, reject) => {
|
|
158
|
+
switch (this.noble.state) {
|
|
159
|
+
case 'poweredOn':
|
|
160
|
+
resolve();
|
|
161
|
+
return;
|
|
162
|
+
case 'unsupported', 'unauthorized', 'poweredOff':
|
|
163
|
+
let err = new Error('Failed to initialize the Noble object: ' + this.noble.state);
|
|
164
|
+
reject(err);
|
|
165
|
+
return;
|
|
166
|
+
default: // 'resetting', 'unknown'
|
|
167
|
+
this.noble.once('stateChange', (state) => {
|
|
168
|
+
if (state === 'poweredOn') {
|
|
169
|
+
resolve();
|
|
170
|
+
} else {
|
|
171
|
+
let err = new Error('Failed to initialize the Noble object: ' + state);
|
|
172
|
+
reject(err);
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
return promise;
|
|
178
|
+
}
|
|
178
179
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
180
|
+
_getDeviceObject(peripheral, id, model) {
|
|
181
|
+
let ad = switchbotAdvertising.parse(peripheral);
|
|
182
|
+
if (this._filterAdvertising(ad, id, model)) {
|
|
183
|
+
let device = null;
|
|
184
|
+
switch (ad.serviceData.model) {
|
|
185
|
+
case 'H':
|
|
186
|
+
device = new SwitchbotDeviceWoHand(peripheral, this.noble);
|
|
187
|
+
break;
|
|
188
|
+
case 'e':
|
|
189
|
+
device = new SwitchbotDeviceWoHumi(peripheral, this.noble);
|
|
190
|
+
break;
|
|
191
|
+
case 'T':
|
|
192
|
+
device = new SwitchbotDeviceWoSensorTH(peripheral, this.noble);
|
|
193
|
+
break;
|
|
194
|
+
case 's':
|
|
195
|
+
device = new SwitchbotDeviceWoPresence(peripheral, this.noble);
|
|
196
|
+
break;
|
|
197
|
+
case 'd':
|
|
198
|
+
device = new SwitchbotDeviceWoContact(peripheral, this.noble);
|
|
199
|
+
break;
|
|
200
|
+
case 'c':
|
|
201
|
+
device = new SwitchbotDeviceWoCurtain(peripheral, this.noble);
|
|
202
|
+
break;
|
|
203
|
+
default: // 'resetting', 'unknown'
|
|
204
|
+
device = new SwitchbotDevice(peripheral, this.noble);
|
|
205
|
+
}
|
|
206
|
+
return device;
|
|
207
|
+
} else {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
210
211
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
212
|
+
_filterAdvertising(ad, id, model) {
|
|
213
|
+
if (!ad) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
if (id) {
|
|
217
|
+
id = id.toLowerCase().replace(/\:/g, '');
|
|
218
|
+
let ad_id = ad.address.toLowerCase().replace(/[^a-z0-9]/g, '');
|
|
219
|
+
if (ad_id !== id) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
if (model) {
|
|
224
|
+
if (ad.serviceData.model !== model) {
|
|
225
|
+
return false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return true;
|
|
229
|
+
}
|
|
229
230
|
|
|
230
|
-
|
|
231
|
+
/* ------------------------------------------------------------------
|
|
231
232
|
* startScan([params])
|
|
232
233
|
* - Start to monitor advertising packets coming from switchbot devices
|
|
233
234
|
*
|
|
@@ -264,58 +265,58 @@ class Switchbot {
|
|
|
264
265
|
* - Promise object
|
|
265
266
|
* Nothing will be passed to the `resolve()`.
|
|
266
267
|
* ---------------------------------------------------------------- */
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
268
|
+
startScan(params) {
|
|
269
|
+
let promise = new Promise((resolve, reject) => {
|
|
270
|
+
// Check the parameters
|
|
271
|
+
let valid = parameterChecker.check(params, {
|
|
272
|
+
model: { required: false, type: 'string', enum: ['H', 'T', 'e', 's', 'd', 'c'] },
|
|
273
|
+
id: { required: false, type: 'string', min: 12, max: 17 },
|
|
274
|
+
}, false);
|
|
274
275
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
276
|
+
if (!valid) {
|
|
277
|
+
reject(new Error(parameterChecker.error.message));
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
279
280
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
if (!params) {
|
|
282
|
+
params = {};
|
|
283
|
+
}
|
|
283
284
|
|
|
284
|
-
|
|
285
|
-
|
|
285
|
+
// Initialize the noble object
|
|
286
|
+
this._init().then(() => {
|
|
286
287
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
288
|
+
// Determine the values of the parameters
|
|
289
|
+
let p = {
|
|
290
|
+
model: params.model || '',
|
|
291
|
+
id: params.id || ''
|
|
292
|
+
};
|
|
292
293
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
294
|
+
// Set an handler for the 'discover' event
|
|
295
|
+
this.noble.on('discover', (peripheral) => {
|
|
296
|
+
let ad = switchbotAdvertising.parse(peripheral);
|
|
297
|
+
if (this._filterAdvertising(ad, p.id, p.model)) {
|
|
298
|
+
if (this.onadvertisement && typeof (this.onadvertisement) === 'function') {
|
|
299
|
+
this.onadvertisement(ad);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
});
|
|
302
303
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
304
|
+
// Start scaning
|
|
305
|
+
this.noble.startScanning(this._PRIMARY_SERVICE_UUID_LIST, true, (error) => {
|
|
306
|
+
if (error) {
|
|
307
|
+
reject(error);
|
|
308
|
+
} else {
|
|
309
|
+
resolve();
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
}).catch((error) => {
|
|
313
|
+
reject(error);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
return promise;
|
|
317
|
+
}
|
|
317
318
|
|
|
318
|
-
|
|
319
|
+
/* ------------------------------------------------------------------
|
|
319
320
|
* stopScan()
|
|
320
321
|
* - Stop to monitor advertising packets coming from switchbot devices
|
|
321
322
|
*
|
|
@@ -325,12 +326,12 @@ class Switchbot {
|
|
|
325
326
|
* [Returen value]
|
|
326
327
|
* - none
|
|
327
328
|
* ---------------------------------------------------------------- */
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
329
|
+
stopScan() {
|
|
330
|
+
this.noble.removeAllListeners('discover');
|
|
331
|
+
this.noble.stopScanning();
|
|
332
|
+
}
|
|
332
333
|
|
|
333
|
-
|
|
334
|
+
/* ------------------------------------------------------------------
|
|
334
335
|
* wait(msec) {
|
|
335
336
|
* - Wait for the specified time (msec)
|
|
336
337
|
*
|
|
@@ -341,22 +342,22 @@ class Switchbot {
|
|
|
341
342
|
* - Promise object
|
|
342
343
|
* Nothing will be passed to the `resolve()`.
|
|
343
344
|
* ---------------------------------------------------------------- */
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
345
|
+
wait(msec) {
|
|
346
|
+
return new Promise((resolve, reject) => {
|
|
347
|
+
// Check the parameters
|
|
348
|
+
let valid = parameterChecker.check({ msec: msec }, {
|
|
349
|
+
msec: { required: true, type: 'integer', min: 0 }
|
|
350
|
+
});
|
|
350
351
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
352
|
+
if (!valid) {
|
|
353
|
+
reject(new Error(parameterChecker.error.message));
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
// Set a timer
|
|
357
|
+
setTimeout(resolve, msec);
|
|
358
|
+
});
|
|
359
|
+
}
|
|
359
360
|
|
|
360
361
|
}
|
|
361
362
|
|
|
362
|
-
|
|
363
|
+
module.exports = Switchbot;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-switchbot",
|
|
3
|
-
"version": "1.1.3-beta.
|
|
3
|
+
"version": "1.1.3-beta.5",
|
|
4
4
|
"description": "The node-switchbot is a Node.js module which allows you to move your Switchbot (Bot)'s arm and Switchbot Curtain(Curtain), also monitor the temperature/humidity from SwitchBot Thermometer & Hygrometer (Meter).",
|
|
5
5
|
"main": "./lib/switchbot.js",
|
|
6
6
|
"files": [
|
|
@@ -11,9 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
13
|
"check": "npm install && npm outdated",
|
|
14
|
-
"update": "ncu -u && npm update && npm install"
|
|
15
|
-
"lint": "eslint lib/**.js",
|
|
16
|
-
"prepublishOnly": "npm run lint && npm install"
|
|
14
|
+
"update": "ncu -u && npm update && npm install"
|
|
17
15
|
},
|
|
18
16
|
"keywords": [
|
|
19
17
|
"switchbot",
|
|
@@ -39,11 +37,6 @@
|
|
|
39
37
|
"@abandonware/noble": "^1.9.2-15"
|
|
40
38
|
},
|
|
41
39
|
"devDependencies": {
|
|
42
|
-
"
|
|
43
|
-
"eslint-config-standard": "^16.0.3",
|
|
44
|
-
"eslint-plugin-import": "^2.25.4",
|
|
45
|
-
"eslint-plugin-node": "^11.1.0",
|
|
46
|
-
"eslint-plugin-promise": "^5.2.0",
|
|
47
|
-
"npm-check-updates": "^12.0.5"
|
|
40
|
+
"npm-check-updates": "^12.0.2"
|
|
48
41
|
}
|
|
49
42
|
}
|