I'm trying to make an automatic watering system with a 1602 I2C LCD, a relay for toggling the pump and a capacitive soil moisture sensor

I need the system to output 1L of water and the 1L flow time is 3.98 seconds, I will put a manual override button and I'm using the LiquidCrystal_I2C library, the LCD is for displaying data: soil moisture and watering cycle (watering, not watering and manual override). I need the code, thank you for helping.

Forum is not a free code writing and give away institution. You write the code and we help adjusting it, if needed.

try a web search for arduino watering system

I already tried. Didn't help.

What code did YOU write, and in what way did it not work with the equipment you did not tell us about.

You are not going to find code that does exactly what you want with the exact components that you have. You will either have to learn how to program an Arduino, pay someone to write the code for you, abandon your project or hang around here for a few days in hope that someone will do everything for you. One more option is to just buy a plant watering system.

If you want to learn, start here:
https://docs.arduino.cc/learn/

I am making the code, will send when I am done.

Yopu need to try again, I know for a fact there are 19 results in Documentation, 39 in the Project Hub, 121 in the Blog and 71 in the Store. There are also 500+ forum posts so when you say you got no help from a web search I wonder what your problem is.

Normally a new user builds the project, writes the code then when they can't figure out what they did wrong shows us ALL the code in code tags, makes a hand drwn diagram showing the path of every wire and posts a picture of that . THEN the forum volunteers can offer helpful suggestions.

If you just want somebody to do your work then we have a paid section. My rate is $500/hr with a 3 month minimum paid 1 month in advance plus expenses and the hourly rate includes travel time door to door.

I'll do it for $499.
Simulating tropic rain forest or Las Vegas, NV at random Monday, 2pm in June.

// https://forum.arduino.cc/t/im-trying-to-make-an-automatic-watering-system-with-a-1602-i2c-lcd-a-relay-for-toggling-the-pump-and-a-capacitive-soil-moisture-sensor/1442240

#include <LiquidCrystal_I2C.h>
#define I2C_ADDR    0x27
#define LCD_COLUMNS 20
#define LCD_LINES   4
LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

int buttonpin = A3; // button wired pin >> button N.O. >> GND
int relaypin = 2; // water dumper
unsigned long timer, timeout = 3980, starttime;

void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  pinMode(buttonpin, INPUT_PULLUP);
  pinMode(relaypin, OUTPUT);

  starttime = millis();
  lcd.setCursor(0, 0);
  lcd.print("Strt: ");
  lcd.println(starttime);
}

void loop() {
  int buttonpressed = digitalRead(buttonpin);
  if (buttonpressed == 0 || millis() - timer >= timeout + starttime) {
    timer = millis(); // store new time

    if (buttonpressed == 0) { // button pressed
      lcd.setCursor(12, 1);
      lcd.print("OVRD");
    }

    // dump 1L bucket onto soil.
    digitalWrite(relaypin, HIGH);

    lcd.setCursor(12, 0);
    lcd.println("H20!");
    lcd.setCursor(0, 1);
    lcd.print("End : ");
    lcd.println(timer);
    while (1) {}; // stay here
  }
}

Start:

Timeout:

Override:

Awww, now you did it for nothing.

This is the code I made:

#include <LiquidCrystal_I2C.h>     

LiquidCrystal_I2C lcd(0x27, 16, 2);

const int soilMoisturePin = A0;
const int BUTTON_PIN = 3; 
const int RELAY_PIN  = 7;

int sensorValue = 0;
int moisturePercent = 0;

void setup() 
  {
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Zemlja ");
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(RELAY_PIN, OUTPUT);
}

void loop() 
  {
  sensorValue = analogRead(soilMoisturePin);
  moisturePercent = map(sensorValue, 0, 1020, 100, 0);
  lcd.setCursor(0, 0);
  lcd.print(moisturePercent);
  lcd.print(" %  ");
  if(moisturePercent<40||digitalRead(7),HIGH){
    WateringInProgress();
  }
  delay(1000);
}

void WateringInProgress() {
  digitalWrite(RELAY_PIN, HIGH);
  delay(3800);
  digitalWrite(RELAY_PIN, HIGH);
 
}

Zemlja means dirt in Croatian if anyone is wondering.

