#include <LiquidCrystal_I2C.h>

#define I2C_ADDR    0x27
#define LCD_COLUMNS 20
#define LCD_LINES   4
#define LED_PIN3 7 // Backyard
#define LED_PIN2 8 // Frontyard
#define LED_PIN1 9 // Footpath

LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

uint8_t heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000,
};

// The pins and state for the relay modules.
const int relay1Pin = 12;
const int relay2Pin = 11;
const int relay3Pin = 10;

byte relay1State    = LOW;
byte relay2State    = LOW;
byte relay3State    = LOW;

// The pins and state for the buttonss.
const int button1Pin = 5;
const int button2Pin = 4;
const int button3Pin = 3;
const int button4Pin = 2; //Interrupt

byte button1State    = LOW;
byte button2State    = LOW;
byte button3State    = LOW;

volatile int button4State; //for subroutine

const unsigned long shortRun = 2.0 * 60.0 * 60.0 * 1000.0; //2 hours
const unsigned long longRun  = 3.0 * 60.0 * 60.0 * 1000.0; //3 hours

unsigned long TimeLeft1 = 0.0;
unsigned long TimeLeft2 = 0.0;
unsigned long TimeLeft3 = 0.0;

unsigned long currentMillis = 0;

unsigned long startRelay1Millis = 0;
unsigned long startRelay2Millis = 0;
unsigned long startRelay3Millis = 0;

void(* resetFunc) (void) = 0;

void buttonInterrupt() {
  button4State = digitalRead(button4Pin);  

  if (button4State == HIGH) {
    
    digitalWrite(relay1Pin,LOW);
    digitalWrite(relay2Pin,LOW);
    digitalWrite(relay3Pin,LOW);
    button1State    = LOW;
    button2State    = LOW;
    button3State    = LOW;
    digitalWrite(LED_PIN1,LOW);
    digitalWrite(LED_PIN2,LOW);
    digitalWrite(LED_PIN3,LOW);
    resetFunc();
    Serial.println("All stopped!");
    button4State = LOW;
  }
}

void setup() {

lcd.createChar(3, heart);

// Init display
  lcd.init();
  lcd.backlight();

  // Print something
  lcd.setCursor(3, 0);
  lcd.print("Rod's Watering");
  lcd.setCursor(3, 1);
  lcd.print("    System");
  lcd.setCursor(1, 2);
  lcd.print("       v1.10            ");
  lcd.setCursor(10, 3);
  lcd.print("\x03");
  
// Set pins as output.
pinMode(relay1Pin, OUTPUT);
pinMode(relay2Pin, OUTPUT);
pinMode(relay3Pin, OUTPUT);

//Set pins for input.
pinMode(button1Pin, INPUT);
pinMode(button2Pin, INPUT);
pinMode(button3Pin, INPUT);
pinMode(button4Pin, INPUT);
pinMode(LED_PIN3, OUTPUT);
pinMode(LED_PIN2, OUTPUT);
pinMode(LED_PIN1, OUTPUT);

attachInterrupt(digitalPinToInterrupt(button4Pin), buttonInterrupt, CHANGE);
Serial.begin(9600);

}

