/*
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/462986726733227009
TO sketch with modifications
Plus constant to adjust the watering interval and further parameters
Prints the time (hours, mins, secs) until next Watering if required
2026/05/01
ec2021
*/
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
// Constants to be adjusted by TO
constexpr unsigned long measurementInterval {1000}; // Measure the moisture every second
constexpr unsigned long minWateringInterval {15 * 60 * 1000UL}; // Check watering every 15 min = 15*60*1000UL
constexpr int dryLevel {40}; // The moisture level in % where watering shall be started
constexpr int wateringDuration {3800}; // 3800 ms watering duration
constexpr byte soilMoisturePin = A0;
constexpr byte BUTTON_PIN = 3;
constexpr byte RELAY_PIN = 7;
int sensorValue = 0;
int moisturePercent = 0;
unsigned long lastMeasurement = 0;
unsigned long lastWatering = 0;
unsigned long countDown = 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 (lastMeasurement == 0 || millis() - lastMeasurement >= measurementInterval) {
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(" % ");
lcd.setCursor(0, 1);
if (moisturePercent <= dryLevel) {
if (countDown > 0) {
int hours = countDown / 3600;
int mins = (countDown - hours * 3600) / 60;
int secs = countDown - mins * 60 - hours * 3600;
char msg[16];
sprintf(msg, "Next: %02d:%02d:%02d", hours, mins, secs);
lcd.print(msg);
countDown--;
}
} else {
lcd.print(F(" "));
}
}
btnDown = !digitalRead(BUTTON_PIN); // No debouncing required as WateringInProgress() includes delay(3800)
if (wateringRequired() || btnDown) {
WateringInProgress();
}
}
bool wateringRequired() {
if (moisturePercent > dryLevel) {
return false;
}
if (lastWatering == 0 || millis() - lastWatering >= minWateringInterval) {
return true;
} else {
return false;
}
}
void WateringInProgress() {
if (btnDown) {
lcd.setCursor(0,0);
lcd.print("Manual override");
}
lcd.setCursor(0,1);
lcd.print("Watering ");
digitalWrite(RELAY_PIN, HIGH);
delay(wateringDuration);
digitalWrite(RELAY_PIN, LOW);
lastWatering = millis();
countDown = minWateringInterval/1000;
lcd.clear();
}