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