Community project

Automatic Plant Watering

Arduino
Photo of Automatic Plant Watering
Generated with AI

anthony Bolduc

Published October 11, 2026

This project automates watering for up to four potted plants using capacitive soil moisture sensors and individual relay-controlled water pumps. The Arduino Uno continuously monitors each plant's soil moisture level and triggers its pump to run for a set duration whenever the soil dries below a configurable threshold, with a built-in delay between waterings to prevent overwatering.

The guide provides a complete wiring diagram, parts list, and step-by-step assembly instructions for safely integrating the power supply, relay module, sensors, and pumps. Included firmware handles sensor calibration, moisture calculation, and pump scheduling with serial output for monitoring and debugging each plant's watering cycle.

Wiring diagram

Wiring diagram for Automatic Plant Watering

Gather all the parts

QtyComponent
1

Capacitive Soil Moisture Sensor v1.2

A three-wire probe that measures how moist the soil is without exposed metal contacts.

1

Capacitive Soil Moisture Sensor v1.2

A three-wire probe that measures how moist the soil is without exposed metal contacts.

1

Capacitive Soil Moisture Sensor v1.2

A three-wire probe that measures how moist the soil is without exposed metal contacts.

1

Capacitive Soil Moisture Sensor v1.2

A three-wire probe that measures how moist the soil is without exposed metal contacts.

1

4-Channel 5V Optocoupler Relay Module

A four-switch module that lets the Uno safely turn the separate pump power on and off.

1

WayinTop 3–6V DC Submersible Water Pump

A small two-wire pump that pushes water through tubing when switched on.

1

WayinTop 3–6V DC Submersible Water Pump

A small two-wire pump that pushes water through tubing when switched on.

1

WayinTop 3–6V DC Submersible Water Pump

A small two-wire pump that pushes water through tubing when switched on.

1

WayinTop 3–6V DC Submersible Water Pump

A small two-wire pump that pushes water through tubing when switched on.

1

Regulated 5V 3A DC Power Supply

A regulated supply that provides enough 5V current for the relay coils and water pumps.

1

1N4007 Diode

1N4007

General-purpose silicon rectifier diode in DO-204AL (DO-41) axial through-hole package. Rated 1A average forward current and 1000V peak reverse voltage (VRRM). Forward voltage drop ~0.7V at typical load (up to 1.1V at full 1A). Used here in series with LM7805 Vout for reverse polarity protection: anode to LM7805 output, cathode to 5V rail, resulting in ~4.3V on the output rail. Not suitable for high-frequency switching (reverse recovery ~2µs–30µs); intended for DC or 50/60Hz rectification only.

1

1N4007 Diode

1N4007

General-purpose silicon rectifier diode in DO-204AL (DO-41) axial through-hole package. Rated 1A average forward current and 1000V peak reverse voltage (VRRM). Forward voltage drop ~0.7V at typical load (up to 1.1V at full 1A). Used here in series with LM7805 Vout for reverse polarity protection: anode to LM7805 output, cathode to 5V rail, resulting in ~4.3V on the output rail. Not suitable for high-frequency switching (reverse recovery ~2µs–30µs); intended for DC or 50/60Hz rectification only.

1

1N4007 Diode

1N4007

General-purpose silicon rectifier diode in DO-204AL (DO-41) axial through-hole package. Rated 1A average forward current and 1000V peak reverse voltage (VRRM). Forward voltage drop ~0.7V at typical load (up to 1.1V at full 1A). Used here in series with LM7805 Vout for reverse polarity protection: anode to LM7805 output, cathode to 5V rail, resulting in ~4.3V on the output rail. Not suitable for high-frequency switching (reverse recovery ~2µs–30µs); intended for DC or 50/60Hz rectification only.

1

1N4007 Diode

1N4007

General-purpose silicon rectifier diode in DO-204AL (DO-41) axial through-hole package. Rated 1A average forward current and 1000V peak reverse voltage (VRRM). Forward voltage drop ~0.7V at typical load (up to 1.1V at full 1A). Used here in series with LM7805 Vout for reverse polarity protection: anode to LM7805 output, cathode to 5V rail, resulting in ~4.3V on the output rail. Not suitable for high-frequency switching (reverse recovery ~2µs–30µs); intended for DC or 50/60Hz rectification only.

