TUYA and Nodered

Recently I wanted to control Tuya-based devices from the GX. Most of the smart timers, plugs, isolators etc that we get locally all seem to use Tuya.

I thought, for those interested I would document my experience and how to go about it.

My use case was to control a geyser, I wanted to use all the free battery capacity in the morning but not hit the ESS limit.

My plan was to create a control logic that monitors the geyser state and battery SOC and turns the geyser on/off as needed until it is at temp.

First step is getting the local access key for each device. This requires moving the device from any third party tuya apps onto the default Tuya smart life app, which is required to access the API.

Follow this video for how to get the local key:

Controlling the device via the cloud was too slow, instead managing them over the LAN is much more reliable.

For this you need the device IP of each, you need to set this to be static on the device or via your home router using reserved DHCP.

At this point you can load node-red-contrib-tuya-smart-device on the cerbo and use the tuya smart device node to connect using the local IP and local key of the device.

My flow is basic it uses the dps register 1 of tuya to turn the device on and off and tracks power consumptions from register 23.

You can query what your device supports via the tuya API on their dev portal.

For my use case, I turn the device on via a normal timer on the app and have a smart scene set that tracks when power drops below 100W (indicating it is heated) and then it turns the geyser off. So no matter how it is activated it will run as long as required to fully heat, then stop.

My flow tracks if the geyser turned itself off, or if it was stopped due to SOC minima, in the latter case, it will keep heating the geyser once the SOC is 4% above the min ESS value (this could be done smarter and linked to the ESS node) and is turned off at 2% above ESS min SOC.

It is a really useful way to control devices via the Cerbo, optimise use and avoid unnecessary grid usage.

The same method can be used for activating pumps, turning on light bulbs (or setting their colour). Next project is to make some house lighting LED’s pulse in red on grid loss.

flows-7 2.json.zip (6.2 KB)

4 Likes

Thanks a lot for sharing!

I’m trying to integrate a tuya/Smartlife compatible wifi EV charger, installed the Smartlife app and could connect it to my internet box over wifi, and integrate it to iot.tuya.com to fetch the id and local key. I installed the node-red-contrib-tuya-smart-device on my CerboGX (venus large) and can set up everything over there, so this shouldn’t be a problem. But I’m missing a step before that!

I’d like to connect the ev charger directly to the CerboGX AP (as I did with a few tasmota devices that have a local admin AP for setting the wifi connection), but since this AP has no internet, the ev charger doesn’t connect to this AP when trying to associate it through smartlife (having the phone connected to the CerboGX AP or over LTE…).

I was hoping to be able to bridge the internet from the ISP box wifi (it is too far for an ethernet cable, don’t know if this would be a game changer) to the Cerbo GX AP so that the Smartlife could pair the tuya device to the Cerbo GX, but I read that this is not planned by Victron, and would require patching the whole venus OS, so this is apparently not an option for me.

I’m curious where your tuya device are connected: Cerbo GX AP or internet connected wlan to which the Cerbo is connected?

I also tried to reach the IP of the tuya device on my ISP box wifi in node-red (using only the local IP - which I ping successfully from the cerbo SSH access - and the local key), but it doesnt connect, here is the debug output:

"find() timed out. Is the device powered on and the ID or IP correct?"0]
"findDevice(): Cannot find the device, re-trying..."
{ state: "ERROR" }
{ state: "DISCONNECTED" }

Sorry for this long post - I fully understand I’m mainly fighting around tuya/Smartlife’s design to be fully online at all time rather than Victron’s design choice to not bridge internet access (which I understand given the resources constraint), but it would be helpful to know if I can achieve this connection and to which wifi network I should hook the ev charger in order to pass the next step.

I have a meshed wifi system from Aruba that covers my entire property with a dedicated IOT network.
Due to its location the GX is also on wifi and this is the only interface and has internet access, so they are all logically on the same LAN segment.

Thanks a lot for this quick reply, it’s good news that it worked over wifi through the network on which the Cerbo is connected. I guess I have another problem to reach it from the Cerbo (tried through node-red or using tuya-cli from ssh, no luck) then, but at least I have the confirmation that it could work in this scenario. I suspect it could be a firewall blocking the 6668 port on the wlan network, I’ll try to investigate this next week with the administrator of the network.

