From 76846be64d96a5cd1709e20574e24f7ebf8d4b40 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:21:18 +0100 Subject: [PATCH 1/8] "undefined" can also be a valid value to return on get when no value came back --- index.d.ts | 2 +- index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 1cfe04f..9b66596 100644 --- a/index.d.ts +++ b/index.d.ts @@ -75,7 +75,7 @@ declare module 'tuyapi' { disconnect(): void; isConnected(): boolean; - get(options: GetOptions): Promise; + get(options: GetOptions): Promise; refresh(options: RefreshOptions): Promise; set(options: SingleSetOptions|MultipleSetOptions): Promise; toggle(property: number): Promise; diff --git a/index.js b/index.js index 5821cd8..e69fd8c 100644 --- a/index.js +++ b/index.js @@ -131,7 +131,7 @@ class TuyaDevice extends EventEmitter { * @example * // get all available data from device * tuya.get({schema: true}).then(data => console.log(data)) - * @returns {Promise} + * @returns {Promise} * returns boolean if single property is requested, otherwise returns object of results */ async get(options = {}) { @@ -183,7 +183,7 @@ class TuyaDevice extends EventEmitter { data = await this.set(setOptions); } - if (typeof data !== 'object' || options.schema === true) { + if (data === undefined || typeof data !== 'object' || options.schema === true) { // Return whole response return data; } From e183901066c19df369eef1ec42719e9359408366 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:25:06 +0100 Subject: [PATCH 2/8] Move the set check to the right place ... because it only matters if we want to really process a set if tthere is another one somehow "still in progress". Makes no sense to check this before the set is queued --- index.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index e69fd8c..4e23751 100644 --- a/index.js +++ b/index.js @@ -392,10 +392,6 @@ class TuyaDevice extends EventEmitter { delete payload.data.t; } - if (options.shouldWaitForResponse && this._setResolver) { - throw new Error('A set command is already in progress. Can not issue a second one that also should return a response.'); - } - debug('SET Payload:'); debug(payload); @@ -411,8 +407,10 @@ class TuyaDevice extends EventEmitter { // Queue this request and limit concurrent set requests to one return this._setQueue.add(() => pTimeout(new Promise((resolve, reject) => { - // Make sure we only resolve or reject once - let resolvedOrRejected = false; + + if (options.shouldWaitForResponse && this._setResolver) { + throw new Error('A set command is already in progress. Can not issue a second one that also should return a response.'); + } // Send request and wait for response try { From eb0024705d87a193c4175157b8c471f82535db2c Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:28:37 +0100 Subject: [PATCH 3/8] set: Enhance reject or resolve checks --- index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/index.js b/index.js index 4e23751..3749aab 100644 --- a/index.js +++ b/index.js @@ -405,6 +405,9 @@ class TuyaDevice extends EventEmitter { sequenceN }); + // Make sure we only resolve or reject once + let resolvedOrRejected = false; + // Queue this request and limit concurrent set requests to one return this._setQueue.add(() => pTimeout(new Promise((resolve, reject) => { @@ -421,12 +424,14 @@ class TuyaDevice extends EventEmitter { // Send request this._send(buffer).catch(error => { if (options.shouldWaitForResponse && !resolvedOrRejected) { + resolvedOrRejected = true; reject(error); } }); if (options.shouldWaitForResponse) { this._setResolver = data => { if (!resolvedOrRejected) { + resolvedOrRejected = true; resolve(data); } }; From 566b4d5cead4645ad58508f953eabfa745abcdeb Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:30:30 +0100 Subject: [PATCH 4/8] Infos --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 3749aab..5a5410e 100644 --- a/index.js +++ b/index.js @@ -456,6 +456,7 @@ class TuyaDevice extends EventEmitter { 'error', 'Timeout waiting for status response from device id: ' + this.device.id ); + // This case returns an undefined when set-for-get is used! })); } @@ -465,7 +466,7 @@ class TuyaDevice extends EventEmitter { * wraps the entire operation in a retry. * @private * @param {Buffer} buffer buffer of data - * @returns {Promise} returned data for request + * @returns {Promise} returned data for request */ _send(buffer) { const sequenceNo = this._currentSequenceN; From 04a71e021ef52737145637a23355bf0e01252689 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:30:57 +0100 Subject: [PATCH 5/8] Infos --- index.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 5a5410e..d5b8a91 100644 --- a/index.js +++ b/index.js @@ -457,6 +457,7 @@ class TuyaDevice extends EventEmitter { 'Timeout waiting for status response from device id: ' + this.device.id ); // This case returns an undefined when set-for-get is used! + // Alternative would be to throw but this would be breaking. })); } @@ -568,13 +569,19 @@ class TuyaDevice extends EventEmitter { // Automatically ask for dp_refresh so we // can emit a `dp_refresh` event as soon as possible if (this.globalOptions.issueRefreshOnConnect) { - this.refresh(); + this.refresh().catch(error => { + debug('Error refreshing on connect: ' + error); + this.emit('error', error); + }); } // Automatically ask for current state so we // can emit a `data` event as soon as possible if (this.globalOptions.issueGetOnConnect) { - this.get(); + this.get().catch(error => { + debug('Error getting on connect: ' + error) + this.emit('error', error); + }); } // Resolve From c67a4dcd3beb01349153b10c2ba5cb6ad7488172 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:34:51 +0100 Subject: [PATCH 6/8] Revert ""undefined" can also be a valid value to return on get when no value came back" This reverts commit 76846be64d96a5cd1709e20574e24f7ebf8d4b40. --- index.d.ts | 2 +- index.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/index.d.ts b/index.d.ts index 9b66596..1cfe04f 100644 --- a/index.d.ts +++ b/index.d.ts @@ -75,7 +75,7 @@ declare module 'tuyapi' { disconnect(): void; isConnected(): boolean; - get(options: GetOptions): Promise; + get(options: GetOptions): Promise; refresh(options: RefreshOptions): Promise; set(options: SingleSetOptions|MultipleSetOptions): Promise; toggle(property: number): Promise; diff --git a/index.js b/index.js index d5b8a91..e83fa65 100644 --- a/index.js +++ b/index.js @@ -131,7 +131,7 @@ class TuyaDevice extends EventEmitter { * @example * // get all available data from device * tuya.get({schema: true}).then(data => console.log(data)) - * @returns {Promise} + * @returns {Promise} * returns boolean if single property is requested, otherwise returns object of results */ async get(options = {}) { @@ -183,7 +183,7 @@ class TuyaDevice extends EventEmitter { data = await this.set(setOptions); } - if (data === undefined || typeof data !== 'object' || options.schema === true) { + if (typeof data !== 'object' || options.schema === true) { // Return whole response return data; } From 821cc526beb6e4b02c9d13ac3685fa2c66bc0943 Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:36:38 +0100 Subject: [PATCH 7/8] Set will throw on timeouts --- index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index e83fa65..ff92ebf 100644 --- a/index.js +++ b/index.js @@ -456,8 +456,10 @@ class TuyaDevice extends EventEmitter { 'error', 'Timeout waiting for status response from device id: ' + this.device.id ); - // This case returns an undefined when set-for-get is used! - // Alternative would be to throw but this would be breaking. + if (!resolvedOrRejected) { + resolvedOrRejected = true; + throw new Error('Timeout waiting for status response from device id: ' + this.device.id); + } })); } From 960babe7d771537b5baceef7ed2012fd1ef9e91f Mon Sep 17 00:00:00 2001 From: Ingo Fischer Date: Mon, 6 Jan 2025 13:39:49 +0100 Subject: [PATCH 8/8] linter --- index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.js b/index.js index ff92ebf..2c12c9b 100644 --- a/index.js +++ b/index.js @@ -410,7 +410,6 @@ class TuyaDevice extends EventEmitter { // Queue this request and limit concurrent set requests to one return this._setQueue.add(() => pTimeout(new Promise((resolve, reject) => { - if (options.shouldWaitForResponse && this._setResolver) { throw new Error('A set command is already in progress. Can not issue a second one that also should return a response.'); } @@ -581,7 +580,7 @@ class TuyaDevice extends EventEmitter { // can emit a `data` event as soon as possible if (this.globalOptions.issueGetOnConnect) { this.get().catch(error => { - debug('Error getting on connect: ' + error) + debug('Error getting on connect: ' + error); this.emit('error', error); }); }