#include <Keypad.h>
#include <LiquidCrystal_I2C.h>

const int buttonPin = 13;
LiquidCrystal_I2C lcd(0x27, 20, 4);
const byte ROWS = 4; // Four rows
const byte COLS = 4; // Four columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
uint8_t rowPins[ROWS] = {14, 27, 26, 25}; // GIOP14, GIOP27, GIOP26, GIOP25
uint8_t colPins[COLS] = {33, 32, 18, 19}; // GIOP33, GIOP32, GIOP18, GIOP19
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

const String password = "1234"; // Set your password here
String input = "";              // Variable to store user input
int maxAttempts = 3;            // Max attempts allowed
int attempts = 0;
int selectedRoom = 0;
int selectedRow = 0;
const int buzzerPin = 12;
bool passwordVerified = false;  // Flag to track password verification status

int room1row1 = 15;
int room1row2 = 2;
int room1row3 = 4;

int room2row1 = 16;
int room2row2 = 17;
int room2row3 = 5;

unsigned long lastInteraction = 0; // Variable to track last interaction time
const unsigned long standbyTimeout = 60000; // 1 minute timeout

void setup() {
  Serial.begin(9600);
  pinMode(buzzerPin, OUTPUT);
  pinMode(room1row1, OUTPUT);
  pinMode(room1row2, OUTPUT);
  pinMode(room1row3, OUTPUT);
  pinMode(room2row1, OUTPUT);
  pinMode(room2row2, OUTPUT);
  pinMode(room2row3, OUTPUT);
  lcd.init();
  lcd.backlight();
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop() {
  char key = keypad.getKey();
  
  if (key) {
    lastInteraction = millis(); // Update last interaction time
    if (!passwordVerified) {
      if (key == '#') { // Check password
        if (input == password) {
          lcd.clear();
          lcd.print("Access Granted");
          attempts = 0; // Reset attempts if password is correct
          input = "";   // Clear input
          passwordVerified = true; // Set password verified flag
          
          selectRoom();
        } else {
          attempts++;
          lcd.clear();
          lcd.print("Access Denied");
          
          if (attempts >= maxAttempts) {
            buzz();
            lcd.clear();
            lcd.print("Too many attempts");
            delay(5000); // Lock system for 5 seconds
            attempts = 0; // Reset attempts after lockout
          }
        }
        input = ""; // Clear input after checking
      } else if (key == '*') { // Clear input
        input = "";
        lcd.clear();
        lcd.print("Input cleared");
        delay(1000); // Display message for a moment
      } else {
        input += key; // Append key press to input string
        lcd.clear();
        lcd.print("Input: ");
        lcd.print(input);
      }
    } else {
      selectRoom();
    }
  }

  // Check for inactivity
  if (millis() - lastInteraction > standbyTimeout) {
    passwordVerified = false; // Reset password verification status
    lcd.clear();
    lcd.print("Standby Mode");
    lcd.noBacklight();
    while (millis() - lastInteraction > standbyTimeout) {
      // Wait for any key press to exit standby mode
      if (keypad.getKey()) {
        lcd.backlight();
        lcd.clear();
        lcd.print("System On");
        delay(1000);
        lastInteraction = millis(); // Reset last interaction time
        break;
      }
    }
  }
}

void buzz() {
  tone(buzzerPin, 1000); // 1000 Hz sound
  delay(500);            // 500 ms duration
  noTone(buzzerPin);     // Turn off buzzer
}

void selectRoom() {
  lcd.clear();
  lcd.print("Select room (1/2): ");
  lcd.setCursor(0, 1);
  lcd.print("A=Off R1, B=Off R2");
  lcd.setCursor(0, 2);
  lcd.print("C=Off All, D=On All");
  lcd.setCursor(0, 3);
  lcd.print("8=On R1, 9=On R2");
  while (true) {
    char roomKey = keypad.getKey();
    if (roomKey) {
      lastInteraction = millis(); // Update last interaction time
      if (roomKey == '1') {
        selectedRoom = 1;
        lcd.clear();
        lcd.print("Room 1 selected");
        delay(1000);
        selectRow();
        break;
      } else if (roomKey == '2') {
        selectedRoom = 2;
        lcd.clear();
        lcd.print("Room 2 selected");
        delay(1000);
        selectRow();
        break;
      } else if (roomKey == 'A') {
        lcd.clear();
        lcd.print("Turning off Room 1");
        offlightroom1all();
        delay(1000);
        updateStatus();
        break;
      } else if (roomKey == 'B') {
        lcd.clear();
        lcd.print("Turning off Room 2");
        offlightroom2all();
        delay(1000);
        updateStatus();
        break;
      } else if (roomKey == 'C') {
        lcd.clear();
        lcd.print("Turning off all lights");
        offlightall();
        delay(1000);
        updateStatus();
        break;
      } else if (roomKey == 'D') {
        lcd.clear();
        lcd.print("Turning on all lights");
        openlightall();
        delay(1000);
        updateStatus();
        break;
      } else if (roomKey == '8') {
        lcd.clear();
        lcd.print("Turning on Room 1");
        openlightroom1all();
        delay(1000);
        updateStatus();
        break;
      } else if (roomKey == '9') {
        lcd.clear();
        lcd.print("Turning on Room 2");
        openlightroom2all();
        delay(1000);
        updateStatus();
        break;
      }
    }
  }
}

void selectRow() {
  lcd.clear();
  lcd.print("Select row (1/2/3): ");
  while (true) {
    char rowKey = keypad.getKey();
    if (rowKey) {
      lastInteraction = millis(); // Update last interaction time
      if (rowKey == '1') {
        selectedRow = 1;
        lcd.clear();
        lcd.print("Row 1 selected");
        delay(1000);
        controlLights();
        break;
      } else if (rowKey == '2') {
        selectedRow = 2;
        lcd.clear();
        lcd.print("Row 2 selected");
        delay(1000);
        controlLights();
        break;
      } else if (rowKey == '3') {
        selectedRow = 3;
        lcd.clear();
        lcd.print("Row 3 selected");
        delay(1000);
        controlLights();
        break;
      }
    }
  }
}

void controlLights() {
  lcd.clear();
  lcd.print("Current Status:");
  lcd.setCursor(0, 1);
  if (selectedRoom == 1) {
    if (selectedRow == 1) lcd.print(digitalRead(room1row1) ? "R1 ON" : "R1 OFF");
    else if (selectedRow == 2) lcd.print(digitalRead(room1row2) ? "R2 ON" : "R2 OFF");
    else if (selectedRow == 3) lcd.print(digitalRead(room1row3) ? "R3 ON" : "R3 OFF");
  } else if (selectedRoom == 2) {
    if (selectedRow == 1) lcd.print(digitalRead(room2row1) ? "R1 ON" : "R1 OFF");
    else if (selectedRow == 2) lcd.print(digitalRead(room2row2) ? "R2 ON" : "R2 OFF");
    else if (selectedRow == 3) lcd.print(digitalRead(room2row3) ? "R3 ON" : "R3 OFF");
  }
  delay(2000); // Display current status for 2 seconds

  lcd.clear();
  lcd.print("Press A=ON, B=OFF");

  while (true) {
    char lightKey = keypad.getKey();
    if (lightKey) {
      lastInteraction = millis(); // Update last interaction time
      if (lightKey == 'A') {
        if (selectedRoom == 1) {
          if (selectedRow == 1) digitalWrite(room1row1, HIGH);
          else if (selectedRow == 2) digitalWrite(room1row2, HIGH);
          else if (selectedRow == 3) digitalWrite(room1row3, HIGH);
        } else if (selectedRoom == 2) {
          if (selectedRow == 1) digitalWrite(room2row1, HIGH);
          else if (selectedRow == 2) digitalWrite(room2row2, HIGH);
          else if (selectedRow == 3) digitalWrite(room2row3, HIGH);
        }
        lcd.clear();
        lcd.print("Lights ON");
        updateStatus();
        delay(1000);
        break;
      } else if (lightKey == 'B') {
        if (selectedRoom == 1) {
          if (selectedRow == 1) digitalWrite(room1row1, LOW);
          else if (selectedRow == 2) digitalWrite(room1row2, LOW);
          else if (selectedRow == 3) digitalWrite(room1row3, LOW);
        } else if (selectedRoom == 2) {
          if (selectedRow == 1) digitalWrite(room2row1, LOW);
          else if (selectedRow == 2) digitalWrite(room2row2, LOW);
          else if (selectedRow == 3) digitalWrite(room2row3, LOW);
        }
        lcd.clear();
        lcd.print("Lights OFF");
        updateStatus();
        delay(1000);
        break;
      }
    }
  }
}

void updateStatus() {
  lcd.clear();
  lcd.print("Room 1: ");
  lcd.print(digitalRead(room1row1) ? "R1 ON " : "R1 OFF ");
  lcd.print(digitalRead(room1row2) ? "R2 ON " : "R2 OFF ");
  lcd.print(digitalRead(room1row3) ? "R3 ON " : "R3 OFF ");
  lcd.setCursor(0, 1);
  lcd.print("Room 2: ");
  lcd.print(digitalRead(room2row1) ? "R1 ON " : "R1 OFF ");
  lcd.print(digitalRead(room2row2) ? "R2 ON " : "R2 OFF ");
  lcd.print(digitalRead(room2row3) ? "R3 ON " : "R3 OFF ");
}

void openlightroom1all() {
  digitalWrite(room1row1, HIGH);
  digitalWrite(room1row2, HIGH);
  digitalWrite(room1row3, HIGH);
}

void offlightroom1all() {
  digitalWrite(room1row1, LOW);
  digitalWrite(room1row2, LOW);
  digitalWrite(room1row3, LOW);
}

void openlightroom2all() {
  digitalWrite(room2row1, HIGH);
  digitalWrite(room2row2, HIGH);
  digitalWrite(room2row3, HIGH);
}

void offlightroom2all() {
  digitalWrite(room2row1, LOW);
  digitalWrite(room2row2, LOW);
  digitalWrite(room2row3, LOW);
}

void openlightroom1row1() {
  digitalWrite(room1row1, HIGH);
  digitalWrite(room1row2, HIGH);
  digitalWrite(room1row3, LOW);
}

void openlightroom1row2() {
  digitalWrite(room1row1, LOW);
  digitalWrite(room1row2, LOW);
  digitalWrite(room1row3, HIGH);
}

void openlightroom2row1() {
  digitalWrite(room2row1, HIGH);
  digitalWrite(room2row2, HIGH);
  digitalWrite(room2row3, LOW);
}

void openlightroom2row2() {
  digitalWrite(room2row1, LOW);
  digitalWrite(room2row2, LOW);
  digitalWrite(room2row3, HIGH);
}

void openlightall() {
  digitalWrite(room1row1, HIGH);
  digitalWrite(room1row2, HIGH);
  digitalWrite(room1row3, HIGH);
  digitalWrite(room2row1, HIGH);
  digitalWrite(room2row2, HIGH);
  digitalWrite(room2row3, HIGH);
  updateStatus();
}

void offlightall() {
  digitalWrite(room1row1, LOW);
  digitalWrite(room1row2, LOW);
  digitalWrite(room1row3, LOW);
  digitalWrite(room2row1, LOW);
  digitalWrite(room2row2, LOW);
  digitalWrite(room2row3, LOW);
  updateStatus();
}