Introduction
This is Python tutorial relating to monitoring plants. Indeed, it seems hard to remember every week or so to water plants and sometimes a reminder could serve us a lot. We’re all busy and forgetting to water our own plants is absolutely ok, lol.
OK, so if you’re a visual person, you can just ignore this article and watch the tutorial above to follow up with how to build the plant monitoring IoT system. If not, feel free to follow this article. So python will monitor our plant thanks to Tuya API cloud.
Getting Started
So the first thing you need to do is create an account on Tuya using this link. Please check the video for details on how to do that since it seems impossible to write the steps down. This article will focus on the python code instead. Please watch the video up to the point where you get your Tuya API key and ID to define the API credentials and access the endpoints.
Installing the Tuya modules via pip
Now, we’re going to use our good old buddy, “pip” to install the following modules
!pip3 install tuya-connector-python
!pip3 install tuya-iot-py-sdk
!pip3 install pycryptodomex
Define our Access ID, Access Key and Endpoint
As mentioned, after you create your Tuya account you will have access to two important things, the Access ID and Access Key, let’s define them as such
ACCESS_ID = "7cvey7v7azt99v7mox7z"
ACCESS_KEY = "79415ad8a4d44a8db80920cb4ed8cd20"
API_ENDPOINT = "https://openapi-weaz.tuyaeu.com"
Note that, because I’m being nice with you, I’m sharing my credentials (Access ID and Access key) but you should not share them with anyone, otherwise they will be able to control your IoT devices from any part of the world. Also note that, since I’m based in Nice, France, that is in Europe, the above endpoint will look like the above (tuyaeu).
Connect to our Tuya API endpoint
Now, let’s proceed to connect to our Tuya API cloud via Tuya’s very own TuyaOpenAPI()
from tuya_connector import TuyaOpenAPI
openapi = TuyaOpenAPI(API_ENDPOINT,ACCESS_ID,ACCESS_KEY)
openapi.connect()
If all goes well, you should be able to see the following JSON response from the API cloud
{'result': {'access_token': '22b6aa36107ee30aebd30292dc4f38d7',
'expire_time': 5865,
'refresh_token': '9f76f71089a775bc2d7daf5854b5e740',
'uid': 'bay1632079226744ZEW2'},
'success': True,
't': 1633866895317}
Define device ID
Now, just like you define variable (example: x=1), we will proceed to define our own devices that are the RGB LED strip and the humidity/temperature sensor
RGB_DEVICE_ID = "68560540807d3a1a9573"
SENSOR_DEVICE_ID = "9be9a7703302248c4esjma"
Note that you have to create your devices using Tuya’s platform in order to proceed. Also, I encourage you to watch the video above to know how to exactly do this.
Get IoT node specifications
Tuya makes it really easy to get all the functions we have at our disposal using a simple API call. For example, the following call
response = openapi.get("/v1.0/iot-03/devices/{}/specification".format(RGB_DEVICE_ID))
print(response)
prints the following response
{'result': {'category': 'dj',
'functions': [{'code': 'switch_led',
'desc': '{}',
'name': '开关',
'type': 'Boolean',
'values': '{}'},
{'code': 'bright_value',
'desc': '{"min":25,"scale":0,"unit":"","max":255,"step":1}',
'name': '亮度',
'type': 'Integer',
'values': '{"min":25,"scale":0,"unit":"","max":255,"step":1}'},
{'code': 'flash_scene_1',
'desc': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}',
'name': '柔光模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'flash_scene_2',
'desc': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}',
'name': '缤纷模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'flash_scene_3',
'desc': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}',
'name': '炫彩模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'work_mode',
'desc': '{"range":["white","colour"]}',
'name': '工作模式',
'type': 'Enum',
'values': '{"range":["white","colour"]}'},
{'code': 'temp_value',
'desc': '{"min":0,"scale":0,"unit":"","max":255,"step":1}\t',
'name': '色温',
'type': 'Integer',
'values': '{"min":0,"scale":0,"unit":"","max":255,"step":1}\t'},
{'code': 'colour_data',
'desc': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}',
'name': '彩光模式数',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'scene_data',
'desc': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}',
'name': '情景模式数',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'flash_scene_4',
'desc': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}',
'name': '斑斓模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'}],
'status': [{'code': 'bright_value',
'name': '亮度值',
'type': 'Integer',
'values': '{"min":25,"scale":0,"unit":"","max":255,"step":1}'},
{'code': 'colour_data',
'name': '彩光模式数',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'scene_data',
'name': '情景模式数',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'flash_scene_2',
'name': '缤纷模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'switch_led', 'name': '开关', 'type': 'Boolean', 'values': '{}'},
{'code': 'work_mode',
'name': '工作模式',
'type': 'Enum',
'values': '{"range":["white","colour"]}'},
{'code': 'temp_value',
'name': '冷暖值',
'type': 'Integer',
'values': '{"min":0,"scale":0,"unit":"","max":255,"step":1}\t'},
{'code': 'flash_scene_1',
'name': '柔光模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'flash_scene_3',
'name': '炫彩模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'},
{'code': 'flash_scene_4',
'name': '斑斓模式',
'type': 'Json',
'values': '{"h":{"min":1,"scale":0,"unit":"","max":360,"step":1},"s":{"min":1,"scale":0,"unit":"","max":255,"step":1},"v":{"min":1,"scale":0,"unit":"","max":255,"step":1}}'}]},
'success': True,
't': 1633866895551}
The way we interpret the above is as follows: For example, the first function is switch_led and it accepts a boolean (either ON/OFF). To discover more functionalities, please refer to the video above.
Change the LED Strip color
I will show you a bonus here on how to switch colors of the RGB strip as follows:
command = {"commands":[{"code":"colour_data","value":{'h':0,'s':100,'v':40}}]}
openapi.post("/v1.0/iot-03/devices/{}/commands".format(RGB_DEVICE_ID),command)
As you can see, all we did is “pack-up” a JSON in a variable called command, where we define the color defined in an hsv basis instead of an rgb one. Feel free to experiment with different colors.
Read temperature/humidity information from sensor
Now that we have the RGB all set up, we will configure it to blink when the plants need watering. But FIRST. How do we know that the plant needs to be watered ? That’s where the humidity sensor comes into play. The humidity sensor is placed on the surface of the soil of the plant. All we need to do now is configure it properly so that we can read its humidity. This is attained as follows:
response = openapi.get("/v1.0/iot-03/devices/{}/status".format(SENSOR_DEVICE_ID))
response
If done properly, you should receive the following API response
{'result': [{'code': 'humidity_current', 'value': 6050},
{'code': 'va_battery', 'value': 100},
{'code': 'temp_current', 'value': 2340}],
'success': True,
't': 1633868016000}
which basically reads as follows: Humidity is 60.5%, Battery life is 100% and temperature is 23.4 degrees Celsius. For better parsing, we can do this
humidity = response['result'][0]['value'] / 100
battery = response['result'][1]['value']
temperature = response['result'][2]['value'] / 100
print("Humidity = " + str(humidity))
print("Battery = " + str(battery))
print("Temperature = " + str(temperature))
which outputs this in our case
Humidity = 60.5
Battery = 100
Temperature = 23.4
Monitor my Plant
Now, we are ready to define the main loop to monitor our plants and save our planet ! This is where a Python loop could save nature
humidityThreshold = 70
LedEn = True
sensorReadingTime = 5 # seconds
while True:
response = openapi.get('/v1.0/iot-03/devices/{}/status'.format(SENSOR_DEVICE_ID))
humidity = response['result'][0]['value'] / 100
time.sleep(sensorReadingTime)
if humidity < humidityThreshold:
LedEn = False
else:
LendEn = True
commandLEDStrip = {"commands":[{"code":"switch_led","value":LedEn}]}
openapi.post('/v1.0/iot-03/devices/{}/commands'.format(RGB_DEVICE_ID),commandLEDStrip)
So all we did above was set the humidity threshold to 70%, i.e. if the humidity sensed by the sensor is less than 70, we turn the RGB strip off as a reminder to water our plants, else it stays on. I really urge you to check the last part of the video as a demo of the above loop.

Subscribe to my channel to support us ! We are very close to 100K subscribers <3 w/ love. The algorithmic chef – Ahmad Bazzi. Click here to subscribe. Check my other articles here
Thanks for sharing Tuya with us. I have registered.