node-switchbot 1.3.0 → 1.4.2-beta.0

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.
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ const SwitchbotDevice = require("./switchbot-device.js");
3
+
4
+ /**
5
+ * @see https://github.com/OpenWonderLabs/SwitchBotAPI-BLE/blob/latest/devicetypes/plugmini.md
6
+ */
7
+ class SwitchbotDeviceWoPlugMini extends SwitchbotDevice {
8
+ /**
9
+ * @returns {Promise<boolean>} resolves with a boolean that tells whether the plug in ON(true) or OFF(false)
10
+ */
11
+ readState() {
12
+ return this._operateBot([0x57, 0x0f, 0x51, 0x01]);
13
+ }
14
+
15
+ /**
16
+ * @private
17
+ */
18
+ _setState(reqByteArray) {
19
+ const base = [0x57, 0x0f, 0x50, 0x01];
20
+ return this._operateBot([].concat(base, reqByteArray));
21
+ }
22
+
23
+ /**
24
+ * @returns {Promise<boolean>} resolves with a boolean that tells whether the plug in ON(true) or OFF(false)
25
+ */
26
+ turnOn() {
27
+ return this._setState([0x01, 0x80]);
28
+ }
29
+
30
+ /**
31
+ * @returns {Promise<boolean>} resolves with a boolean that tells whether the plug in ON(true) or OFF(false)
32
+ */
33
+ turnOff() {
34
+ return this._setState([0x01, 0x00]);
35
+ }
36
+
37
+ /**
38
+ * @returns {Promise<boolean>} resolves with a boolean that tells whether the plug in ON(true) or OFF(false)
39
+ */
40
+ toggle() {
41
+ return this._setState([0x02, 0x80]);
42
+ }
43
+
44
+ /**
45
+ * @private
46
+ */
47
+ _operateBot(bytes) {
48
+ const req_buf = Buffer.from(bytes);
49
+ return new Promise((resolve, reject) => {
50
+ this._command(req_buf)
51
+ .then((res_bytes) => {
52
+ const res_buf = Buffer.from(res_bytes);
53
+ if (res_buf.length === 2) {
54
+ let code = res_buf.readUInt8(1);
55
+ if (code === 0x00 || code === 0x80) {
56
+ const is_on = code === 0x80;
57
+ resolve(is_on);
58
+ } else {
59
+ reject(
60
+ new Error(
61
+ "The device returned an error: 0x" + res_buf.toString("hex")
62
+ )
63
+ );
64
+ }
65
+ } else {
66
+ reject(
67
+ new Error(
68
+ "Expecting a 2-byte response, got instead: 0x" +
69
+ res_buf.toString("hex")
70
+ )
71
+ );
72
+ }
73
+ })
74
+ .catch((error) => {
75
+ reject(error);
76
+ });
77
+ });
78
+ }
79
+ }
80
+
81
+ module.exports = SwitchbotDeviceWoPlugMini;
@@ -1,9 +1,6 @@
1
- 'use strict';
2
- const SwitchbotDevice = require('./switchbot-device.js');
1
+ "use strict";
2
+ const SwitchbotDevice = require("./switchbot-device.js");
3
3
 
4
- class SwitchbotDeviceWoPresence extends SwitchbotDevice {
4
+ class SwitchbotDeviceWoPresence extends SwitchbotDevice {}
5
5
 
6
-
7
- }
8
-
9
- module.exports = SwitchbotDeviceWoPresence;
6
+ module.exports = SwitchbotDeviceWoPresence;
@@ -1,9 +1,6 @@
1
- 'use strict';
2
- const SwitchbotDevice = require('./switchbot-device.js');
1
+ "use strict";
2
+ const SwitchbotDevice = require("./switchbot-device.js");
3
3
 
