A Step-By-Step Guide

Back to the Roots: A Raspberry Pi Plant Watering System Focusing On Essential Matters

Water Your Green Friends in the Simplest Way You Imagine

dropberry
Technology Hits

--

My tutorial is probably not the first how-to-save-your-plants-because-you-suck-at-gardening guide you stumble upon. Watering plants with a Raspberry Pi is one of the most stereotypical projects: Tons of tutorials exist on the world wide web.

Indoor plants on wooden trays with limp leaves
Plants on Their Way to a Gruesome Death - Photo by Ceyda Çiftci on Unsplash

And that’s good. Because we all have different plants: Some need a bit more love, some don’t mind if you ignore them for several weeks. Therefore, we all have various demands on the features of our watering system (except that it’s supposed to water our plants).

There is no all-in-one solution for everyone. So, my water system goes back to the roots: it waters my plants when their soil is too dry. Nothing more, nothing less. For whom that’s enough — perfect. For whom not — no problem. View it as a starting point and tune the project according to your wishes.

In my tutorial, I explain how to connect the electronic components to a functioning circuit and control them with basic Python programming. We will also scratch the surface of cronjobs. In general, my project is beginner-friendly and the hardware is affordable.

First of All: How Does My Watering System Work?

Good question; great you’re asking.

Meme: Tony Stark sitting in a car, saying ‘That is an excellent question’
Tony Stark Appreciating Your Question (Source)

As I said, my concept is straightforward:

  • A sensor checks the plants’ moisture every 4 hours and logs the measured data with the current time to a file.
  • If the soil is too dry, a pump waters the flowers for 4 seconds. That is also written in the log file.
  • If the soil is wet, nothing happens.

The basic principle: Water the plants if needed, let the water soak in and check moisture after a specified period again.

That’s it, no more magic. Your green friends receive water when needed, and you comprehend when the pump runs. The latter is not just a nice-to-know but also great for debugging because you see if everything works as intended. Of course, change the period for checking the moisture and watering after your needs.

My system serves up to 8 plants. And either they stay close, or you have to run long cables. Also, be aware that moisture sensors get imprecise over time. The system isn’t appropriate for demanding plants because you would need to renew the sensors constantly.

Still sounds too complicated? Get familiar with the Raspberry Pi GPIO pins in my beginner-friendly LED tutorial.

Requirements

Necessary:

If you haven’t set up your Raspberry Pi yet, read my tutorial about working with your tiny computer headless. For getting started with a monitor, check out the official documentation.

Optional for Debugging:

  • LEDs
  • Resistors
  • Multimeter

I used a Raspberry Pi Zero W, but my tutorial works for every Pi with GPIO pins. Remember: For the Pi Zero, you have to solder the pins.

Some requirements placed on a wooden table: modified USB cable as external power source, Raspberry Pi Zero, PVC tube, solderless breadboard, moisture sensor, pump, ADC MCP3008, jumper wires and mosfet relais
Most of the Necessary Requirements

Some Tipps for the Requirements:

  1. Do not save money on the moisture sensor. It will be exposed 24/7 to the soil’s minerals destroying its protective layer. Also, a more expensive sensor lives longer than a cheap one (check out more helpful information).
  2. Buy a complete mosfet relais (as linked above) and not just the single mosfet. The relais is way easier to operate.
  3. As an Analog-to-Digital converter (ADC), I use the MCP3008. You can follow my tutorial with any ADC which works with SPI as communication protocol. However, I tailored the guide to the MCP3008.
  4. Be careful with the voltage of you’re external power source. It must be appropriate to the voltage of your pump. If necessary, place a resistor in between. I used a 5V power supply with a USB cable ending in 2 RPI headers (similar to the linked product).

Generally speaking: Please don’t buy the cheapest material. You care about your plants? Then care about mother earth too. Sustainable hardware costs a bit more but goes easy on nature’s resources.

Short Deep Dive: Why We Need the ADC and The Mosfet

Since the purpose of those two electronic components may be vague, here is a short overview.

ADC MCP3008:

Common moisture sensors return analog values. The problem: Raspberry Pis only understand digital input. That’s why we need the ADC to do what its name indicates: transforming analog to digital signals. Consisting of 10 Bits, the MCP3008 returns values between 0 and 1023 (2¹⁰ = 1024).¹

For more information on ADCs, check the following video.

Introduction to ADCs

Mosfet Relais:

The mosfet serves as a regulator between our external power source and the pump. It is connected via its signal pin to one of the Pi’s GPIO pins. If we set that pin to HIGH, the mosfet allows current to flow from the power source to the pump. If set to LOW, the mosfet closes the current flow.

