TC
Troy’s Tech Corner
build tech2026-02-1030 min

Build an Automated Plant Watering System with Raspberry Pi

Never kill your plants again! Build an automated watering system that monitors soil moisture and waters your plants exactly when they need it. Perfect for forgetful gardeners, frequent travelers, or anyone who wants healthy plants without the daily maintenance.

What You're Building

An automated plant watering system that:

  • Monitors soil moisture levels continuously
  • Waters plants automatically when soil is dry
  • Prevents overwatering and underwatering
  • Logs watering history and moisture data
  • Sends notifications to your phone
  • Supports multiple plants
  • Runs on schedule or sensor-triggered
  • Web dashboard for monitoring

Difficulty: ⭐⭐⭐ Intermediate Time Required: 2-3 hours Cost: $40-80 per plant Plant Survival Rate: 100%!

What You'll Need

Required Components

Raspberry Pi

  • Any Raspberry Pi with GPIO pins works
  • Raspberry Pi Zero 2 W - Perfect for this (cheap, Wi-Fi built-in)
  • Raspberry Pi 3 B+ or 4 - If you have one already
  • microSD card: 8GB minimum

Soil Moisture Sensor

  • Capacitive soil moisture sensor (recommended)
  • Or resistive sensor (cheaper, degrades faster)
  • Measures moisture in soil
  • ~$5-10 per sensor

Water Pump

  • 5V DC submersible water pump OR
  • 12V peristaltic pump (more precise)
  • Flow rate: 1-3 L/min is plenty
  • ~$5-15

Relay Module

  • 5V relay module (single channel per pump)
  • Or multi-channel for multiple plants
  • Allows Pi to control pump power
  • ~$3-8

Power Supply

  • Raspberry Pi power supply
  • Separate 5V or 12V power for pump (if needed)
  • Power adapter matching pump voltage

Tubing and Container

  • Silicone tubing (fits pump outlet)
  • Water reservoir (bucket, bottle, etc.)
  • Drip stakes or nozzles (optional)

Wiring

  • Jumper wires (male-to-female)
  • Breadboard (optional, for prototyping)
  • Wire connectors or solder

Optional Enhancements

Multiple Plants

  • Additional sensors and pumps
  • Multi-channel relay
  • Larger water reservoir

Improved Delivery

  • Drip irrigation stakes
  • Adjustable flow valves
  • Timer valves

Monitoring

  • Temperature/humidity sensor (DHT22)
  • Light sensor
  • pH sensor (advanced)

Enclosure

  • Weatherproof box for electronics
  • Keep Pi and electronics dry!

Component Selection Guide

Soil Moisture Sensors

Capacitive (Recommended):

  • Doesn't corrode
  • More accurate
  • Lasts longer
  • Slightly more expensive ($8-12)

Resistive:

  • Cheaper ($3-5)
  • Corrodes over time (6-12 months)
  • Less accurate
  • Good for testing/learning

Recommendation: Capacitive for long-term use

Water Pumps

5V Submersible:

  • Powered by Pi's 5V pin (small pumps only)
  • Sits in water reservoir
  • Cheap ($5-8)
  • Good for 1-2 plants

12V Submersible:

  • More powerful
  • Requires separate 12V power supply
  • Better for multiple plants
  • ~$10-15

Peristaltic Pump:

  • Most precise dosing
  • Doesn't touch water (longer life)
  • More expensive ($15-30)
  • Best for exact water amounts

Recommendation: 5V submersible for beginners, peristaltic for precision

Relay Modules

Single Channel:

  • $3-5
  • One pump/plant
  • Simple wiring

Multi-Channel (2, 4, 8 channels):

  • $8-15
  • Multiple pumps
  • Expandable system

Make sure: Relay rated for your pump voltage

How It Works

The Process:

  1. Sensor reads soil moisture every few minutes
  2. Pi converts analog signal to digital reading
  3. If soil is dry (below threshold):
    • Activate relay
    • Turn on pump
    • Water for X seconds
    • Turn off pump
  4. Log data (time, moisture level, watering event)
  5. Repeat monitoring

Safety features:

  • Maximum watering time (prevent flooding)
  • Minimum time between waterings (prevent overwatering)
  • Low water level detection (optional)

Step-by-Step Build Guide

Step 1: Setup Raspberry Pi

Install Raspberry Pi OS Lite:

# Use Raspberry Pi Imager
# Choose: Raspberry Pi OS Lite (64-bit)
# Enable SSH
# Configure Wi-Fi
# Flash to microSD

