codetheweb / tuyapi Goto Github PK
View Code? Open in Web Editor NEW🌧 An easy-to-use API for devices that use Tuya's cloud services. Documentation: https://codetheweb.github.io/tuyapi.
License: MIT License
🌧 An easy-to-use API for devices that use Tuya's cloud services. Documentation: https://codetheweb.github.io/tuyapi.
License: MIT License
As I find it hard to find some information on if sombody managed to update the firmware of a tuya device utilizing any kind of OTA update, I thought this might be the right place to ask.
thisRequest.dps[options.dps.toString] = options.set;
Seems to be missing the () behind toString. This caused issues setting dps values with using this package from homebridge.
For example:
tuya.set({id: 'xxxxxxxxxxxxxxxxxxxx', 'dps': 2, set: true}).then(() => console.log('device was changed'))
Would fail because toString is not a function in prototype.
Proposed change:
thisRequest.dps[options.dps.toString()] = options.set;
or even:
if (options.dps === undefined) {
thisRequest.dps = {1: options.set};
} else {
thisRequest.dps = {};
thisRequest.dps[options.dps] = options.set;
}
Line 233 in 290d6e9
Hi !
Thanks for that grat project. Makes my new wall switch works together with my smarthome.
I bought a Xenon / Jinvoo (Tuya based) Wall switch with two buttons.
Like this one: https://de.aliexpress.com/item/Manufacturer-Xenon-Wall-Switch-110-240V-Smart-Wi-Fi-Switch-button-Glass-Panel-3-gang-Ivory/32774600013.html
I first tried to flash it with tasmota FW, without success. So after hours of research, i found this project. After some small code changes , i successfully integrate the switch into my smarthome environment (iobroker mainly).
Only problem with the tuyapi was, that it only supports one datapoint (Means one button). So i add that functionality to the getStatus and setStatus method. I like to share my changes here, maybe someone also has that requirement. I just tested it with my wall switch! Works fine for me.
`
/**
Gets the device's current status.
@param {function(error, result)} callback
@param {number} [dpId=1] - DataPoint for multi switch devices
*/
TuyaDevice.prototype.getStatus = function (callback, dpId) {
var dpId = dpId || 1;
// Add data to command
if ('gwId' in requests[this.type].status.command) {
requests[this.type].status.command.gwId = this.id;
}
if ('devId' in requests[this.type].status.command) {
requests[this.type].status.command.devId = this.id;
}
// Create byte buffer from hex data
const thisData = Buffer.from(JSON.stringify(requests[this.type].status.command));
const buffer = this._constructBuffer(thisData, 'status');
this._send(buffer).then(data => {
// Extract returned JSON
try {
data = data.toString();
data = data.slice(data.indexOf('{'), data.lastIndexOf('}') + 1);
data = JSON.parse(data);
return callback(null, data.dps[dpId]);
} catch (err) {
return callback(err, null);
}
});
};
/**
Sets the device's status.
@param {boolean} on - true
for on, false
for off
@param {function(error, result)} callback - returns true
if the command succeeded
@param {number} [dpId=1] - DataPoint for multi switch devices
*/
TuyaDevice.prototype.setStatus = function (on, callback, dpId) {
const thisRequest = requests[this.type][on ? 'on' : 'off'];
var dpId = dpId || 1;
// Add data to command
const now = new Date();
if ('gwId' in thisRequest.command) {
thisRequest.command.gwId = this.id;
}
if ('devId' in thisRequest.command) {
thisRequest.command.devId = this.id;
}
if ('uid' in thisRequest.command) {
thisRequest.command.uid = this.uid;
}
if ('dps' in thisRequest.command) {
thisRequest.command.dps = JSON.parse("{""+dpId+"": "+on+"}");
}
if ('t' in thisRequest.command) {
thisRequest.command.t = (parseInt(now.getTime() / 1000, 10)).toString();
}
// Encrypt data
this.cipher.start({iv: ''});
this.cipher.update(forge.util.createBuffer(JSON.stringify(thisRequest.command), 'utf8'));
this.cipher.finish();
// Encode binary data to Base64
const data = forge.util.encode64(this.cipher.output.data);
// Create MD5 signature
const preMd5String = 'data=' + data + '||lpv=' + this.version + '||' + this.key;
const md5hash = forge.md.md5.create().update(preMd5String).digest().toHex();
const md5 = md5hash.toString().toLowerCase().substr(8, 16);
// Create byte buffer from hex data
const thisData = Buffer.from(this.version + md5 + data);
const buffer = this._constructBuffer(thisData, [on ? 'on' : 'off']);
// Send request to change status
this._send(buffer).then(data => {
return callback(null, true);
}).catch(err => {
return callback(err, null);
});
};
`
I am able to get all the info I outlined in this post:
https://github.com/python-tuya/python-tuya/issues/1#issuecomment-338845744
Yet still have no idea where to find the UID and KEY values.
I tried to use the Charles app and had my phone send all traffic through a socks 5 proxy to Charles and I'm still not seeing the local key or uid values. Maybe the first json string is unencrypted getStatus. I want to say that my ssl cert reversing things just arn't working on this. How did you go about de-ssl-ing the packets?
Here is a sample of a turn on and off on the port 6668:
..U..............WA=...U..U..................Q.....U..U........
...F{"devId":"002009262c3ae817e19a","gwId":"002009262c3ae817e19a"}.%.}...U..U........
...Y....{"devId":"002009262c3ae817e19a","dps":{"1":false,"2":0,"4":0,"5":0,"6":1231}}m..u...U..U.............3.137ed7a48ff271e52PZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrH+Cke6uc2p1Ffl2AYvLF2rJ/ngc/EJeIXiGOrY9vFbniEA7LmOkCK66N6cb80iql2E6CfiCza+ivc2mlfUf/R6#..+...U..U.................x.p....U..U.................3.18cc58581a5d5a855PZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrExYLyT9xR3tTqTGAN2CNEnUVALV5jheBKxuaLpNTjRUjLaZ1j+jBoZrAxZ3zcs680=.w.....U..U.............3.13e5530644a4a031bPZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrHZfccCsWIkuo2QNShDjqQTc3M4KsH/I2MnjRbt/S9QjCEA7LmOkCK66N6cb80iql2E6CfiCza+ivc2mlfUf/R6..V....U..U.................x.p....U..U.................3.193b1f16eed69c377PZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrGWjcMctZYp4nF91mDoV1IAimI/NF3StveQCtVjcSl9SrP68joOZ7crLpwap1yx6Yg=%..c...U..U.............3.1dc00201b701beaebPZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrH1KeS3CuQ4u4P1rw/XcyzgLp2Aku7lI6waA1S7B9BFOpQwKyaho9oabVmurTqLWf0eXxemklZskZ2kBFPM0jP0-......U..U.................x.p....U..U.................3.1fc9bdc270429fa20PZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrH1KeS3CuQ4u4P1rw/XcyzgiI7p9y6Lbv2lzwUJxWzM96kcavlH4f0O206Ug9wDxr0=.an....U..U..............WA=...U..U..................Q.....U..U.................3.1f7999523619c1b0fPZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrEMvogScDF7HlUxg8PL+6kEFSeJWX5zoexl2+xqyc4q+52ImmB+2QokNliV3Z0xKcS2+FDD7CoX+maVSU6uu+SX..F....U..U.............3.18daa6bfa06b70c03PZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrH+Cke6uc2p1Ffl2AYvLF2r7ngm4iiyI4XOoMcDODAPoiEA7LmOkCK66N6cb80iql2E6CfiCza+ivc2mlfUf/R6.......U..U.................x.p....U..U.................3.1827be0aa4d4fe1c1PZq9YjgtkdqtS8Iw4vKCwi7AJ2Vr3dvbNaio1F9WYrExYLyT9xR3tTqTGAN2CNEnnDaemapmVsqahVhvk7lmTcDtRNjY/DkG+XjLCooic0k=.&r....U
I've written a simple test function, it works and returns status: true or false, but frequently returns "(node:nnnnn) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error communicating with device. Make sure nothing else is trying to control it or connected to it.
." - just wondered if the cause of the error is known?
Just a quick note to say I think the setup instructions are missing a step. In Charles I had to explicitly allow SSL connections from all hosts. I can post a screenshot when I am back at the machine I did it on, but from memory it was in preferences and I just allowed a *
wildcard.
Without this, Charles only sees some connections and not the ones required to get the ID and details.
So close, at least I feel like it. My environment is Ubuntu via HyperV on a windows 10. The VM has access to the same wireless as the power strip I'm attempting to take hostage. I wish I were smart enough to figure this out by myself. I do very much appreciate the work you're doing.
My debug is shared on my g-drive here ==> https://docs.google.com/document/d/1mWSme6a7RJfqUNIP__O028pZ5n2UY5srr9-5aUCX9bU/edit?usp=sharing
I keep getting an issue when running tuya-cli link-wizard around permission access
Error: EACCES: permission denied, open '/Users/James/.config/configstore/@tuyapi/cli.json'
You don't have access to this file.
Im a total noob so please help me in child friendly comms!
Is there a way to control individual outlets on a power strip? I can with pytuya but no with tuyapi. Thanks
I've created the Tuya account and obtained the ID and Key from the site.
When I go to add a device I get the following error.
Device(s) failed to be registered!
Error: Timed out wating for device(s) to connect to cloud
at Promise (/usr/local/lib/node_modules/@tuyapi/cli/node_modules/@tuyapi/cloud/index.js:275:12)
at
the wizard is on a Docker environment with oznu homebridge and its homebridge-config-ui-x installed via its homebridge-syno-spk package on my nas synology ds218+
I'm using this smart plug "https://www.amazon.fr/gp/product/B07BKY4QFV/ref=oh_aui_detailpage_o07_s00?ie=UTF8&psc=1" with the Smart Life app.
I put the switch in pairing mode but the wizard never finds it. Instantly can add it back to the Smart Life app though.
I use the iOS APP KEY from Tuya for apikey in the wizard and iOS APP Secret from Tuya for apisecret in the wizard. Am I doing something wrong?
I am French and quite bad in English, excuse me in advance for errors in pronunciation, spelling, grammar and especially comprehension.
Hey, thanks for your fantastic work.
I get an error using tuya-cli
I have no problems adding the plug with this app https://play.google.com/store/apps/details?id=com.tuya.smartlife&hl=de
✖ Device(s) failed to be registered! { Error: getaddrinfo EAI_AGAIN at Object._errnoException (util.js:1022:11) at errnoException (dns.js:55:15) at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:92:26) code: 'EAI_AGAIN', errno: 'EAI_AGAIN', syscall: 'getaddrinfo', hostname: 'broadcasthost' }
I'm having issues since the change to throw on index.js line 281. It seems execution completely halts and does not get caught when _send is being executed, if there is an error. I get:
Scripts/node_modules/tuyapi/index.js:281
throw err;
^
Error: Error communicating with device. Make sure nothing else is trying to control it or connected to it.
at _errnoException (util.js:992:11)
at TCP.onread (net.js:618:25)
,though the former error(err) line seemed to be functional. I'm not a Node expert but it seems now I can't rely on the reject Promise from the set method such that I can perform retries because I don't actually get it. Any thoughts?
I'm getting the following quite frequently, using the basic toggle example provided. I've tried to figure out what is going on but I simply don't get js and how it works.
(node:6521) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Error communicating with device. Make sure nothing else is trying to control it or connected to it. (node:6521) DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
edit:
unparagoned/njsTuya#1
Mostly the toggle works but getting the state afterword is a problem.
What I've done is just rework myscript so it doesn't ask for the state again and it seems to be working fine. I just add some code around it and assume if a return result is true then it's changed state, rather than performing a second get call.
Edit: I get the errors now and then with the modified code but it's much less frequent.
Issue: It seems like every update not just the major 2.0 breaks my wrapper. Rather than just bitching I was wondering if it's worth considering a more elegant solution.
Is there an API or generic setup so heating functions have universal names and behaviour. I'm not sure if NEST/HIVE have a nice API.
How easy is it to switch between the various ports?
https://github.com/codetheweb/tuyapi
python-tuya a Python port by clach04 https://github.com/clach04/python-tuya
m4rcus.TuyaCore a .NET port by Marcus-L https://github.com/Marcus-L/m4rcus.TuyaCore
It would be quite nice if there was a way to easily switch the backend system between the various ports. This might not be an issues as such so maybe you guys just need to give me a reading list and close this ticket.
Hello. The script works fine, I can switch my plug on/off but, the node process doesn't quit and I get an infinite loop :
Status: true
Result of setting status to false: true
New status: false
{ Error: read ECONNRESET
at exports._errnoException (util.js:1020:11)
at TCP.onread (net.js:568:26) code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }
{ Error: read ECONNRESET
at exports._errnoException (util.js:1020:11)
at TCP.onread (net.js:568:26) code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }
[again and again]
running on ubuntu 17.10 node v6.11.4 and rasbpian node v6.12.2.
Any clue ?
Notice I also get the same problem with only a getStatus :
const TuyaDevice = require('tuyapi');
var tuya = new TuyaDevice({
type: 'outlet',
ip: '192.168.0.18',
id: 'xxxx',
key: 'xxxx'
});
tuya.getStatus(function(error, status) {
if (error) { return console.log(error); }
console.log('Status: ' + status);
});
Sometimes the application shows the error:
"Error communicating with device. Make sure nothing else is trying to control it or connected to it."
And I only use one instance of the software. I tried to restart de application, but nothing.
There is any way to see the blocked connections, o do something?
The first time I tried the link-wizard I said yes remember key, however it did not work with the same results as the other open failed to register issue. I was not sure if I had added the correct secret key so wish to try again. How do I un-save the keys?
Hello, Im having trouble using Charles to get the IDs , I followed the direction and signed ther certificatte on my iphone and everything but still just getting gibberish, the text doesnt display like your direction does.
https://gyazo.com/7f40922412ab92efe1004e7ff12933c8
Is there an easier way to pull the required IDs? Basically i'm trying to get the ID to implement into my own ios App to allow controlling of the switches I have.
Hi together,
I have a tuya smart plug and i am totally excited to integrate it in my homebridge configuration.
@codetheweb I have followed your SETUP.md but i can not get this POST request you are actually getting.
In my Charles after re-adding the device to my app i can see just this:
https://imgur.com/a/F904M
https://imgur.com/a/jfJXa
Can someone help me?
Lorenzo.
(For reference you should invert point 4 and 5 of your guide)
Hey guys,
I'm not able to get it running. It throws the following error:
/node_modules/node-forge/lib/aes.js:203
var len = tmp.length();
^
TypeError: tmp.length is not a function
at forge.aes.Algorithm.initialize (/node_modules/node-forge/lib/aes.js:203:19)
at new forge.cipher.BlockCipher (/node_modules/node-forge/lib/cipher.js:118:18)
at Object.forge.cipher.createCipher (/node_modules/node-forge/lib/cipher.js:42:10)
at new TuyaCipher (/node_modules/tuyapi/lib/cipher.js:13:30)
at new TuyaDevice (/node_modules/tuyapi/index.js:42:24)
at /app.js:28:13
at Array.forEach (native)
at initDevices (/app.js:26:18)
at Object.<anonymous> (/app.js:36:1)
at Module._compile (module.js:577:32)
Any ideas?
#17 Hey guys.
I'm trying to install the package as mentioned in the FAQ:
npm install codetheweb/tuyapi
Which returns
npm WARN enoent ENOENT: no such file or directory, open '/home/openhabian/package.json’
npm WARN openhabian No description
npm WARN openhabian No repository field.
npm WARN openhabian No README data
npm WARN openhabian No license field.
I don't know how to resolve this
Hi, the script was running fine for a few months, and now I got this issue surfaced in the last few weeks. I can confirm that the uuid and localkey are correct and freshly retrieved.
I'm using tuyapi v2.0.3.
Could you please help? Thanks!
(node:4890) UnhandledPromiseRejectionWarning: Error: resolveIds() timed out. Is the device ID correct and is the device powered on?
at timeout (/home/nvidia/mining_monitor/node_modules/tuyapi/index.js:129:11)
at Timeout.setTimeout [as _onTimeout] (/home/nvidia/mining_monitor/node_modules/p-timeout/index.js:19:13)
at ontimeout (timers.js:458:11)
at tryOnTimeout (timers.js:296:5)
at Timer.listOnTimeout (timers.js:259:5)
(node:4890) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:4890) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Running your example code from console in Ubuntu:
$ node ./tuya_test
/home/oriz/node_modules/tuyapi/index.js:55
const thisData = Buffer.from(JSON.stringify(requests[this.type].status.command));
^
TypeError: this is not a typed array.
at Function.from (native)
at TuyaDevice.getStatus.callback [as getStatus] (/home/oriz/node_modules/tuyapi/index.js:55:27)
at Object. (/home/oriz/tuya_test:10:6)
at Module._compile (module.js:410:26)
at Object.Module._extensions..js (module.js:417:10)
at Module.load (module.js:344:32)
at Function.Module._load (module.js:301:12)
at Function.Module.runMain (module.js:442:10)
at startup (node.js:136:18)
at node.js:966:3
Please advise?
Hello @codetheweb,
Thank you for your awesome code. Im a completely noob (I'm a humble MD student trying to make my home smart on a budget) and I'm having a hard time figuring out how to use all the information here to get my outlet to work with Homebridge. For example, I'm able to get all the parameters
ip: 'xxx.yyy.0.zzz', (The IP on the tuya server and the local IP on my router)
id: 'xxxxxxxxxxxxxxxxxxxx',
uid: 'xxxxxxxxxxxxxxxxxxxx',
key: 'xxxxxxxxxxxxxxxx'});
but I have no Idea what to do with them, what file I have to create (if any) or in which file do I have to put them to make it work. Could you please direct me on the right track, or provide me with some links to read and learn how I can make it work?
I would really appreciate any help, and sorry for any inconvenience.
How to get the ip address of my light bulb (geeni) that the internet says is a tuya?:
I tried to look on my routers setup tool however i do not see any thing that looks like my bulb
Thanks
Describe the bug
Unable to use tuya.set()
To Reproduce
const TuyaDevice = require('tuyapi');
let tuya = new TuyaDevice({
id: '012005726001946e7f40',
key: 'xxxxxxxxxxxxxxxx',
ip: '192.168.0.3'});
tuya.get().then(status => {
console.log('Status:', status);
tuya.set({set: !status}).then(result => {
console.log('Result of setting status to ' + !status + ': ' + result);
tuya.get().then(status => {
console.log('New status:', status);
return;
});
});
});
Expected behavior
Expect the lights to go off?
Debug Output
TuyAPI Device: +0ms
TuyAPI { id: '012005726001946e7f40',
TuyAPI key: 'xxxxxxxxxxxxxxxx',
TuyAPI ip: '192.168.0.3',
TuyAPI port: 6668,
TuyAPI version: 3.1,
TuyAPI cipher:
TuyAPI TuyaCipher {
TuyAPI cipher:
TuyAPI { algorithm: [Object],
TuyAPI mode: [Object],
TuyAPI blockSize: 16,
TuyAPI _finish: false,
TuyAPI _input: null,
TuyAPI output: null,
TuyAPI _op: [Function],
TuyAPI _decrypt: false },
TuyAPI decipher:
TuyAPI { algorithm: [Object],
TuyAPI mode: [Object],
TuyAPI blockSize: 16,
TuyAPI _finish: false,
TuyAPI _input: null,
TuyAPI output: null,
TuyAPI _op: [Function],
TuyAPI _decrypt: true },
TuyAPI version: 3.1 } } +1ms
TuyAPI Payload: { gwId: '012005726001946e7f40', devId: '012005726001946e7f40' } +2ms
TuyAPI Socket attempt 1 +2ms
TuyAPI Sending this data: 000055aa000000000000000a000000467b2267774964223a223031323030353732363030313934366537663430222c226465764964223a223031323030353732363030313934366537663430227d000000000000aa55 +0ms
TuyAPI Socket connected. +7ms
TuyAPI Received data back: +21ms
TuyAPI 000055aa000000000000000a00000114000000007b226465764964223a223031323030353732363030313934366537663430222c22647073223a7b2231223a747275652c2232223a227768697465222c2233223a3235352c2234223a3235352c2235223a226666303030303030303066666666222c2236223a223030666630303030303030303030222c2237223a226666666635303031303066663030222c2238223a226666666638303033666630303030303066663030303030306666303030303030303030303030303030303030222c2239223a226666666635303031666630303030222c223130223a226666666630353035666630303030303066663030666666663030666630306666303030306666303030303030227d7de27ffec00000aa55 +0ms
Status: true
TuyAPI Payload: +2ms
TuyAPI { devId: '012005726001946e7f40',
TuyAPI uid: '',
TuyAPI t: '1534822576',
TuyAPI dps: { '1': false } } +0ms
TuyAPI Socket attempt 1 +2ms
TuyAPI Sending this data: 000055aa000000000000000700000087332e316532626163616135653561633834616546476b39646c4379644c4372414a524b736e4634664851646a4138624e33724973577443384d5346547974637648666d4f693557676c47794d6837675562616447522f77712b2b324e6b62336f3577505955312f4d4d685151564551797462737a6e356a5a6156374f6e513d000000000000aa55 +0ms
TuyAPI Socket connected. +23ms
TuyAPI Socket attempt 2 +6s
TuyAPI Sending this data: 000055aa000000000000000700000087332e316532626163616135653561633834616546476b39646c4379644c4372414a524b736e4634664851646a4138624e33724973577443384d5346547974637648666d4f693557676c47794d6837675562616447522f77712b2b324e6b62336f3577505955312f4d4d685151564551797462737a6e356a5a6156374f6e513d000000000000aa55 +0ms
Desktop (please complete the following information):
Firstly, I love the work you have done with the tuyapi library.
I am using tuyapi library with these Goldair Wifi controllable heaters http://www.goldair.co.nz/product-catalogue/heating/panel-heaters which I found use the Tuya IOT framework. The mobile app annoyingly does not have a schedule feature - only a simple timer you have to set every day. I have implemented my own schedule using crontab running on a Raspberry Pi.
Here are some notes on how I got this working.
Device Encryption Key discovery is done by finding these in the mobile app log file.
Heater Settings
'1': true, -on/off
'2': 14, -setpoint
'3': 19, -current Temp, readonly
'4': 'C', - 'C' comfort, 'ECO', 'AF' AntiFreeze
'6': false, -child lock on
'12': 0, -fault, readonly
'101': 'stop', -power level 'stop','1','2','3','4','5','auto'
'102': 1440, -timer in mins
'103': false, -timer on
'104': true, -led display on
'105': 'auto', -mode 'auto', 'user' - what is the difference?
'106': 14 -eco temp set point between 5-31
Code snippet of scheduling (crontab calls this with a scene param)
if (scene == 'evening'){
//evening 18 deg, on, LED on
tuya.set({id: Heater1Id, dpscommand:'{"1":true,"2":18,"6":true,"104":true}'}).then(() => console.log('Heater1Id was changed'));
tuya.set({id: Heater2Id, dpscommand:'{"1":true,"2":18,"6":true,"104":true}'}).then(() => console.log('Heater2Id was changed'));
tuya.set({id: Heater3Id, dpscommand:'{"1":true,"2":18,"6":true,"104":true}'}).then(() => console.log('Heater3Id was changed'));
}
if (scene == 'night'){
//night 18 deg, locked, LED off
tuya.set({id: Heater1Id, dpscommand:'{"1":true,"2":18,"6":true,"104":false}'}).then(() => console.log('Heater1Id was changed'));
tuya.set({id: Heater2Id, dpscommand:'{"1":true,"2":18,"6":true,"104":false}'}).then(() => console.log('Heater2Id was changed'));
tuya.set({id: Heater3Id, dpscommand:'{"1":true,"2":18,"6":true,"104":false}'}).then(() => console.log('Heater3Id was changed'));
}
if (scene == 'morning'){
//morning 7am, turn off, LED on, locked
tuya.set({id: Heater1Id, dpscommand:'{"1":false,"2":18,"6":true,"104":true}'}).then(() => console.log('Heater1Id was changed'));
tuya.set({id: Heater2Id, dpscommand:'{"1":false,"2":18,"6":true,"104":true}'}).then(() => console.log('Heater2Id was changed'));
tuya.set({id: Heater3Id, dpscommand:'{"1":false,"2":18,"6":true,"104":true}'}).then(() => console.log('Heater3Id was changed'));
}
Extension to device set method to allow multiple settings to be changed at one time
/*
* @param {Object} options - options for setting properties
* @param {String} [options.id] - ID of device
* @param {Boolean} options.set - `true` for on, `false` for off
* @param {Number} [options.dps] - dps index to change
* @param {String} [options.dpscommand] - dps command string
*/
...
if (options.dpscommand !== undefined) {
thisRequest.dps = JSON.parse(options.dpscommand)
}
I hope this helps.
I had both getters and setters working before, but now only the getter functions work.
I can still control the smart bulb using the android app.
If I run this test script
const TuyaDevice = require( 'tuyapi' );
let tuya = new TuyaDevice({
id: 'abcdefghij1234567890',
key: 'abcdef1234567890',
ip: '192.168.1.120' });
tuya.get().then( status => {
console.log( 'Status:', status );
tuya.get( { schema: true } ).then( schema => {
console.log( 'Schema:', schema );
tuya.set( { dps: 2, set: 128 } ).then( status => {
console.log( 'StatSet:', status );
}).catch( err => { console.log( 'err:', err ) } );
});
});
It prints:
Status: true
Schema: { devId: 'abcdefghij1234567890',
dps: { '1': true, '2': 140, '3': 0 } }
err: Error: Timeout waiting for response
at Timeout._sendTimeout.setTimeout [as _onTimeout] (C:\Users\abc\node_modules\tuyapi\index.js:301:16)
at ontimeout (timers.js:498:11)
at tryOnTimeout (timers.js:323:5)
at Timer.listOnTimeout (timers.js:290:5)
I've made sure the android app is not connected to the bulb when running the scripts.
I'm rather puzzled. Any ideas what could be wrong?
Describe the bug
A clear and concise description of what the bug is.
I believe I have a similar problem as described in issue #54
Unfortunately I have no idea which IP adress to put into for
broadcasthost ip
Additional context
I am not sure if my socket can actually be registered with your API,...
it works fine with the Smart Life ios App.
The machine I use above is a linux Mint machine
this is my output on the console
xxx@xxx ~ $ tuya-cli link-wizard
? Make the indicator light on your device flash.
For most devices, this means holding down the main button.
Press return when it's blinking. Yes
? What's your WiFi called? XXXXXXX
? What's the password for your WiFi? [hidden]
? How many devices do you want to link? 1
? Do you want to save devices that are successfully linked? Yes
✖ Device(s) failed to be registered!
{ Error: getaddrinfo ENOTFOUND broadcasthost
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:50:26)
errno: 'ENOTFOUND',
code: 'ENOTFOUND',
syscall: 'getaddrinfo',
hostname: 'broadcasthost' }
The current code I'm using is:
let tuya = new TuyaDevice({
id: args.id,
key: 'XXXXXXXXXXXXXXX'});
console.log("Resolving IP for device '" + args.id + "'...");
tuya.resolveIds().then(() => {
console.log("IDs resolved, performing action...");
if (args.action == 'status') {
tuya.get().then(status => {
console.log("status=" + status);
});
} else if (args.action == 'on') {
tuya.set({set: true})
} else if (args.action == 'off') {
tuya.set({set: false})
} else {
process.exit(1);
}
});
I see it output Resolving IP for...
but it never makes it to IDs resolved...
, suggestions?
I am wondering if this might be another scenario were a reject would be useful. My cron'd script failed this morning due to this throw.
Line 255 in f07a2a5
I'm trying to get this to work with some smart bulbs and light strip, but currently the only missing piece for me is how you got the prefix & suffix in requests.json.
Are they just the packet header/footer or is there more to it than that?
Awesome work here by the way, thanks for all your work!
Ideally we'd decrypt the payload if it's not JSON, but as a short-term fix we may be able to just wrap get()
in a retry.operation()
.
Okay, the issue is something I'm not sure of but its some socket error so I'm pasting the callback
"minichota@Matthew:/mnt/c/Windows/System32$ sudo tuya-cli link-wizard
? Make the indicator light on your device flash.
For most devices, this means holding down the main button.
Press return when it's blinking. Yes
? What's your WiFi called? something-.-
? What's the password for your WiFi? [hidden]
? How many devices do you want to link? 1
? Do you want to save devices that are successfully linked? Yes
⠹ Registering devices(s)...events.js:183
throw er; // Unhandled 'error' event
^
Error [ERR_SOCKET_CANNOT_SEND]: Unable to send data
at Socket.onListenError (dgram.js:362:22)
at Object.onceWrapper (events.js:315:30)
at emitOne (events.js:116:13)
at Socket.emit (events.js:211:7)
at _handle.lookup (dgram.js:267:14)
at _combinedTickCallback (internal/process/next_tick.js:141:11)"
I'm on windows and I'm not sure, I'm using bash to run this, can someone please explain
Hey guys,
Running NodeJS version 6.12.2 on Ubuntu 16.04. Installed tuyapi per npm instructions and setup a test file with per the Readme page: getStatus, setStatus, then another getStatus.
When I run the file I have the connected lamp turned on. I'm also making sure I'm out of any TuyaSmart apps on the the phone/tablet.
The first getStatus function returns a Status: true message.
The next setStatus function does turn off the lamp and returns a Result of setting status false: true message.
The next message this is displayed in the console is:
SyntaxError: Unexpected token � in JSON at position 56
at Object.parse (native)
at _send.then.err (/home/utladmin/node/tuyapi/node_modules/tuyapi/index.js:64:19)
at process._tickCallback (internal/process/next_tick.js:109:7)
I would think maybe something could be wrong with the id, uid or key for the outlet, but the fact that it can turn lamp off makes me think these variables are correct.
Any thoughts/help would be very much appreciated. Thanks,
C:\tmp>npm install @codetheweb/tuyapi
npm ERR! code E404
npm ERR! 404 Not Found: @codetheweb/tuyapi@latest
npm ERR! A complete log of this run can be found in:
npm ERR! ......2017-11-30T02_11_55_438Z-debug.log
where 2017-11-30T02_11_55_438Z-debug.log contains:
0 info it worked if it ends with ok
1 verbose cli [ 'C:\\Program Files\\nodejs\\node.exe',
1 verbose cli 'C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js',
1 verbose cli 'install',
1 verbose cli '@codetheweb/tuyapi' ]
2 info using [email protected]
3 info using [email protected]
4 verbose npm-session c8ac1559b4c1c76e
5 silly install loadCurrentTree
6 silly install readLocalPackageData
7 http fetch GET 404 https://registry.npmjs.org/@codetheweb%2ftuyapi 339ms
8 silly fetchPackageMetaData error for @codetheweb/tuyapi@latest 404 Not Found: @codetheweb/tuyapi@latest
9 verbose stack Error: 404 Not Found: @codetheweb/tuyapi@latest
9 verbose stack at fetch.then.res (C:\Program Files\nodejs\node_modules\npm\node_modules\pacote\lib\fetchers\registry\fetch.js:42:19)
9 verbose stack at tryCatcher (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\util.js:16:23)
9 verbose stack at Promise._settlePromiseFromHandler (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\promise.js:512:31)
9 verbose stack at Promise._settlePromise (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\promise.js:569:18)
9 verbose stack at Promise._settlePromise0 (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\promise.js:614:10)
9 verbose stack at Promise._settlePromises (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\promise.js:693:18)
9 verbose stack at Async._drainQueue (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\async.js:133:16)
9 verbose stack at Async._drainQueues (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\async.js:143:10)
9 verbose stack at Immediate.Async.drainQueues (C:\Program Files\nodejs\node_modules\npm\node_modules\bluebird\js\release\async.js:17:14)
9 verbose stack at runCallback (timers.js:789:20)
9 verbose stack at tryOnImmediate (timers.js:751:5)
9 verbose stack at processImmediate [as _immediateCallback] (timers.js:722:5)
10 verbose cwd C:\tmp
11 verbose Windows_NT 10.0.14393
12 verbose argv "C:\\Program Files\\nodejs\\node.exe" "C:\\Program Files\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install" "@codetheweb/tuyapi"
13 verbose node v8.9.1
14 verbose npm v5.5.1
15 error code E404
16 error 404 Not Found: @codetheweb/tuyapi@latest
17 verbose exit [ 1, true ]
I've created the Tuya account and obtained the ID and Key from the site.
When I go to add a device I get the following error.
× Device(s) failed to be registered!
Error: Timed out wating for device(s) to connect to cloud
at Promise (C:\Users\xxxxxx\AppData\Roaming\npm\node_modules@tuyapi\cli\node_modules@tuyapi\cloud\index.js:275:12)
at
I'm using this smart plug https://www.amazon.com/gp/product/B07CHMDP1G/ref=oh_aui_detailpage_o09_s00?ie=UTF8&psc=1 with the Smart Life app. Running Charles on my iPhone I can confirm it's communicating through the Tuya Cloud. I put the switch in pairing mode but the wizard never finds it. Instantly can add it back to the Smart Life app though.
I use the iOS APP KEY from Tuya for apikey in the wizard and iOS APP Secret from Tuya for apisecret in the wizard. Am I doing something wrong?
Hello, I asked this question before but I didn't get any reply. I have installed homebridge-tuya-outlet, and I found the DevID but u don't know how to found the local key. Also, can you tell me what's the full steps that can put tuya into HomeKit?Thanks so much.
With https://github.com/bobalob/TuyaKeyGrab
with eFamilyCloud app 1.07 apk
tips with capture packet won't work for me (android8)
This only affects devices with more than one channel so is not a high priority.
Adding an if clause like the following to index.js around line 190 will fix it:
if (options.dps !== undefined) {
resolve(data.dps[options.dps]);
}
else {
resolve(data.dps['1']);
}
Thanks!
This work is most impressive. Unfortunately for me I'm having an issue with the SETUP process. I got my API Key and Secret from tuya. Then I attempted the CLI WIZARD steps provided. My wifi password is a 10 digit string and as a result, I believe it is failing a password validity check. This is the error message I get.
[21:51:50] openhabian@openHABianPi:/etc/openhab2/scripts$ tuya-cli link-wizard
? Make the indicator light on your device flash.
For most devices, this means holding down the main button.
Press return when it's blinking. Yes
? What's your WiFi called? skittles
? What's the password for your WiFi? [hidden]
? How many devices do you want to link? 1
? Do you want to save devices that are successfully linked? Yes
✖ Device(s) failed to be registered!
Error: Invalid WiFi password
at TuyaLink.registerSmartLink (/usr/lib/node_modules/@tuyapi/cli/node_modules/@tuyapi/link/lib/link.js:64:11)
at TuyaLinkWizard.linkDevice (/usr/lib/node_modules/@tuyapi/cli/node_modules/@tuyapi/link/index.js:93:23)
at
at process._tickCallback (internal/process/next_tick.js:188:7)
root@openhab:/etc/openhab2/scripts/njsTuya/scripts# tuya-cli link-wizard
? Make the indicator light on your device flash.
For most devices, this means holding down the main button.
Press return when it's blinking. Yes
? What's your WiFi called? NETGEAR05
? What's the password for your WiFi? [hidden]
? How many devices do you want to link? 1
? Do you want to save devices that are successfully linked? Yes
✖ Device(s) failed to be registered!
{ code: 'ILLEGAL_CLIENT_ID', message: 'Illegal clientId' }
Hi,
I am unable to link successfully using either tuyapi-cli link-wizard
or by using the sample dev.js script code shown at https://github.com/TuyaAPI/link.
I did have to add 255.255.255.255 broadcasthost
to my hosts file to get past the first error, but I consistently arrive at the error:
- Registering devices(s)...
× Device(s) failed to be registered!
Error: Timed out wating for device(s) to connect to cloud
at Promise (...\@tuyapi\cli\node_modules\@tuyapi\cloud\index.js:275:12)
at <anonymous>
I am seeing consistent results on two different computers (Windows 10 running Cygwin and Mac running OSX) and with two different devices.
Does the brand of the devices (smart plugs) matter? They both link successfully using the Tuya android apps.
Any suggestions?
Thanks,
Don
Some discussion on #5 are about figuring out the registration process, I'm starting a thread here so we can focus on this particular issue.
I recorded with fiddler on my old phone the action of adding a new device to the SmartLife App. I also recorded with WireShark all the UDP packets sent by either the device I was registering or the phone I was using to register the device.
I will try to make something readable of all of this and post all the info here, i will just need a little time.
My conclusion from a quick glance a the data:
So my guess is:
That's how i imagine the registration works.
I just thought if maybe it is possible/and or a good idea to emulate a tuya device with tuyapi.
So you can listen on port 6668 and get the messages from a local running app like Smart life.
So, you remove your hardware plug to make it inactive, then start an emulation on your PC with the known ID and localKey.
[13:56:33] root@smarthome:~/node_modules/cli-master# npm i @tuyapi/cli -g
(node:17491) [DEP0022] DeprecationWarning: os.tmpDir() is deprecated. Use os.tmpdir() instead.
npm ERR! git clone [email protected]:tuyapi/cli Cloning into bare repository '/root/.npm/_git-remotes/git-github-com-tuyapi-cli-3083bead'...
npm ERR! git clone [email protected]:tuyapi/cli Warning: Permanently added the RSA host key for IP address '192.30.253.112' to the list of known hosts.
npm ERR! git clone [email protected]:tuyapi/cli Permission denied (publickey).
npm ERR! git clone [email protected]:tuyapi/cli fatal: Could not read from remote repository.
npm ERR! git clone [email protected]:tuyapi/cli
npm ERR! git clone [email protected]:tuyapi/cli Please make sure you have the correct access rights
npm ERR! git clone [email protected]:tuyapi/cli and the repository exists.
npm ERR! addLocal Could not install tuyapi/cli
npm ERR! Error: ENOENT: no such file or directory, stat 'tuyapi/cli'
npm ERR! If you need help, you may report this entire log,
npm ERR! including the npm and node versions, at:
npm ERR! http://github.com/npm/npm/issues
npm ERR! System Linux 4.14.52-v7+
npm ERR! command "/usr/bin/node" "/usr/bin/npm" "i" "@tuyapi/cli" "-g"
npm ERR! cwd /root/node_modules/cli-master
npm ERR! node -v v8.11.1
npm ERR! npm -v 1.4.21
npm ERR! path tuyapi/cli
npm ERR! syscall stat
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! /root/node_modules/cli-master/npm-debug.log
npm ERR! not ok code 0
[14:07:44] root@smarthome:~/node_modules/cli-master#
hi there,
First thank you for your valuable contributions to the tuya library. I realize this is a long shot, but i am wondering if anyone had success in calling the tuya cloud API? i used fiddler and i was able to decipher a lot of the information on the calls, but there is one thing missing.
How is tuya calculating the MD5 hash? I was not able to replicate their "sign" parameter to the URL and the details on this as slim. Most of the info is located at https://docs.tuya.com/en/cloudapi/cloud_access.html#access-mode (search for accesskey) but i could not get it to work following the example. (I had to order my parameters, i used localKey as the accessKey, and then i did a utf-8 encoded MD5 hash). For the time, i got it in seconds using Unix epoch time.
Once i complete my work, i will share the PowerShell script that can be replicated into standard http/json requests.
Hi,
In requests.json how did you find the prefix and suffix for status, on and off?
I can use your sample code to get the status of my Smart Plug without any issues and can switch on but not off. From a plug switched off to on I do get an error but it does come on:
Status: false
Result of setting status to true: true
SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at _send (/home/pi/node_modules/tuyapi/index.js:62:21)
at Socket.client.on.data (/home/pi/node_modules/tuyapi/index.js:137:14)
at emitOne (events.js:115:13)
at Socket.emit (events.js:210:7)
at addChunk (_stream_readable.js:250:12)
at readableAddChunk (_stream_readable.js:237:11)
at Socket.Readable.push (_stream_readable.js:195:10)
at TCP.onread (net.js:586:20)
But then I try to turn off again
Status: true
{ Error: read ECONNRESET
at exports._errnoException (util.js:1026:11)
at TCP.onread (net.js:607:25) code: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read' }
Could the suffix / prefix be my issue? My Smart Plug is a UK version, not sure if that could be the issue (https://www.amazon.co.uk/Wireless-Switch-Function-Android-Devices/dp/B071SDNGW2/ref=sr_1_3?ie=UTF8&qid=1510959884&sr=8-3&keywords=smart+plug)?
Thanks
It looks like there might be a typo at (line 356):
client.on('error', err => {
error(e);
});
e should actually be err.
I'm also seeing failure with this merge to consistently control my switches where the previous version had no issues. I do not believe the above typo is the cause, but I did find it because of the failure to set state. It could be messing with my retry logic however.
If the message contains more open braces "{" than close braces "}" the function goes into an infinite loop.
The real fix would be to clean up the decrypted message to remove the invalid brace at the end. I have seen similar characters at the end of messages when using zero padding in AES (not 100% sure this is the issue.) I cleaned up my messages by switching to PKCS7 padding.
A quick fix is to check for the number of close braces before entering the loop
var leftBrackets = stringOccurrence(data, '{');
var rightBrackets = stringOccurrence(data, '}');
if (leftBrackets > rightBrackets) { leftBrackets = rightBrackets }
but this could end up with bad returned JSON if there happens to be other invalid '{' and '}' characters
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.