Tuya Switch Control (Jinvoo, Smart Life)

I use the Lonsonho Smart Plug.

The get command really helps but unfortunately I still cannot find the Power Switch
Get 0 Returns ON (don’t now what is does)
Get 1 Returns ON (That’s The LED Indicator)
Get 2 Returns Colour (does this means i can change the LED Colour using this switch?)
Get 3 Returns 180
Get 4 Returns 1
Get 5 Returns 0081180083ff81
Get 6 Returns cf38000168ffff
Get 7 Returns ffff500100ff00
Get 8 Returns ffff8003ff000000ff000000ff000000000000000000
Get 9 Returns ffff5001ff0000
Get 10 Returns ffff0505ff000000ff00ffff00ff00ff0000ff000000
Get 11 Returns undefined
I changed the PowerSwitch using the Smart Life app and checked the status again. unfortunately nothing changed. Any idea?

After using the useful Packet Capture tool i found out i had to use dps 101 for switching the power. Thank you so much for the great script and your help!

I was just about to ask you to try 101. I edited my post so maybe you missed it but if you run the following it should have brought back all the valid dps numbers including 101

node njstuya.js -ip x.x.x.x -id xxxxxxxxxxxxx -key xxxxxxxxxx -get '{ "schema": true}'

Should have returned something like the following.

{ devId: '04324234', dps: { '1': false } 
....
devId: '04324234', dps: { '101': false } 
}

I think probably a better approach is to follow the way of python tuyapy and go through the web interface. this way no having to find out/hack localkey etc

Thanks for pointing it out. I hadn’t heard of tuyapy before, but it seems like it should work quite well. I had to switch over from using my jinvoo app to smart life but after I did that I could see my device.
Some people quite like the off-line aspect of the script but getting the device key is a pain the ass. So so adding optional for the cloud seems like a decent way to go. Users can then choose if they want to use it over the cloud, local or both.

Edit: I’ve written some scripts that allow you to control your devices over the cloud without requiring any special keys are anything. I’ll integrate them with njstuya in the next week or so.

If you use NODERED there is a tuyasmart plugin that works extremely well. Still needs the id and key, but works. Below is one of my many flows to control the switch and energy. You will also need an Openhab plugin.

