Tuya Switches w/ Power Usage Data (No TuyaConvert Needed)

I just pushed version 1.1.2 to PyPi. This fixes an issue with some device using different dps keys.

TuyaPower2MQTT - PyPi Module

Description

Python module to pull power and state data from Tuya / Smart Life / Jinvoo WiFi smart socket/switch devices. Tested on RaspberryPi, Linux, Windows 10 and MacOS.

It might look long and complicate, but it’s not. I’ve just tried to give as much detail as possible to make it easy to follow for all levels of user. Until 2 weeks ago, I’d never touched python, so I’m learning myself. Feel free to message me if you have any questions or suggestions for enhancements.

Preparation

  1. All python dependencies for TuyaPower2MQTT will be automatically installed. However, you may need to install python-crypto via apt/yum/etc. If this is your first pip package then you may also need to install python-pip.

    Note: Do this with your default user (eg Pi), not the Home assistant account.

    
    sudo apt-get install python-crypto python-pip
    
    
  2. You’ll need a Mosquitto (MQTT) server to publish the data to. If you don’t already have one running, I recommend following this simple tutorial: Installing an MQTT server on Debian. Note, you can try installing MQTT without adding the repo suggested in the first step. Don’t forget to add your MQTT integration into Home assistant.

  3. Determine the firmware version for the device(s) that you want to get data for. You can do this via the Tuya / Smart Life / Jinvoo apps by drilling down into the individual devices. Do this now as it’ll save time later.

    Note: If you have a device with firmware 1.0.5 or above you may need to follow step 2 in this guide to finding your device key. I had some trouble doing this using a new android device with dualband WiFi, but no problem with an older 2.4Ghz device.

Installation

Using your default user account, we need to install the TuyaPower2MQTT python package from PyPi. This will automatically install several dependency’s.


pip install tuyapower2mqtt

Now we need to find out exactly where pip installed the tuyapower2mqtt package.


pip show tuyapower2mqtt

You should see something similar to this:

Let’s edit the script to ensure that we can publish the stats to our MQTT server.


sudo nano /your/path/to/tuyapower2mqtt/getstats.py

Edit the MQTT section to suit your server.


# Setup MQTT server with your credentials
# EDIT THIS
MQTTSERVER="127.0.0.1"
MQTTUSER="{mqttusername}"
MQTTPASSWORD="{mqttpassword}"
MQTTTOPIC="devices/tuya/plug/" # Keep trailing slash
MQTTPORT=1883
MQTTRETAIN=False #True / False
# STOP EDITING

Now we need to grab the path of python itself, in order that we can run it from cron later.


which python

Now that we have both paths and set the MQTT credentials we should do a quick test, just to make sure everything works as expected.

Assume we have the following device:


ID: dev123456789
IP: 192.168.0.50
KEY: ghhthrtjztj5ztw4rer
FIRMWARE: 1.0.2

Now we need to subscribe to the appropriate MQTT topic ready to check our first device message:


 mosquitto_sub -t "devices/tuya/plug/dev123456789" -u {mqttusername} -P {mqttpassword}

Note: The channel is specific to your device and is essentially "devices/tuya/plug/{your-device-id}".

Now open another terminal and enter the directory for TuyaPower2MQTT that we got a few moments ago:


cd $HOME
cd /path/to/your/python/packages/tuyapower2mqtt/

enter and call the tuyapower2mqtt script. To do this we need to enter the relevant data in this format:


python getstats.py {DEVICEID} {DEVICEIP} {DEVICEKEY} {VERSION} 

For devices with firmware 1.0.4 and below you’ll typically need to use the following format. Substitute the dummy data for that of your device:


python getstats.py "dev123456789" "192.168.0.50" "ghhthrtjztj5ztw4rer" "3.1"

Note: The “3.1” refers to the tuya api version and not the actual firmware number on the device. The device ID and KEY are optional with this api version. However, the script requires at least a placeholder or empty quotes to work. Therefore it’s recommended that you add the key and device id anyway, since you may need this if the device gets a firmware update.

For devices with firmware 1.0.5 and above you’ll typically need to use the following format. Substitute the dummy data for that of your device:


python getstats.py "dev123456789" "192.168.0.50" "ghhthrtjztj5ztw4rer" "3.3"