I really wish I could bridge the internet connection from the wlan0 to the ap0, even just for associating the tuya device to the CerboGX network directly (simpler to set up and the device would continue to receive commands from the cerbo when the local network is down)… I’ve read that it’s complicated to do so from eth0 to wifi0 but I’m wondering if it could be done from wlan0 to ap0 by adding bridge=wlan0 in /etc/hostapd.conf and restarting hostapd from SSH. But I’m wary to try if this breaks the AP and access to the Cerbo via SSH…

Of course, I wouldn’t use the AP as a router for anything else than pairing the device to the AP network. Any feedback or ideas on this are welcome!

Thanks for this work!

If you’re still available, I need some assistance getting this to work with a EG4 Hybrid mini-split in my off-grid cabin running Venus OS on an RPi

Following all the outlined steps, plus others to find all the DP ids.

The flows seem to be working, but the only output from the tuya-smart-device node is:

msg.payload : Object {data:object,deviceId:“XXXXXX”,deviceName:“Solar AC 26A”}

The Client State output reports “CONNECTED” on deployment

The payload of the inject node is: (gets current temperature)

{
    "operation": "GET",
    "payload": {
        "dps": 3
    }
}

Any ideas would be appreciated.

Thanks

Hi Dave.
A good place to start is to use the tuya dev site tools to poll the device capabilities.
This will provide a list of all the fields it supports and their ID’s.
Some devices behave differently.
Once you have a list of instructions it supports, you can try manually poll the ones you need.
Have you assigned the device a fixed IP or static DHCP address?
What does a debug node for that flow return?

Hi Nick:

Thanks for the quick reply.

After some experimentation, It’s working, just not as I expected.

Using tuya-smart-device: trying to poll for the current temp using Inject node with payload:

{
    "operation": "GET",
    "payload": {
        "dps": 3
    }
}
  • Successfully connects using the DeviceVirtualID set to DeviceID from the dev site with the local key as above
    • However, rather than returning a single value, the output returns payload with all of them.
    • {"data":{"dps":{"1":false,"2":23,"3":12,"4":"hot","6":false,"9":false,"10":false,"11":true,"19":75,"20":53,"21":"c","22":"off","23":"auto","24":0,"101":false,"104":false,"105":false,"106":0,"107":1088770,"108":0,"109":0,"110":1595113,"111":0,"112":false,"119":60}},"deviceId":"eb02c05c482b5be272pdwo","deviceName":"Solar AC 26A"}
      
    • Although I could not find what dps==119 refers to (see list of dps codes below)

Even though asking for specific values would be simpler, I can work with this.

Tomorrow I’ll see if I can use SET to turn it on/off.

Thanks.

BTW If the StaticIP is used, it times out with “Cannot find device, retrying…”

DP_ID         CODE
switch        { "code": "1", }
temp_set      { "code": "2", }
TempCurrent C { "code": "3", }  Celsius
Mode          { "code": "4", }
ECO           { "code": "6", }
Anion         { "code": "9", } 
ElectricityHeat { "code": "10", }
Light         { "code": "11", }
SetTemp       { "code": "19", }
TempCurrent F { "code": "20", } Farenheit
temp_unit_convert  { "code": "21", }
Status        { "code": "22", }
FanSpeed      { "code": "23", }
Fault         { "code": "24", }
Sleep         { "code": "101", }
Horizontal    { "code": "104", }
Vertical      { "code": "105", }
SolarInputNow { "code": "106", }
TotalSavingEnergy          { "code": "107", }
SolarInputPercentage       { "code": "108", }
ElectricityInputPercentage { "code": "109", }
TotalConsumputionPower     { "code": "110", }
GridPowerConsumption       { "code": "111", }
AC Limiter                 { "code": "112", }

Just remember you can’t have both IP and device ID set in the node, one or the other.
So it is returning an array, fair enough, in some respects easier just needs the code adjusted.
Implementations seem to vary between manufacturers, but tend to be common within a manufacturers product range.
I have found you need to take a new device and monitor how it behaves with a debug node, then adjust your flow accordingly.