Assemble it in 7 steps

1. Set up safe power first

Keep the Uno unplugged. Do not use the rectangular 9V battery as the pump supply: it cannot reliably provide the pump startup current. Use a regulated 5V supply rated for at least 3A for the pumps and relay. Leave the small yellow JD-VCC jumper installed on the relay board. Power the Uno from its USB cable.

  • Put a strip of masking tape on the 5V supply wires: red for +5V and black for GND.
  • Keep water containers and wet tubing away from the Uno, relay module, breadboard, and USB connector.
  • Do not connect the pump supply's +5V wire to the Uno 5V pin. The pumps must receive power through the relay contacts, not through the Uno.
  • Do not use the 9V battery with the breadboard supply for the pumps; voltage sag can cause unreliable pumping and Arduino resets.

2. Make the shared ground rail

Use the blue breadboard rail as ground. Run a black jumper from an Uno GND pin to that rail. Run another black jumper from the regulated pump supply GND to the same rail. This shared return path lets the Uno correctly control the relay board.

  • All black ground wires must be electrically joined on the same blue rail.
  • A missing shared ground can make relays chatter, fail to switch, or turn on unexpectedly.

3. Wire the four soil probes

Use the Uno's 5V pin only for the soil probes. Run one red jumper from Uno 5V to a separate red sensor-power rail, then connect every sensor VCC to it. Connect every sensor GND to the blue ground rail with black jumpers. Connect sensor 1 AOUT to Uno A0 with a yellow jumper, sensor 2 AOUT to A1 with a green jumper, sensor 3 AOUT to A2 with a blue jumper, and sensor 4 AOUT to A3 with a white jumper. Put sensor 1 in your first pot now; the other three can be connected when you expand.

  • VCC → Uno 5V (power); each GND → shared blue rail (ground); AOUT → A0/A1/A2/A3 (moisture signal).
  • Push only the coated sensing end into soil. Keep the small circuit board above the soil and dry.
  • Make sure VCC and GND are not swapped — swapped power can damage a sensor.

4. Wire the relay control side

With the JD-VCC jumper still fitted, connect relay VCC to the regulated pump supply +5V with a red jumper and relay GND to the shared blue ground rail with a black jumper. Connect relay IN1 to Uno D2 with a yellow jumper, IN2 to D3 with a green jumper, IN3 to D4 with a blue jumper, and IN4 to D5 with a white jumper. The common 4-channel relay type is active-LOW, so the uploaded code keeps these pins HIGH to leave every pump off.

  • Control wires: IN1 → D2 (pump 1 control), IN2 → D3 (pump 2 control), IN3 → D4 (pump 3 control), IN4 → D5 (pump 4 control).
  • The small LEDs on the relay board usually light when a channel is active.
  • Do not remove the JD-VCC jumper for this beginner build. The separate relay-coil wiring required without it is different.
  • Before attaching water tubing, plug in the Uno and confirm no relay channel clicks on at startup.

5. Wire pump 1 through relay channel 1

For the first pot, run a thicker red wire from the regulated pump supply +5V to relay COM1. Run a red wire from relay NO1 to pump 1 positive wire. Connect pump 1 negative wire to the shared blue ground rail with a black wire. Place diode 1 directly across the pump wires: its striped end goes to pump positive / the NO1 wire, and its unstriped end goes to pump negative / ground. NO means the pump stays off until the relay is commanded on.

  • Pump 1: supply +5V → COM1 (power); NO1 → pump positive (switched power); pump negative → shared ground (return).
  • The stripe on a 1N4007 diode marks its cathode; it must face the pump positive wire.
  • A reversed flyback diode makes a short circuit when the pump relay turns on and can damage the supply or wiring.
  • Keep the diode leads insulated so they cannot touch each other or wet surfaces.

6. Reserve matching wiring for pots 2 through 4