Note: Devices with newer firmware versions use the v3.3 api and do require a valid key and device details to work effectively.

In the terminal we used to subscribe to the topic, you should now see something similar to this:


{ "deviceid": "dev123456789", "datetime": "2019-11-02T20:30:05Z", "switch": "False", "power": "0.0", "current": "0.0", "voltage": "228.0" }

If you got any other result, you’ve most likely entered the wrong version number. Otherwise, check you are using the correct device IP, device KEY and device ID.

Making This Useful
Now we have a way to get the power data from our Tuya / Smart Life / Jinvoo device, but we need to make this useful. We need it automated so that we can get this data on a regular basis to make it useful.

The simple solution to that is, cron!

Enter the following in you bash terminal (not python!):


crontab -e

If prompted select your editor of preference. Personally I use nano, I like its simplicity. Once crontab is open scroll down past all the comments and enter the tuyapower2mqtt command we just tested:


* * * * *  python getstats.py "dev123456789" "192.168.0.50" "ghhthrtjztj5ztw4rer" "3.1"

or


* * * * *  python getstats.py "dev123456789" "192.168.0.50" "ghhthrtjztj5ztw4rer" "3.3"

The stars at the beginning, tell cron that we want to run this script every minute of the day 24/7. If you need different timings, just make the relevant changes according to standard cron formatting. I’d be cautious of doing calls too often as it could cause the device to lock you out.

Since we’re now relying on cron to poll the devices, we need to make sure it knows which version of python to use and where to find the TuyaPower2MQTT package. To do this we need to put in the absolute paths to Python and TuyaPower2MQTT that we checked for earlier on.

Remember?


which python

and


pip show tuyapower2mqtt

Go ahead and add these into the entry we made in crontab. On my system the command now looks like this:


* * * * *  /home/pi/berryconda3/bin/python /home/pi/berryconda3/lib/python3.6/site-packages/tuyapower2mqtt/getstats.py "dev123456789" "192.168.0.50" "ghhthrtjztj5ztw4rer" "3.3"

Multiple Devices?

To get stats for more than one device simply duplicate the line we just entered into crontab, substituting in the data for your next device. The only limitation to the number of devices you can use is the MQTT / HA server and network.

BONUS: Integration with Home Assistant
At this point you should be successfully gathering and broadcasting your device data onto individual topics in MQTT. But, we want this to be useful in Home Assistant. So, here’s a quick example of how you can do that.

I personally use several of these devices for letting my Wife know when the washing machine and dryer are finished, and to let me know when the 3d printer has finished. They are all located in the basement, whilst we live on the 1st floor. No more walking up and down stairs several times to check!

P.s. I know it’s OUR WASHING! At least I’m making it a bit easier for my wife, right?

Step 1. Create some sensors.


- platform: mqtt
  name: "Tuya Dryer Switch"
  state_topic: "devices/tuya/plug/dev123456789"
  unit_of_measurement: W
  value_template: "{{ value_json.switch }}"

- platform: mqtt
  name: "Tuya Dryer Power"
  state_topic: "devices/tuya/plug/dev123456789"
  unit_of_measurement: W
  value_template: "{{ value_json.power }}"

- platform: mqtt
  name: "Tuya Dryer Current"
  state_topic: "devices/tuya/plug/dev123456789"
  unit_of_measurement: mA
  value_template: "{{ value_json.current }}"

- platform: mqtt
  name: "Tuya Dryer Voltage"
  state_topic: "devices/tuya/plug/dev123456789"
  unit_of_measurement: V
  value_template: "{{ value_json.voltage }}" 

The above code now gives us 4 sensors detecting each of the attributes we get from TuyaPower2MQTT via MQTT. Notice that this uses the MQTT platform and is updated automatically whenever a message is published with our device topic. Remember to replace our dummy device id with that of your actual Tuya device.

Step 2. Create a Binary Sensor.
This enables us to detect when the machine has effectively stopped its programme but the Tuya device it uses is still switched on.


- platform: template
  sensors:
    dryer_status:
      friendly_name: "Dryer Status"
      delay_on:
        minutes: 2
      delay_off:
        minutes: 25
      value_template: >-
        {{ states('sensor.tuya_dryer_power')|float > 5 }}

You’ll need to play around with the delay_on & delay_off, and the power level values by monitoring the peaks and troughs in your devices power usage. You can do this by watching the usage in the Tuya app whilst the device is running.

