Practical case: plant irrigation with Raspberry Pi

Practical case: plant irrigation pump controller with — hero

Objective and use case

What you’ll build: A Raspberry Pi plant irrigation controller that reads a digital soil-moisture sensor and activates a relay-driven water pump when the soil is too dry. The system performs short watering cycles, then pauses before rechecking to avoid overwatering and relay chatter.

Why it matters / Use cases

  • Automates watering for a single houseplant, herb pot, or small seedling tray without constant manual checks.
  • Helps maintain more consistent soil conditions by reacting within seconds of a dry-state signal rather than waiting hours or days for human intervention.
  • Provides a simple introduction to GPIO control, relay switching, and sensor-based automation on Raspberry Pi.
  • Useful for low-voltage indoor setups where a 5 V pump can run in short bursts such as 2–10 seconds per cycle.

Expected outcome

  • A working Python-based controller that polls the moisture sensor on a timed interval, for example every 30–60 seconds.
  • Automatic pump activation only when the sensor reports dry soil, with a controlled watering window such as 3–5 seconds.
  • Low compute overhead on the Raspberry Pi, typically well under 5% CPU and with no meaningful GPU load for this headless automation task.
  • A safer low-voltage prototype that keeps the Pi on 5 V, uses an isolated GPIO relay module, and powers the pump from a separate suitable supply.

Audience: Beginners, students, and DIY makers building their first sensor-and-actuator project; Level: Basic

Architecture/flow: Digital soil moisture sensor detects dry/wet state → Raspberry Pi GPIO reads thresholded digital signal → control script decides whether watering is needed → GPIO output toggles relay → relay powers external pump for a short cycle → system waits a cooldown period, then checks again.

Educational validation note

Before publication, this case passed the Prometeo automated validation gate with status PASS. The validator checked the code blocks, article structure, copy/paste-safe commands and consistency with the supported device catalog.

Published validation evidence

  • Automatic result: PASS.
  • Parsed structure: 3 sections, 3 tables and 10 code blocks detected before publication.
  • Checked code: 4 Python/py_compile, 6 Bash/copy-paste checks.
  • Supported catalog: the article text was checked against Prometeo’s validation-capable device profiles, and unsupported stacks block publication.
  • Report findings: no blocking findings.

This validation confirms syntax and tool compatibility for the published material, but it does not replace physical testing on your exact hardware, wiring and runtime environment.

Educational safety note

This project is an educational prototype, not a certified product. Before powering the setup, verify the pinout of your exact ULX3S board revision, keep FPGA I/O signals at 3.3 V, never connect 5 V directly to I/O pins, disconnect power before changing wiring, and use suitable external supplies for loads, motors or servos while sharing ground only when the wiring requires it.


title: Practical Case: Raspberry Pi Plant Irrigation Pump Controller
slug: practical-case-raspberry-pi
level: Basic


Raspberry Pi Plant Irrigation Pump Controller

This practical case shows how to build a plant irrigation pump controller with a Raspberry Pi. The controller reads a soil moisture sensor and switches a water pump through a relay when the soil is dry.

Safety note

This is an educational low-voltage project. Keep the Raspberry Pi on 5 V only and use a relay module designed for Raspberry Pi GPIO isolation. Do not connect mains voltage directly to GPIO. Power the pump from its own suitable supply, share ground only where required by the relay design, and keep water away from electronics.

Conceptual block diagram

High-level view: what enters the system, what each block processes, and what comes out.

Functional architecture

Digital soil moisture sensor detects dry…

Raspberry Pi GPIO reads thresholded digit…

control script decides whether watering i…

GPIO output toggles relay

relay powers external pump for a short cycle

system waits a cooldown period, then chec…

Conceptual signal and responsibility flow between device blocks.

Objective

Build a Raspberry Pi based controller that:

  • measures soil moisture,
  • decides whether a plant needs irrigation,
  • activates a pump for a short watering cycle,
  • waits before checking again.

Because a Raspberry Pi does not have a built-in analog input, this tutorial uses a digital soil moisture module with an adjustable threshold and digital output.

Parts

  • Raspberry Pi with Raspberry Pi OS
  • MicroSD card
  • Digital soil moisture sensor module with DO, VCC, GND
  • 1-channel 5 V relay module compatible with 3.3 V GPIO trigger
  • Small DC water pump
  • External power supply matched to the pump
  • Jumper wires
  • Breadboard or screw terminals
  • Tubing and water container