In theory, it’s possible to replace the mosfet and battery with the 5V pin of the Raspberry Pi. However, the tiny computer is not as strong as it appears. Employing the 5V pin as a power source may result in the Pi’s dangerous overload.

Setting-Up The Circuit

Wiring the electronic components together is simple. The following shows the schematic (with an unrealisticly big 9V battery):

Circuit of the project: ADC connected to Pi, moisture sensor connected to Pi and ADC, mosfet relais connected to 9V battery and pump
Electronic Circuit for Plant System (Made With Fritzing)

Let’s do it step by step:

  • Wire the MCP3008 to the Raspberry Pi. The following table shows how to connect the pins:
Technical drawing of MCP3008 with its Pins. Next to it a table showing which pins of MCP3008 connnect to which GPIO pins of Pi
Pins of ADC MCP3008 and Corresponding GPIO Pins
  • Connect the sensor to your ADC by wiring the sensor’s signal pin to one of the 8 channels (I chose CH0). Also, connect GND and VCC to the Pi’s GND and 3.3V pins.
  • Lastly, configure the mosfet. Connect the Vin with your external power source and Vout with your pump. Then, wire the mosfet to the Raspberry Pi: connect its signal pin to any of the Pi’s GPIOs (I took GPIO 4), GND to GND, and VDD to 3.3V.
Constructed Circuit Diagram (Without External Power Source) as Real Photo
Constructed Circuit Diagram (Without External Power Source)

We’re done! Not that difficult, was it?

A Little Bit of Good Old Coding

I chose to program in Python since it’s a convenient language for scripting. The task of the software is to read out the moisture and, depending on its value, turn on the pump. Further, the program logs significant information.

First of all, we connect to our Pi and open a terminal. Before starting to code, we install the libraries allowing us to interact with the Pi’s pins. As always, we update our packages before:

$ sudo apt update && sudo apt upgrade
$ sudo apt install python-rpi.gpio python3-rpi.gpio

Then open an empty file with your favorite editor. My choice is ‘vim’.

$ vim watersystem.py

At first, we have to import the needed libraries to our script:

import RPi.GPIO as GPIO  # interact with Pis pins
import datetime # to log the current time
import spidev # to interact with the MCP3008 via SPI
import time # to run our pump for 5 sec

To interact with the MCP3008, we create an SPI connection and a small function that reads the data from a given channel:

# create SPI connection
spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 1000000 # 1 MHz

# function to read out data from MCP3008
def readData(channel):
adc = spi.xfer2([1,(8+channel)<<4,0])
data = ((adc[1]&3) << 8) + adc[2]
return data

Then, we specify general GPIO settings and create one variable for the pin of the pump (the one connected to the mosfet’s signal pin). Also, we define the threshold for too-dry soil.

To detect the value of your sensor indicating dryness, modify the script to only print moisture.

pinPump = 4                      # GPIO pin of pump
needsWater = 630 # sensor value for dry air

# general GPIO settings
GPIO.setwarnings(False) # ignore warnings (unrelevant here)
GPIO.setmode(GPIO.BCM) # refer to GPIO pin numbers
GPIO.setup(pinPump, GPIO.OUT) # Pi can send voltage to pump
GPIO.output(pinPump, GPIO.LOW) # turn pump off

In the next step, we determine the moisture and write it in our log file with the current timestamp.

Adjust the file input as you wish!

I calculated the values in percent for better readability. My sensor represents 0% dryness with a value of about 330 and 100% with 780.

# read moisture data from channel 0
moisture = readData(0)

# write time and current moisture in statistic file
f = open("/home/pi/WateringStats.txt", "a")
currentTime = datetime.datetime.now()
f.write(str(currentTime) + ":\n")

# 450 = 780 - 330
f.write("Current moisture: " + str(round((moisture-330) / 450 * 100, 2)) +
"% (" + str(moisture) + ")\n")

If the moisture is too low, we start the pump for 4 seconds and log that it watered our plants.

How long you run the pump depends on your plants.

Logging the moisture directly after pumping is pointless because the water needs time to soak in, and the sensor would indicate pure water.

# if plants are to dry, start pumping and record the moisture in file
if moisture > needsWater:
t_end = time.time() + 4 # pump runs 4 seconds

# actual pumping
while (time.time() < t_end):
GPIO.output(pinPump, GPIO.HIGH)

GPIO.output(pinPump, GPIO.LOW) # turn pump off
f.write("Plants got watered!\n")

At the end of the script, break a new line for the next logging entry and close the file.

f.write("\n")    # line break for next log entry
f.close() # close file
GPIO.cleanup() # proper clean up of used pins

Combining everything, we receive the following script:

import RPi.GPIO as GPIO
import datetime
import spidev
import time