[{"id":"5f16131c.a1f42c","type":"openhab-v2-in","z":"30c0a648.302bba","name":"","controller":"2535dec5.17e512","item":"SmartLifeSW12b","ohCompatibleTimestamp":false,"eventTypes":["ItemCommandEvent"],"outputAtStartup":true,"storeStateInFlow":false,"x":80,"y":740,"wires":[["9c605353.6e998"],[]]},{"id":"9c605353.6e998","type":"change","z":"30c0a648.302bba","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"ON","fromt":"str","to":"{\"set\":true, \"dpsIndex\": 2}","tot":"json"},{"t":"change","p":"payload","pt":"msg","from":"OFF","fromt":"str","to":"{\"set\":false, \"dpsIndex\": 2}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":740,"wires":[["3fbbcb4c.2cd4a4"]]},{"id":"3fbbcb4c.2cd4a4","type":"tuya-smart","z":"30c0a648.302bba","deviceName":"Mini Plug 12b","deviceIp":"192.168.1.67","deviceId":"10670365bcddc2fa5507","deviceKey":"4283f743e3a856b0","request":"{\"schema\": true}","pollingInterval":10,"x":440,"y":740,"wires":[["6af32640.d2b8b8","9fd1da8.12c2428"]]},{"id":"6af32640.d2b8b8","type":"switch","z":"30c0a648.302bba","name":"","property":"payload.data.dps[\"2\"]","propertyType":"msg","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":570,"y":740,"wires":[["f1080e07.bb6ac"],["bbe5d8ea.f10fa8"]]},{"id":"9fd1da8.12c2428","type":"function","z":"30c0a648.302bba","name":"Power","func":"var newmsg = {};\nnewmsg.payload = {};\nnewmsg.payload = msg.payload.data.dps[\"8\"]/10;\nreturn newmsg;","outputs":1,"noerr":0,"x":570,"y":780,"wires":[["cd6437f4.ae41f8"]]},{"id":"cd6437f4.ae41f8","type":"openhab-v2-out","z":"30c0a648.302bba","name":"","controller":"2535dec5.17e512","item":"SmartLifeSW12Energy","topic":"ItemCommand","topicType":"oh_cmd","payload":"payload","payloadType":"msg","storeStateInFlow":false,"x":800,"y":780,"wires":[]},{"id":"bbe5d8ea.f10fa8","type":"openhab-v2-out","z":"30c0a648.302bba","name":"","controller":"2535dec5.17e512","item":"SmartLifeSW12b","topic":"ItemUpdate","topicType":"oh_cmd","payload":"OFF","payloadType":"oh_payload","storeStateInFlow":false,"x":790,"y":740,"wires":[]},{"id":"2535dec5.17e512","type":"openhab-v2-controller","z":"","name":"Openhab","protocol":"https","host":"192.168.1.64","port":"8443","path":"","username":"","password":"","allowRawEvents":true}]

If you have a link I can stick it in the OP.

Done. You can now just setup the devices normally using your Tuya/Smart life app and stick those details into key.json and use that control the devices without needing to MITM the local key for each device.

Hi I’m having some difficulty making rules for this and getting it to work. I have a power strip (with four dps)… and I can run this code in ssh: /usr/bin/node /etc/openhab2/scripts/njstuya.js -ip 192.168.2.243 -id xxxxxxx -key xxxx -set "{ \"dps\": 2, \"set\": true }" with the x’s as my id and key. And it works. However when I try to run the executeCommandLine I can’t seem to get it to work. All examples I’ve found use just “ON” or “OFF” which doesn’t work for my strip. Any advice or suggestions? Thanks!

I know the formatting of the set/get value is quite temperamental. Also if you are using windows I think the execcommand needs some special formatting for spaces. I actually changed the docs and formatting of the set/get commands so it would work on windows through the command line, but it seems like that might be the cause of the issue. I only tested the new formatting using the terminal/console on windows and linux and like you found it works fine. If I send the command '{"dps":2, "set":true}' to LivingRoomHeaterCommand it works. So try that format out. Since you are on linux that should work fine.

/usr/bin/node /etc/openhab2/scripts/njstuya.js -ip 192.168.2.243 -id xxxxxxx -key xxxx -set '{"dps":2, "set":true}'

Ah I see. No "\" in the command and difference spacing.

I’m trying to implement this simple code:
rule “TEST3 rule”
when
Item TEST3 changed
then

executeCommandLine("/usr/bin/node /etc/openhab2/scripts/njstuya.js -ip 192.168.2.243 -id xxxxxxx -key xxxx -set '{"dps":2, "set":true}'")
end

But when I toggle “TEST3” switch, nothing seems to be happening. Running on a Raspberry Pi too. Any idea on the spacing for this command? I’ll try out the living room rules, though it seems a bit overkill for the simple on/off I’m going for. Thanks so much for the help thus far!

If you are trying to add the command directly to the command string then it gets a bit more complicated since you need to scape everything since there is an outer set of quotes that need escaping. The spaces don’t matter. I don’t have any devices that require dps settings and just added support at the request of others. So I only really tested it as a command line tool and haven’t ever tested against a rule before. The rules are a bit a of a mess but I have was working on getting cloud support and considering just making a proper binding. The previous control script was very unreliable so lots of the crap in the rules was aimed at that, but I should update them with nice clean rules.

I would recommend that you pass the argument to the rule, it helps having to escape everything. So if you pass -set '{"dps":1, "set":true}' to item testTuya it should work fine.

rule "Test dps"
when
    Item tesTuya received command
then
    var setCommand="node /etc/openhab2/scripts/node_modules/njstuya -ip 10.xx -id xx -key xx " + receivedCommand.toString
    var resp = executeCommandLine(setCommand, 5000)
    if(db) { logInfo("Tuya", "New broadcast {} resp {}", setCommand, resp)  }
end

I would also suggest you pass the item ip, key, id as well or have it as some kind of variable than fixed into separate rules.

But if you want to test it directly or hardcoded then if you escape everything any of the following should work.
As a variable

    var setCommand = "'{\"dps\":1,\"set\":true}'"
    var resp = executeCommandLine("node /etc/openhab2/scripts/node_modules/njstuya -ip 192.168.xx -id xx -key xx -set " + setCommand, 5000)

Or hardcoded

    executeCommandLine("node /etc/openhab2/scripts/node_modules/njstuya -ip 192.168.xx -id xx -key xx -set " + '\'{"dps": 1, "set":true}\'', 5000)
    executeCommandLine("node /etc/openhab2/scripts/node_modules/njstuya -ip 192.168.xx -id xx -key xx -set '{\"dps\": 1, \"set\":true}'", 5000)

Edit: I’ve redone the items and rules.
Items

//Tuya items and thermo
//  Complete ip/id/key

// Tuya Group Devices 
Group gTuyaActions "Tuya Action to run"
Group:Switch gTuyaStates "Tuya devices"
// Tuya devices
Switch LivingRoomHeater	"Heater state"  (gTuyaStates, gSwitch)  [ "Switchable" ]
Switch BedroomHeater	"Heater state"  (gTuyaStates, gSwitch)  [ "Switchable" ]
Number KitchenThermostatCurrentTemp "Kitchen Thermostat Current Temperature" (gKitchenThermostat)  //[ "CurrentTemperature" ]
Number KitchenThermostatTargetTemp "Kitchen Thermostat Target Temperature" (gKitchenThermostat) {autoupdate="true"}//[ "TargetTemperature" ]
// Send current time to refresh to be able to query when previous refresh was
String TuyaRefresh "Refresh"

// Tuya Devices with sensistive data edit before sharing. 
String LivingRoomHeaterCommand "-ip 10.x.x.x -id xx -key xx" (gTuyaActions)
String BedroomHeaterCommand "-ip 10.x.x.x -id xx -key xx" (gTuyaActions)

Rules

var _DEBUG = false
var db = false
var Timer statusTimer = null
var Timer errorTimer = null

rule "Execute Tuya Action"
when
    Member of gTuyaActions received command
then
    if(db) logInfo("TUYA", "Group trigger {} command", triggeringItem, receivedCommand)

    var setCommand="node /etc/openhab2/scripts/node_modules/njstuya " + triggeringItem.label + " " + receivedCommand.toString
    var tuyaDevice = triggeringItem.name.replace('Command','')
    
    // Runs command vis njstuya
    var resp = executeCommandLine(setCommand, 5000)
    
    if(resp === null)   resp = "Error null"
    if(resp.contains("Error") || resp.contains("Warning") || resp.length < 2){
        logInfo("Tuya", "Error in response [{}] ", resp)
        postUpdate(tuyaDevice, "UNDEF")
        
        // refresh on Error only once after good state. 
        if (errorTimer === null) {
            errorTimer = createTimer(now.plusMillis(1500),  [ | 
                triggeringItem.sendCommand("STATUS")
                errorTimer.cancel()
                errorTimer = null
            ])
        }
    }
    else {
        if(db) logInfo("Tuya", "Updating state [{}] ", resp)   
        postUpdate(tuyaDevice, resp)
        // Reset errorTimer to null if state is good
        if (errorTimer !== null) {
            errorTimer.cancel()
            errorTimer = null
        } 
    }
    if(db) { logInfo("Tuya", "New broadcast {} resp {}", setCommand, resp)  }
end

rule "Tuya Refresh"
when
    Item TuyaRefresh received command
    or
    Time cron "13 0/2 * * * ?"
then
    gTuyaActions.allMembers.forEach[ device | sendCommand(device, "status")]
end


rule "Update Thermostat Value"
when
    Item HueKitchenTemp changed
then
    if(db) { logInfo("Thermostat", "update kitchen temp {}", HueKitchenTemp)}
    KitchenThermostatCurrentTemp.postUpdate(Float::parseFloat(String::format("%s",HueKitchenTemp.state).replace(' ','')))
end

rule "Control Temp"
when
    Item KitchenThermostatCurrentTemp changed
    or 
    Item KitchenThermostatTargetTemp changed
then
    logInfo("Thermostat", "Set {} change temperature from {} to {}", LivingRoomHeater ,KitchenThermostatCurrentTemp.state, KitchenThermostatTargetTemp.state)
    var isCold =  (KitchenThermostatCurrentTemp.state as Number) < (KitchenThermostatTargetTemp.state as Number)
    var setCommand = if(isCold) 'ON' else 'OFF'


    //When using slider you can get lots of changes, this should prevent lots of commands in a row
    if(!LivingRoomHeater.state.toString.contains(setCommand) && statusTimer === null) {
        if(db) { logInfo("Thermostat", " logic {} state {} cmd{}", LivingRoomHeater.state.toString.contains(setCommand), LivingRoomHeater.state.toString, setCommand)}
        if(db) { logInfo("Thermostat", " is cold {} set command {}", isCold, setCommand)}
        LivingRoomHeaterCommand.sendCommand(setCommand)


        // Update state
        if (statusTimer !== null) {
            statusTimer.cancel()
            statusTimer = null
        } 

        statusTimer = createTimer(now.plusMillis(1500),  [ | 
            LivingRoomHeaterCommand.sendCommand("STATUS")
            statusTimer.cancel()
            statusTimer = null
        ])
    } else if (statusTimer !== null) {
        statusTimer.cancel()
        statusTimer = null
    } 

end

Hi @unparagoned
I was able using your script to control my smart plug which has 2 outlets (dps1 and dps2). Thank you!

However, without switching (just idling), approximately every minute I observed the following ERROR messages in the log:

2019-03-29 22:04:42.924 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ‘(node:20295) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected end of JSON input’

2019-03-29 22:04:42.942 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at JSON.parse ()’

2019-03-29 22:04:42.946 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at TuyaDevice.runCommand (/etc/openhab2/scripts/node_modules/njstuya/njstuya.js:231:54)’

2019-03-29 22:04:42.949 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at emitTwo (events.js:131:20)’

2019-03-29 22:04:42.953 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at TuyaDevice.emit (events.js:214:7)’

2019-03-29 22:04:42.956 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at Socket.client.on.data (/etc/openhab2/scripts/node_modules/tuyapi/index.js:425:16)’

2019-03-29 22:04:42.961 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at emitOne (events.js:116:13)’

2019-03-29 22:04:42.965 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at Socket.emit (events.js:211:7)’

2019-03-29 22:04:42.969 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at addChunk (_stream_readable.js:263:12)’

2019-03-29 22:04:42.972 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at readableAddChunk (_stream_readable.js:250:11)’

2019-03-29 22:04:42.976 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ’ at Socket.Readable.push (_stream_readable.js:208:10)’

2019-03-29 22:04:42.979 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ‘(node:20295) 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)’