Wiring

The Raspberry Pi reads the sensor digital output and controls the relay input.

FunctionModule PinRaspberry Pi PinBCM GPIO
Soil sensor powerVCCPin 13.3 V
Soil sensor groundGNDPin 6GND
Soil sensor digital outputDOPin 11GPIO17
Relay powerVCCPin 25 V
Relay groundGNDPin 9GND
Relay control inputINPin 13GPIO27

Pump side wiring

The relay switches the pump supply, not the Raspberry Pi power rail.

Pump circuit itemConnect to
Pump supply positiveRelay COM
Relay NOPump positive lead
Pump negative leadPump supply negative
Relay NCNot used

Use NO (normally open) so the pump stays off when the Raspberry Pi is booting or powered down.

How it works

A typical digital soil moisture module exposes a comparator output:

  • DO = 0 or 1 depending on the board design and trimmer threshold,
  • the trimmer sets the dry/wet switching point.

This guide assumes:

  • GPIO17 == LOW means dry soil
  • GPIO17 == HIGH means wet soil

If your sensor behaves the opposite way, the test script below will show it clearly.

Enable GPIO access

Update packages and install the GPIO library:

sudo apt update
sudo apt install -y python3-gpiozero

Code 1: Sensor and relay wiring test

Save as sensor_relay_test.py:

#!/usr/bin/env python3
from gpiozero import DigitalInputDevice, OutputDevice
from signal import pause
import time

SENSOR_PIN = 17
RELAY_PIN = 27

sensor = DigitalInputDevice(SENSOR_PIN, pull_up=False)
relay = OutputDevice(RELAY_PIN, active_high=False, initial_value=False)

def state_text() -> str:
    return "WET/HIGH" if sensor.value == 1 else "DRY/LOW"

print("Reading soil sensor for 10 seconds...")
for _ in range(10):
    print(f"Sensor raw state: {sensor.value} ({state_text()})")
    time.sleep(1)

print("Turning pump relay ON for 2 seconds...")
relay.on()
time.sleep(2)
print("Turning pump relay OFF")
relay.off()

Run it:

python3 sensor_relay_test.py

Expected result

  • When you move the sensor between dry and wet soil, the printed state changes.
  • The relay should click once when turned on and again when turned off.
  • If the relay behavior is inverted, the active_high=False setting is likely correct for your relay module. Many Raspberry Pi relay boards are active low.

Code 2: Plant irrigation pump controller

Save as irrigation_controller.py:

#!/usr/bin/env python3
from gpiozero import DigitalInputDevice, OutputDevice
import time
from datetime import datetime

SENSOR_PIN = 17
RELAY_PIN = 27

CHECK_INTERVAL_SECONDS = 30
PUMP_ON_SECONDS = 5
POST_WATERING_DELAY_SECONDS = 60
MAX_CYCLES_PER_HOUR = 6

# Assumption for this tutorial:
# sensor.value == 0 means dry soil
# sensor.value == 1 means wet soil
DRY_SENSOR_VALUE = 0

sensor = DigitalInputDevice(SENSOR_PIN, pull_up=False)
relay = OutputDevice(RELAY_PIN, active_high=False, initial_value=False)

cycle_timestamps = []

def now_text() -> str:
    return datetime.now().strftime("%Y-%m-%d %H:%M:%S")

def is_dry() -> bool:
    return sensor.value == DRY_SENSOR_VALUE

def prune_old_cycles() -> None:
    global cycle_timestamps
    cutoff = time.time() - 3600
    cycle_timestamps = [t for t in cycle_timestamps if t >= cutoff]

def can_water() -> bool:
    prune_old_cycles()
    return len(cycle_timestamps) < MAX_CYCLES_PER_HOUR

def water_once() -> None:
    print(f"{now_text()} Pump ON for {PUMP_ON_SECONDS} s")
    relay.on()
    time.sleep(PUMP_ON_SECONDS)
    relay.off()
    cycle_timestamps.append(time.time())
    print(f"{now_text()} Pump OFF")