When you add the other pots, repeat the same switched-positive wiring: pump supply +5V to COM2, COM3, and COM4; NO2 to pump 2 positive, NO3 to pump 3 positive, and NO4 to pump 4 positive; each pump negative to the shared ground rail. Place a diode across each pump with its striped end on that pump's positive wire and unstriped end on that pump's negative wire. Connect tubing from each pump to its own pot.

  • Pump 2 uses relay channel 2, pump 3 uses channel 3, and pump 4 uses channel 4.
  • Keep each pump submerged in its water container before testing; running a small submersible pump dry can shorten its life.
  • Do not join the four NO terminals together: each NO terminal must feed only its own pump so the code can water one pot at a time.

7. Place tubing and perform a dry safety check

Put each pump in a water container, attach tubing firmly, and route each tube end into its matching pot. Keep all electronics higher than the water level. Before watering a real plant, test with a cup or tray under the tube. Upload the code through Schematik's Deploy button, then open the Serial Monitor at 9600 baud to see the raw readings and moisture percentages.

  • For the one-pot start, connect only sensor 1 and pump 1 physically; the code already reserves the other three channels.
  • Adjust MOISTURE_THRESHOLD_PERCENT and PUMP_RUN_MS only after observing how much water reaches your pot in three seconds.
  • Unplug both USB and the pump supply before moving wires.
  • If a pump runs immediately after startup, unplug the pump supply first, then check that the relay input wiring and active-LOW setting match the code.

Review all connections

1. Connections between "soil_sensor_1" and "Arduino"

Functionsoil_sensor_1Arduino
powerVCC5V
groundGNDGND
analogAOUTGPIO 14

2. Connections between "soil_sensor_2" and "Arduino"

Functionsoil_sensor_2Arduino
powerVCC5V
groundGNDGND
analogAOUTGPIO 15

3. Connections between "soil_sensor_3" and "Arduino"

Functionsoil_sensor_3Arduino
powerVCC5V
groundGNDGND
analogAOUTGPIO 16

4. Connections between "soil_sensor_4" and "Arduino"

Functionsoil_sensor_4Arduino
powerVCC5V
groundGNDGND
analogAOUTGPIO 17

5. Connections between "relay_4ch" and "Arduino"

Functionrelay_4chArduino
powerVCC5V
groundGNDGND
digitalIN1GPIO 2
digitalIN2GPIO 3
digitalIN3GPIO 4
digitalIN4GPIO 5
powerCOM15V
dataNO1 → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT
powerCOM25V
dataNO2 → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT
powerCOM35V
dataNO3 → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT
powerCOM45V
dataNO4 → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT

6. Connections between "pump_1" and "Arduino"

Functionpump_1Arduino
groundPUMP-GND

7. Connections between "pump_2" and "Arduino"

Functionpump_2Arduino
groundPUMP-GND

8. Connections between "pump_3" and "Arduino"

Functionpump_3Arduino
groundPUMP-GND

9. Connections between "pump_4" and "Arduino"

Functionpump_4Arduino
groundPUMP-GND

10. Connections between "flyback_diode_1" and "Arduino"

Functionflyback_diode_1Arduino
powerAnode → WayinTop 3–6V DC Submersible Water Pump PUMP-EXT
powerCathode → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT

11. Connections between "flyback_diode_2" and "Arduino"

Functionflyback_diode_2Arduino
powerAnode → WayinTop 3–6V DC Submersible Water Pump PUMP-EXT
powerCathode → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT

12. Connections between "flyback_diode_3" and "Arduino"

Functionflyback_diode_3Arduino
powerAnode → WayinTop 3–6V DC Submersible Water Pump PUMP-EXT
powerCathode → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT

13. Connections between "flyback_diode_4" and "Arduino"

Functionflyback_diode_4Arduino
powerAnode → WayinTop 3–6V DC Submersible Water Pump PUMP-EXT
powerCathode → WayinTop 3–6V DC Submersible Water Pump PUMP+EXT

14. Connections between "pump_supply_5v" and "Arduino"

Functionpump_supply_5vArduino
power+5V5V
groundGNDGND

Deploy the firmware

