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

#define TRIGGER_PIN 12
#define ECHO_PIN 14
#define RELAY_PIN 13
#define BUZZER_PIN 27
#define LCD_ADDRESS 0x27
#define LCD_COLUMNS 16
#define LCD_ROWS 2
#define OK_BUTTON_PIN 4
#define OK_BUTTON_LONG_PRESS_DURATION 2000 // 2 seconds in milliseconds
#define UP_BUTTON_PIN 2
#define DOWN_BUTTON_PIN 0

#define EEPROM_MODE_ADDRESS 0
#define EEPROM_TANK_HEIGHT_ADDRESS 1
#define EEPROM_HIGH_VALUE_ADDRESS 2
#define EEPROM_LOW_VALUE_ADDRESS 3

LiquidCrystal_I2C lcd(LCD_ADDRESS, LCD_COLUMNS, LCD_ROWS);

int mode; // 0 for auto, 1 for manual
int tankHeight = 0; // Default tank height
int highValue = 80; // Default high value
int lowValue = 5; // Default low value

enum MenuItem {
  MODE,
  TANK_HEIGHT,
  HIGH_VALUE,
  LOW_VALUE
};

int selectedMenuItem = MODE;
bool inMenu = false;

unsigned long okButtonPressedTime = 0;

void setup() {
  pinMode(TRIGGER_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(OK_BUTTON_PIN, INPUT_PULLUP); // Assuming the button is active low
  pinMode(UP_BUTTON_PIN, INPUT_PULLUP); // Assuming the button is active low
  pinMode(DOWN_BUTTON_PIN, INPUT_PULLUP); // Assuming the button is active low

  lcd.init();
  lcd.backlight();
  lcd.clear();

  // Load settings from EEPROM
  mode = EEPROM.read(EEPROM_MODE_ADDRESS);
  tankHeight = EEPROM.read(EEPROM_TANK_HEIGHT_ADDRESS);
  highValue = EEPROM.read(EEPROM_HIGH_VALUE_ADDRESS);
  lowValue = EEPROM.read(EEPROM_LOW_VALUE_ADDRESS);

  // Display initial water level
  displayWaterLevel(50); // Example water level, replace with actual measurement
}

void loop() {
  // Measure water level and display if not in menu
  if (!inMenu) {
    float distance = measureDistance();
    int waterLevel = map(distance, 5, 80, 0, 100); // Assuming water levels are between 5 and 80 cm
    waterLevel = constrain(waterLevel, 0, 100); // Ensure water level stays within range

    displayWaterLevel(waterLevel);
  }

  // Check for long press on OK button to enter menu
  if (!inMenu && digitalRead(OK_BUTTON_PIN) == LOW) {
    unsigned long currentTime = millis();
    if (currentTime - okButtonPressedTime >= OK_BUTTON_LONG_PRESS_DURATION) {
      okButtonPressedTime = currentTime;
      enterMenu();
    }
  }

  // Check for navigation buttons press
  if (inMenu) {
    if (digitalRead(UP_BUTTON_PIN) == LOW) {
      selectedMenuItem = (selectedMenuItem + 1) % 4;
      updateMenuSelection(selectedMenuItem);
      delay(200); // Debounce delay
    } else if (digitalRead(DOWN_BUTTON_PIN) == LOW) {
      selectedMenuItem = (selectedMenuItem - 1 + 4) % 4;
      updateMenuSelection(selectedMenuItem);
      delay(200); // Debounce delay
    }
  }

  // Check for exit from menu
  if (inMenu && digitalRead(OK_BUTTON_PIN) == LOW) {
    exitMenu();
  }
}

void enterMenu() {
  inMenu = true;
  okButtonPressedTime = millis();
  displayMainMenu();
}

void exitMenu() {
  inMenu = false;
  lcd.clear();
}

void updateMenuSelection(int menuItem) {
  lcd.setCursor(0, 0);
  switch (menuItem) {
    case MODE:
      lcd.print("1. Mode");
      break;
    case TANK_HEIGHT:
      lcd.print("2. Tank Height");
      break;
    case HIGH_VALUE:
      lcd.print("3. High Value");
      break;
    case LOW_VALUE:
      lcd.print("4. Low Value");
      break;
  }
  lcd.setCursor(0, menuItem);
  lcd.print(">");
}

void displayMainMenu() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("1. Mode");
  lcd.setCursor(0, 1);
  lcd.print(">"); // Initially highlight the first menu item
}

float measureDistance() {
  digitalWrite(TRIGGER_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIGGER_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGER_PIN, LOW);

  unsigned long duration = pulseIn(ECHO_PIN, HIGH);
  float distance = duration / 29.1 / 2; // Convert pulse duration to distance in cm
  return distance;
}

void displayWaterLevel(int level) {
  // Set cursor to the position where "Water Level: " starts
  lcd.setCursor(0, 0);
  // Print "Water Level: "
  lcd.print("Water Level: ");
  // Set cursor to the position where the water level value starts
  lcd.setCursor(13, 0); // Assuming "Water Level: " takes up 13 characters
  // Clear the current water level content
  lcd.print("    "); // Clear 4 characters to ensure the old content is overwritten
  // Set cursor back to the water level position
  lcd.setCursor(13, 0);
  // Print the new water level value
  lcd.print(level);
  // Print the "%" symbol
  lcd.print("%");
}
NOCOMNCVCCGNDINLED1PWRRelay Module