Boot and update:

sudo apt update
sudo apt upgrade -y

Step 2: Enable Required Interfaces

Enable I2C (for some sensors):

sudo raspi-config
# Interface Options → I2C → Enable

Install Python libraries:

sudo apt install python3-pip python3-gpiozero python3-rpi.gpio -y
pip3 install adafruit-circuitpython-ads1x15 --break-system-packages

Step 3: Wire the Components

Soil Moisture Sensor to Pi:

  • VCC → 3.3V (Pin 1)
  • GND → GND (Pin 6)
  • AOUT → Requires ADC (see below)

Note: Raspberry Pi doesn't have analog inputs. You need an ADC (Analog-to-Digital Converter).

Option 1: Use ADS1115 ADC Module ($8-12):

  • VDD → 3.3V
  • GND → GND
  • SCL → GPIO 3 (Pin 5)
  • SDA → GPIO 2 (Pin 3)
  • A0 → Sensor AOUT

Option 2: Use sensor with digital output:

  • Some sensors have DOUT (digital out)
  • DOUT → Any GPIO pin (e.g., GPIO 17, Pin 11)

Relay Module to Pi:

  • VCC → 5V (Pin 2)
  • GND → GND (Pin 6)
  • IN → GPIO 18 (Pin 12) (signal pin)

Water Pump to Relay:

  • Pump + wire → Relay COM (common)
  • Power supply + → Relay NO (normally open)
  • Power supply - → Pump - wire

Safety: Never connect pump directly to Pi GPIO! Always use relay.

Step 4: Test Components Individually

Test soil moisture sensor:

# test_sensor.py
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
import time

# Create I2C bus
i2c = busio.I2C(board.SCL, board.SDA)

# Create ADC object
ads = ADS.ADS1115(i2c)

# Create analog input on channel 0
chan = AnalogIn(ads, ADS.P0)

# Read values
while True:
    print(f"Raw: {chan.value}, Voltage: {chan.voltage:.2f}V")
    time.sleep(1)

Run: python3 test_sensor.py

Test relay and pump:

# test_pump.py
import RPi.GPIO as GPIO
import time

RELAY_PIN = 18

GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY_PIN, GPIO.OUT)

print("Turning pump ON for 3 seconds...")
GPIO.output(RELAY_PIN, GPIO.HIGH)  # Turn on
time.sleep(3)
GPIO.output(RELAY_PIN, GPIO.LOW)   # Turn off
print("Pump OFF")

GPIO.cleanup()

Run: python3 test_pump.py

Pump should run for 3 seconds.

Step 5: Calibrate Soil Sensor

Find dry and wet values:

# calibrate_sensor.py
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
import time

i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS.ADS1115(i2c)
chan = AnalogIn(ads, ADS.P0)

print("=== Sensor Calibration ===")
print("Place sensor in DRY soil...")
input("Press Enter when ready...")

dry_values = []
for i in range(10):
    dry_values.append(chan.value)
    time.sleep(0.5)
dry_value = sum(dry_values) / len(dry_values)
print(f"Dry value: {dry_value}")

print("\nNow water the soil thoroughly...")
print("Place sensor in WET soil...")
input("Press Enter when ready...")

wet_values = []
for i in range(10):
    wet_values.append(chan.value)
    time.sleep(0.5)
wet_value = sum(wet_values) / len(wet_values)
print(f"Wet value: {wet_value}")

print(f"\n=== Results ===")
print(f"Dry: {dry_value}")
print(f"Wet: {wet_value}")
print(f"Range: {dry_value - wet_value}")
print(f"\nUse these values in your main script!")

Note these values - you'll use them in the main code.

Step 6: Write Main Watering Script

# auto_water.py
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn
import RPi.GPIO as GPIO
import time
from datetime import datetime

# Configuration
RELAY_PIN = 18
DRY_VALUE = 20000  # Replace with your calibrated value
WET_VALUE = 10000  # Replace with your calibrated value
MOISTURE_THRESHOLD = 30  # Water when moisture < 30%
WATERING_DURATION = 5  # Seconds to run pump
CHECK_INTERVAL = 300  # Check every 5 minutes (300 seconds)
MIN_WATER_INTERVAL = 3600  # Don't water more than once per hour

# Setup
GPIO.setmode(GPIO.BCM)
GPIO.setup(RELAY_PIN, GPIO.OUT)
GPIO.output(RELAY_PIN, GPIO.LOW)

