@@ -177,7 +177,8 @@ class TuyaDevice extends EventEmitter {
177
177
debug ( 'GET needs to use SEND instead of DP_QUERY to get data' ) ;
178
178
const setOptions = {
179
179
dps : options . dps ? options . dps : 1 ,
180
- set : null
180
+ set : null ,
181
+ isSetCallToGetData : true
181
182
} ;
182
183
data = await this . set ( setOptions ) ;
183
184
}
@@ -233,18 +234,20 @@ class TuyaDevice extends EventEmitter {
233
234
payload . cid = options . cid ;
234
235
}
235
236
236
- debug ( 'GET Payload:' ) ;
237
+ debug ( 'GET Payload (refresh) :' ) ;
237
238
debug ( payload ) ;
238
239
240
+ const sequenceN = ++ this . _currentSequenceN ;
239
241
// Create byte buffer
240
242
const buffer = this . device . parser . encode ( {
241
243
data : payload ,
242
244
commandByte : CommandType . DP_REFRESH ,
243
- sequenceN : ++ this . _currentSequenceN
245
+ sequenceN
244
246
} ) ;
245
247
246
248
// Send request and parse response
247
249
return new Promise ( ( resolve , reject ) => {
250
+ this . _expectRefreshResponseForSequenceN = sequenceN ;
248
251
// Send request
249
252
this . _send ( buffer ) . then ( async data => {
250
253
if ( data === 'json obj data unvalid' ) {
@@ -254,7 +257,8 @@ class TuyaDevice extends EventEmitter {
254
257
// For schema there's currently no fallback options
255
258
const setOptions = {
256
259
dps : options . requestedDPS ? options . requestedDPS : this . _dpRefreshIds ,
257
- set : null
260
+ set : null ,
261
+ isSetCallToGetData : true
258
262
} ;
259
263
data = await this . set ( setOptions ) ;
260
264
}
@@ -283,6 +287,8 @@ class TuyaDevice extends EventEmitter {
283
287
* if specified, use device id of zigbee gateway and cid of subdevice to set its property
284
288
* @param {Boolean } [options.multiple=false]
285
289
* Whether or not multiple properties should be set with options.data
290
+ * @param {Boolean } [options.isSetCallToGetData=false]
291
+ * Wether or not the set command is used to get data
286
292
* @param {Object } [options.data={}] Multiple properties to set at once. See above.
287
293
* @param {Boolean } [options.shouldWaitForResponse=true] see
288
294
* [#420](https://github.com/codetheweb/tuyapi/issues/420) and
@@ -333,6 +339,14 @@ class TuyaDevice extends EventEmitter {
333
339
334
340
options . shouldWaitForResponse = typeof options . shouldWaitForResponse === 'undefined' ? true : options . shouldWaitForResponse ;
335
341
342
+ // When set has only null values then it is used to get data
343
+ if ( ! options . isSetCallToGetData ) {
344
+ options . isSetCallToGetData = true ;
345
+ Object . keys ( dps ) . forEach ( key => {
346
+ options . isSetCallToGetData = options . isSetCallToGetData && dps [ key ] === null ;
347
+ } ) ;
348
+ }
349
+
336
350
// Get time
337
351
const timeStamp = parseInt ( Date . now ( ) / 1000 , 10 ) ;
338
352
@@ -378,16 +392,21 @@ class TuyaDevice extends EventEmitter {
378
392
delete payload . data . t ;
379
393
}
380
394
395
+ if ( options . shouldWaitForResponse && this . _setResolver ) {
396
+ throw new Error ( 'A set command is already in progress. Can not issue a second one that also should return a response.' ) ;
397
+ }
398
+
381
399
debug ( 'SET Payload:' ) ;
382
400
debug ( payload ) ;
383
401
384
402
const commandByte = this . device . version === '3.4' ? CommandType . CONTROL_NEW : CommandType . CONTROL ;
403
+ const sequenceN = ++ this . _currentSequenceN ;
385
404
// Encode into packet
386
405
const buffer = this . device . parser . encode ( {
387
406
data : payload ,
388
407
encrypted : true , // Set commands must be encrypted
389
408
commandByte,
390
- sequenceN : ++ this . _currentSequenceN
409
+ sequenceN
391
410
} ) ;
392
411
393
412
// Queue this request and limit concurrent set requests to one
@@ -398,6 +417,7 @@ class TuyaDevice extends EventEmitter {
398
417
this . _send ( buffer ) ;
399
418
if ( options . shouldWaitForResponse ) {
400
419
this . _setResolver = resolve ;
420
+ this . _setResolveAllowGet = options . isSetCallToGetData ;
401
421
} else {
402
422
resolve ( ) ;
403
423
}
@@ -407,6 +427,9 @@ class TuyaDevice extends EventEmitter {
407
427
} ) , this . _responseTimeout * 2500 , ( ) => {
408
428
// Only gets here on timeout so clear resolver function and emit error
409
429
this . _setResolver = undefined ;
430
+ this . _setResolveAllowGet = undefined ;
431
+ delete this . _resolvers [ sequenceN ] ;
432
+ this . _expectRefreshResponseForSequenceN = undefined ;
410
433
411
434
this . emit (
412
435
'error' ,
@@ -424,6 +447,7 @@ class TuyaDevice extends EventEmitter {
424
447
* @returns {Promise<Any> } returned data for request
425
448
*/
426
449
_send ( buffer ) {
450
+ const sequenceNo = this . _currentSequenceN ;
427
451
// Retry up to 5 times
428
452
return pRetry ( ( ) => {
429
453
return new Promise ( ( resolve , reject ) => {
@@ -433,7 +457,7 @@ class TuyaDevice extends EventEmitter {
433
457
this . client . write ( buffer ) ;
434
458
435
459
// Add resolver function
436
- this . _resolvers [ this . _currentSequenceN ] = data => resolve ( data ) ;
460
+ this . _resolvers [ sequenceNo ] = data => resolve ( data ) ;
437
461
} catch ( error ) {
438
462
reject ( error ) ;
439
463
}
@@ -756,7 +780,36 @@ class TuyaDevice extends EventEmitter {
756
780
757
781
// Returned DP refresh response is always empty. Device respond with command 8 without dps 1 instead.
758
782
if ( packet . commandByte === CommandType . DP_REFRESH ) {
759
- debug ( 'Received DP_REFRESH empty response packet.' ) ;
783
+ // If we did not get any STATUS packet, we need to resolve the promise.
784
+ if ( typeof this . _setResolver === 'function' ) {
785
+ debug ( 'Received DP_REFRESH empty response packet without STATUS packet from set command - resolve' ) ;
786
+ this . _setResolver ( packet . payload ) ;
787
+
788
+ // Remove resolver
789
+ this . _setResolver = undefined ;
790
+ this . _setResolveAllowGet = undefined ;
791
+ delete this . _resolvers [ packet . sequenceN ] ;
792
+ this . _expectRefreshResponseForSequenceN = undefined ;
793
+ } else {
794
+ // Call data resolver for sequence number
795
+ if ( packet . sequenceN in this . _resolvers ) {
796
+ debug ( 'Received DP_REFRESH response packet - resolve' ) ;
797
+ this . _resolvers [ packet . sequenceN ] ( packet . payload ) ;
798
+
799
+ // Remove resolver
800
+ delete this . _resolvers [ packet . sequenceN ] ;
801
+ this . _expectRefreshResponseForSequenceN = undefined ;
802
+ } else if ( this . _expectRefreshResponseForSequenceN && this . _expectRefreshResponseForSequenceN in this . _resolvers ) {
803
+ debug ( 'Received DP_REFRESH response packet without data - resolve' ) ;
804
+ this . _resolvers [ this . _expectRefreshResponseForSequenceN ] ( packet . payload ) ;
805
+
806
+ // Remove resolver
807
+ delete this . _resolvers [ this . _expectRefreshResponseForSequenceN ] ;
808
+ this . _expectRefreshResponseForSequenceN = undefined ;
809
+ } else {
810
+ debug ( 'Received DP_REFRESH response packet - no resolver found for sequence number' + packet . sequenceN ) ;
811
+ }
812
+ }
760
813
return ;
761
814
}
762
815
@@ -788,16 +841,33 @@ class TuyaDevice extends EventEmitter {
788
841
}
789
842
790
843
// Status response to SET command
791
-
792
- // 3.4 response sequenceN is not '0' just next TODO verify
793
- if ( /* Former code: packet.sequenceN === 0 && */
844
+ if (
794
845
packet . commandByte === CommandType . STATUS &&
795
846
typeof this . _setResolver === 'function'
796
847
) {
797
848
this . _setResolver ( packet . payload ) ;
798
849
799
850
// Remove resolver
800
851
this . _setResolver = undefined ;
852
+ this . _setResolveAllowGet = undefined ;
853
+ delete this . _resolvers [ packet . sequenceN ] ;
854
+ this . _expectRefreshResponseForSequenceN = undefined ;
855
+ return ;
856
+ }
857
+
858
+ // Status response to SET command which was used to GET data and returns DP_QUERY response
859
+ if (
860
+ packet . commandByte === CommandType . DP_QUERY &&
861
+ typeof this . _setResolver === 'function' &&
862
+ this . _setResolveAllowGet === true
863
+ ) {
864
+ this . _setResolver ( packet . payload ) ;
865
+
866
+ // Remove resolver
867
+ this . _setResolver = undefined ;
868
+ this . _setResolveAllowGet = undefined ;
869
+ delete this . _resolvers [ packet . sequenceN ] ;
870
+ this . _expectRefreshResponseForSequenceN = undefined ;
801
871
return ;
802
872
}
803
873
@@ -807,6 +877,7 @@ class TuyaDevice extends EventEmitter {
807
877
808
878
// Remove resolver
809
879
delete this . _resolvers [ packet . sequenceN ] ;
880
+ this . _expectRefreshResponseForSequenceN = undefined ;
810
881
}
811
882
}
812
883
0 commit comments