Our washing machine for example has a huge surge of power when it starts and drops off after 20 mins or so. It then continues to use a much lower level for the remainder of the program. When the programme is finished it still draws a noticeable current. The dryer however, has big long troughs where it uses almost no power before starting up again. However, once it’s finished the programme it draws essentially nothing hence the long ‘delay_off’.

3. Create Some Automations
The following code notifies us via the Alexa devices in our home. It does this once the device has finished beyond reasonable doubt (see binary sensor), and then at intervals of 15 & 30 minutes if the Tuya plug is still switched on.


#
# Notify: Dryer is finished
#
- id: Dryer Just Finished
  alias: Dryer Just Finished
  trigger:
    platform: state
    entity_id: binary_sensor.dryer_status
    to: 'off'
  action:
    - service: script.device_activity
      data:
        alexa_message: "The Dryer is  finished."

#
# Notify: Dryer finished 15mins ago
#
- id: Dryer Finished
  alias: Dryer Finished
  trigger:
    platform: state
    entity_id: binary_sensor.dryer_status
    to: 'off'
    for: "00:15:00"
  condition:
    condition: state
    entity_id: switch.dev123456789
    state: 'on'
  action:
    - service: script.device_activity
      data:
        alexa_message: "The dryer  finished 15 minutes ago!"

#
# Notify: Dryer finished 30mins ago
#
- id: Dryer Finished Final
  alias: Dryer Finished Final
  trigger:
    platform: state
    entity_id: binary_sensor.dryer_status
    to: 'off'
    for: "00:30:00"
  condition:
    condition: state
    entity_id: switch.dev123456789
    state: 'on'
  action:
    - service: script.device_activity
      data:
        alexa_message: "The dryer finished 30 minutes ago. I'm going to turn off the plug."
    - service: switch.turn_off
      entity_id: switch.dev123456789

Notice that these automations use the binary sensor to detect that the Dryer has finished, but that the physical Tuya switch is still on. If we’d already collected the clothes, we’d have turned the socket off and wouldn’t get anymore alerts. If we’ve still not got the laundry after 30mins, Home Assistant kindly turns off the Tuya switch to save wasting electricity.

The automations above notify us of the device status via Alexa. You can of course use any notify method you want. Just adapt the sensors accordingly.

Bonus #2: The Alexa Script
Since a big part of using Home assistant for us is having Alexa announce when things happen, I created a number of template scripts that make it easy to keep a standardised approach to how different announcement types are made. It keeps things working more cohesively and makes it easier to update things (eg volume levels or the alexa devices to use).

In this case I have an Alexa script that I use specifically for the Washer, Dryer & 3d Printer:


#
# DEVICE FINISHED CYCLE
#
device_activity:
  alias: "device_activity"
  sequence: 
    - service: script.utility_alexa_say
      data_template:
        alexa_entity: media_player.kitchen
        alexa_volume: 0.8
        alexa_message: "{{ alexa_message }}"
        alexa_volume_reset: 0.6
    - delay:
        seconds: 5
    - service: script.utility_alexa_say
      data_template:
        alexa_entity: media_player.lounge
        alexa_volume: 0.8
        alexa_message: "{{ alexa_message }}"
        alexa_volume_reset: 0.6


#
# UTILITY ALEXA TTS
#
utility_alexa_say:
  alias: Alexa TTS Script
  sequence:
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ alexa_entity }}"
        volume_level: "{{ alexa_volume }}"
    - delay:
        seconds: 2
    - service: notify.alexa_media
      data_template:
        target: "{{ alexa_entity }}"
        data:
          type: tts
        message: "{{ alexa_message }}"
    - delay:
        seconds: 2
    - service: media_player.volume_set
      data_template:
        entity_id: "{{ alexa_entity }}"
        volume_level: "{{ alexa_volume_reset }}"

CALL FOR HELP!
If you can think of any way to improve this setup, I’d love to hear it and improve this guide &/or the TuyaPower2MQTT package. I’d really like to get this setup work 100% within Home Assistant, without the need for cron jobs. Sadly, I keep running into issues with a shell_command setup and the Python scripts integration doesn’t allow imports, which this needs.

GOT QUESTIONS?
Feel free to post questions / suggestions / comments below. I’ll do my best to help & answer.

