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