Hi @tinoshark1 ,

what's your intention concerning the part after the OR?

And what about this

  digitalWrite(RELAY_PIN, HIGH);
  delay(3800);
  digitalWrite(RELAY_PIN, HIGH);

Ok, here is a modified version of your code that probably meets your intention:

/*
   Forum: https://forum.arduino.cc/t/im-trying-to-make-an-automatic-watering-system-with-a-1602-i2c-lcd-a-relay-for-toggling-the-pump-and-a-capacitive-soil-moisture-sensor/1442240
   Wokwi: https://wokwi.com/projects/462850559170269185

  TO sketch with modifications

  2026/05/01
  ec2021

*/

#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

const int soilMoisturePin = A0;
const int BUTTON_PIN = 3;
const int RELAY_PIN  = 7;

int sensorValue = 0;
int moisturePercent = 0;
constexpr unsigned long interval = 200; // Measure the moisture every 200 ms
unsigned long lastMeasurement = 0;
byte btnDown;

void setup()
{
  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Zemlja ");
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(RELAY_PIN, OUTPUT);
}

void loop()
{
  if (millis() - lastMeasurement >= interval) {
    lastMeasurement = millis();
    sensorValue = analogRead(soilMoisturePin);
    sensorValue = constrain(sensorValue, 0, 1020);
    moisturePercent = map(sensorValue, 0, 1020, 100, 0);
    lcd.setCursor(0, 0);
    lcd.print(moisturePercent);
    lcd.print(" %   ");
  }
  btnDown = !digitalRead(BUTTON_PIN);
  if (moisturePercent < 40 || btnDown) {
    WateringInProgress();
  }
}

void WateringInProgress() {
  if (btnDown) {
    lcdPrint("Manual override");
  } else {
    lcdPrint("Watering       ");
  }
  digitalWrite(RELAY_PIN, HIGH);
  delay(3800);
  digitalWrite(RELAY_PIN, LOW);
  lcdPrint("Not watering    ");
}

void lcdPrint(char* msg) {
  lcd.setCursor(0, 1);
  lcd.print(msg);
}

You can test it on Wokwi:

https://wokwi.com/projects/462850559170269185

Good luck!
ec2021

My intention for the OR is if I press the button (manual override) or if soil moisture is under 40%.

I thought so.

See my modifications to your sketch. You used the relay pin instead of the button pin.

And as the button pin uses pullup its state would be LOW if pressed, not HIGH.

Finally the part after OR should use a == to compare the digitalRead() with LOW rather than a comma (,).

Just check the Wokwi simulation. It uses a slide potentiometer so that you can manually change the analogRead() result that would come from the moisture sensor.

Thank you!

This code will drown your plants.

It takes time for water to soak into soil and change the sensor reading. After watering, your code does not wait long enough before taking another reading, and may give water again immediately, causing a flood.

Think about the shortest time you want between a watering and the next watering. 1000ms or 200ms is much too short. I would suggest 5 to 10 minutes.

That's a fair argument. I missed to post it, thanks!

The placement of the moisture sensor will also have a significant influence.

@tinoshark1:

You better test the watering system to find out which delay is required to achieve a valid measurement of the watering result.

What are you watering?
Pots, trays, type of plants? How many?
The secret of good watering is little and often.
You don't want the soil/compost to dry out, but you don't want to flood it either.
Plants, apart from aquatic, don't like having their feet wet for extended times.
What you are looking for is as far as possible, an even dampness.
The makeup of the growing medium matters too.
If you add too much water, it drains from the pot etc. taking nutrients with it, and if in a tray or saucer, drowns the plant from below.
I would add a second sensor at the base and if that gets too wet, stop the watering.
Your flow rate of 1-litre in nearly 4-seconds is too high for a single pot below say 30-cm diameter.
Are you adding nutrients as well?
A peristaltic pump would be a good choice for controlled watering.
A well designed system, and ideal for an Arduino, is one that maintains ideal growing conditions.
A little tip. Add say 1 drop of washing up liquid to 1-litre of your water. The detergent acts as a wetting agent and helps moisturise dry medium.

3.98... probably a code/timing test.

I am using a square long pot with 2 bell peppersband 1 tomato