11 Likes

Do say more, I’m interested in that!

@borger @rhoppel @Steaders1965 @Nath @Malaga82 @teitelbot @Micke_Hedqvist @chilman4081
Here you go! My walkthrough is finally ready.

Thanks for doing this. Im not in a rush to get my tuya devices going right now as my sonoffs are working at this moment. Im also not sure how to install any python using my VM hassio setup yet. Do you think this will become a hassio addon like zigbee2mgtt?

1 Like

I’ve no plans to turn it into a Hassio addon since I don’t use that, but if someone else wanted to help with the development of that I’d be happy to accept a pull request for it.

However, I am considering making it into making it available via HACS. This would then make it available to HASSIO users. I’ve no idea how feasible this is as this stage, but I’ll do what I can.

4 Likes

HACS would be great for me

1 Like

BTW how did you learn python so quickly?

Looked at an existing project and it all seemed logical. I do php, c#, etc so the jump to python was fairly straightforward.

Thanks, Phill
After three weeks of struggling with a completely new topic about the home automation for a newbie like me, Tuya switches start working for me. I am very grateful for your help. Thank you!

1 Like

Great! I’m glad it helped you and thanks for the feedback. It’s good to see that people are able to make use of it and get the desired results.

Hello Phill!
Thank you for the writeup, it was very helpful!
Have you ever had an experience where you only get the switch state sent to MQTT?

I don’t see any power values reported, just “switch”: “True”/“False”.

The values seem to be correct, as if I change any of them I get a “No response from plug” error.

It sounds like you have devices which don’t record / report power usage etc. Can you get the info in the tuya app?

I accidentally upgraded that one to the latest firmware using the ‘smart life’ app before I realized that it would make things more difficult.
It being my only Version 3.3 device might be part of the problem, but I can see the power reported in the app and it breaks the script if I change the key, which makes me think that the key I found is correct too.

Strange thing is that the new app (Jinvoo Smart) which one of the guides to find the key told me to download says that the firmware on that switch is 1.0.3 still, which it shouldn’t be… (also specifying version 3.1 in the script breaks) so maybe that has something to do with it?

Yes very strange. What firmware does Tuya say is on it?

Apparently the firmware of these devices is actually very dependent on the manufacturer. So for example Firmware v1.02 from one manufacturer might be the same as firmware version 1.23 on another manufacturers device.

It might be that your device reports stats on different id’s to the devices that I tested the v3.3 protocol with. Or, maybe there is an even never one. Are you able to install & run python scripts? If so, I could knock up a script that we can use to test your device with.

I’m able to install and run python scripts!
What do you think we should test out?

As to the Tuya app, do you mean the one listed as “Tuya Smart”? If so, that one lists Wi0Fi and MCU as version 1.0.3.

As a side note, I’ve built a docker image to do the publish to MQTT that should be publicly available here: Docker

It’s not as fleshed out yet as I would like it to be; however, it seems to work!
Currently it only supports one device per container and you can’t change all of the options yet; however, I’ll updated it a bit more when I have time.

Well, when I implemented the v3,3 protocol I had to determine which values were the various points of interest(wattage, amps etc) from a chain of data. It might be that the data comes in different orders for different devices.

I can make a script that just outputs all the data then use several samples to establish which pertain to what on your device. It may be that nothing is returned and then we know it is a different issue.

P.s. There already is a tuya docker version that I was involved in. Look on pypi.org and do a search for tuyapower. You will find my script and another one, the other one (tuyapower not tuyapower2mqtt) is more focused on docker.

Oh wow, I didn’t know that existed!

The status data returned from my switch using pytuya.OutletDevice(deviceid, ip, key).status() is:

{'devId': 'XXX', 'dps': {'1': True, '2': 0, '4': 160, '5': 204, '6': 1239}

Is this what you were referring to?
Some of the values look close… but don’t look perfect.

If you are getting results with that then you should be getting them with my script too. It’s all based in the same underlying code.

Hello Phill!

The problem is that the indexes are mismatched for my version 3.3 devices. For some reason I don’t have index 19 like you have seen.

I have opened a pull request that fixes this problem for me at your repo and should still work for index 19 devices: Version 3.3 power index fix by WeldFire · Pull Request #1 · codeclinic/TuyaPower2MQTT · GitHub