//project written by Subhadip Biswas

#include <Keypad.h>
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_SSD1306.h>

#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);


#define Password_Lenght 5 // Give enough room for 4 chars + NULL char

int pos = 0;    // variable to store the servo position

String password = "1234";
char Data[Password_Lenght]; // 4 is the number of chars it can hold + the null char = 5
char Master[Password_Lenght];
byte data_count = 0, master_count = 0;
bool Pass_is_good;
char customKey;

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

unsigned long previousMillis = 0;
const unsigned long interval = 20000; // 10 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

// int ExterIn = LOW;
#include "Led_Status.h"

void setup()
{
  display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS);
  display.clearDisplay();
  display.setTextSize(2);
  display.setTextColor(WHITE);
  wlecome_status();
  display.setCursor(5, 25);
  display.println("INITIALIZE");
  display.display();
  // digitalWrite(lock, HIGH);
  delay(1500);
  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();
  delay(1000);
  display.clearDisplay();
  display.setCursor(34, 10);
  display.println("SANCS");
  display.setCursor(5, 40);
  display.println("SMART LOCK");
  display.display();


}

void loop() {
  DEMSTOP();
  Open();
  Timeout();
  DoorProg();

  if ((digitalRead(sw1) == LOW) && (sig == 0) && (flag == 0))
  { InputSig();
    sig = 1;
  }

}



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(* resetFunc) (void) = 0; // for reboot

