tuyapi: Payload returns nulls
Describe the bug Null payload informations returned
To Reproduce
- Run async example node asyn.js (https://github.com/codetheweb/tuyapi)
const TuyAPI = require('tuyapi');
const device = new TuyAPI({
id: 'xxxxxxxxxxxxxxxxxxxx',
key: 'xxxxxxxxxxxxxxxx'});
let stateHasChanged = false;
// Find device on network
device.find().then(() => {
// Connect to device
device.connect();
});
// Add event listeners
device.on('connected', () => {
console.log('Connected to device!');
});
device.on('disconnected', () => {
console.log('Disconnected from device.');
});
device.on('error', error => {
console.log('Error!', error);
});
device.on('data', data => {
console.log('Data from device:', data);
console.log(`Boolean status of default property: ${data.dps['1']}.`);
// Set default property to opposite
if (!stateHasChanged) {
device.set({set: !(data.dps['1'])});
// Otherwise we'll be stuck in an endless
// loop of toggling the state.
stateHasChanged = true;
}
});
// Disconnect after 10 seconds
setTimeout(() => { device.disconnect(); }, 10000);
- Check data from device
Expected behavior Not null values returned
Debug Output
Post the output of your program/app/script when run with the DEBUG environment variable set to *. Example: DEBUG=* node test.js. Copy the output and paste it below (in between the code fences):
node async.js
Connected to device!
Error! json obj data unvalid
Data from device: { dps:
{ '1': null,
'2': null,
'3': null,
'101': null,
'102': null,
'103': null } }
Boolean status of default property: null.
Data from device: { dps: { '1': true }, t: 1593283963 }
Boolean status of default property: true.
Disconnected from device.
Desktop (please complete the following information):
- OS: Raspbian Buster
- Node Version v10.21.0
- HW techkin smartplugs https://www.amazon.de/gp/product/B07CDCYLQ6/
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Comments: 30 (22 by maintainers)
Thanks @codetheweb. Thinking about using SET instead of GET, I wonder if a better option would be to simply implement a fallback to using CONTROL_NEW instead. That seems to be the method that works for these devices. The CONTROL_NEW command seems to have a slightly different schema, basically no gwId: property, otherwise the same and change the command code. That seems to be what other implementations are doing such as:
https://redmine.telecom-bretagne.eu/projects/xaal/repository/entry/code/Python/branches/0.7/devices/protocols/Tuya/xaal/tuya/tuyaclient.py
Unless I’m reading that completely wrong (I’m quite worse at Python vs Javascript, which is perhaps a sad statement) it appears they just try DP_QUERY, if they detect the “json obj data unvalid” message they call fix_buggy_dp_query(), which uses CONTROL_NEW instead.
That’s basically the same as I’m doing in my code, but I’m falling back to a SET with null, since TuyAPI abstacts the commands. I’ll try to hack my local TuyAPI to use the CONTROL_NEW fallback and see if it works.
This behavior is now opt-in in v6.0.0.
OK, I think I’ve worked out how to deal with this for my code at least. After reading the mile long #246 thread, it seems that some devices don’t return an invalid response and, after that, the proper data, however, some devices appear to never return valid data to a DP_QUERY. I see some libraries using a CONTROL_NEW command as a fallback, although I’m still not sure I fully understand it, but I couldn’t work out any way to do that in TuyAPI without changing the code (I see no way to control the command type for get().
However, I did find that if I detect a null response to a get() that it’s still possible get the device to send an update by using the send() command. It seems that if you issue a “send()” with a null payload to the DPS key you want to get(), you can cajole the device to at least send a data update with the value. So far this seems to work for me and the devices I have access to with this behavior. I just trap the invalid response, log it as invalid, issue a send() and wait for the data update. I have no idea if this works for all devices, but as I noted above, it seems OK for the ones I have.
If I manage to get more time perhaps I’ll try to do some packet traces and then decode them and see if I can get more clarity on how the Tuya app itself deals with this, but I don’t know if that time will come soon.
I’m struggling with this as well. Newer devices seem to use a new command type (DP_QUERY_NEW perhaps?) and so I can’t seem to get on demand DPS updates from these devices using get(). I can set(), and I can subscribe to data updates and get data if changes are made to the device, but get() always returns invalid data which means I can’t get initial device state. I’m trying to research this in more detail in some other projects that implement tuya protocol which don’t seem to have this problem.