4
- class SwitchbotDeviceWoSensorTH extends SwitchbotDevice {
4
+ class SwitchbotDeviceWoSensorTH extends SwitchbotDevice {}
5
5
 
6
-
7
- }
8
-
9
- module.exports = SwitchbotDeviceWoSensorTH;
6
+ module.exports = SwitchbotDeviceWoSensorTH;
@@ -1,25 +1,25 @@
1
- 'use strict';
2
- const parameterChecker = require('./parameter-checker.js');
3
- const switchbotAdvertising = require('./switchbot-advertising.js');
1
+ "use strict";
2
+ const parameterChecker = require("./parameter-checker.js");
3
+ const switchbotAdvertising = require("./switchbot-advertising.js");
4
4
 
5
5
  class SwitchbotDevice {
6
6
  /* ------------------------------------------------------------------
7
- * Constructor
8
- *
9
- * [Arguments]
10
- * - peripheral | Object | Required | The `peripheral` object of noble,
11
- * | | | which represents this device
12
- * - noble | Noble | Required | The Nobel object created by the noble module.
13
- * ---------------------------------------------------------------- */
7
+ * Constructor
8
+ *
9
+ * [Arguments]
10
+ * - peripheral | Object | Required | The `peripheral` object of noble,
11
+ * | | | which represents this device
12
+ * - noble | Noble | Required | The Nobel object created by the noble module.
13
+ * ---------------------------------------------------------------- */
14
14
  constructor(peripheral, noble) {
15
15
  this._peripheral = peripheral;
16
16
  this._noble = noble;
17
17
  this._chars = null;
18
18
 
19
- this._SERV_UUID_PRIMARY = 'cba20d00224d11e69fb80002a5d5c51b';
20
- this._CHAR_UUID_WRITE = 'cba20002224d11e69fb80002a5d5c51b';
21
- this._CHAR_UUID_NOTIFY = 'cba20003224d11e69fb80002a5d5c51b';
22
- this._CHAR_UUID_DEVICE = '2a00';
19
+ this._SERV_UUID_PRIMARY = "cba20d00224d11e69fb80002a5d5c51b";
20
+ this._CHAR_UUID_WRITE = "cba20002224d11e69fb80002a5d5c51b";
21
+ this._CHAR_UUID_NOTIFY = "cba20003224d11e69fb80002a5d5c51b";
22
+ this._CHAR_UUID_DEVICE = "2a00";
23
23
 
24
24
  this._READ_TIMEOUT_MSEC = 3000;
25
25
  this._WRITE_TIMEOUT_MSEC = 3000;
@@ -35,10 +35,10 @@ class SwitchbotDevice {
35
35
  this._was_connected_explicitly = false;
36
36
  this._connected = false;
37
37
 
38
- this._onconnect = () => { };
39
- this._ondisconnect = () => { };
40
- this._ondisconnect_internal = () => { };
41
- this._onnotify_internal = () => { };
38
+ this._onconnect = () => {};
39
+ this._ondisconnect = () => {};
40
+ this._ondisconnect_internal = () => {};
41
+ this._onnotify_internal = () => {};
42
42
  }
43
43
 
44
44
  // Getters
@@ -55,8 +55,8 @@ class SwitchbotDevice {
55
55
  return this._modelName;
56
56
  }
57
57
  get connectionState() {
58
- if (!this._connected && this._peripheral.state === 'disconnecting') {
59
- return 'disconnected';
58
+ if (!this._connected && this._peripheral.state === "disconnecting") {
59
+ return "disconnected";
60
60
  } else {
61
61
  return this._peripheral.state;
62
62
  }
@@ -64,29 +64,29 @@ class SwitchbotDevice {
64
64
 
65
65
  // Setters
66
66
  set onconnect(func) {
67
- if (!func || typeof (func) !== 'function') {
68
- throw new Error('The `onconnect` must be a function.');
67
+ if (!func || typeof func !== "function") {
68
+ throw new Error("The `onconnect` must be a function.");
69
69
  }
70
70
  this._onconnect = func;
71
71
  }
72
72
  set ondisconnect(func) {
73
- if (!func || typeof (func) !== 'function') {
74
- throw new Error('The `ondisconnect` must be a function.');
73
+ if (!func || typeof func !== "function") {
74
+ throw new Error("The `ondisconnect` must be a function.");
75
75
  }
76
76
  this._ondisconnect = func;
77
77
  }
78
78
 
79
79
  /* ------------------------------------------------------------------
80
- * connect()
81
- * - Connect the device
82
- *
83
- * [Arguments]
84
- * - none
85
- *
86
- * [Return value]
87
- * - Promise object
88
- * Nothing will be passed to the `resolve()`.
89
- * ---------------------------------------------------------------- */
80
+ * connect()
81
+ * - Connect the device
82
+ *
83
+ * [Arguments]
84
+ * - none
85
+ *
86
+ * [Return value]
87
+ * - Promise object
88
+ * Nothing will be passed to the `resolve()`.
89
+ * ---------------------------------------------------------------- */
90
90
  connect() {
91
91
  this._was_connected_explicitly = true;
92
92
  return this._connect();
@@ -95,28 +95,34 @@ class SwitchbotDevice {
95
95
  _connect() {
96
96
  return new Promise((resolve, reject) => {
97
97
  // Check the bluetooth state
98
- if (this._noble.state !== 'poweredOn') {
99
- reject(new Error('The Bluetooth status is ' + this._noble.state + ', not poweredOn.'));
98
+ if (this._noble.state !== "poweredOn") {
99
+ reject(
100
+ new Error(
101
+ "The Bluetooth status is " + this._noble.state + ", not poweredOn."
102
+ )
103
+ );
100
104
  return;
101
105
  }
102
106
 
103
107
  // Check the connection state
104
108
  let state = this.connectionState;
105
- if (state === 'connected') {
109
+ if (state === "connected") {
106
110
  resolve();
107
111
  return;
108
- } else if (state === 'connecting' || state === 'disconnecting') {
109
- reject(new Error('Now ' + state + '. Wait for a few seconds then try again.'));
112
+ } else if (state === "connecting" || state === "disconnecting") {
113
+ reject(
114
+ new Error("Now " + state + ". Wait for a few seconds then try again.")
115
+ );
110
116
  return;
111
117
  }
112
118
 
113
119
  // Set event handlers for events fired on the `Peripheral` object
114
- this._peripheral.once('connect', () => {
120
+ this._peripheral.once("connect", () => {
115
121
  this._connected = true;
116
122
  this._onconnect();
117
123
  });
118
124
 
119
- this._peripheral.once('disconnect', () => {
125
+ this._peripheral.once("disconnect", () => {
120
126
  this._connected = false;
121
127
  this._chars = null;
122
128
  this._peripheral.removeAllListeners();
@@ -130,15 +136,18 @@ class SwitchbotDevice {
130
136
  reject(error);
131
137
  return;
132
138
  }
133
- this._getCharacteristics().then((chars) => {
134
- this._chars = chars;
135
- return this._subscribe();
136
- }).then(() => {
137
- resolve();
138
- }).catch((error) => {
139
- this._peripheral.disconnect();
140
- reject(error);
141
- });
139
+ this._getCharacteristics()
140
+ .then((chars) => {
141
+ this._chars = chars;
142
+ return this._subscribe();
143
+ })
144
+ .then(() => {
145
+ resolve();
146
+ })
147
+ .catch((error) => {
148
+ this._peripheral.disconnect();
149
+ reject(error);
150
+ });
142
151
  });
143
152
  });
144
153
  }
@@ -147,9 +156,11 @@ class SwitchbotDevice {
147
156
  return new Promise((resolve, reject) => {
148
157
  // Set timeout timer
149
158
  let timer = setTimeout(() => {
150
- this._ondisconnect_internal = () => { };
159
+ this._ondisconnect_internal = () => {};
151
160
  timer = null;
152
- reject(new Error('Failed to discover services and characteristics: TIMEOUT'));
161
+ reject(
162
+ new Error("Failed to discover services and characteristics: TIMEOUT")
163
+ );
153
164
  }, 5000);
154
165
 
155
166
  // Watch the connection state
@@ -157,22 +168,26 @@ class SwitchbotDevice {
157
168
  if (timer) {
158
169
  clearTimeout(timer);
159
170
  timer = null;
160
- this._ondisconnect_internal = () => { };
171
+ this._ondisconnect_internal = () => {};
161
172
  }
162
- reject(new Error('Failed to discover services and characteristics: DISCONNECTED'));
173
+ reject(
174
+ new Error(
175
+ "Failed to discover services and characteristics: DISCONNECTED"
176
+ )
177
+ );
163
178
  };
164
179
 
165
180
  // Discover services and characteristics
166
181
  (async () => {
167
182
  let service_list = await this._discoverServices();
168
183
  if (!timer) {
169
- throw new Error('');
184
+ throw new Error("");
170
185
  }
171
186
 
172
187
  let chars = {
173
188
  write: null,
174
189
  notify: null,
175
- device: null
190
+ device: null,
176
191
  };
177
192
 
178
193
  for (let service of service_list) {
@@ -192,14 +207,13 @@ class SwitchbotDevice {
192
207
  if (chars.write && chars.notify) {
193
208
  resolve(chars);
194
209
  } else {
195
- reject(new Error('No characteristic was found.'));
210
+ reject(new Error("No characteristic was found."));
196
211
  }
197
-
198
212
  })().catch((error) => {
199
213
  if (timer) {
200
214
  clearTimeout(timer);
201
215
  timer = null;
202
- this._ondisconnect_internal = () => { };
216
+ this._ondisconnect_internal = () => {};
203
217
  reject(error);
204
218
  } else {
205
219
  // Do nothing
@@ -226,7 +240,7 @@ class SwitchbotDevice {
226
240
  if (service) {
227
241
  resolve(service_list);
228
242
  } else {
229
- reject(new Error('No service was found.'));
243
+ reject(new Error("No service was found."));
230
244
  }
231
245
  });
232
246
  });
@@ -248,7 +262,7 @@ class SwitchbotDevice {
248
262
  return new Promise((resolve, reject) => {
249
263
  let char = this._chars.notify;
250
264
  if (!char) {
251
- reject(new Error('No notify characteristic was found.'));
265
+ reject(new Error("No notify characteristic was found."));
252
266
  return;
253
267
  }
254
268
  char.subscribe((error) => {
@@ -256,11 +270,11 @@ class SwitchbotDevice {
256
270
  reject(error);
257
271
  return;
258
272
  }
259
- char.on('data', (buf) => {
273
+ char.on("data", (buf) => {
260
274
  this._onnotify_internal(buf);
261
275
  });
262
276
  resolve();
263
- })
277
+ });
264
278
  });
265
279
  }
266
280
 
@@ -279,26 +293,28 @@ class SwitchbotDevice {
279
293
  }
280
294
 
281
295
  /* ------------------------------------------------------------------
282
- * disconnect()
283
- * - Disconnect the device
284
- *
285
- * [Arguments]
286
- * - none
287
- *
288
- * [Return value]
289
- * - Promise object
290
- * Nothing will be passed to the `resolve()`.
291
- * ---------------------------------------------------------------- */
296
+ * disconnect()
297
+ * - Disconnect the device
298
+ *
299
+ * [Arguments]
300
+ * - none
301
+ *
302
+ * [Return value]
303
+ * - Promise object
304
+ * Nothing will be passed to the `resolve()`.
305
+ * ---------------------------------------------------------------- */
292
306
  disconnect() {
293
307
  return new Promise((resolve, reject) => {
294
308
  this._was_connected_explicitly = false;
295
309
  // Check the connection state
296
310
  let state = this._peripheral.state;
297
- if (state === 'disconnected') {
311
+ if (state === "disconnected") {
298
312
  resolve();
299
313
  return;
300
- } else if (state === 'connecting' || state === 'disconnecting') {
301
- reject(new Error('Now ' + state + '. Wait for a few seconds then try again.'));
314
+ } else if (state === "connecting" || state === "disconnecting") {
315
+ reject(
316
+ new Error("Now " + state + ". Wait for a few seconds then try again.")
317
+ );
302
318
  return;
303
319
  }
304
320
 
@@ -323,74 +339,93 @@ class SwitchbotDevice {
323
339
  }
324
340
 
325
341
  /* ------------------------------------------------------------------
326
- * getDeviceName()
327
- * - Retrieve the device name
328
- *
329
- * [Arguments]
330
- * - none
331
- *
332
- * [Return value]
333
- * - Promise object
334
- * The device name will be passed to the `resolve()`.
335
- * ---------------------------------------------------------------- */
342
+ * getDeviceName()
343
+ * - Retrieve the device name
344
+ *
345
+ * [Arguments]
346
+ * - none
347
+ *
348
+ * [Return value]
349
+ * - Promise object
350
+ * The device name will be passed to the `resolve()`.
351
+ * ---------------------------------------------------------------- */
336
352
  getDeviceName() {
337
353
  return new Promise((resolve, reject) => {
338
- let name = '';
339
- this._connect().then(() => {
340
- if (!this._chars.device) {
341
- // Some models of Bot don't seem to support this characteristic UUID
342
- throw new Error('The device does not support the characteristic UUID 0x' + this._CHAR_UUID_DEVICE + '.');
343
- }
344
- return this._read(this._chars.device);
345
- }).then((buf) => {
346
- name = buf.toString('utf8');
347
- return this._disconnect();
348
- }).then(() => {
349
- resolve(name);
350
- }).catch((error) => {
351
- reject(error);
352
- });
354
+ let name = "";
355
+ this._connect()
356
+ .then(() => {
357
+ if (!this._chars.device) {
358
+ // Some models of Bot don't seem to support this characteristic UUID
359
+ throw new Error(
360
+ "The device does not support the characteristic UUID 0x" +
361
+ this._CHAR_UUID_DEVICE +
362
+ "."
363
+ );
364
+ }
365
+ return this._read(this._chars.device);
366
+ })
367
+ .then((buf) => {
368
+ name = buf.toString("utf8");
369
+ return this._disconnect();
370
+ })
371
+ .then(() => {
372
+ resolve(name);
373
+ })
374
+ .catch((error) => {
375
+ reject(error);
376
+ });
353
377
  });
354
378
  }
355
379
 
356
380
  /* ------------------------------------------------------------------
357
- * setDeviceName(name)
358
- * - Set the device name
359
- *
360
- * [Arguments]
361
- * - name | String | Required | Device name. The bytes length of the name
362
- * | | | must be in the range of 1 to 20 bytes.
363
- *
364
- * [Return value]
365
- * - Promise object
366
- * Nothing will be passed to the `resolve()`.
367
- * ---------------------------------------------------------------- */
381
+ * setDeviceName(name)
382
+ * - Set the device name
383
+ *
384
+ * [Arguments]
385
+ * - name | String | Required | Device name. The bytes length of the name
386
+ * | | | must be in the range of 1 to 20 bytes.
387
+ *
388
+ * [Return value]
389
+ * - Promise object
390
+ * Nothing will be passed to the `resolve()`.
391
+ * ---------------------------------------------------------------- */
368
392
  setDeviceName(name) {
369
393
  return new Promise((resolve, reject) => {
370
394
  // Check the parameters
371
- let valid = parameterChecker.check({ name: name }, {
372
- name: { required: true, type: 'string', minBytes: 1, maxBytes: 100 }
373
- });
395
+ let valid = parameterChecker.check(
396
+ { name: name },
397
+ {
398
+ name: { required: true, type: "string", minBytes: 1, maxBytes: 100 },
399
+ }
400
+ );
374
401
 
375
402
  if (!valid) {
376
403
  reject(new Error(parameterChecker.error.message));
377
404
  return;
378
405
  }
379
406
 
380
- let buf = Buffer.from(name, 'utf8');
381
- this._connect().then(() => {
382
- if (!this._chars.device) {
383
- // Some models of Bot don't seem to support this characteristic UUID
384
- throw new Error('The device does not support the characteristic UUID 0x' + this._CHAR_UUID_DEVICE + '.');
385
- }
386
- return this._write(this._chars.device, buf);
387
- }).then(() => {
388
- return this._disconnect();
389
- }).then(() => {
390
- resolve();
391
- }).catch((error) => {
392
- reject(error);
393
- });
407
+ let buf = Buffer.from(name, "utf8");
408
+ this._connect()
409
+ .then(() => {
410
+ if (!this._chars.device) {
411
+ // Some models of Bot don't seem to support this characteristic UUID
412
+ throw new Error(
413
+ "The device does not support the characteristic UUID 0x" +
414
+ this._CHAR_UUID_DEVICE +
415
+ "."
416
+ );
417
+ }
418
+ return this._write(this._chars.device, buf);
419
+ })
420
+ .then(() => {
421
+ return this._disconnect();
422
+ })
423
+ .then(() => {
424
+ resolve();
425
+ })
426
+ .catch((error) => {
427
+ reject(error);
428
+ });
394
429
  });
395
430
  }
396
431
 
@@ -400,24 +435,29 @@ class SwitchbotDevice {
400
435
  _command(req_buf) {
401
436
  return new Promise((resolve, reject) => {
402
437
  if (!Buffer.isBuffer(req_buf)) {
403
- reject(new Error('The specified data is not acceptable for writing.'));
438
+ reject(new Error("The specified data is not acceptable for writing."));
404
439
  return;
405
440
  }
406
441
 
407
442
  let res_buf = null;
408
443
 
409
- this._connect().then(() => {
410
- return this._write(this._chars.write, req_buf);
411
- }).then(() => {
412
- return this._waitCommandResponse();
413
- }).then((buf) => {
414
- res_buf = buf;
415
- return this._disconnect();
416
- }).then(() => {
417
- resolve(res_buf);
418
- }).catch((error) => {
419
- reject(error);
420
- });
444
+ this._connect()
445
+ .then(() => {
446
+ return this._write(this._chars.write, req_buf);
447
+ })
448
+ .then(() => {
449
+ return this._waitCommandResponse();
450
+ })
451
+ .then((buf) => {
452
+ res_buf = buf;
453
+ return this._disconnect();
454
+ })
455
+ .then(() => {
456
+ resolve(res_buf);
457
+ })
458
+ .catch((error) => {
459
+ reject(error);
460
+ });
421
461
  });
422
462
  }
423
463
 
@@ -425,8 +465,8 @@ class SwitchbotDevice {
425
465
  return new Promise((resolve, reject) => {
426
466
  let timer = setTimeout(() => {
427
467
  timer = null;
428
- this._onnotify_internal = () => { };
429
- reject(new Error('COMMAND_TIMEOUT'));
468
+ this._onnotify_internal = () => {};
469
+ reject(new Error("COMMAND_TIMEOUT"));
430
470
  }, this._COMMAND_TIMEOUT_MSEC);
431
471
 
432
472
  this._onnotify_internal = (buf) => {
@@ -434,7 +474,7 @@ class SwitchbotDevice {
434
474
  clearTimeout(timer);
435
475
  timer = null;
436
476
  }
437
- this._onnotify_internal = () => { };
477
+ this._onnotify_internal = () => {};
438
478
  resolve(buf);
439
479
  };
440
480
  });
@@ -445,7 +485,7 @@ class SwitchbotDevice {
445
485
  return new Promise((resolve, reject) => {
446
486
  // Set a timeout timer
447
487
  let timer = setTimeout(() => {
448
- reject('READ_TIMEOUT');
488
+ reject("READ_TIMEOUT");
449
489
  }, this._READ_TIMEOUT_MSEC);
450
490
 
451
491
  // Read charcteristic data
@@ -468,7 +508,7 @@ class SwitchbotDevice {
468
508
  return new Promise((resolve, reject) => {
469
509
  // Set a timeout timer
470
510
  let timer = setTimeout(() => {
471
- reject('WRITE_TIMEOUT');
511
+ reject("WRITE_TIMEOUT");
472
512
  }, this._WRITE_TIMEOUT_MSEC);
473
513
 
474
514
  // write charcteristic data
@@ -485,7 +525,6 @@ class SwitchbotDevice {
485
525
  });
486
526
  });
487
527
  }
488
-
489
528
  }
490
529
 
491
- module.exports = SwitchbotDevice;
530
+ module.exports = SwitchbotDevice;