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
-
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 installpython-pip
.Note: Do this with your default user (eg Pi), not the Home assistant account.
sudo apt-get install python-crypto python-pip
-
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.
-
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.