i2c = busio.I2C(board.SCL, board.SDA)
ads = ADS.ADS1115(i2c)
sensor = AnalogIn(ads, ADS.P0)

last_watering = 0

def get_moisture_percent():
    """Convert sensor reading to percentage (0=dry, 100=wet)"""
    raw = sensor.value
    percent = ((DRY_VALUE - raw) / (DRY_VALUE - WET_VALUE)) * 100
    return max(0, min(100, percent))  # Clamp between 0-100

def water_plant():
    """Activate pump for specified duration"""
    print(f"[{datetime.now()}] Watering plant for {WATERING_DURATION} seconds...")
    GPIO.output(RELAY_PIN, GPIO.HIGH)
    time.sleep(WATERING_DURATION)
    GPIO.output(RELAY_PIN, GPIO.LOW)
    print(f"[{datetime.now()}] Watering complete")

def log_data(moisture, watered):
    """Log moisture level and watering events"""
    with open('watering_log.txt', 'a') as f:
        f.write(f"{datetime.now()},{moisture:.1f},{watered}\n")

print("=== Automated Plant Watering System ===")
print(f"Monitoring soil moisture every {CHECK_INTERVAL} seconds")
print(f"Watering threshold: {MOISTURE_THRESHOLD}%")
print(f"Watering duration: {WATERING_DURATION} seconds\n")

try:
    while True:
        moisture = get_moisture_percent()
        print(f"[{datetime.now()}] Moisture: {moisture:.1f}%", end="")
        
        current_time = time.time()
        time_since_watering = current_time - last_watering
        
        if moisture < MOISTURE_THRESHOLD:
            if time_since_watering > MIN_WATER_INTERVAL:
                print(" - DRY! Watering...")
                water_plant()
                last_watering = current_time
                log_data(moisture, True)
            else:
                time_remaining = int(MIN_WATER_INTERVAL - time_since_watering)
                print(f" - DRY but recently watered ({time_remaining}s remaining)")
                log_data(moisture, False)
        else:
            print(" - OK")
            log_data(moisture, False)
        
        time.sleep(CHECK_INTERVAL)

except KeyboardInterrupt:
    print("\n\nShutting down...")
    GPIO.cleanup()
    print("GPIO cleaned up. Goodbye!")

Save and run:

python3 auto_water.py

Step 7: Auto-Start on Boot

Create systemd service:

sudo nano /etc/systemd/system/autowater.service

Add:

[Unit]
Description=Automated Plant Watering
After=network.target

[Service]
ExecStart=/usr/bin/python3 /home/pi/auto_water.py
WorkingDirectory=/home/pi
StandardOutput=inherit
StandardError=inherit
Restart=always
User=pi

[Install]
WantedBy=multi-user.target

Enable and start:

sudo systemctl enable autowater.service
sudo systemctl start autowater.service

Check status:

sudo systemctl status autowater.service

System now starts automatically on boot!

Physical Installation

Water Reservoir Setup

  1. Choose container: Bucket, large bottle, or tank
  2. Place pump in water: Submerge fully
  3. Secure tubing: Connect to pump outlet
  4. Route tubing to plant pot
  5. Secure tubing end near plant base (drip stake optional)

Tips:

  • Reservoir higher than plant = gravity assist
  • Mark water level to monitor
  • Opaque container prevents algae growth

Electronics Protection

Weatherproof enclosure:

  1. Mount Pi and relay in plastic box
  2. Drill holes for wires
  3. Seal holes with hot glue or silicone
  4. Keep electronics elevated (above water level)
  5. Good ventilation prevents condensation

Cable management:

  • Secure all connections
  • Use waterproof connectors if possible
  • Label wires for troubleshooting

Advanced Features

Multiple Plants

Add more sensors and pumps:

# multi_plant.py
PLANTS = [
    {
        "name": "Tomato",
        "sensor_channel": ADS.P0,
        "relay_pin": 18,
        "threshold": 30,
        "duration": 5
    },
    {
        "name": "Basil",
        "sensor_channel": ADS.P1,
        "relay_pin": 23,
        "threshold": 40,
        "duration": 3
    }
]

# Loop through each plant in monitoring
for plant in PLANTS:
    moisture = get_moisture(plant["sensor_channel"])
    if moisture < plant["threshold"]:
        water_plant(plant["relay_pin"], plant["duration"])

Web Dashboard

