#define BLYNK_TEMPLATE_ID "TMPL6Cp9xkuhl"
#define BLYNK_TEMPLATE_NAME "CIRCUIT BREAKER"
#define BLYNK_AUTH_TOKEN "Z_x5w6hOWryEo5REsNFyK55BVcjL96Ct"

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <BlynkSimpleEsp32.h>
#include <Keypad.h>

char auth[] = "Z_x5w6hOWryEo5REsNFyK55BVcjL96Ct";
char ssid[] = "Wokwi-GUEST";       
char pass[] = "";   

LiquidCrystal_I2C lcd(0x27, 16, 2);

const byte ROWS = 4;
const byte COLS = 4;
char keys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {23, 22, 21, 19};
byte colPins[COLS] = {18, 5, 17, 16};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

String inputPassword = "";
String correctPassword = "1234";
const byte MAX_ATTEMPTS = 3;
byte failedAttempts = 0;
bool systemArmed = false;

const int relayPin = 25;
const int buzzerPin = 26;
const int ledPin = 15;
const int potPin = 34;
const int faultButton = 32;

int faultThreshold = 2000;
bool faultCondition = false;
unsigned long lastFaultTime = 0;
const unsigned long FAULT_RESET_TIME = 10000;

void setup() {
  Serial.begin(9600);

  lcd.init();
  lcd.backlight();
  lcd.clear();
  lcd.print("Circuit Breaker");
  lcd.setCursor(0, 1);
  lcd.print("Enter Password");

  pinMode(relayPin, OUTPUT);
  pinMode(buzzerPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(faultButton, INPUT_PULLUP);

  digitalWrite(relayPin, LOW);
  digitalWrite(buzzerPin, LOW);
  digitalWrite(ledPin, LOW);

  Blynk.begin(auth, ssid, pass);
}

void loop() {
  Blynk.run();
  checkFaultConditions();

  if (faultCondition) {
    handleFault();
  } else if (failedAttempts >= MAX_ATTEMPTS) {
    systemLocked();
  } else {
    handleKeypadInput();
  }

  // === LED STATUS CONTROL ===
  if (systemArmed && !faultCondition) {
    digitalWrite(ledPin, HIGH);
  } else {
    digitalWrite(ledPin, LOW);
  }

  // === SERIAL DEBUG ===
  Serial.print("System Armed: ");
  Serial.print(systemArmed);
  Serial.print(" | Fault: ");
  Serial.print(faultCondition);
  Serial.print(" | LED: ");
  Serial.println(digitalRead(ledPin));
}

void checkFaultConditions() {
  int potValue = analogRead(potPin);
  bool manualFault = digitalRead(faultButton) == LOW;

  if ((potValue > faultThreshold || manualFault) && systemArmed) {
    faultCondition = true;
    lastFaultTime = millis();
  }
}

void handleFault() {
  digitalWrite(relayPin, LOW);
  digitalWrite(buzzerPin, HIGH);
  digitalWrite(ledPin, LOW);
  systemArmed = false;

  lcd.clear();
  lcd.print("FAULT DETECTED!");
  lcd.setCursor(0, 1);
  lcd.print("Reset to continue");

  Blynk.logEvent("fault", "Circuit fault detected!");

  int potValue = analogRead(potPin);
  bool manualFault = digitalRead(faultButton) == LOW;

  if ((potValue <= faultThreshold && !manualFault) || 
      (millis() - lastFaultTime > FAULT_RESET_TIME)) {
    resetFault();
  }
}

void resetFault() {
  faultCondition = false;
  digitalWrite(buzzerPin, LOW);
  displayPasswordScreen();
}

void handleKeypadInput() {
  char key = keypad.getKey();
  if (!key) return;

  if (key == '*') {
    inputPassword = "";
    lcd.clear();
    lcd.print("Enter Password:");
    lcd.setCursor(0, 1);
  } 
  else if (key == '#') {
    if (inputPassword == correctPassword) {
      grantAccess();
    } else {
      denyAccess();
    }
    inputPassword = "";
  } 
  else {
    if (inputPassword.length() < 6) {
      inputPassword += key;
      lcd.clear();
      lcd.print("Enter Password:");
      lcd.setCursor(0, 1);
      lcd.print(inputPassword);
    } else {
      lcd.clear();
      lcd.print("Max 6 digits!");
      delay(1000);
      lcd.clear();
      lcd.print("Enter Password:");
      inputPassword = "";
    }
  }
}

void grantAccess() {
  lcd.clear();
  lcd.print("ACCESS GRANTED");
  systemArmed = true;
  failedAttempts = 0;

  digitalWrite(relayPin, HIGH);
  digitalWrite(ledPin, HIGH);  // Ensure LED is ON immediately

  Blynk.logEvent("access", "Circuit breaker activated");

  delay(2000);
  lcd.clear();
  lcd.print("System: ARMED");
  lcd.setCursor(0, 1);
  lcd.print("Monitoring...");
}

void denyAccess() {
  lcd.clear();
  lcd.print("ACCESS DENIED");
  failedAttempts++;

  digitalWrite(buzzerPin, HIGH);
  digitalWrite(ledPin, HIGH);
  delay(500);
  digitalWrite(buzzerPin, LOW);
  digitalWrite(ledPin, LOW);

  if (failedAttempts < MAX_ATTEMPTS) {
    delay(1500);
    displayPasswordScreen();
  } else {
    Blynk.logEvent("security", "Too many failed attempts!");
  }
}

void systemLocked() {
  lcd.clear();
  lcd.print("SYSTEM LOCKED");
  lcd.setCursor(0, 1);
  lcd.print("Press RESET");

  static unsigned long lastBlink = 0;
  if (millis() - lastBlink > 1000) {
    digitalWrite(ledPin, !digitalRead(ledPin));
    digitalWrite(buzzerPin, !digitalRead(buzzerPin));
    lastBlink = millis();
  }
}

void displayPasswordScreen() {
  lcd.clear();
  lcd.print("Enter Password:");
}

BLYNK_WRITE(V0) {
  if (param.asInt() == 1) {
    resetSystem();
  }
}

void resetSystem() {
  systemArmed = false;
  faultCondition = false;
  failedAttempts = 0;
  inputPassword = "";

  digitalWrite(relayPin, LOW);
  digitalWrite(buzzerPin, LOW);
  digitalWrite(ledPin, LOW);

  displayPasswordScreen();
  Blynk.logEvent("system", "System has been reset");
}
NOCOMNCVCCGNDINLED1PWRRelay Module