void loop() {
  // put your main code here, to run repeatedly:

  if(buttonPressed(button1Pin)) {
    Serial.print("Green pressed!  - ");
    Serial.print(shortRun);
    Serial.print(" milliseconds  -  ");
    Serial.println(button1State);

    if (button1State == HIGH) {
      Serial.println(" Button 1 state is already HIGH");
    }
    else { if (button1State == LOW && button2State == LOW && button3State == LOW) {
      button1State    = HIGH;
      Serial.println(" Button 1 state is HIGH");
      startRelay1Millis = millis();
    }
    }
  }

  if(buttonPressed(button2Pin)) {
    Serial.print("Blue pressed!   - ");
    Serial.print(shortRun);
    Serial.print(" milliseconds  -  ");
    Serial.println(button2State);

    if (button2State == HIGH) {
      Serial.println(" Button 2 state is already HIGH");
    }
    else { if (button1State == LOW && button2State == LOW && button3State == LOW) {
      button2State    = HIGH;
      Serial.println(" Button 2 state is HIGH");
      startRelay2Millis = millis();
    }
    }  
  }
  
  if(buttonPressed(button3Pin)) {
    Serial.print("Yellow pressed! - ");
    Serial.print(longRun);
    Serial.print(" milliseconds  -  ");
    Serial.println(button3State);

    if (button3State == HIGH) {
      Serial.println(" Button 3 state is already HIGH");
    }
    else { if (button1State == LOW && button2State == LOW && button3State == LOW) {
      button3State    = HIGH;
      Serial.println(" Button 3 state is HIGH");
      startRelay3Millis = millis();
      
    }
    }  
  }

  currentMillis = millis();

  if (button1State == HIGH) {

  TimeLeft1 = (shortRun - currentMillis - startRelay1Millis) / 60000.0;
  lcd.setCursor(3, 0);
  lcd.print("Rod's Watering");
  lcd.setCursor(3, 1);
  lcd.print("    System");
  lcd.setCursor(1, 2);
  lcd.print(" Watering footpath  ");
  lcd.setCursor(4, 3);
  lcd.print(TimeLeft1);
  lcd.setCursor(8, 3);
  lcd.print("minutes \x03");

    uint8_t heart2[8] = {0};
    for (int i = 0; i < 8; i++) {
       heart2[i] = heart[i];
       lcd.createChar(3, heart2);
       delay(100);   
    }

    if (currentMillis - startRelay1Millis <= shortRun) {
      digitalWrite(relay1Pin,HIGH);
      digitalWrite(LED_PIN1,HIGH);
    }
    if (currentMillis - startRelay1Millis >= shortRun) {
      digitalWrite(relay1Pin,LOW);
      digitalWrite(LED_PIN1,LOW);
      button1State    = LOW;
     }
  }

  if (button2State == HIGH) {

TimeLeft2 = (shortRun - currentMillis - startRelay2Millis) / 60000.0;
  lcd.setCursor(3, 0);
  lcd.print("Rod's Watering");
  lcd.setCursor(3, 1);
  lcd.print("    System");
  lcd.setCursor(1, 2);
  lcd.print("Watering frontyard");
  lcd.setCursor(4, 3);
  lcd.print(TimeLeft2);
  lcd.setCursor(7, 3);
  lcd.print(" minutes \x03");
    
     uint8_t heart2[8] = {0};
    for (int i = 0; i < 8; i++) {
       heart2[i] = heart[i];
       lcd.createChar(3, heart2);
       delay(100);   
    }

    if (currentMillis - startRelay2Millis <= shortRun) {
      digitalWrite(relay2Pin,HIGH);
      digitalWrite(LED_PIN2,HIGH);
    }
    if (currentMillis - startRelay2Millis >= shortRun) {
      digitalWrite(relay2Pin,LOW);
      digitalWrite(LED_PIN2,LOW);
      button2State    = LOW;
    }
  }

  if (button3State == HIGH) {

  TimeLeft3 = (longRun - currentMillis - startRelay3Millis) / 60000.0;
  lcd.setCursor(3, 0);
  lcd.print("Rod's Watering");
  lcd.setCursor(3, 1);
  lcd.print("    System");
  lcd.setCursor(1, 2);
  lcd.print("Watering back yard");
  lcd.setCursor(4, 3);
  lcd.print(TimeLeft3);
  lcd.setCursor(8, 3);
  lcd.print("minutes \x03");
      
     uint8_t heart2[8] = {0};
    for (int i = 0; i < 8; i++) {
       heart2[i] = heart[i];
       lcd.createChar(3, heart2);
       delay(100);   
    }

    if (currentMillis - startRelay3Millis <= longRun) {
       digitalWrite(relay3Pin,HIGH);
       digitalWrite(LED_PIN3,HIGH);
    }
    if (currentMillis - startRelay3Millis >= longRun) {
      digitalWrite(relay3Pin,LOW);
      digitalWrite(LED_PIN3,LOW);
      button3State    = LOW;
    }
  }
} // end of void loop

// Generic function to check if a button is pressed
int buttonPressed(uint8_t button) {
  static uint16_t lastStates = 0;
  uint8_t state = digitalRead(button);
  if (state != ((lastStates >> button) & 1)) {
    lastStates ^= 1 << button;
    return state == HIGH;
  }
  return false;
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module