// Automatic plant watering controller for Arduino Uno.
// Relay modules like the common 4-channel optocoupler board normally turn ON
// when their IN pin is LOW. If yours behaves opposite, swap these two values.
const byte RELAY_ON = LOW;
const byte RELAY_OFF = HIGH;

const byte SOIL_PINS[4] = {A0, A1, A2, A3};
const byte RELAY_PINS[4] = {2, 3, 4, 5};

// Calibration values: larger reading = drier for these capacitive probes.
// Change each pair after testing that particular sensor in air and in wet soil.
const int DRY_READING[4] = {654, 654, 654, 654};
const int WET_READING[4] = {330, 330, 330, 330};

// A plant is watered when its reading is below this percentage.
const int MOISTURE_THRESHOLD_PERCENT = 35;
const unsigned long PUMP_RUN_MS = 3000UL;             // 3 seconds per watering
const unsigned long RECHECK_DELAY_MS = 30UL * 60000UL; // 30 minutes
const unsigned long REPORT_INTERVAL_MS = 5000UL;       // serial report every 5 seconds

unsigned long nextAllowedWaterTime[4] = {0, 0, 0, 0};
unsigned long lastReportTime = 0;

int readAverageRaw(byte sensorIndex) {
  const byte samples = 10;
  long total = 0;
  for (byte i = 0; i < samples; i++) {
    total += analogRead(SOIL_PINS[sensorIndex]);
    delay(5);
  }
  return total / samples;
}

int rawToMoisturePercent(byte sensorIndex, int raw) {
  long percent = map(raw, DRY_READING[sensorIndex], WET_READING[sensorIndex], 0, 100);
  return constrain(percent, 0, 100);
}

void allPumpsOff() {
  for (byte i = 0; i < 4; i++) {
    digitalWrite(RELAY_PINS[i], RELAY_OFF);
  }
}

void waterOnePot(byte potIndex) {
  // allPumpsOff makes this safe even after changing the program later:
  // only one relay, and therefore only one pump, can run at a time.
  allPumpsOff();
  Serial.print(F("Watering pot "));
  Serial.print(potIndex + 1);
  Serial.print(F(" for "));
  Serial.print(PUMP_RUN_MS / 1000UL);
  Serial.println(F(" seconds."));

  digitalWrite(RELAY_PINS[potIndex], RELAY_ON);
  delay(PUMP_RUN_MS);
  digitalWrite(RELAY_PINS[potIndex], RELAY_OFF);

  nextAllowedWaterTime[potIndex] = millis() + RECHECK_DELAY_MS;
  Serial.print(F("Pump "));
  Serial.print(potIndex + 1);
  Serial.println(F(" stopped; this pot will wait before it can water again."));
}

void reportMoisture() {
  Serial.println(F("--- Soil moisture ---"));
  for (byte i = 0; i < 4; i++) {
    int raw = readAverageRaw(i);
    int percent = rawToMoisturePercent(i, raw);
    Serial.print(F("Pot "));
    Serial.print(i + 1);
    Serial.print(F(": raw "));
    Serial.print(raw);
    Serial.print(F(", moisture "));
    Serial.print(percent);
    Serial.println(F("%"));
  }
}

void setup() {
  Serial.begin(9600);

  for (byte i = 0; i < 4; i++) {
    pinMode(RELAY_PINS[i], OUTPUT);
  }
  allPumpsOff(); // critical for active-LOW relay boards: pumps stay off at startup

  Serial.println(F("Automatic plant watering controller ready."));
  Serial.println(F("Open Serial Monitor at 9600 baud."));
}

void loop() {
  unsigned long now = millis();

  if (now - lastReportTime >= REPORT_INTERVAL_MS) {
    lastReportTime = now;
    reportMoisture();
  }

  // Check each pot in order.  waterOnePot blocks briefly on purpose, so no
  // second pump can begin while the first pump is running.
  for (byte i = 0; i < 4; i++) {
    if (now >= nextAllowedWaterTime[i]) {
      int raw = readAverageRaw(i);
      int moisture = rawToMoisturePercent(i, raw);
      if (moisture < MOISTURE_THRESHOLD_PERCENT) {
        waterOnePot(i);
        break;
      }
    }
  }
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik