node-switchbot 2.5.0-beta.3 → 2.5.0-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/dist/device.js CHANGED
@@ -1,46 +1,37 @@
1
1
  import { Buffer } from 'node:buffer';
2
2
  import { Advertising } from './advertising.js';
3
3
  import { parameterChecker } from './parameter-checker.js';
4
- import { CHAR_UUID_DEVICE, CHAR_UUID_NOTIFY, CHAR_UUID_WRITE, COMMAND_TIMEOUT_MSEC, READ_TIMEOUT_MSEC, SERV_UUID_PRIMARY, WRITE_TIMEOUT_MSEC, } from './settings.js';
4
+ import { CHAR_UUID_DEVICE, CHAR_UUID_NOTIFY, CHAR_UUID_WRITE, READ_TIMEOUT_MSEC, SERV_UUID_PRIMARY, WRITE_TIMEOUT_MSEC, } from './settings.js';
5
+ /**
6
+ * Represents a Switchbot Device.
7
+ */
5
8
  export class SwitchbotDevice {
6
9
  _noble;
7
10
  _peripheral;
8
- _characteristics;
11
+ _characteristics = null;
9
12
  _id;
10
13
  _address;
11
14
  _model;
12
15
  _modelName;
13
- _explicitly;
14
- _connected;
15
- onnotify_internal;
16
- ondisconnect_internal;
17
- onconnect_internal;
16
+ _explicitly = false;
17
+ _connected = false;
18
+ onnotify_internal = () => { };
19
+ ondisconnect_internal = async () => { };
20
+ onconnect_internal = async () => { };
18
21
  /**
19
- * Constructor for the Device class.
20
- *
21
- * @param {object} peripheral - The `peripheral` object from noble, representing this device.
22
- * @param {Noble} noble - The Noble object created by the noble module.
23
- *
24
- * This constructor initializes a new instance of the Device class with the specified peripheral and noble objects.
22
+ * Initializes a new instance of the SwitchbotDevice class.
23
+ * @param peripheral The peripheral object from noble.
24
+ * @param noble The Noble object.
25
25
  */
26
26
  constructor(peripheral, noble) {
27
27
  this._peripheral = peripheral;
28
28
  this._noble = noble;
29
- this._characteristics = null;
30
- // Save the device information
31
- const ad = Advertising.parse(peripheral);
32
- this._id = ad ? ad.id : null;
33
- this._address = ad ? ad.address : null;
34
- this._model = ad ? ad.serviceData.model : null;
35
- this._modelName = ad ? ad.serviceData.modelName : null;
36
- this._explicitly = false;
37
- this._connected = false;
38
- this._explicitly = false;
39
- this._connected = false;
40
- this.onconnect = () => { };
41
- this.ondisconnect = () => { };
42
- this.ondisconnect_internal = () => { };
43
- this.onnotify_internal = () => { };
29
+ Advertising.parse(peripheral).then((ad) => {
30
+ this._id = ad?.id ?? '';
31
+ this._address = ad?.address ?? '';
32
+ this._model = ad?.serviceData.model ?? '';
33
+ this._modelName = ad?.serviceData.modelName ?? '';
34
+ });
44
35
  }
45
36
  // Getters
46
37
  get id() {
@@ -56,30 +47,14 @@ export class SwitchbotDevice {
56
47
  return this._modelName;
57
48
  }
58
49
  get connectionState() {
59
- if (!this._connected && this._peripheral.state === 'disconnecting') {
60
- return 'disconnected';
61
- }
62
- else {
63
- return this._peripheral.state;
64
- }
50
+ return this._connected ? 'connected' : this._peripheral.state;
65
51
  }
66
52
  get onconnect() {
67
53
  return this.onconnect_internal;
68
54
  }
69
- /**
70
- * Sets the asynchronous connection handler.
71
- *
72
- * This setter assigns a function to be used as the asynchronous connection handler. The handler
73
- * is expected to be a function that returns a Promise, which resolves once the connection process
74
- * is complete. The resolution of the Promise does not carry any value.
75
- *
76
- * @param func A function that returns a Promise, representing the asynchronous operation of connecting.
77
- * This function is expected to be called without any arguments.
78
- * @throws Error if the provided argument is not a function, ensuring type safety.
79
- */
80
55
  set onconnect(func) {
81
- if (!func || typeof func !== 'function') {
82
- throw new Error('The `onconnect` must be a function that returns a Promise<void>.');
56
+ if (typeof func !== 'function') {
57
+ throw new TypeError('The `onconnect` must be a function that returns a Promise<void>.');
83
58
  }
84
59
  this.onconnect_internal = async () => {
85
60
  await func();
@@ -88,72 +63,37 @@ export class SwitchbotDevice {
88
63
  get ondisconnect() {
89
64
  return this.ondisconnect_internal;
90
65
  }
91
- /**
92
- * Sets the asynchronous disconnection handler.
93
- *
94
- * This setter configures a function to act as the asynchronous disconnection handler. The handler
95
- * should be a function that returns a Promise, which resolves when the disconnection process
96
- * is complete. The resolution of the Promise does not carry any value.
97
- *
98
- * @param func A function that returns a Promise, representing the asynchronous operation of disconnecting.
99
- * This function is expected to be called without any arguments.
100
- * @throws Error if the provided argument is not a function, to ensure that the handler is correctly typed.
101
- */
102
66
  set ondisconnect(func) {
103
- if (!func || typeof func !== 'function') {
104
- throw new Error('The `ondisconnect` must be a function that returns a Promise<void>.');
67
+ if (typeof func !== 'function') {
68
+ throw new TypeError('The `ondisconnect` must be a function that returns a Promise<void>.');
105
69
  }
106
70
  this.ondisconnect_internal = async () => {
107
71
  await func();
108
72
  };
109
73
  }
110
74
  /**
111
- * Initiates an asynchronous connection process.
112
- *
113
- * This method marks the device as being connected explicitly by setting a flag, then proceeds
114
- * to initiate the actual connection process by calling an internal asynchronous method `connect_internalAsync`.
115
- * The `connect_internalAsync` method is responsible for handling the low-level connection logic.
116
- *
117
- * @returns A Promise that resolves when the connection process initiated by `connect_internalAsync` completes.
118
- * The resolution of this Promise does not carry any value, indicating that the focus is on
119
- * the completion of the connection process rather than the result of the connection itself.
75
+ * Connects to the device.
76
+ * @returns A Promise that resolves when the connection is complete.
120
77
  */
121
78
  async connect() {
122
79
  this._explicitly = true;
123
- return await this.connect_internal();
80
+ await this.connect_internal();
124
81
  }
125
82
  /**
126
- * Initiates the device connection process.
127
- *
128
- * This method is marked as deprecated and is scheduled for removal in a future version. It is recommended
129
- * to use `disconnectAsync()` instead. The method returns a Promise that resolves when the device is successfully
130
- * connected or rejects if the connection cannot be established.
131
- *
132
- * The connection process involves several steps:
133
- * 1. Checks the Bluetooth adapter's state. If it's not powered on, the promise is rejected.
134
- * 2. Checks the current connection state of the device. If already connected, the promise resolves immediately.
135
- * If in the process of connecting or disconnecting, the promise is rejected advising to wait.
136
- * 3. Sets up event handlers for 'connect' and 'disconnect' events on the peripheral device to manage connection state.
137
- * 4. Initiates the connection. If an error occurs during this step, the promise is rejected.
138
- * 5. Once connected, retrieves the device's characteristics and subscribes to them. If this process fails, the device
139
- * is disconnected, and the promise is rejected.
140
- *
141
- * @returns A Promise<void> that resolves when the device is connected or rejects with an error.
83
+ * Internal method to handle the connection process.
84
+ * @returns A Promise that resolves when the connection is complete.
142
85
  */
143
86
  async connect_internal() {
144
- // Check the bluetooth state
145
87
  if (this._noble._state !== 'poweredOn') {
146
88
  throw new Error(`The Bluetooth status is ${this._noble._state}, not poweredOn.`);
147
89
  }
148
- // Check the connection state
149
90
  const state = this.connectionState;
150
91
  if (state === 'connected') {
151
92
  return;
152
93
  }
153
- else if (state === 'connecting' || state === 'disconnecting') {
94
+ if (state === 'connecting' || state === 'disconnecting') {
154
95
  throw new Error(`Now ${state}. Wait for a few seconds then try again.`);
155
96
  }
156
- // Set event handlers for events fired on the `Peripheral` object
157
97
  this._peripheral.once('connect', async () => {
158
98
  this._connected = true;
159
99
  await this.onconnect();
@@ -162,49 +102,33 @@ export class SwitchbotDevice {
162
102
  this._connected = false;
163
103
  this._characteristics = null;
164
104
  this._peripheral.removeAllListeners();
165
- try {
166
- await this.ondisconnect_internal();
167
- await this.ondisconnect();
168
- }
169
- catch (error) {
170
- throw new Error('Error during disconnect:', error);
171
- }
105
+ await this.ondisconnect_internal();
172
106
  });
173
- // Connect
174
107
  await this._peripheral.connectAsync();
175
- const chars = await this.getCharacteristics();
176
- this._characteristics = chars;
108
+ this._characteristics = await this.getCharacteristics();
177
109
  await this.subscribe();
178
110
  }
111
+ /**
112
+ * Retrieves the device characteristics.
113
+ * @returns A Promise that resolves with the device characteristics.
114
+ */
179
115
  async getCharacteristics() {
180
- // Set timeout timer
181
- let timer = setTimeout(async () => {
182
- await this.ondisconnect_internal();
183
- timer = null;
116
+ const timer = setTimeout(() => {
184
117
  throw new Error('Failed to discover services and characteristics: TIMEOUT');
185
118
  }, 5000);
186
119
  try {
187
- // Discover services and characteristics
188
- const service_list = await this.discoverServices();
189
- if (!timer) {
190
- throw new Error('Failed to discover services and characteristics.');
191
- }
192
- const chars = {
193
- write: null,
194
- notify: null,
195
- device: null,
196
- };
197
- for (const service of service_list) {
198
- const char_list = await this.discoverCharacteristics(service);
199
- for (const char of char_list) {
120
+ const services = await this.discoverServices();
121
+ const chars = { write: null, notify: null, device: null };
122
+ for (const service of services) {
123
+ const characteristics = await this.discoverCharacteristics(service);
124
+ for (const char of characteristics) {
200
125
  if (char.uuid === CHAR_UUID_WRITE) {
201
126
  chars.write = char;
202
127
  }
203
- else if (char.uuid === CHAR_UUID_NOTIFY) {
128
+ if (char.uuid === CHAR_UUID_NOTIFY) {
204
129
  chars.notify = char;
205
130
  }
206
- else if (char.uuid === CHAR_UUID_DEVICE) {
207
- // Some models of Bot don't seem to support this characteristic UUID
131
+ if (char.uuid === CHAR_UUID_DEVICE) {
208
132
  chars.device = char;
209
133
  }
210
134
  }
@@ -214,80 +138,48 @@ export class SwitchbotDevice {
214
138
  }
215
139
  return chars;
216
140
  }
217
- catch (error) {
218
- if (timer) {
219
- clearTimeout(timer);
220
- this.ondisconnect_internal = () => { };
221
- }
222
- throw error;
223
- }
224
141
  finally {
225
- if (timer) {
226
- clearTimeout(timer);
227
- this.ondisconnect_internal = () => { };
228
- }
142
+ clearTimeout(timer);
229
143
  }
230
144
  }
145
+ /**
146
+ * Discovers the device services.
147
+ * @returns A Promise that resolves with the list of services.
148
+ */
231
149
  async discoverServices() {
232
- return await this._peripheral.discoverServicesAsync([])
233
- .then((service_list) => {
234
- const services = service_list.filter((s) => s.uuid === SERV_UUID_PRIMARY);
235
- if (services.length === 0) {
236
- throw new Error('No service was found.');
237
- }
238
- return services;
239
- })
240
- .catch((error) => {
241
- throw error;
242
- });
150
+ const services = await this._peripheral.discoverServicesAsync([]);
151
+ const primaryServices = services.filter(s => s.uuid === SERV_UUID_PRIMARY);
152
+ if (primaryServices.length === 0) {
153
+ throw new Error('No service was found.');
154
+ }
155
+ return primaryServices;
243
156
  }
244
157
  /**
245
- * Asynchronously discovers the characteristics of the specified service.
246
- * This method is an asynchronous version of the deprecated `discoverCharacteristics` method.
247
- * It attempts to discover the characteristics of the specified service and returns a Promise that resolves with the list of characteristics.
248
- * If the discovery process fails, the Promise is rejected with an error.
249
- * @param service The service object for which characteristics will be discovered.
250
- * @returns A Promise that resolves with the list of characteristics or rejects with an error.
158
+ * Discovers the characteristics of a service.
159
+ * @param service The service to discover characteristics for.
160
+ * @returns A Promise that resolves with the list of characteristics.
251
161
  */
252
162
  async discoverCharacteristics(service) {
253
- return service.discoverCharacteristicsAsync([])
254
- .then((char_list) => {
255
- return char_list;
256
- })
257
- .catch((error) => {
258
- throw error;
259
- });
163
+ return await service.discoverCharacteristicsAsync([]);
260
164
  }
165
+ /**
166
+ * Subscribes to the notify characteristic.
167
+ * @returns A Promise that resolves when the subscription is complete.
168
+ */
261
169
  async subscribe() {
262
- const char = this._characteristics ? this._characteristics.notify : null;
170
+ const char = this._characteristics?.notify;
263
171
  if (!char) {
264
172
  throw new Error('No notify characteristic was found.');
265
173
  }
266
- char.subscribeAsync()
267
- .then(() => {
268
- char.on('data', (buf) => {
269
- this.onnotify_internal(buf);
270
- });
271
- })
272
- .catch((error) => {
273
- throw error;
274
- });
174
+ await char.subscribeAsync();
175
+ char.on('data', this.onnotify_internal);
275
176
  }
276
177
  /**
277
- * Asynchronously unsubscribes from the device's notification characteristic.
278
- *
279
- * This method checks if the notification characteristic object exists within the cached characteristics
280
- * (`this.chars`). If the characteristic is found, it proceeds to remove all event listeners attached to it
281
- * to prevent any further handling of incoming data notifications. Then, it asynchronously unsubscribes from
282
- * the notification characteristic using `unsubscribeAsync()`, effectively stopping the device from sending
283
- * notifications to the client.
284
- *
285
- * If the notification characteristic is not found, the method simply returns without performing any action.
286
- *
287
- * @return A Promise that resolves to `void` upon successful unsubscription or if the characteristic is not found.
178
+ * Unsubscribes from the notify characteristic.
179
+ * @returns A Promise that resolves when the unsubscription is complete.
288
180
  */
289
181
  async unsubscribe() {
290
- const char = this._characteristics ? this._characteristics.notify : null;
182
+ const char = this._characteristics?.notify;
291
183
  if (!char) {
292
184
  return;
293
185
  }
@@ -295,188 +187,73 @@ export class SwitchbotDevice {
295
187
  await char.unsubscribeAsync();
296
188
  }
297
189
  /**
298
- * Asynchronously disconnects from the device.
299
- *
300
- * This method handles the disconnection process by first checking the current
301
- * connection state of the device. If the device is already disconnected, the
302
- * method resolves immediately. If the device is in the process of connecting or
303
- * disconnecting, it throws an error indicating that the operation should be retried
304
- * after a brief wait. Otherwise, it proceeds to unsubscribe from any subscriptions
305
- * and then initiates the disconnection process.
306
- *
307
- * Note: This method sets a flag to indicate that the disconnection was not initiated
308
- * by the user explicitly.
309
- *
310
- * @returns A Promise that resolves when the disconnection process has completed.
311
- * The Promise does not pass any value upon resolution.
190
+ * Disconnects from the device.
191
+ * @returns A Promise that resolves when the disconnection is complete.
312
192
  */
313
193
  async disconnect() {
314
194
  this._explicitly = false;
315
195
  const state = this._peripheral.state;
316
196
  if (state === 'disconnected') {
317
- return; // Resolves the promise implicitly
197
+ return;
318
198
  }
319
- else if (state === 'connecting' || state === 'disconnecting') {
199
+ if (state === 'connecting' || state === 'disconnecting') {
320
200
  throw new Error(`Now ${state}. Wait for a few seconds then try again.`);
321
201
  }
322
- await this.unsubscribe(); // Wait for unsubscribe to complete
202
+ await this.unsubscribe();
323
203
  await this._peripheral.disconnectAsync();
324
204
  }
325
205
  /**
326
- * Disconnects from the device asynchronously if the connection was not initiated by the user.
327
- *
328
- * This method checks the `explicitly` flag to determine if the connection was initiated by the user.
329
- * If not, it proceeds to disconnect from the device by calling `this.disconnectAsync()`. After the disconnection,
330
- * it sets `explicitly` to true to prevent future disconnections when the connection is user-initiated.
331
- *
332
- * This approach ensures that automatic disconnections only occur when the user has not explicitly initiated the connection,
333
- * avoiding unnecessary disconnections in user-initiated sessions.
334
- *
335
- * @returns A Promise that resolves once the device has been successfully disconnected, applicable only when the
336
- * connection was not user-initiated.
206
+ * Internal method to handle disconnection if not explicitly initiated.
207
+ * @returns A Promise that resolves when the disconnection is complete.
337
208
  */
338
209
  async disconnect_internal() {
339
210
  if (!this._explicitly) {
340
211
  await this.disconnect();
341
- this._explicitly = true; // Ensure this condition is updated to prevent re-entry or incorrect logic flow.
212
+ this._explicitly = true;
342
213
  }
343
214
  }
344
215
  /**
345
- * Asynchronously retrieves the device name.
346
- * This method is designed to fetch the name of the device asynchronously and return it as a promise.
347
- * It is marked as deprecated and will be removed in a future version. Use `getDeviceNameAsync` instead.
348
- *
349
- * @deprecated since version 2.4.0. Will be removed in version 3.0.0. Use `getDeviceNameAsync()` instead.
216
+ * Retrieves the device name.
350
217
  * @returns A Promise that resolves with the device name.
351
218
  */
352
219
  async getDeviceName() {
353
- let name = '';
354
- await this.connect_internal()
355
- .then(async () => {
356
- if (!this._characteristics || !this._characteristics.device) {
357
- // Some models of Bot don't seem to support this characteristic UUID
358
- throw new Error(`The device does not support the characteristic UUID 0x${CHAR_UUID_DEVICE}.`);
359
- }
360
- return await this.read(this._characteristics.device);
361
- })
362
- .then((buf) => {
363
- name = buf.toString('utf8');
364
- return this.disconnect_internal();
365
- })
366
- .then(() => {
367
- return name;
368
- })
369
- .catch((error) => {
370
- throw new Error(error);
371
- });
372
- }
373
- /**
374
- * Asynchronously retrieves the device name.
375
- * This method initiates a connection to the device, checks for the presence of a specific characteristic UUID,
376
- * reads the characteristic to obtain the device name, and then disconnects from the device.
377
- * It ensures that the device supports the required characteristic for fetching the name. If the characteristic
378
- * is not supported, it throws an error. The method encapsulates the entire process of connecting, reading,
379
- * and disconnecting, making it convenient to get the device name with a single call.
380
- *
381
- * @returns A Promise that resolves with the device name as a string.
382
- */
383
- async getDeviceNameAsnyc() {
384
220
  await this.connect_internal();
385
- if (!this._characteristics || !this._characteristics.device) {
221
+ if (!this._characteristics?.device) {
386
222
  throw new Error(`The device does not support the characteristic UUID 0x${CHAR_UUID_DEVICE}.`);
387
223
  }
388
224
  const buf = await this.read(this._characteristics.device);
389
- const name = buf.toString('utf8');
390
225
  await this.disconnect_internal();
391
- return name;
392
- }
393
- /**
394
- * Asynchronously sets the device name to the specified value.
395
- * Validates the new name to ensure it meets the criteria of being a string with a byte length between 1 and 100 bytes.
396
- * If the validation fails, the promise is rejected with an error detailing the validation issue.
397
- * Upon successful validation, the device name is updated, and the promise resolves without passing any value.
398
- *
399
- * @param name The new device name as a string. Must be 1 to 100 bytes in length.
400
- * @returns A Promise that resolves to `void` upon successful update of the device name.
401
- * @deprecated since version 2.4.0. Will be removed in version 3.0.0. Use `setDeviceNameAsync()` instead.
402
- */
403
- setDeviceName(name) {
404
- return new Promise((resolve, reject) => {
405
- // Check the parameters
406
- const valid = parameterChecker.check({ name }, {
407
- name: { required: true, type: 'string', minBytes: 1, maxBytes: 100 },
408
- }, true);
409
- if (!valid) {
410
- reject(new Error(parameterChecker.error.message));
411
- return;
412
- }
413
- const buf = Buffer.from(name, 'utf8');
414
- this.connect_internal()
415
- .then(() => {
416
- if (!this._characteristics || !this._characteristics.device) {
417
- // Some models of Bot don't seem to support this characteristic UUID
418
- throw new Error(`The device does not support the characteristic UUID 0x${CHAR_UUID_DEVICE}.`);
419
- }
420
- return this.write(this._characteristics.device, buf);
421
- })
422
- .then(() => {
423
- return this.disconnect_internal();
424
- })
425
- .then(() => {
426
- return;
427
- resolve();
428
- })
429
- .catch((error) => {
430
- throw new Error(error);
431
- });
432
- });
226
+ return buf.toString('utf8');
433
227
  }
434
228
  /**
435
- * Asynchronously sets the device name to the specified value.
436
- * This method begins by validating the provided name to ensure it meets the criteria of being a string with a byte length between 1 and 100 bytes.
437
- * If the name does not pass validation, the method throws an error with a message detailing the validation issue.
438
- * After passing validation, the method converts the name into a UTF-8 encoded buffer.
439
- * It then initiates a connection to the device. If the device does not support the required characteristic UUID for setting the device name,
440
- * an error is thrown indicating the lack of support.
441
- * Upon successfully connecting and verifying support, the method writes the new name to the device using the appropriate characteristic.
442
- * Finally, it disconnects from the device, completing the name update process.
443
- *
444
- * @param name The new device name as a string. Must be 1 to 100 bytes in length.
445
- * @returns A Promise that resolves to `void` upon successful update of the device name.
229
+ * Sets the device name.
230
+ * @param name The new device name.
231
+ * @returns A Promise that resolves when the name is set.
446
232
  */
447
- async setDeviceNameAsync(name) {
448
- // Check the parameters
449
- const valid = parameterChecker.check({ name }, {
450
- name: { required: true, type: 'string', minBytes: 1, maxBytes: 100 },
451
- }, true);
233
+ async setDeviceName(name) {
234
+ const valid = parameterChecker.check({ name }, { name: { required: true, type: 'string', minBytes: 1, maxBytes: 100 } }, true);
452
235
  if (!valid) {
453
236
  throw new Error(parameterChecker.error.message);
454
237
  }
455
238
  const buf = Buffer.from(name, 'utf8');
456
239
  await this.connect_internal();
457
- if (!this._characteristics || !this._characteristics.device) {
458
- // Some models of Bot don't seem to support this characteristic UUID
240
+ if (!this._characteristics?.device) {
459
241
  throw new Error(`The device does not support the characteristic UUID 0x${CHAR_UUID_DEVICE}.`);
460
242
  }
461
243
  await this.write(this._characteristics.device, buf);
462
244
  await this.disconnect_internal();
463
245
  }
464
246
  /**
465
- * Asynchronously sends a command to the device and awaits a response.
466
- * This method encapsulates the process of sending a command encapsulated in a Buffer to the device,
467
- * and then waiting for the device to respond. The method ensures that the device is connected before sending the command,
468
- * writes the command to the device's write characteristic, waits for a response on the notify characteristic,
469
- * and finally disconnects from the device. The response from the device is returned as a Buffer.
470
- *
471
- * @param req_buf A Buffer containing the command to be sent to the device.
472
- * @returns A Promise that resolves with a Buffer containing the device's response to the command.
247
+ * Sends a command to the device and awaits a response.
248
+ * @param req_buf The command buffer.
249
+ * @returns A Promise that resolves with the response buffer.
473
250
  */
474
251
  async command(req_buf) {
475
252
  if (!Buffer.isBuffer(req_buf)) {
476
253
  throw new TypeError('The specified data is not acceptable for writing.');
477
254
  }
478
255
  await this.connect_internal();
479
- if (!this._characteristics || !this._characteristics.write) {
256
+ if (!this._characteristics?.write) {
480
257
  throw new Error('No characteristics available.');
481
258
  }
482
259
  await this.write(this._characteristics.write, req_buf);
@@ -486,122 +263,61 @@ export class SwitchbotDevice {
486
263
  }
487
264
  /**
488
265
  * Waits for a response from the device after sending a command.
489
- * This method sets up a promise that resolves when a response is received from the device or rejects if a timeout occurs.
490
- * A timer is started to enforce a command timeout. If the response is received before the timeout, the timer is cleared.
491
- * The method sets an internal handler (`onnotify_internal`) to process the incoming response.
492
- * If the response is not received within the specified timeout period, the promise is rejected with a 'COMMAND_TIMEOUT' error.
493
- * Once a response is received or a timeout occurs, the internal handler is reset to an empty function to prevent memory leaks.
494
- * @deprecated since version 2.4.0. Will be removed in version 3.0.0. Use `_waitCommandResponseAsync()` instead.
495
- *
496
- * @returns A Promise that resolves with the received Buffer or rejects with an error if a timeout occurs.
266
+ * @returns A Promise that resolves with the response buffer.
497
267
  */
498
- _waitCommandResponse() {
499
- return new Promise((resolve, reject) => {
500
- let timer = setTimeout(() => {
501
- timer = undefined;
502
- this.onnotify_internal = () => { };
503
- reject(new Error('COMMAND_TIMEOUT'));
504
- }, COMMAND_TIMEOUT_MSEC);
268
+ async _waitCommandResponseAsync() {
269
+ const timeout = READ_TIMEOUT_MSEC;
270
+ let timer = null;
271
+ const timeoutPromise = new Promise((_, reject) => {
272
+ timer = setTimeout(() => reject(new Error('READ_TIMEOUT')), timeout);
273
+ });
274
+ const readPromise = new Promise((resolve) => {
505
275
  this.onnotify_internal = (buf) => {
506
276
  if (timer) {
507
277
  clearTimeout(timer);
508
- timer = undefined;
509
278
  }
510
- this.onnotify_internal = () => { };
511
- return buf;
279
+ resolve(buf);
512
280
  };
513
281
  });
282
+ return await Promise.race([readPromise, timeoutPromise]);
514
283
  }
515
284
  /**
516
- * Asynchronously waits for a response from the device after sending a command.
517
- * This method sets up a promise that resolves when a response is received from the device or rejects if a timeout occurs.
518
- * A timer is started to enforce a command timeout. If the response is received before the timeout, the timer is cleared.
519
- * The method sets an internal handler (`onnotify_internalAsync`) to process the incoming response.
520
- * If the response is not received within the specified timeout period, the promise is rejected with a 'COMMAND_TIMEOUT' error.
521
- * Once a response is received or a timeout occurs, the internal handler is reset to an empty function to prevent memory leaks.
522
- *
523
- * @returns A Promise that resolves with the received Buffer or rejects with an error if a timeout occurs.
524
- */
525
- async _waitCommandResponseAsync() {
526
- const timeout = READ_TIMEOUT_MSEC; // Timeout period in milliseconds
527
- let timer = null;
528
- // Setup a timeout to reject the operation if it takes too long
529
- const timeoutPromise = new Promise((_, reject) => {
530
- timer = setTimeout(() => reject(new Error('READ_TIMEOUT')), timeout);
531
- });
532
- // Setup the read operation promise
533
- const readPromise = await this.onnotify_internal();
534
- // Wait for either the read operation to complete or the timeout to occur
535
- const result = await Promise.race([readPromise, timeoutPromise]);
536
- // Clear the timeout if the read operation completes successfully
537
- if (timer) {
538
- clearTimeout(timer);
539
- }
540
- return result;
541
- }
542
- /**
543
- * Asynchronously reads data from the specified characteristic of the device with a timeout.
544
- * This method attempts to read data from the device's characteristic and sets a timeout to handle cases where the read operation takes too long.
545
- * If the read operation does not complete within the specified timeout period, an error is thrown.
546
- * Once the read operation completes successfully, the timeout is cleared to prevent it from triggering.
547
- *
548
- * @param char The characteristic of the device from which data will be read.
549
- * @returns A Promise that resolves with the data read from the characteristic or rejects with an error if a timeout occurs.
550
- *
551
- * @throws Error if the read operation fails or if a timeout occurs.
285
+ * Reads data from a characteristic with a timeout.
286
+ * @param char The characteristic to read from.
287
+ * @returns A Promise that resolves with the data buffer.
552
288
  */
553
289
  async read(char) {
554
- let timer = setTimeout(() => {
290
+ const timer = setTimeout(() => {
555
291
  throw new Error('READ_TIMEOUT');
556
292
  }, READ_TIMEOUT_MSEC);
557
- // Setup the read operation promise
558
- const readPromise = await char.readAsync()
559
- .then((result) => {
560
- if (timer) {
561
- clearTimeout(timer);
562
- timer = undefined;
563
- }
564
- else {
565
- throw new Error('READ_TIMEOUT');
566
- }
293
+ try {
294
+ const result = await char.readAsync();
295
+ clearTimeout(timer);
567
296
  return result;
568
- });
569
- // Wait for either the read operation to complete or the timeout to occur
570
- const result = await Promise.race([readPromise, timer]);
571
- // Clear the timeout if the read operation completes successfully
572
- if (timer) {
297
+ }
298
+ catch (error) {
573
299
  clearTimeout(timer);
300
+ throw error;
574
301
  }
575
- return result;
576
302
  }
577
303
  /**
578
- * Asynchronously writes data to a specified characteristic of the device.
579
- * This method sends a buffer of data to the device's characteristic and sets a timeout to handle cases where the write operation takes too long.
580
- * If the write operation does not complete within the specified timeout period, an error is thrown.
581
- * Once the write operation completes successfully, the timeout is cleared to prevent it from triggering.
582
- *
583
- * @param char The characteristic of the device to which the data will be written.
584
- * @param buf A Buffer containing the data to be written to the device.
585
- * @returns A Promise that resolves when the write operation completes successfully or rejects with an error if a timeout occurs.
304
+ * Writes data to a characteristic with a timeout.
305
+ * @param char The characteristic to write to.
306
+ * @param buf The data buffer.
307
+ * @returns A Promise that resolves when the write is complete.
586
308
  */
587
309
  async write(char, buf) {
588
- let timer = setTimeout(() => {
310
+ const timer = setTimeout(() => {
589
311
  throw new Error('WRITE_TIMEOUT');
590
312
  }, WRITE_TIMEOUT_MSEC);
591
- // write characteristic data
592
- await char.writeAsync(buf, false)
593
- .then(() => {
594
- if (timer) {
595
- clearTimeout(timer);
596
- timer = undefined;
597
- }
598
- else {
599
- throw new Error('READ_TIMEOUT');
600
- }
601
- })
602
- .catch((error) => {
603
- throw new Error(`WRITE_TIMEOUT, ${error}`);
604
- });
313
+ try {
314
+ await char.writeAsync(buf, false);
315
+ clearTimeout(timer);
316
+ }
317
+ catch (error) {
318
+ clearTimeout(timer);
319
+ throw error;
320
+ }
605
321
  }
606
322
  }
607
323
  //# sourceMappingURL=device.js.map