# create SPI connection
spi = spidev.SpiDev()
spi.open(0,0)
spi.max_speed_hz = 1000000 # 1 MHz

# function to read out data from MCP3008
def readData(channel):
adc = spi.xfer2([1,(8+channel)<<4,0])
data = ((adc[1]&3) << 8) + adc[2]
return data

pinPump = 4 # GPIO pin of pump
needsWater = 630 # sensor value for dry air

# general GPIO settings
GPIO.setwarnings(False) # ignore warnings (unrelevant here)
GPIO.setmode(GPIO.BCM) # refer to GPIO pin numbers
GPIO.setup(pinPump, GPIO.OUT) # Pi can send voltage to pump
GPIO.output(pinPump, GPIO.LOW) # turn pump off

# read moisture data from channel 0
moisture = readData(0)

# write time and current moisture in statistic file
f = open("/home/pi/WateringStats.txt", "a")
currentTime = datetime.datetime.now()
f.write(str(currentTime) + ":\n")

# 450 = 780 - 330, moisture in %
f.write("Current moisture: " + str(round((moisture-330) / 450 * 100, 2)) +
"% (" + str(moisture) + ")\n")

# if plants are to dry, start pumping and record the moisture in file
if moisture > needsWater:
t_end = time.time() + 4 # pump runs 4 seconds

# actual pumping
while (time.time() < t_end):
GPIO.output(pinPump, GPIO.HIGH)

GPIO.output(pinPump, GPIO.LOW) # turn pump off
f.write("Plants got watered!\n")

f.write("\n") # line break for next log entry
f.close() # close file
GPIO.cleanup() # proper clean up of used pins

In the end, that’s how the script formats the output file. I added the heading when I created the file in the first place. Next to the percent is the plain value of the moisture sensor.

Output of log file in terminal. Shows 3 log entries with timestamp and moisture value in percent and not converted
Output of Log File

Congrats, we almost made it!

Before testing the water system on actual plants, I recommend to try it on dummy soil to see if everything works as expected. Your plants may not forgive a wrong setup!

Last but Not Least: Scheduling The Program

After we set up the circuit and wrote the script, only one crucial step is missing: the periodic execution of our code. For that, cronjobs come in handy.

Cron is short for ‘Command run on notice’. An intern UNIX program, the cron daemon, executes all commands specified in the cron table at their defined time.²

So, to create a cronjob, we have to add a new entry in the cron table. Execute the following command to open the cron table. The file will be opened with your default editor.

$ crontab -e

Each crontab entry consists of a defined running time and the corresponding command. With cronjobs, it's possible to specify time intervals.

Explaining the syntax of cronjobs exceeds the scope of this article. Click for more information and employ an easy-to-use time calculator.

I want the program to run every 4 hours. I write ‘python watersystem.py’ for execution since I called my script ‘watersystem.py’. The final entry looks in my case:

0 */4 * * * python watersystem.py

My script gets executed at 0:00, 4:00, 8:00, 12:00, 16:00, and 20:00 every day. Place your specification at the end of the file.

Considerable Tipps

Throughout building the watering system, I stumbled across several obstacles I like you to avoid. Here is a summary of the most important ones:

  1. Take time to measure the correct threshold indicating your soil is dry and needs water through the pump. If it’s too high or too low, your plants run the danger of either drowning or drying out — resulting in a cruel death for sure.
  2. Check how much water your pump pumps within a small interval of seconds. At first, I set the pump to run for the enormous time of 30 seconds — and almost killed my flower doing so.
  3. Direct consequence drawn by numbers 1 and 2: don’t test your setup right away on your precious plants. After some time, you will get a feeling for how your sensor and pump work but at the beginning, it’s better to test your script at extra soil.
  4. When hardware problems occur, check if all electronic components are compatible with each other. My pump and my previous mosfet weren’t compatible and I spent hours examining why my circuit won’t work. So, check for that in the first place. Also, verify that current flows throughout the whole circuit.

Final Thoughts

I kept my promise: my system goes back to the roots. The introduced automatic watering system waters your plants when they lack water — and that’s it. Even by covering the basics, it already looks damn hot:

Water system connected to coffee plants
Final Plant System at Work

All requirements for my indoor plants to grow bright and glorious are fulfilled by my plant project. However, now it’s time to tune up the system according to your imagination: Connect a small display to illustrate the moisture of your plants or host a website to access their well-being from the other end of the world. Set your creativity free!

With the help of a small electric circuit, Python and Cronjobs, we created a basic Raspberry Pi watering system. It’s one of many plant projects— but it’s the only one you need to get the real job done.

--

--

dropberry
Technology Hits

It's me, Mario! Or almost, at least I wish I could spend my life jumping through magic worlds. Instead I'm an IT student with a strong propensity to sarcasm.