2019-03-29 22:04:42.983 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ‘(node:20295) [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.’

2019-03-29 22:04:42.986 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ‘(node:20295) UnhandledPromiseRejectionWarning: undefined’

2019-03-29 22:04:42.991 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ‘(node:20295) 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: 2)’

2019-03-29 22:04:43.002 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Transformed response is '(node:20295) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected end of JSON input

at JSON.parse (<anonymous>)

at TuyaDevice.runCommand (/etc/openhab2/scripts/node_modules/njstuya/njstuya.js:231:54)

at emitTwo (events.js:131:20)

at TuyaDevice.emit (events.js:214:7)

at Socket.client.on.data (/etc/openhab2/scripts/node_modules/tuyapi/index.js:425:16)

at emitOne (events.js:116:13)

at Socket.emit (events.js:211:7)

at addChunk (_stream_readable.js:263:12)

at readableAddChunk (_stream_readable.js:250:11)

at Socket.Readable.push (_stream_readable.js:208:10)

(node:20295) 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:20295) [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.

(node:20295) UnhandledPromiseRejectionWarning: undefined

(node:20295) 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: 2)

(node:20295) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected end of JSON input

at JSON.parse (<anonymous>)

at TuyaDevice.runCommand (/etc/openhab2/scripts/node_modules/njstuya/njstuya.js:231:54)

at emitTwo (events.js:131:20)

at TuyaDevice.emit (events.js:214:7)

at Socket.client.on.data (/etc/openhab2/scripts/node_modules/tuyapi/index.js:425:16)

at emitOne (events.js:116:13)

at Socket.emit (events.js:211:7)

at addChunk (_stream_readable.js:263:12)

at readableAddChunk (_stream_readable.js:250:11)

at Socket.Readable.push (_stream_readable.js:208:10)

(node:20295) 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:20295) [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.

(node:20295) UnhandledPromiseRejectionWarning: undefined

(node:20295) 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: 2)’

Any idea?

However, without switching (just idling), approximately every minute I observed the following ERROR messages in the log:

I don’t understand how you can be getting an error if you are just idling. My script only starts up and runs when you run a command. If you are using some of my rules then there should be a cron job that runs every now and then to get the state or update the state.

It looks like you are running a -Set command but the arguments is not properly formatted. So have a look at any cron jobs you have running and see what commands they are running

Also try and enable warnings and errors in any rules so we can see what command is being sent., change the debug lines in the rules to true.

@unparagoned

I looked at my rules folder and renamed all recently changed files’ extension from xxx.rules to xxx.yyyrules and restarted the openhab2.service. That did not help.

I looked at /var/spool/cron/crontabs/ (I assume that this is where cron jobs are stored) but the folder is empty.

I also renamed your script folder from node_modules to _node_modules just to see what error messages I got and I saw these but I have no idea what they meant

2019-03-30 09:58:52.382 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: 'module.js:550'
2019-03-30 09:58:52.394 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: '    throw err;'
2019-03-30 09:58:52.397 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: '    ^'
2019-03-30 09:58:52.400 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: ''
2019-03-30 09:58:52.404 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: 'Error: Cannot find module '/etc/openhab2/scripts/node_modules/njstuya''
2019-03-30 09:58:52.406 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: '    at Function.Module._resolveFilename (module.js:548:15)'
2019-03-30 09:58:52.410 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: '    at Function.Module._load (module.js:475:25)'
2019-03-30 09:58:52.412 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: '    at Function.Module.runMain (module.js:694:10)'
2019-03-30 09:58:52.416 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: '    at startup (bootstrap_node.js:204:16)'
2019-03-30 09:58:52.418 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Exec [ERROR]: '    at bootstrap_node.js:625:3'
2019-03-30 09:58:52.426 [DEBUG] [hab.binding.exec.handler.ExecHandler] - Transformed response is 'module.js:550
    throw err;
    ^
Error: Cannot find module '/etc/openhab2/scripts/node_modules/njstuya'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._load (module.js:475:25)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3
module.js:550
    throw err;
    ^
Error: Cannot find module '/etc/openhab2/scripts/node_modules/njstuya'
    at Function.Module._resolveFilename (module.js:548:15)
    at Function.Module._load (module.js:475:25)
    at Function.Module.runMain (module.js:694:10)
    at startup (bootstrap_node.js:204:16)
    at bootstrap_node.js:625:3'

You must have a rule in /etc/openhab2/rules that runs the exec binding which is trying to call njstuya. If you just install njstuya by itself it doesn’t do anything, so you can’t be getting errors. You must have something that is trying to execute it. The errors above are just because you renamed node_modules to _node_modules. So whatever rule you have in openhab trying to run the node script fails, since it’s looking in the wrong place.

GadgetAngel
Your formatting may be off a bit.

Here is what I am talking about, I ran these two commands back to back. I do not understand why it states “undefined” and then I run it again and it does what it should had done the first time

PS C:\openhab2\userdata\etc\scripts> node  c:/openhab2/userdata/etc/scripts/node_modules/njstuya/njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -set '{ \"dps\": 2, \"set\": \"white\" }' DEBUG=*
(node:12400) UnhandledPromiseRejectionWarning: undefined
(node:12400) 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:12400) [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.
PS C:\openhab2\userdata\etc\scripts> node  c:/openhab2/userdata/etc/scripts/node_modules/njstuya/njstuya.js -ip 192.168.0.30 -id asdasd -key asdasda -set '{ \"dps\": 2, \"set\": \"white\" }' DEBUG=*
OFF
PS C:\openhab2\userdata\etc\scripts>

I tried stepping thru your code but you are more familiar with the code then me, since their is alot of timing stuff going on. It take me to long to figure out what variables I need to look at.

But if you could figure out why the above happens, I would appreciate it.

I am leaning toward using your code but I have to know if it executed correctly. I hate the idea of having to send a command twice just to make sure the command goes thru to the bulb

BTW it reported that the bulb is OFF when it was ON

Try

c:/openhab2/userdata/etc/scripts/node_modules/njstuya/njstuya.js -ip 192.168.0.30 -id asdasd -key asdasda -set '{ "dps": 2, "set": white }'
or
c:/openhab2/userdata/etc/scripts/node_modules/njstuya/njstuya.js -ip 192.168.0.30 -id asdasd -key asdasda -set "{ \"dps\": 2, \"set\": white }"
or
c:/openhab2/userdata/etc/scripts/node_modules/njstuya/njstuya.js -ip 192.168.0.30 -id asdasd -key asdasda -set '{ \"dps\": 2, \"set\": white }'

Or something like that.

Also I’m not sure my script properly deals or even know if it’s possible to easily deal with devices that use the dps options. There simply are so many types and variations when devices use multiple dps, and can be color, a fan, etc. You need to query the dps yourself and then convert that to a state. My script probably just works for switches.

here is the output from the commands you suggested:

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\openHAB2\userdata\etc\scripts\node_modules\njstuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -set '{ "dps": 2, "set": white }'
(node:2972) UnhandledPromiseRejectionWarning: undefined
(node:2972) 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:2972) [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.

C:\Windows\system32>
C:\Windows\system32>
C:\Windows\system32>"c:\Program Files\nodejs\node" c:\openHAB2\userdata\etc\scripts\node_modules\njstuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -set "{ \"dps\": 2, \"set\": white }"
(node:1772) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected token w in JSON at position 19
    at JSON.parse (<anonymous>)
    at TuyaDevice.runCommand (c:\openHAB2\userdata\etc\scripts\node_modules\njstuya\njstuya.js:231:54)
    at TuyaDevice.emit (events.js:194:15)
    at Socket.client.on.data (c:\openHAB2\userdata\etc\scripts\node_modules\tuyapi\index.js:425:16)
    at Socket.emit (events.js:189:13)
    at addChunk (_stream_readable.js:284:12)
    at readableAddChunk (_stream_readable.js:265:11)
    at Socket.Readable.push (_stream_readable.js:220:10)
    at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
(node:1772) 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:1772) [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.
(node:1772) UnhandledPromiseRejectionWarning: undefined
(node:1772) 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: 2)

C:\Windows\system32>
C:\Windows\system32>
C:\Windows\system32>"c:\Program Files\nodejs\node" c:\openHAB2\userdata\etc\scripts\node_modules\njstuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -set '{ \"dps\": 2, \"set\": white }'
(node:6284) UnhandledPromiseRejectionWarning: SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at TuyaDevice.runCommand (c:\openHAB2\userdata\etc\scripts\node_modules\njstuya\njstuya.js:231:54)
    at TuyaDevice.emit (events.js:194:15)
    at Socket.client.on.data (c:\openHAB2\userdata\etc\scripts\node_modules\tuyapi\index.js:425:16)
    at Socket.emit (events.js:189:13)
    at addChunk (_stream_readable.js:284:12)
    at readableAddChunk (_stream_readable.js:265:11)
    at Socket.Readable.push (_stream_readable.js:220:10)
    at TCP.onStreamRead [as onread] (internal/stream_base_commons.js:94:17)
(node:6284) 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:6284) [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.
(node:6284) UnhandledPromiseRejectionWarning: undefined
(node:6284) 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: 2)

C:\Windows\system32>

Here is What DOES WORK:

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\openHAB2\userdata\etc\scripts\node_modules\njstuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -set "{ \"dps\": 2, \"set\": \"white\" }"
OFF

C:\Windows\system32>

Because I have to specify the full path for node.exe and it resides in “Program Files” I have to use double quotes in the path. So I have no choice on windows, I MUST use double quotes. Since I am stuck with double quotes, I must use double quotes around the -set string. Mixing the quotes NEVER works for me because I have to use a pair for the path definition (needed for executeCommandLine call in rules file).

HERE is my trying to access node.exe two different ways on windows, you can see from the output that cmd.exe can not use single quotes in the path definition:

C:\Windows\system32>'c:\Program Files\nodejs\node'
The filename, directory name, or volume label syntax is incorrect.

C:\Windows\system32>"c:\Program Files\nodejs\node"
>
(To exit, press ^C again or type .exit)
>

C:\Windows\system32>

Hey, unparagoned:

I would like to add some code to your script. How do we go about doing that?

What I have added will not effect anyone else because my new command switch calls a new function.

I added a new command line switch to your njstuya.js file which allows the user to set multiple dps values in one command.

The new command switch -multi uses a function, I wrote (modeled after your setState function) to call tuyapi but allows the multi dps set to occur. The -multi command has the following format:

-multi { “dps index as number”: dpsvalue, “dps index as a number”: dpsvalue }

The first key is the dps index expressed as a character, then the colon, then the value (for that dps index) followed by the comma

so the -multi command line switch can be used to set one dps or multiple dps’ values

MULTIPLE DPS values set (dps 1,2,3,4,5,6)
-multi { "1": true, "2": "string", "3": 255, "4": 255, "5": "string", "6": "string" }

ONE DPS value set (dps 1)
-multi { "1": true }

I will get your project from github, but I am not familiar with github enough to know how to get the changes I added back to you. I use WebStorm for my projects and it does have an interface with github.

Here is an example of it running:

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\Users\joann\WebstormProjects\njsTuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -multi "{ \"1\": false }"
OFF

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\Users\joann\WebstormProjects\njsTuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -multi "{ \"1\": true, \"2\": \"scene_2\" }"
ON

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\Users\joann\WebstormProjects\njsTuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -multi "{ \"2\": \"white\", \"3\": 255, \"4\": 255 }"
OFF

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\Users\joann\WebstormProjects\njsTuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -multi "{ \"2\": \"colour\", \"5\": \"00ff040079ffff\" }"
OFF

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\Users\joann\WebstormProjects\njsTuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -multi "{ \"1\": false }"
OFF

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\Users\joann\WebstormProjects\njsTuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -multi "{ \"1\": true, \"2\": \"white\", \"3\": 138, \"4\": 255 }"
ON

C:\Windows\system32>"c:\Program Files\nodejs\node" c:\Users\joann\WebstormProjects\njsTuya\njstuya.js -ip 192.168.0.30 -id 5846055184f3eb20bfaf -key afb9b013346054e6 -multi "{ \"1\": true, \"2\": \"white\", \"3\": 27, \"4\": 255 }"
ON

Created a PULL request let me know if you have any questions.

let me know what you want to do.

Windows is just a complete nightmare when it comes to trying to format the JSON strings, single and double quotes. One will work on the command line then stop if you use that format in the exec command from a rule. Really I should just say no windows support, it’s silly and stupid. It’s probably cheaper in terms of my time to buy everyone who has a problem with windows a raspberrypi.

Also thanks for your pull request but can you get it to work as is by just passing passing the correctly formatted set command? Something like below but with the quotes fixed to work on windows?

-set '{ "multiple": true, "data": {  "2": scene, "6": bd76000168ffff } } }'