tuyapi: Device returning JSON error
This bug was already mentioned in the TuyApi/Cli repo, but it fits here better, since it seems to fail already within TuyApi itself, not just in cli.
How I run into this Testing TuyApi with the sample code, I let the library find the device using the UDP broadcast, and it finds it, and determines it’s version 3.3 (at least thats what TuyApi returns together with it’s IP address).
Issue at TuyApi/Cli: https://github.com/TuyaAPI/cli/issues/23#issuecomment-525759663
My latest findings in the linked issue (copy from the other issue, to keep it clean):
@codetheweb (2 edits and more testing at the end of this feedback)
This is the response of a custom script against TuyAPI:
TuyAPI Finding missing IP undefined or ID XXXXXXXXXXXXXXXXX +0ms
TuyAPI Received UDP message. +77ms
TuyAPI UDP data: +3ms
TuyAPI { payload:
TuyAPI { ip: '192.168.1.XXX',
TuyAPI gwId: 'XXXXXXXXXXXXXXXXX',
TuyAPI active: 2,
TuyAPI ablilty: 0,
TuyAPI encrypt: true,
TuyAPI productKey: 'XXXXXXXXXXXXXXXXX',
TuyAPI version: '3.3' },
TuyAPI leftover: false,
TuyAPI commandByte: 19,
TuyAPI sequenceN: 0 } +0ms
TuyAPI Connecting to 192.168.1.XXX... +4ms
TuyAPI Socket connected. +73ms
Connected to device!
TuyAPI GET Payload: +1ms
TuyAPI { gwId: 'XXXXXXXXXXXXXXXXX',
TuyAPI devId: 'XXXXXXXXXXXXXXXXX' } +0ms
TuyAPI Received data: 000055aa000000010000000a0000002c00000001e43a9f9fb09424634104f66db124feee8e3bf2aeee7be51f9590b6b57c1fe62e4f61356e0000aa55 +86ms
TuyAPI Parsed: +0ms
TuyAPI { payload: 'json obj data unvalid',
TuyAPI leftover: false,
TuyAPI commandByte: 10,
TuyAPI sequenceN: 1 } +0ms
Data from device: json obj data unvalid
Using this almost unchanged sample code:
const TuyAPI = require('tuyapi');
const device = new TuyAPI({
id: 'XXXXXXXXXXXXXXXXX',
key: 'XXXXXXXXXXXXXXXXX'});
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);
Command:
DEBUG=* node index.js
// EDIT 1/2 //
In file node_modules/tuyapi/lib/message-parser.js I followed it to getPayload (line 173) and did some console.log’s, in the first try statement I can log the buffer, then after that it does:
data = this.cipher.decrypt(data);
Followed by another console.log which gives me the following (partially cutted unrelated feedback):
TuyAPI Received data: 000055aa000000010000000a0000002c00000001e43a9f9fb09424634104f66db124feee8e3bf2aeee7be51f9590b6b57c1fe62e4f61356e0000aa55 +13ms
========== BEFORE this.cipher.decrypt ==========
<Buffer e4 3a 9f 9f b0 94 24 63 41 04 f6 6d b1 24 fe ee 8e 3b f2 ae ee 7b e5 1f 95 90 b6 b5 7c 1f e6 2e>
========== AFTER this.cipher.decrypt ==========
json obj data unvalid
No idea how to move further, also no idea if the json obj data unvalid text is really the decrypted text, or an error from cipher (given the spelling error in unvalid).
// EDIT 2/2 //
Tested more in cipher, the weird error is already generated here:
node_modules/tuyapi/lib/cipher.js (line 75)
const decipher = crypto.createDecipheriv('aes-128-ecb', this.key, '');
result = decipher.update(data, format, 'utf8');
result += decipher.final('utf8');
It’s the literal content of result after this part.
Tested a bit more on the cipher stuff:
const decipher = crypto.createDecipheriv('aes-128-ecb', this.key, '');
result = decipher.update(data, format, 'utf8');
console.log( 'RESULT 1' );
console.log( result );
result += decipher.final('utf8');
console.log( 'RESULT 2' );
console.log( result );
Results in:
RESULT 1
json obj data un
RESULT 2
json obj data unvalid
At this point it goes to crypto, and now i’m clueless what I could test more. Looks like the decryption works perfectly, since it fails when I change alghoritm, so the error is the decoded message. Do I guess the JSON payload is not correct or something, for my device:
const payload = {
gwId: this.device.gwID,
devId: this.device.id
};
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 1
- Comments: 120 (18 by maintainers)
Damn Github mobile, closed it by accident.
Released in v5.3.1.
Sorry I haven’t responded for the last few days, I’ve been busy with university final exams. I’ll take a look by the end of the weekend.
@codetheweb I’m not completely sure anymore what did the trick to solve the problem. I did a complete rewrite of clach04’s code. The first thing that comes to mind is that some devices not always give replies in the same order. Most of the devices first return the status and a acknowledgement after, some do it the other way around. See
def _select_replyline 138 in my code. Then there was also an issue with devices that wouldn’t post its dps values. For those I had to force the query at line 71 and 72Not the most elegant solution but it seems to work in most cases.
@codetheweb Ok, so I got a working solution, based on your latest patch branch. Basically doing the same ( I think) that happens in the python lib.
at index.js starting at line 317 is this:
if changed to
we can at least supress the error. Not the most elagant but it does the trick…
PS. sorry for flooding this thread 😄
Zo komen we ergens 👍 Ik ga nog even doorspitten, en eventuele bevindingen hier neer rammen. (maar ff NL, is toch niet echt on-topic of informatief zo)
Thanks man, je bent een redder vandaag.
Yes, I’ll take a look at it asap and report back here.
Thanks for the report @realjax. I’ll try to compare libraries sometime this week and see if there’s anything I should change.
Did a bit of a rewrite of pytuya https://github.com/TradeFace/tuya/blob/master/client.py It now works correctly for all my 3.3 tuya devices.