Author: Joel Städe S226YV This tutorial provides the steps on how to build your own self watering pot. It will monitor the soil and trigger the opening of a solenoid valve. This tutorial will show how to do the following: * Collect sensory data on soil moisture. * Sending the data to a broker over a local network. * Visualize the data using the library plotly in python. Estimated time to build: 5-6 hours # Objective It is easy to forget to water your plants. Not only will the pot water itself but with this addon for a pot it will be possible to adjust the amount of water it receives and monitor how often it waters itself. The Smartpot will send data over to a local broker With the MQTT protocol. On the broker the data will be analyzed and decide whether its supposed to be watered or not. The aquired data is then saved in a file which will be used for the data visualizing. # Material Below you will find all the hardware that was used to put together this device including specification: | Hardware | Specification | Price | | -------- | -------- | -------- | | ESP32 | Devkit | 99kr | | [9V battery](https://soldered.com/product/industrial-battery-9v/) | Voltage 9V | 55kr | | [9v battery holder](https://www.google.se/search?q=9v+battery+holder+elimex&tbm=isch&ved=2ahUKEwiFrOKo4-z_AhVp7LsIHdDyDwYQ2-cCegQIABAA&oq=9v+battery+holder+elimex&gs_lcp=CgNpbWcQAzoECCMQJzoFCAAQgAQ6BggAEAUQHjoECAAQHlC6DVi3HGCWHWgAcAB4AIABWogBgQiSAQIxNJgBAKABAaoBC2d3cy13aXotaW1nwAEB&sclient=img&ei=jrmfZIWtBunY7_UP0OW_MA&bih=880&biw=1920#imgrc=xMLtbTQGdSNpiM) | With soldered wires | 15kr | | [40 x male-female cables](https://soldered.com/product/set-of-male-female-cables-40-pieces/) | male-female | 50kr | | [40 x female-female cables](https://soldered.com/product/set-of-female-female-cables-40-pieces/) | female-female | 50kr | | [65 x male-male cables](https://soldered.com/product/set-of-cables-for-breadboard-65-pieces/) | male-male | 65kr | | [Breadboard](https://soldered.com/product/breadboard/) | Number of holes: 400 | 40kr | | [Small solenoid](https://soldered.com/product/small-solenoid-5-6v/) | Voltage: 6V, Current: 1A | 45kr | | [Soil Moisture Sensor](https://soldered.com/product/simple-soil-humidity-sensor/) | Comparator onboard: LM393 | 55kr | | [Gluegun](https://praktiker.bg/en/Hot-melt-glue-gun/%D0%9F%D0%9E%D0%AF%D0%9B%D0%9D%D0%98%D0%9A-%D0%97%D0%90-%D0%A1%D0%98%D0%9B%D0%98%D0%9A%D0%9E%D0%9D-PREMIUM/p/131349) | Silicone glue gun | 50kr | | [Plastic cups](https://www.plastic-sofia.com/200-ml-cups-2) | | 12kr | | Any house plant | || | Total Cost | | 538kr | # Computer Setup Installation of IDE Requirements: * Internet connectivity * Computer (Windows 10 was used for this tutorial) Download and installation of IDE: 1. Download the installer for [Pycharm](https://www.jetbrains.com/pycharm/download/?section=windows). 2. Download the installer for [Thonny](https://thonny.org/). # Broker Setup Now when the ESP32 has been flashed it is time to setup the MQTT broker on the computer: 1. Open Pycharm. 2. Install the following libraries using the these commands in the terminal of Pycharm: ``` pip install streamlit pip install paho pip install plotly ``` 3. Copy paste in this code> ``` import paho.mqtt.client as mqtt import json import time BROKER_HOST = 'Host Pc IP' BROKER_PORT = 1883 BROKER_USERNAME = 'Windows User Name' BROKER_PASSWORD = 'Windows User Password' TOPIC = 'getTargetMoisture' def on_message(client, userdata, msg): if msg.topic == "getMoistureTarget": print("Received message:", msg.topic, msg.payload.decode()) payload = json.loads(msg.payload.decode('utf-8')) # Define the parameters newmoisture = sum(payload['Moisture']) / len(payload['Moisture']) print("Average moisture measured: " + str(newmoisture)) time.sleep(3) file_path = 'data.txt' with open(file_path, 'a') as file: file.write(str(newmoisture) + '\n') if newmoisture > 0.5: client.publish("newTargetMoisture1", True) print("Water") else: client.publish("newTargetMoisture1", False) print("Don't Water") client = mqtt.Client() client.on_message = on_message # Subscribe to a specific topic to trigger the data retrieval and publishing subscribe_topic = 'getMoistureTarget' # Replace with the desired trigger topic client.subscribe(subscribe_topic) client.connect("192.168.100.6") client.subscribe("#") client.loop_forever() ``` 4. Change the following Variables to setup MQTT and the MSSQL connection with your IP address. (Open cmd and run ipconfig and search for your network adapter to find your IPv4 address.) ``` BROKER_HOST = 'Host Pc IP' BROKER_PORT = 1883 BROKER_USERNAME = 'Windows User Name' BROKER_PASSWORD = 'Windows User Password' ``` 5. Then run in. For the data visualization the library streamlit was used to host a local instance of the dashboard. To achieve this: 1. Made use of the streamlit library. 2. Created a new python script in the same folder as main. 3. Then copy paste in this code to host an instance: ``` import streamlit as st import numpy as np import plotly.graph_objects as go file_path = 'data.txt' def load_file_into_array(file_path): try: with open(file_path, 'r') as file: array_contents = [line.strip() for line in file] print("File contents loaded into the array successfully.") return array_contents except Exception as e: print("Error occurred:", e) return [] def main(): moisture_data = load_file_into_array(file_path) # Set the background color for the Streamlit app st.set_page_config(layout="wide", page_title="Moisture Level Graph App", page_icon="📈") # Add a title to the app st.title("Moisture Level Graph App") st.write("This is a simple Streamlit app to plot the moisture level graph with interactive hover effects.") # Create the interactive plot using Plotly fig = go.Figure() fig.add_trace(go.Scatter(x=np.arange(len(moisture_data)), y=moisture_data, mode='markers', marker=dict(size=10))) fig.update_layout(title="Moisture Level Over Time", xaxis_title="Time", yaxis_title="Moisture Level", hovermode='closest') st.plotly_chart(fig) if __name__ == "__main__": main() ``` 4. Run it by calling the file in the terminal of Pycharm like so: streamlit run .\Datavirtualization.py 5. Keep it running. This will host the data virtualization under http://localhost:8501/ # ESP32 Setup The Broker is now online and after we setup the ESP32 for gathering data we will then proceed with sending this data to the broker. Requirements: * Computer * Micro USB-cable * 5 volt charging adapter Download firmware for the ESP32: 1. Launch Thonny and plug in the ESP32. 2. Head to Run > Configure Interpreter > Install or update Micropython. 3. Choose the following(Change the port to match your ESP32)): ![](https://hackmd.io/_uploads/HJPjcJY_3.png) 4. Click install. Download the needed library and code: 1. Download the following library [MQTT.Simple](https://pypi.org/project/micropython-umqtt.simple/#files). 2. Open simple.py with Thonny, press Ctrl+Shift+S and save it on your micropython device as simple.py. 3. Copy paste the following codes and save them with the given names: main.py ``` import network import time from transmittingscript import * from receivingscript import * from machine import Pin ID = "1" # Replace with your wifi credentials your_ssid = "A1_7286" your_password = "485754439A6352AA" client_name = "sub_client" broker_ip = "192.168.100.6" # Initialize GPIO2 as an output pin gpio_pin = Pin(2, Pin.OUT) # Set the pin high to turn off the solenoid at launch gpio_pin.off() # Wifi connection script def connect_to_wifi(ssid, password): sta_if = network.WLAN(network.STA_IF) if not sta_if.isconnected(): print('Connecting to Wi-Fi...') sta_if.active(True) sta_if.connect(ssid, password) while not sta_if.isconnected(): pass print('Wi-Fi connection successful!') print('Network information:', sta_if.ifconfig()) connect_to_wifi(your_ssid, your_password) # Function to be executed every hour def main_function(timer): start_transmitting(ID, client_name, broker_ip) start_receiving(ID) start_transmitting(ID, client_name, broker_ip) start_receiving(ID) # Create a Timer object timer = Timer(0) # Set the timer to trigger the main function every hour (3600 seconds) timer.init(period=3600000, mode=Timer.PERIODIC, callback=main_function) ``` transmittingscript.py ``` from simple import MQTTClient import ujson import machine import time # Callback function for when the connection to the broker is established def on_connect(client): print("Connected to MQTT broker") def start_transmitting(ID, client_name, broker_ip): client = MQTTClient(client_name, broker_ip, keepalive=60) client.set_callback(on_connect) client.connect() pin = machine.Pin(32, machine.Pin.IN) data_array = [] i = 0 while i < 60: data_array.append(pin.value()) time.sleep(0.1) i += 1 data = { "ID": ID, "Moisture": data_array } json_data = ujson.dumps(data) client.publish("getMoistureTarget", json_data) # Disconnect from the broker client.disconnect() ``` receivingscript.py ``` import sys import network import ujson from umqtt.simple import MQTTClient from machine import Pin mqtt_server = "Brokers IP" mqtt_password = "Users Password" mqtt_username = "User" mqtt_port = 1883 mqtt_topic = "newTargetMoisture1" client = MQTTClient("ESP32Client", mqtt_server, port=mqtt_port, user=mqtt_username, password=mqtt_password, keepalive=60) gpio_pin = Pin(2, Pin.OUT) def callback(topic, msg): if msg == True: print("Water") gpio_pin.on() else: print("Don't Water") gpio_pin.off() time.sleep(5) gpio_pin.off() sys.exit() def connect_mqtt(): client.set_callback(callback) client.connect() client.subscribe(mqtt_topic) print("MQTT connected") def run(): while True: try: client.wait_msg() except OSError: connect_mqtt() def start_receiving(ID): connect_mqtt() run() ``` 4. Open main.py and change the following to your details: ``` your_ssid = "Your Wifi name" your_password = "Your Wifi password" broker_ip = "your brokers ip"' ``` * You can run ipconfig in cmd to get your local ip. 5. Open receivingscript.py and change the following: ``` mqtt_server = "Your brokers ip" mqtt_username = "Broker computer name" mqtt_password = "Password on broker user" ``` 6. When done, test the script. First start the python script on the broker. 7. Then run main.py on the esp32. 8. There should be payloads visible in the terminal on the ESP32 and the broker pc. ## Choice Of Platform Currently there is just one broker pc and one pot which are communicating via MQTT. Using the library paho. My plan would have been to have the users phone act as the broker. But this is if I were to evolve the idea into a finished product. Choose plotly to visualize the moisture level of the pot: ![](https://hackmd.io/_uploads/rkCWC3-t2.png) It will update when the smartpot sends new data available under http://localhost:8501/. ## Data Transmission and Connectivity The ESP32 is connected to the Wifi. There is no LORA connectivity in Bulgaria where I reside otherwise that would have been another option. The data is sent every hour using MQTT. When received by the broker, it will average the 60 readings that were sent and give back a signal to the esp32 to water or not depending on the readings. The data is save in a text file and loaded up as an array. There used to be a database but it got all wiped just prior to the delivery because of a harddrive failure. ## Battery The 9v battery which was used is enough to run the Solenoid valve for roughly 20 hours. The valve can at most be open for 5 seconds each hour. This means the Smartpot can run for: 20 / (5 / 3600) = 600 Days The ESP32 is powered by a 5v charge adaptor. It runs for about a total of 12 seconds at most. ## Assembling Here is the diagram of how the assembled Smartpot should look like: ![](https://hackmd.io/_uploads/SJRQinyF2.png) In this project the valve was attached to the bottom of a plastic glass with glue like this: ![](https://hackmd.io/_uploads/r1V8_6gK2.jpg) A hole was poked into the plastic glass and the valve was then glued with silicone glue on it. After everything is assembled the sensor needs to be adjusted. This is done by screwing this one marked in yellow: ![](https://hackmd.io/_uploads/HJd6Rn1K2.jpg) You should see the light marked in red will turn on and off. After that it should be screwed to the point where the light is just on turned when it has been watered. The moisture sensor needs to be pushed into the soil of the plant. The plastic glass is glued to the top of the pot. And the final result could look like this: ![](https://hackmd.io/_uploads/B1nzb6-Yh.jpg) ## Project Reflection The original idea of the project included temperature measurements and a website to control the level of moisture. In hindsight it would not have been possible to change the target moisture with my equipment. The moisture sensor I chose is manually adjusted with a screwdriver. The range of the sensor is very narrow and it needs to be adjusted to the range you want to use. Ended up using my local machine as the broker. Prefer this because then the device will not be reliant on internet connectivity to work. Have frequent internet problems and this may have been an issue. The website got scrapped because I ran out of time and had some data loss in a harddrive failure. Led to the removal of the database. Although this did not change the end result of the project. But the end result of the project fulfills the criterias of my main idea. The main idea was to build a pot which waters itself. It fulfills that task. Would have preferred to have the ESP32 solar powered but was having issues with hardware shortage. Had issues obtaining hardware. Where I live they do not sell the raspberry pi pico. Had to opt for an ESP32 instead. It has performed very well and it has a micropython firmware which made it possible for me to make use of the lections. ## General Reflection It was fun and enjoyed learning about IoT. Never realized how huge this field is and how useful these small devices are. Will definetly take the things I learnt with me. Had some good opportunities to problem solve and learn about the workflow of creating IoT devices.