void Open()
{
  customKey = customKeypad.getKey();
  if (customKey == '*') {
    previousMillis = millis(); // Reset the timer
    if (security == 1) {
      m = 0;
      display.clearDisplay();
      display.setCursor(25, 10);
      display.println("ALREADY");
      display.setCursor(30, 35);
      display.println("ACTIVE");
      display.display();
      delay(1500);
      display.clearDisplay();
      display.setCursor(34, 10);
      display.println("SANCS");
      display.setCursor(5, 40);
      display.println("SMART LOCK");
      display.display();
      clearData();
    }
    else {
      display.clearDisplay();
      display.setCursor(34, 10);
      display.println("SETUP");
      display.setCursor(5, 40);
      display.println("DUALE LOCK");
      display.display();
      delay(1000);
      display.clearDisplay();
      display.setCursor(35, 0);
      display.println("ENTER");
      display.setCursor(18, 25);
      display.println("PASSWORD");
      display.setCursor(35, 45);
      display.println("_");// print char at said cursor and show *
      display.setCursor(50, 45);
      display.println("_");// print char at said cursor and show *
      display.setCursor( 65, 45);
      display.println("_");// print char at said cursor and show *
      display.setCursor(80, 45);
      display.println("_");// print char at said cursor and show *
      display.display();
      clearData();
      m = 1;
      security = 1;
    }
  }
  else if ((customKey == '#') && (m == 0)) {
    previousMillis = millis(); // Reset the timer
    display.clearDisplay();
    display.setCursor(34, 10);
    display.println("SANCS");
    display.setCursor(5, 40);
    display.println("SMART LOCK");
    display.display();
    clearData();
  }
  else if ((customKey == '#') && (m == 1)) {
    display.clearDisplay();
    display.setCursor(34, 10);
    display.println("SANCS");
    display.setCursor(5, 40);
    display.println("SMART LOCK");
    display.display();
    clearData();
    m = 0;
    security = 0;
    store = 0;
  }
  else if ((customKey == '1') && (store == 1)) {
    display.clearDisplay();
    display.setCursor(32, 25);
    display.println("ACTIVE");
    display.display();
    delay(3000);
    display.clearDisplay();
    display.setCursor(34, 10);
    display.println("SANCS");
    display.setCursor(5, 40);
    display.println("SMART LOCK");
    display.display();
    clearData();
    security = 1;
    store = 0;
    m = 0;
  }
  else if (customKey) // makes sure a key is actually pressed, equal to (customKey != NO_KEY)
  {
    display.clearDisplay();
    display.setCursor(35, 0);
    display.println("ENTER");
    display.setCursor(18, 25);
    display.println("PASSWORD");
    // display.setCursor(30, 45);
    // display.println("[");
    display.setCursor(35, 45);
    display.println("_");// print char at said cursor and show *
    display.setCursor(50, 45);
    display.println("_");// print char at said cursor and show *
    display.setCursor( 65, 45);
    display.println("_");// print char at said cursor and show *
    display.setCursor(80, 45);
    display.println("_");// print char at said cursor and show *
    // display.setCursor(85, 45);
    // display.println("]");
    // display.display();
    Data[data_count] = customKey ;
    if (data_count == 0) {
      display.setCursor(35, 45);
      display.println("* ");// print char at said cursor and show *
    }
    if (data_count == 1) {
      display.setCursor(35, 45);
      display.println("* ");// print char at said cursor and show *
      display.setCursor(50, 45);
      display.println("* ");// print char at said cursor and show *
    }
    if (data_count == 2) {
      display.setCursor(35, 45);
      display.println("* ");// print char at said cursor and show *
      display.setCursor(50, 45);
      display.println("* ");// print char at said cursor and show *
      display.setCursor(65, 45);
      display.println("* ");// print char at said cursor and show *
    }
    if (data_count == 3) {
      display.setCursor(35, 45);
      display.println("* ");// print char at said cursor and show *
      display.setCursor(50, 45);
      display.println("* ");// print char at said cursor and show *
      display.setCursor(65, 45);
      display.println("* ");// print char at said cursor and show *
      display.setCursor(80, 45);
      display.println("* ");// print char at said cursor and show *
    }
    display.display();
    delay(10);
    data_count++; // increment data array by 1 to store new char, also keep track of the number of chars entered
    previousMillis = millis(); // Reset the timer
  }

  // if (data_count <= 3) display.clearDisplay();

  if (data_count == Password_Lenght - 1) // if the array index is equal to the number of expected chars, compare data to master
  {
    password.toCharArray(Master, password.length() + 1);
    if (!strcmp(Data, Master)) // equal to (strcmp(Data, Master) == 0)
      if (m == 1) {
        display.clearDisplay();
        display.setCursor(0, 0);
        display.println("Press 1 to actvivate");
        display.setCursor(0, 32);
        display.println("Press # to Exit");
        display.display();
        store = 1;
      }
      else
      {
        if ((security == 1) && (key_pad == 0))  {
          display.clearDisplay();
          display.setCursor(10, 0);
          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();
          previousMillis = millis(); // Reset the timer
          key_pad = 1;
        }
        if ((security == 1) && (rfid_key == 1)) {
          display.clearDisplay();
          ServoOpen();
          display.setCursor(10, 0);
          display.println("-WELCOME-");
          display.setCursor(30, 25);
          display.println("Access");
          display.setCursor(20, 45);
          display.println("Granted");
          display.display();
          delay(1500);
          door = 0;
          delay(1000);
          DOpen();
          flag = 1;
          doorpos = 0;
          rfid_key = 0;
          // security = 0;
        }
        if ((security == 0) && (rfid_key == 0)) {
          display.clearDisplay();
          ServoOpen();
          display.setCursor(10, 0);
          display.println("-WELCOME-");
          display.setCursor(30, 25);
          display.println("Access");
          display.setCursor(20, 45);
          display.println("Granted");
          display.display();
          delay(1500);
          door = 0;
          delay(1000);
          DOpen();
          flag = 1;
          doorpos = 0;
          display.clearDisplay();
        }

      }
    else
    {
      display.clearDisplay();
      display.setCursor(8, 0);
      display.println("WRONG CODE");
      display.setCursor(30, 25);
      display.println("Access");
      display.setCursor(30, 45);
      display.println("Denied");
      display.display();
      worng_status();
      delay(500);
      display.clearDisplay();
      display.setCursor(35, 0);
      display.println("ENTER");
      display.setCursor(18, 25);
      display.println("PASSWORD");
      display.setCursor(35, 45);
      display.println("_");// print char at said cursor and show *
      display.setCursor(50, 45);
      display.println("_");// print char at said cursor and show *
      display.setCursor( 65, 45);
      display.println("_");// print char at said cursor and show *
      display.setCursor(80, 45);
      display.println("_");// print char at said cursor and show *
      display.display();
      door = 1;
      previousMillis = millis(); // Reset the timer
      // if ((security == 1) && (m == 1)) {
      //   m = 0;
      //   security = 0;
      //   store = 0;
      // }
    }
    clearData();
  }
}


void Timeout() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    //display.clearDisplay();
    //display.setCursor(34, 10);
    //display.println("SANCS");
    //display.setCursor(5, 40);
    //display.println("SMART LOCK");
    clearData();
    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;
    }

    display.clearDisplay();
    display.display();
  }
}

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

    Stop();

    display.clearDisplay();
    display.setCursor(25, 0);
    display.println("DOOR IS");
    display.setCursor(20, 20);
    display.println("READY TO");
    display.setCursor(34, 45);
    display.println("CLOSE");
    display.display();
    delay(1000);
    display.clearDisplay();
    for (int count = 5; count >= 0; count --) {
      display.setCursor(25, 0);
      display.println("WAIT TO");
      display.setCursor(20, 20);
      display.println("CLOSE in");
      display.setCursor(50, 45);
      display.println((String(count)) + "s");
      display.display();
      delay(1000);
      wait_status();
      display.clearDisplay();
    }
    display.clearDisplay();
    DClose();
    sig = 1;

  }
