//project written by Subhadip Biswas
//More information & support my channel www.youtube.com/techzero
//download liquidcrystal laibary
//download keypad laibary
//I dont use display but you can use,i also written code for display
//Give a schematic in my website https://techzeroyoutube.blogspot.com
//I am use home made keypad.do you find how to make it gotoA my youtube channel www.youtube.com/techzero


#define OLED; //Define Which Display Use in Your Project LCD/OLED

#include <Keypad.h>
//#include <Servo.h>
#include <Wire.h>
#ifdef LCD
#include <LiquidCrystal_I2C.h>
#elif defined(OLED)
#include <Adafruit_SSD1306.h>
#include <SPI.h>
#endif
#include <Wire.h>

#ifdef LCD
//Servo myservo;
int pos = 0;    // variable to store the servo position
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include <LiquidCrystal_I2C.h>

#elif defined(OLED)
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
// The pins for I2C are defined by the Wire-library.
// On an arduino UNO:       A4(SDA), A5(SCL)
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
// On an arduino LEONARDO:   2(SDA),  3(SCL), ...
// On an arduino NodeMcu:   D2(SDA),  D1(SCL), ...
#define OLED_RESET     -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#endif


#define Password_Length 5    // Give enough room for 4 chars + NULL char
int Pass_Lenght = Password_Length - 1;
char Data[Password_Length];  // 4 is the number of chars it can hold + the null char = 5
char Master[Password_Length];
byte data_count = 0;
bool Pass_is_good;
char customKey;

const char* valid_passwords[] = {"1234", "1478", "1548","1801"}; // List of valid passwords
const int num_passwords = sizeof(valid_passwords) / sizeof(valid_passwords[0]);


int redPin = A2; //pin to red led
int greenPin = A3; //pin to green led
int sw1 = 9; // pin to inside switch
int lock = 10; // For Lock/Servo
int IN1 = A0; // DOOR MOTOR OPEN ROTATION
int IN2 = A1; // DOOR MOTOR CLOSE ROTATION
int openend = 12; // DOOR OPEN LIMITE SWITCH
int closeend = 13; // DOOR CLOSE LIMITE SWITCH &  DOOR OPENING SIGNAL
int pir = 11; // FOR DOOR CLOSEING SEQURITY
int EMS = 0; //Sudden Stop
int PIRLED = 1; //Emergancy Idicuter

int flag = 0; //variable
int doorpos = 0; //variable
int sig = 0; //variable
int m = 0;        //variable
int key_pad = 0;  //variable
int rfid_key = 0; //variable
int store = 0;    //variable
int wrong = 0;    //variable
int security = 0; //control duale security system 1 means active 0 means deactive
int pirdetc = 0;

unsigned long previousMillis = 0;
const unsigned long interval = 20000; // 20 seconds

const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
bool door = true;

byte rowPins[ROWS] = {2, 3, 4, 5}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {6, 7, 8}; //connect to the column pinouts of the keypad

Keypad customKeypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS); //initialize an instance of class NewKeypad

#include "Led_status.h"
#include "Display.h"


void setup()
{
  dis_setup();
  wlecome_status();

  // #ifdef LCD
  //   lcd.clear();
  //   lcd.setCursor(0, 0);
  //   lcd.print("CONNECTING To");
  //   lcd.setCursor(8, 1);
  //   lcd.print("WiFi....");
  // #elif defined(OLED)
  //   display.clearDisplay();
  //   display.setCursor(5, 10);
  //   display.println("CONNECTING");
  //   display.setCursor(5, 30);
  //   display.println("To WiFi...");
  //   display.display();
  // #endif

  digitalWrite(lock, HIGH);
  delay(3000);
  pinMode(lock, OUTPUT);
  pinMode(redPin, OUTPUT);
  pinMode(greenPin, OUTPUT);
  pinMode(sw1, INPUT_PULLUP);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(openend, INPUT_PULLUP);
  pinMode(closeend, INPUT_PULLUP);
  pinMode(pir, INPUT_PULLUP);
  pinMode (EMS, INPUT_PULLUP);
  pinMode(PIRLED, OUTPUT);
  ServoClose();
  dis_home() ;
  // previousMillis = millis(); // Reset the timer
}


bool checkPassword() {
  for (int i = 0; i < num_passwords; i++) {
    if (strcmp(Data, valid_passwords[i]) == 0) {
      return true;
    }
  }
  return false;
}


void clearData()
{
  while (data_count != 0)
  { // This can be used for any array size,
    Data[data_count--] = 0; //clear array for new data
  }
  return;
}

void ServoOpen()
{
  digitalWrite(lock, HIGH);         // tell servo to go to position in variable 'pos'
  delay(15);                       // waits 15ms for the servo to reach the position
  success_status();
}

void ServoClose()
{
  digitalWrite(lock, LOW);              // tell servo to go to position in variable 'pos'
  delay(20);                       // waits 20ms for the servo to reach the position
  success_timeout();
}


void Open()
{
  customKey = customKeypad.getKey();
  if (customKey) {  // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
    previousMillis = millis();   // Reset the timeout timer
    Data[data_count] = customKey;
    dis_keypad(data_count);
    data_count++;  // increment data array by 1 to store new char, also keep track of the number of chars entered
  }

  if (data_count == Password_Length - 1) {  // if the array index is equal to the number of expected chars, compare data to master
    if (checkPassword()) {
      dis_sucess();
    } else {
      dis_wrong();
    }
    clearData();
  }
}