def main() -> None:
    print(f"{now_text()} Irrigation controller started")
    while True:
        dry = is_dry()
        print(f"{now_text()} Sensor value={sensor.value} dry={dry}")

        if dry:
            if can_water():
                water_once()
                print(f"{now_text()} Waiting {POST_WATERING_DELAY_SECONDS} s after watering")
                time.sleep(POST_WATERING_DELAY_SECONDS)
            else:
                print(f"{now_text()} Watering skipped: hourly cycle limit reached")
                time.sleep(CHECK_INTERVAL_SECONDS)
        else:
            time.sleep(CHECK_INTERVAL_SECONDS)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        relay.off()
        print(f"{now_text()} Stopped by user")

Run it:

python3 irrigation_controller.py

Optional: Start on boot with systemd

Copy the script to a stable path:

mkdir -p /home/pi/irrigation
cp irrigation_controller.py /home/pi/irrigation/
chmod +x /home/pi/irrigation/irrigation_controller.py

Create the service file:

sudo tee /etc/systemd/system/irrigation-controller.service >/dev/null <<'EOF'
[Unit]
Description=Raspberry Pi Plant Irrigation Pump Controller
After=multi-user.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/irrigation
ExecStart=/usr/bin/python3 /home/pi/irrigation/irrigation_controller.py
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

Enable and start it:

sudo systemctl daemon-reload
sudo systemctl enable irrigation-controller.service
sudo systemctl start irrigation-controller.service
sudo systemctl status irrigation-controller.service --no-pager

Calibration

The moisture module usually has a small potentiometer.

  1. Put the probe in soil at the depth you want to monitor.
  2. Run python3 sensor_relay_test.py.
  3. Turn the potentiometer slowly.
  4. Note the point where the digital output changes.
  5. Adjust until the output changes at the dryness level that should trigger irrigation.

Validation method

To support the claim that this Raspberry Pi project implements a working plant irrigation pump controller, validate it with observable evidence:

CheckMethodExpected evidence
Sensor detectionMove the probe between dry soil and moist soil while running sensor_relay_test.pyConsole output changes between dry and wet states
Pump switchingRun sensor_relay_test.pyAudible relay click and visible pump operation for 2 seconds
Automatic irrigationPut the probe in dry soil and run irrigation_controller.pyTimestamped log shows dry detection, pump on, pump off
Recovery after wateringWet the soil after a watering cycleController logs wet state and stops activating the pump
Rate limitingKeep the sensor dry continuouslyLog eventually shows Watering skipped: hourly cycle limit reached

Troubleshooting

The sensor never changes state

  • Check VCC, GND, and DO wiring.
  • Confirm the sensor module is powered from 3.3 V if its output goes directly to Raspberry Pi GPIO.
  • Recalibrate the threshold potentiometer.

The relay clicks but the pump does not run

  • Check the separate pump power supply.
  • Confirm the pump is wired through COM and NO.
  • Verify that the pump voltage matches its power supply.

The pump runs at the wrong time

  • Your sensor logic may be inverted.
  • Change this line in irrigation_controller.py:
DRY_SENSOR_VALUE = 0

If your module reports dry as high, change it to:

DRY_SENSOR_VALUE = 1

Result

You now have a Raspberry Pi plant irrigation pump controller that:

  • monitors soil moisture,
  • drives a pump through a relay,
  • waters only when the plant needs irrigation,
  • includes a simple safety limit to reduce repeated pumping.

Find this product and/or books on this topic on Amazon

Go to Amazon

As an Amazon Associate, I earn from qualifying purchases. If you buy through this link, you help keep this project running.

Quick Quiz

Question 1: What is the main purpose of the Raspberry Pi project described in the article?




Question 2: Which sensor type does the system read to determine whether watering is needed?




Question 3: Why does the system pause before checking the soil again after watering?




Question 4: For what kind of setup is this irrigation controller especially useful?




Question 5: What component switches the water pump on and off?




Question 6: How often does the Python controller poll the moisture sensor in the example?




Question 7: When does the pump activate automatically?




Question 8: What is a typical watering window mentioned in the article?




Question 9: What is said about the Raspberry Pi's compute load for this headless automation task?




Question 10: How should the pump be powered in the safer prototype described?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Telecommunications Electronics Engineer and Computer Engineer (official degrees in Spain).

Follow me:
Scroll to Top