EMERGENCEY:
  if ((digitalRead(pir) == LOW) && (flag == 2))

  {
    flag = 1;
    Stop();
    display.clearDisplay();
    display.setCursor(10, 0);
    display.println("! ERROR !");
    display.setCursor(25, 20);
    display.println("DOOR IS");
    display.setCursor(23, 45);
    display.println("COVERED");
    display.display();
    erro_status();
    delay(1000);
    display.clearDisplay();
    for (int count = 10; count >= 0; count --) {
      display.setCursor(10, 0);
      display.println("! ERROR !");
      display.setCursor(25, 20);
      display.println("WAIT TO");
      display.setCursor(50, 45);
      display.println((String(count)) + "s");
      display.display();
      delay(1000);
      display.clearDisplay();
    }
    display.clearDisplay();
    error_timeout();
    delay(1000);
    DOpen();
  }
DOOR_CLOSEEND:
  if ((digitalRead(closeend) == LOW) && (flag == 2))
  {

    Stop();
    display.clearDisplay();

    for (int count = 5; count >= 0; count --) {
      display.setCursor(5, 10);
      display.println("DOOR CLOSE");
      display.setCursor(20, 30);
      display.println("in ");
      display.setCursor(52, 30);
      display.println((String(count)) + "s");
      display.display();
      delay(1000);
      open_timeout();
      display.clearDisplay();
    }
    ServoClose();
    door = 1;
    display.clearDisplay();
    sig = 0;
    flag = 0;
    delay(1000);
    display.setCursor(34, 10);
    display.println("SANCS");
    display.setCursor(5, 40);
    display.println("SMART LOCK");
    display.display();
  }
}

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)) {
      display.clearDisplay();
      Stop();
      doorpos = 1;
      // flag = 2;
      delay(2000);
      digitalWrite(lock, LOW);
      pause_status();
      display.setCursor(40, 0);
      display.println("DOOR");
      display.setCursor(40, 20);
      display.println("OPEN");
      display.setCursor(30, 45);
      display.println("PAUSED");
      display.display();
    }
    if ((digitalRead(EMS) == HIGH)) {
      display.clearDisplay();
      //  flag = 2;
      DOpen();
      sig = 0;
      digitalWrite(lock, HIGH);
      resume_status();
      doorpos = 1;
      display.setCursor(10, 10);
      display.println(">>>>>>>>");
      display.setCursor(35, 35);
      display.println("OPENING");
      display.display();
    }
    previousMillis = millis(); // Reset the timer
  }

  if (flag == 2) {
    if ((digitalRead(EMS) == LOW)) {
      display.clearDisplay();
      Stop();
      doorpos = 1;
      flag = 2;
      delay(2000);
      digitalWrite(lock, LOW);
      pause_status();
      display.setCursor(40, 0);
      display.println("DOOR");
      display.setCursor(35, 20);
      display.println("CLOSE");
      display.setCursor(30, 45);
      display.println("PAUSED");
      display.display();
    }
    if ((digitalRead(EMS) == HIGH)) {
      display.clearDisplay();
      //  flag = 2;
      DClose();
      sig = 0;
      digitalWrite(lock, HIGH);
      resume_status();
      doorpos = 1;
      display.setCursor(20, 10);
      display.println("<<<<<<<<");
      display.setCursor(5, 35);
      display.println("CLOSING");
      display.display();
    }
    previousMillis = millis(); // Reset the timer
  }

}

void InputSig() {

  if ((security == 1) && (key_pad == 1)) {
    display.clearDisplay();
    ServoOpen();
    display.setCursor(10, 0);
    display.println("-WELCOME-");
    display.setCursor(30, 25);
    display.println("Access");
    display.setCursor(20, 45);
    display.println("Granted");
    display.display();
    previousMillis = millis(); // Reset the timer
    delay(1500);
    door = 0;
    delay(1000);
    DOpen();
    flag = 1;
    doorpos = 0;
    display.clearDisplay();
    // security = 0;
    key_pad = 0;
    clearData();
  }

  else if ((security == 1) && (key_pad == 0)) {
    display.clearDisplay();
    display.setCursor(10, 0);
    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();
    previousMillis = millis(); // Reset the timer
    rfid_key = 1;
    clearData();
  }

  else {
    display.clearDisplay();
    display.setCursor(10, 10);
    display.println("INSIDE TO");
    display.setCursor(30, 35);
    display.println("UNLOCK");
    display.display();
    previousMillis = millis(); // Reset the timer
    delay(100);
    ServoOpen();
    delay(2000);
    DOpen();
    flag = 1;
    door = 0;
    doorpos = 0;
  }

}

/////////// PROJECT WRITTEN BY SUBHADIP BISWAS //////////
////////// THANK YOU ///////////