void Timeout() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    sleep_on_status();
    clearData();
    pirdetc = 0;
    if ((security == 1) && (m == 1)) {
      delay(2000);
      // resetFunc();
      security = 0;
      store = 0;
      m = 0;
    }
    if ((security == 1) && (key_pad == 1)) {
      key_pad = 0;
    }

    if ((security == 1) && (rfid_key == 1)) {
      rfid_key = 0;
    }
#ifdef LCD
    lcd.clear();
    lcd.noBacklight();
    lcd.off();
#elif defined(OLED)
    display.clearDisplay();
    display.display();
#endif
    // pirdetc = 0;
  }
  else {
    sleep_off_status();
  }
}

void DoorProg()
{
DOOR_CLOSE:
  if ((digitalRead(openend) == LOW) && (flag == 1))
  {
    flag = 2;
    Stop();
    dis_close_count();
    DClose();
    sig = 1;

  }
EMERGENCEY:
  if ((digitalRead(pir) == HIGH) && (flag == 2) && (pirdetc == 1))

  {
    flag = 1;
    Stop();

    dis_error();
    error_timeout();
    delay(1000);
    DOpen();
  }
DOOR_CLOSEEND:
  if ((digitalRead(closeend) == LOW) && (flag == 2))
  {
    Stop();
    dis_closed();
    ServoClose();
    door = 1;
    sig = 0;
    flag = 0;
    delay(1000);
    dis_home();
  }
}


void DOpen() {
  //digitalWrite(ENA, HIGH);
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
}


void DClose() {
  //digitalWrite(ENA, HIGH);
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
}
void Stop() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
}

void DEMSTOP()
{
  if (flag == 1) {
    if ((digitalRead(EMS) == LOW)) {
      Stop();
      doorpos = 1;
      // flag = 2;
      delay(2000);
      digitalWrite(lock, LOW);
      pause_status();
      EMS_OP();
      // lcd.clear();
    }
    if ((digitalRead(EMS) == HIGH)) {
      //  flag = 2;
      DOpen();
      sig = 0;
      digitalWrite(lock, HIGH);
      resume_status();
      doorpos = 1;
      EMS_OR();
      // lcd.clear();
    }
    previousMillis = millis(); // Reset the timer
  }

  if (flag == 2) {
    if ((digitalRead(EMS) == LOW)) {
      Stop();
      doorpos = 1;
      flag = 2;
      delay(2000);
      digitalWrite(lock, LOW);
      pause_status();
      EMS_CP();
      // lcd.clear();
    }
    if ((digitalRead(EMS) == HIGH)) {
      //  flag = 2;
      DClose();
      sig = 0;
      digitalWrite(lock, HIGH);
      resume_status();
      doorpos = 1;
      EMS_CR();
      // lcd.clear();
    }
    previousMillis = millis(); // Reset the timer
  }

}

void InputSig() {
#ifdef LCD
  lcd.backlight();
  lcd.on();
#elif defined(OLED)

#endif
  if ((security == 1) && (key_pad == 1)) {
    ServoOpen();
    dis_sucess();
    previousMillis = millis(); // Reset the timer

    door = 0;
    DOpen();
    flag = 1;
    doorpos = 0;
    // security = 0;
    key_pad = 0;
    clearData();
  }

  else if ((security == 1) && (key_pad == 0)) {
#ifdef LCD
    lcd.clear();
    lcd.setCursor(2, 0);
    lcd.print("- WELCOME -");
    lcd.setCursor(1, 1);
    lcd.print("ACCESS GRANTED");
    delay(1500);
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.println("ACTIVE SECURITY+");
    lcd.setCursor(0, 1);
    lcd.println("- GIVE NEXT ID -");
#elif defined(OLED)
    display.clearDisplay();
    display.setCursor(10, 5);
    display.println("-WELCOME-");
    display.setCursor(30, 25);
    display.println("Access");
    display.setCursor(20, 45);
    display.println("Granted");
    display.display();
    delay(1500);
    display.clearDisplay();
    display.setCursor(32, 0);
    display.println("-GIVE-");
    display.setCursor(45, 25);
    display.println("NEXT");
    display.setCursor(52, 50);
    display.println("ID");
    display.display();
#endif
    previousMillis = millis(); // Reset the timer
    rfid_key = 1;
    clearData();
  }

  else {

    dis_inside() ;
    delay(100);
    previousMillis = millis(); // Reset the timer
    ServoOpen();
    delay(2000);
    DOpen();
    flag = 1;
    door = 0;
    doorpos = 0;
  }


}

void loop() {
  if ((digitalRead(pir) == HIGH) && (flag == 0) && (pirdetc == 0)) {
    previousMillis = millis(); // Reset the timer
    dis_home();
    pirdetc = 1;
  }
  DEMSTOP();
  Open();
  DoorProg();
  Timeout();

  if ((digitalRead(sw1) == LOW) && (sig == 0) && (flag == 0))
  { InputSig();
    sig = 1;
  }
}
/////////// PROJECT WRITTEN BY SUBHADIP BISWAS //////////
////////// THANK YOU ///////////