Project Overview
This project creates a smart plant watering system that reminds you to water your plants when motion is detected nearby, or automatically waters based on soil moisture. It’s perfect for indoor plants that are easily forgotten.
Difficulty: Beginner/Intermediate
Estimated time: 2-3 hours
Estimated cost: $20-30
How It Works
A PIR sensor detects when someone approaches the plant. When motion is detected, a soil moisture sensor checks if watering is needed. If the soil is dry, a water pump is activated for a set duration. An LCD or LED indicates the plant’s status. Optionally, the system can water automatically on a schedule regardless of motion.
Materials Needed
- Arduino Uno or ESP32 (1)
- HC-SR501 PIR sensor (1)
- Soil moisture sensor (capacitive type recommended)
- Submersible water pump (5V, small)
- MOSFET or relay module (to control pump)
- Water reservoir (container for water)
- Plastic tubing (for water delivery)
- LCD 16×2 with I2C (optional)
- Buzzer (for reminder alerts, optional)
- LED (for status indication)
- Resistors (220Ω, 10k)
- Jumper wires
- Power supply (5V 2A)
Circuit Diagram
Connection Table
| Component | Pin | Arduino Pin | PIR Sensor | VCC | 5V | PIR Sensor | GND | GND | PIR Sensor | OUT | Digital Pin 2 | Soil Moisture Sensor | VCC | 5V | Soil Moisture Sensor | GND | GND | Soil Moisture Sensor | AO (analog) | Analog Pin A0 | Relay Module | VCC | 5V | Relay Module | GND | GND | Relay Module | IN | Digital Pin 3 | LCD (I2C) | VCC | 5V | LCD (I2C) | GND | GND | LCD (I2C) | SDA | A4 (SDA) | LCD (I2C) | SCL | A5 (SCL) | Buzzer | Positive | Digital Pin 8 | Buzzer | Negative | GND | Status LED | Anode | Digital Pin 13 (through 220Ω) | Status LED | Cathode | GND |
|---|
Arduino Code
// Automatic Plant Watering with PIR
// Waters plants when motion detected and soil is dry
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
const int pirPin = 2;
const int pumpPin = 3;
const int moisturePin = A0;
const int buzzerPin = 8;
const int ledPin = 13;
// Thresholds
const int dryThreshold = 500; // Soil dry below this value (adjust based on sensor)
const int wetThreshold = 800; // Soil wet above this value
// Timing
unsigned long lastMotionTime = 0;
const unsigned long cooldownPeriod = 3600000; // 1 hour between waterings
bool wateredRecently = false;
void setup() {
Serial.begin(9600);
pinMode(pirPin, INPUT);
pinMode(pumpPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(pumpPin, LOW);
digitalWrite(ledPin, LOW);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Plant Watering");
lcd.setCursor(0, 1);
lcd.print("System Ready");
Serial.println("Plant Watering System Ready");
delay(2000);
Serial.println("Waiting 60 seconds for PIR warm-up...");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("PIR warm-up...");
lcd.setCursor(0, 1);
lcd.print("60 seconds");
delay(60000);
}
int readMoisture() {
int value = analogRead(moisturePin);
Serial.print("Soil moisture: ");
Serial.println(value);
return value;
}
bool needsWater() {
int moisture = readMoisture();
return moisture < dryThreshold;
}
void waterPlant() {
Serial.println("Watering plant...");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Watering...");
// Beep before watering
digitalWrite(buzzerPin, HIGH);
delay(200);
digitalWrite(buzzerPin, LOW);
// Turn on pump
digitalWrite(pumpPin, HIGH);
digitalWrite(ledPin, HIGH);
// Water for 5 seconds (adjust based on your setup)
delay(5000);
// Turn off pump
digitalWrite(pumpPin, LOW);
digitalWrite(ledPin, LOW);
// Beep after watering
digitalWrite(buzzerPin, HIGH);
delay(200);
digitalWrite(buzzerPin, LOW);
delay(200);
digitalWrite(buzzerPin, HIGH);
delay(200);
digitalWrite(buzzerPin, LOW);
wateredRecently = true;
lastMotionTime = millis();
Serial.println("Watering complete");
}
void checkAndWater() {
if (needsWater()) {
if (!wateredRecently || (millis() - lastMotionTime > cooldownPeriod)) {
waterPlant();
} else {
Serial.println("Plant needs water but cooldown active");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Needs water!");
lcd.setCursor(0, 1);
lcd.print("Cooldown active");
// Brief beep as reminder
digitalWrite(buzzerPin, HIGH);
delay(100);
digitalWrite(buzzerPin, LOW);
delay(100);
}
} else {
Serial.println("Soil moisture OK");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Soil Moisture OK");
lcd.setCursor(0, 1);
lcd.print("Plant is happy!");
}
}
void displayStatus() {
int moisture = readMoisture();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Moisture: ");
lcd.print(moisture);
lcd.setCursor(0, 1);
if (moisture < dryThreshold) {
lcd.print("DRY - Water soon!");
} else if (moisture < wetThreshold) {
lcd.print("OK");
} else {
lcd.print("WET");
}
}
void loop() {
bool motionDetected = digitalRead(pirPin) == HIGH;
if (motionDetected) {
Serial.println("Motion detected");
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
checkAndWater();
} else {
// Optional: display status periodically even without motion
static unsigned long lastDisplay = 0;
if (millis() - lastDisplay > 10000) { // Every 10 seconds
displayStatus();
lastDisplay = millis();
}
}
delay(100);
}
Soil Moisture Sensor Calibration
- Insert sensor into dry soil and note the analog reading (usually 300-500).
- Water the plant thoroughly and note reading when soil is fully saturated (usually 800-1000).
- Set
dryThresholdto about 100-200 points above the dry reading (e.g., if dry reading is 300, set threshold to 500). - Set
wetThresholdto the saturated reading minus 100-200.
Water Pump Assembly
- Place the submersible pump in the water reservoir.
- Connect tubing from pump outlet to plant soil.
- Secure tubing near plant base.
- Ensure reservoir has enough water for multiple watering cycles.
- Consider adding a water level sensor to detect when reservoir is empty.
Installation Steps
- Assemble electronics: Build circuit on breadboard and test.
- Calibrate soil sensor: Test in dry and wet soil to set thresholds.
- Test pump: Verify pump moves water properly.
- Place sensors: Insert soil moisture sensor into plant pot, mount PIR sensor to detect approach.
- Mount Arduino: Place Arduino and power supply in safe location away from water.
- Final test: Trigger PIR and verify watering occurs when soil is dry.
Project Extensions
- Water level sensor: Add float switch or ultrasonic sensor to detect when reservoir is low and alert you.
- Multiple plants: Add additional soil sensors and solenoid valves for multi-plant watering.
- Wi-Fi monitoring: Use ESP32 to send soil moisture data to phone.
- Rain sensor: Add rain sensor for outdoor plants to prevent watering in rain.
- Temperature sensor: Adjust watering schedule based on temperature.
- Fertilizer dosing: Add second pump for liquid fertilizer.
Troubleshooting
- Pump not running: Check relay wiring. Ensure power supply can handle pump current (pumps can draw 200-500mA).
- Inaccurate soil readings: Capacitive sensors are more reliable than resistive types (resistive sensors corrode over time).
- PIR false triggers: Adjust sensitivity or position away from windows and heat sources.
- Water not reaching plant: Check tubing for kinks. Ensure pump is fully submerged.
Conclusion
This smart plant watering system takes the guesswork out of plant care. It reminds you to water when you’re near the plant and only waters when needed, preventing both under-watering and over-watering.
