#include <EEPROM.h>

#include <Wire.h>
#include <LiquidCrystal_I2C.h>

//LiquidCrystal_I2C lcd(34, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);
// set the LCD address to 0x27 for a 16 chars and 2 line display

//HC-SR04
const int trigPin = 13;
const int echoPin = 12;

long duration;
int distance;
int tankDepth;
int percentage;

//OTHER
int buzzer = 7;
int led = 8;  // to indicate pump is ON
int relay = 2;
int mode = 11;            // spst switch
int measureTankSize = 6;  // push-pull
int startStop = 4;        //push-pull
int pumpInputDry = 5;           //float switch
int pumpOutputDry = 3;       //float switch
//bool state;
bool pump;
//-------------------------------------------------

void setup() {
  Serial.begin(9600);
  lcd.init();      // initialize the lcd
  lcd.backlight();  // Turn on the LCD screen backlight

  pinMode(trigPin, OUTPUT);  //HC-SR04
  pinMode(echoPin, INPUT);

  pinMode(buzzer, OUTPUT);
  pinMode(led, OUTPUT);
  pinMode(relay, OUTPUT);

  pinMode(mode, INPUT_PULLUP);
  pinMode(measureTankSize, INPUT_PULLUP);
  pinMode(startStop, INPUT_PULLUP);
  pinMode(pumpInputDry, INPUT_PULLUP);
  pinMode(pumpOutputDry, INPUT_PULLUP);


  tankDepth = EEPROM.read(0);
  if (tankDepth > 150) {
    tankDepth = 150;
  }
}

void controlPoint() {
  //control point
  digitalWrite(relay, pump);
  digitalWrite(led, pump);
  // delay(1000);
  // digitalWrite(led, 0);
}

void pumpOutDryFunc() {
  lcd.setCursor(5, 1);
  lcd.print("Output DRY!");
  delay(1500);
  lcd.setCursor(5, 1);
  lcd.print("           ");
  delay(1500);
  //thus total 3 sec
}

void loop() {
  //default print
  lcd.setCursor(0, 0);
  lcd.print("WATER LEVEL:");
  lcd.setCursor(0, 1);
  lcd.print("PUMP:");

  //HC-SR04
  digitalWrite(trigPin, LOW);  // Clears the trigPin
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);  // Sets the trigPin on HIGH state for 10 micro seconds
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  duration = pulseIn(echoPin, HIGH);                        //measures the time until the ECHO pin goes LOW (in micro Sec)
  distance = duration * 0.034 / 2;                          // cm
  percentage = ((tankDepth - distance) * 100) / tankDepth;  // filled water = tankDepth - distance(surface)
  if (percentage < 0) {
    percentage = 0;
  }

  //measure Tank Size
  // if (!digitalRead(mode) & !digitalRead(measureTankSize)) {
  if (!pump & !digitalRead(mode) & !digitalRead(measureTankSize)) {
    tankDepth = distance;
    EEPROM.write(0, distance);

    lcd.setCursor(0, 0);
    lcd.print("Level Scanning..");
    delay(3000);
  }

  //Print
  lcd.setCursor(12, 0);
  lcd.print(percentage);
  lcd.print("%   ");

  //mode: AUTO
  if (digitalRead(mode) & percentage < 80 & !digitalRead(pumpInputDry)) {
    pump = 1;
  } else if (digitalRead(mode) & percentage < 80 & digitalRead(pumpInputDry)) {
    lcd.setCursor(5, 1);
    lcd.print("Input DRY!!");
    delay(2000);
    lcd.setCursor(5, 1);
    lcd.print("           ");
    pump = 0;
  }

  //mode: MANUAL
  if (!digitalRead(mode) & !digitalRead(startStop)) {
    pump = !pump;
  }
  while (!digitalRead(startStop)) {  // to make toggle perfect
    delay(50);
  }

  //Overflow condition
  if (percentage > 90) {
    pump = 0;
  }

  //dry run protection
  for (int i = 0; i < 1200; i++) { //each iteration for 3 sec

    //(for AUTO Mode) Pump Input as well as Output - dry run protection (wait then action)
    //45 sec ON, remaining OFF upto 1 hour
    if (digitalRead(mode)) {
      if (digitalRead(pumpInputDry)) { //check i/p also at every iteration
        pump = 0;
        break;
      }
      if (pump == 1 & digitalRead(pumpOutputDry)) { //up to 45 sec (in every one hr)
        pumpOutDryFunc();
        if (i < 20) {
          controlPoint();
        } else {
          pump = 0;
          controlPoint();
          pump = 1;
        }
      } else {
        break;
      }
    }

    //(for MANUAL Mode) Pump output - dry run protection (wait then action)
    //up to 1 min ON then OFF.
    else if (!digitalRead(mode)) {
      if (pump == 1 & digitalRead(pumpOutputDry)) {
        pumpOutDryFunc();
        if (i < 40) {
          controlPoint();
        } else {
          pump = 0;
        }
      } else {
        break;
      }
    }

  }

  //control point
  controlPoint();

  //print
  lcd.setCursor(5, 1);
  if (pump) {
    lcd.print("ON ");
  } else {
    lcd.print("OFF");
  }
  lcd.setCursor(9, 1);
  if (!digitalRead(mode)) {
    lcd.print("Manual");
  } else {
    lcd.print("Auto  ");
  }
  Serial.println(pump);

  delay(500);
}
NOCOMNCVCCGNDINLED1PWRRelay Module