Watering plants with a Raspberry Pi, a Relay HAT and some submersible pumps

· Read in about 7 min · (1363 Words)
hardware embedded diy

Watering plants when you’re not home is a common enough problem and of course plenty of people have done it using some kind of Arduino or RaspberryPi setup. So I figured “how hard can it be” and set out to build my own. Without spending too much thought on it, I bought

  • a Relay HAT (which by the way stands for “Hardware Attached on Top”, as I learned writing this blog post)
  • a selection of 12 Volt submersible water pumps of which I ended up using two
  • a 12 Volt wall plug.
  • PVC hoses and T-shaped couplings in the diameters of the pumps’ outlets

and got to work.


Before I did anything else, I wrote the software for controlling the Relay board, and thus the pumps. It is in large parts based on John M. Wargo’s code linked to on the Seeed Studio Wiki. I modified the code to not have the SMBus device hard coded, as on my Pi the Relay board was on /dev/i2c-0 rather than /dev/i2c-1 which the code seems to assume. The little bit of front end that I added is just about the simplest no-frills implementation imaginable.

#!/usr/bin/env python3

import smbus
from time import sleep
import click
import relay_lib

@click.option('--bus', type=int, default=0, help='I2C bus')
@click.option('--p1', type=int, default=0, help='Run Pump 1 for n seconds')
@click.option('--p2', type=int, default=0, help='Run Pump 2 for n seconds')
@click.option('--p3', type=int, default=0, help='Run Pump 3 for n seconds')
@click.option('--p4', type=int, default=0, help='Run Pump 4 for n seconds')
def water(bus, p1, p2, p3, p4):
    """Hydronator waters your plants to your specifications."""
    i2c = smbus.SMBus(bus)
    if p1 > 0:
        relay_lib.relay_on(1, i2c)
        relay_lib.relay_off(1, i2c)
    if p2 > 0:
        relay_lib.relay_on(2, i2c)
        relay_lib.relay_off(2, i2c)
    if p3 > 0:
        relay_lib.relay_on(3, i2c)
        relay_lib.relay_off(3, i2c)
    if p4 > 0:
        relay_lib.relay_on(4, i2c)
        relay_lib.relay_off(4, i2c)

if __name__ == '__main__':

The full code is on Github

If I could be bothered to refine the code, the one thing I might want to add is to catch Ctrl-C/SIGINT and turn all relays off before exiting.

Hardware and Wetware

The evening before going on vacation, I put everything together:

I cut up the cable of the wall plug and used Wago 222 splices to connect the plus lead to the common terminator of the relays the the minus lead to the pumps. I hooked the NO (normally open) terminators of the relays to a pump each. It was a beautifully disgusting mess of wires:

I'm sure this passes safety regulations

My initial plan was to just drop the pumps in a bucket each, but eventually I figured out that 10 Liters would probably not be enough for the 20 days I would be gone. So I settled on emptying a 65 liter box and filling it with water. I put somewhere around 40 liters in it, because I didn’t want to stress the box too much and was sure that it ought to be enough anyway.

To get the pumps to stay near the bottom of the box and not be drawn upwards by the cables or hoses, I taped the cables and hoses to the box and cornered in one of the pumps with stones.

You ain't going nowhere!

Then I went about putting the plumbing together. Na├»vely I had assumed that with each T-coupling the amount of water going to each side would be about equal. So I thought I could put the two larger plants on one side of the first T-coupling after the pump and the other four plants on the other side. The idea being that the larger plants get more water. Of course this assumption is completely false. How much water goes where depends very much on slopes in the water’s path and things that hinder the flow, like for example sharp curves.

So I measured what my hose routing actually delivers to each plant. I put empty ice cream boxes and similar containers in each tomato plant’s pot, ran the pumps for a set amount of time and then weighed the amount of water that went in each container. Rather than trying to somehow create the perfectly leveled hose routing, I just put hoses from the second pump to the plants that weren’t getting enough from the first.


With that out of the way, all that was left to do was to set up a cron job on the Pi that waters the plants at eight every morning and every evening. And of course I messed that up, see if you can spot the mistake:

0 8,20 * * *  /home/pi/hydronator/hydronator.py -p1 10 -p2 10

Luckily I did check if it worked as expected on the morning before I left. When it didn’t I fortunately quickly saw that I used the wrong number of dashes, fixed it and moved the cron job to five past eight, so that I could see if it works:

5 8,20 * * *  /home/pi/hydronator/hydronator.py --p1 10 --p2 10

It did and so I left for twenty days.

This is what it looked like on the evening before I left


I worried that I might be watering too much, so after a day I logged in remotely and decreased the amount of time I ran the pumps for from 10 seconds each to 8 seconds each.

A couple of days later I realized I had made a big mistake. As you can see on the fotos, the electronics are not exactly what I would call water proof. I figured it should be fine as long as it isn’t very windy and very rainy at the same time. And if not, the breaker will just trip and the plants die. So what.
Well. The breaker most likely to trip in this case would be the residual current circuit breaker. Of which there is one. For the entire apartment. So the entire apartment would be without power. That would not be so bad, if the apartment didn’t contain a fridge and a freezer. But it does, of course. Oops. So I nervously logged into my VPN every day, checking if devices on my home network were still reachable. Thankfully they were the entire time. But next time (if there will be a next time) I will put that circuit on one of those residual current circuit breaker wallplugs (and test that that breaker is the one that actually trips).

A colleague of mine suggested I should have also set up a web cam, so that I can “watch the plants die in real time”. I did try hooking up a webcam to the Pi on the evening when I set everything up. But for some reason the Pi did not properly recognize the cam and kept resetting the USB communication. I suspect the Pi was not delivering enough power for the cam, but I did not have the time or patience to debug it there and then.

So instead I had twenty days of build up before the big reveal. What I found was a bit disappointing at first:

Oh no! Sad tomato plants

I had run out of water and the plants looked very sad indeed. The wet floor planks you see in the picture were me, frantically (over-)watering the poor things.

I did some rough calculations based on my ice-cream-box-water-weighing-experiments and came to the conclusion that I should have run out of water after about half the time I was gone for. I can hardly believe they survived that long without water, so either the water lasted a bit longer, or it rained a lot more than the weather report has led me to believe. Whichever it was, I really should have done the math beforehand. Or even better: tested the whole setup for a week or so, to figure out the right amount of water/pump running time.

But I’m happy to report all of the plants, even the very dead-looking right-most one, came back from their near-death experience and delivered delicious tomatoes. So all’s well that ends well.

Lessons learned

  • water flow in a many-branched hose is highly susceptible to even the smallest inclines
  • tomatoes need a lot of water
  • do the math!
  • use a separate residual current circuit breaker
  • don’t do everything last minute, leaving you with no time to work out the kinks (haha, just kidding, I’ll never learn that lesson)