Simple Flask app:

# dashboard.py
from flask import Flask, render_template
import csv

app = Flask(__name__)

@app.route('/')
def index():
    # Read last 100 log entries
    logs = []
    with open('watering_log.txt', 'r') as f:
        logs = list(csv.reader(f))[-100:]
    
    return render_template('index.html', logs=logs)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

Access dashboard: http://[PI_IP]:5000

Push Notifications

Using Pushover or IFTTT:

import requests

def send_notification(message):
    """Send push notification via Pushover"""
    requests.post("https://api.pushover.net/1/messages.json", data={
        "token": "YOUR_APP_TOKEN",
        "user": "YOUR_USER_KEY",
        "message": message
    })

# Use in script
send_notification(f"Watered plant! Moisture was {moisture:.1f}%")

Environmental Monitoring

Add DHT22 sensor:

import adafruit_dht

dht_sensor = adafruit_dht.DHT22(board.D4)

try:
    temperature = dht_sensor.temperature
    humidity = dht_sensor.humidity
    print(f"Temp: {temperature}°C, Humidity: {humidity}%")
except RuntimeError:
    pass  # Sensor occasionally fails, just skip

Troubleshooting

Pump Doesn't Turn On

Check:

  • Relay wiring correct
  • Power supply connected
  • Pump submerged in water
  • GPIO pin number correct in code

Sensor Gives Weird Readings

Solutions:

  • Re-calibrate (dry and wet values)
  • Check sensor isn't corroded
  • Ensure sensor in soil, not air
  • Check ADC connections

Overwatering Plants

Solutions:

  • Increase moisture threshold (higher number)
  • Reduce watering duration
  • Increase minimum interval between waterings
  • Check for water drainage in pot

Underwatering

Solutions:

  • Lower moisture threshold
  • Increase watering duration
  • Check pump flow rate
  • Ensure tubing not kinked

System Crashes

Solutions:

  • Check power supply adequate
  • Add error handling in code
  • Monitor logs: sudo journalctl -u autowater.service
  • Ensure SD card not corrupted

Tips for Success

Sensor placement:

  • Middle of pot, halfway down
  • Away from drainage holes
  • Consistent depth each time

Watering strategy:

  • Start conservative (less water)
  • Monitor for week, adjust
  • Different plants need different levels

Maintenance:

  • Check water reservoir weekly
  • Clean pump monthly (prevents clogging)
  • Inspect tubing for leaks
  • Replace capacitive sensors yearly

Testing:

  • Test without plants first
  • Use small watering duration initially
  • Monitor closely first few days
  • Keep backup manual watering schedule

Plant-Specific Settings

Moisture thresholds by plant type:

  • Succulents: 20-30%
  • Herbs (basil, mint): 40-50%
  • Vegetables (tomato, pepper): 30-40%
  • Tropical plants: 50-60%
  • Ferns: 60-70%

Research your specific plants for optimal moisture levels!

Cost Breakdown

Single Plant System (~$50):

  • Raspberry Pi Zero 2 W: $15
  • Soil moisture sensor: $8
  • Water pump (5V): $6
  • Relay module: $5
  • ADS1115 ADC: $10
  • Tubing + container: $6
  • microSD + wires: $10

Multi-Plant System (~$80):

  • Raspberry Pi 4: $35
  • 3x Soil sensors: $24
  • 3x Pumps: $18
  • 4-channel relay: $12
  • ADS1115 ADC: $10
  • Tubing + containers: $15
  • Enclosure + extras: $20

What's Next?

Expand your system:

  • Add grow lights (controlled by Pi)
  • Monitor pH levels
  • Automate fertilizer dosing
  • Build greenhouse automation
  • Integrate with Home Assistant
  • Create mobile app
  • Add cameras for plant monitoring

Resources

  • Adafruit sensor tutorials
  • r/raspberry_pi
  • r/gardening
  • GPIO pinout: pinout.xyz

Final Thoughts

An automated plant watering system:

Saves plants from forgetful owners ✅ Perfect for travel - plants stay watered ✅ Learn electronics - sensors, relays, pumps ✅ Expandable - start small, grow system ✅ Practical - actually useful every day

Start with one plant, perfect the system, then expand to your whole garden!


Ready to build your plant watering system? Your plants will thank you!

Enjoyed this guide?

Get more beginner-friendly tech explanations and guides sent to your inbox.

No spam. Unsubscribe at any time. We respect your privacy.

Related Guides