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)):

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:

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:

In this project the valve was attached to the bottom of a plastic glass with glue like this:

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:

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:

## 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.