// 11Sep2022 - v0.1

#include <Adafruit_Fingerprint.h>
#include <Adafruit_GFX.h>       // include Adafruit graphics library
#include <Adafruit_ILI9341.h>   // include Adafruit ILI9341 TFT library
#include <ESP32Servo.h>
#include "BluetoothSerial.h"

//BluetoothSerial SerialBT;
Servo ServoMotor;

char Incoming_value = '1'; //Initialized variable to store recieved data
int Door_stat = 1 , Bypass_stat = 1  ;
int Servo_position = 0, Servo_freq = 1000;
uint8_t p;

unsigned long previousMillis_Waiting = 0;
unsigned long currentMillis_Waiting ;

#define  mySerial Serial1    // Use UART channel 1

#define RELAY_PIN            4
#define ACCESS_DELAY         3000         // Keep lock unlocked for 3 seconds 
#define DOOR_SW              12           // Door status to check if the door is really open or closed
#define BYPASS_BIOMETRIC     13           // To bypass biometric switch / remote switch for manual unlock
#define SERVO_PIN            14

#define TFT_CS    5       // TFT CS  pin is connected to ESP32 pin 5
#define TFT_RST   15      // TFT RST pin is connected to ESP32 pin 15
#define TFT_DC    2       // TFT DC  pin is connected to ESP32 pin 2

// initialize library
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);

void setup() {

  // Uncomment to enable fingerprint scanner
  // Setup_fingerprint_sensor();

  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);

  // Begin the Serial at 115200 Baud
  Serial.begin(115200);
 // SerialBT.begin("Biometric Door Lock System");
  Serial.println("Bluetooth Started! Ready to pair...");

  pinMode(DOOR_SW, INPUT_PULLUP);
  pinMode(BYPASS_BIOMETRIC, INPUT_PULLUP);
  pinMode(RELAY_PIN, OUTPUT);
  digitalWrite(RELAY_PIN, HIGH);   // Switch off relay initially. Relay is LOW level triggered relay so we need to write HIGH.

  ServoMotor.attach(SERVO_PIN);
  ServoMotor.write(0);             // Locked position

  tft.begin();
  tft.fillScreen(ILI9341_BLACK);
  //tft_diagnostics();
  tft.setRotation(1);

  boot_screen();
  delay(3000);

  tft.fillScreen(ILI9341_BLACK);
}

void loop() {

  Door_stat = digitalRead(DOOR_SW);
  Bypass_stat = digitalRead(BYPASS_BIOMETRIC);

  tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);

  // Door closed
  if (Door_stat == 1)
  {

    tft.setCursor(20, 200);
    tft.setTextSize(3);

    tft.print("Status: Closed");

  }

  // Door opened
  if (Door_stat == 0)
  {
    tft.setCursor(20, 200);
    tft.setTextSize(3);

    tft.print("Status: Opened");
    currentMillis_Waiting = millis();
    if (currentMillis_Waiting - previousMillis_Waiting > 10000)
    {
      previousMillis_Waiting = currentMillis_Waiting;

      tft.setCursor(20, 75);
      tft.setTextSize(4);
      tft.setTextColor(ILI9341_YELLOW);
      tft.print("Door opened");

    }

  }

//  if (SerialBT.available() > 0)
  {

 //   Incoming_value = SerialBT.read();
    Serial.print(Incoming_value);
    Serial.print(" ");
  }

  if (Incoming_value == '1' && Bypass_stat == 1)
  {
    Serial.println("Door locked...");
    p = finger.fingerSearch();

    if (p == FINGERPRINT_NOTFOUND)
    {
      Serial.println("Did not find a match");
      tft.setCursor(0, 75);
      tft.setTextSize(4);
      tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
      tft.print(" Not Match   ");
    }

    //        if (p == FINGERPRINT_PACKETRECIEVEERR)
    //        {
    //          Serial.println("Communication error");
    //          tft.setCursor(0, 75);
    //          tft.setTextSize(4);
    //          tft.setTextColor(ILI9341_RED, ILI9341_BLACK);
    //          tft.print("    ERROR   ");
    //        }

    currentMillis_Waiting = millis();
    if (currentMillis_Waiting - previousMillis_Waiting > ACCESS_DELAY)
    {
      previousMillis_Waiting = currentMillis_Waiting;


      tft.setCursor(0, 75);
      tft.setTextSize(4);
      tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
      tft.print("              ");

      digitalWrite(RELAY_PIN, HIGH);
      ServoMotor.write(0);                    // Locked position
    }
  }

  // Make sure the door is closed
  else if ((Incoming_value == '0' || Bypass_stat == 0 || p == FINGERPRINT_OK)  && Door_stat == 1)
  {
    Serial.println("Door unlocked...");
    tft.setCursor(0, 75);
    tft.setTextSize(4);
    tft.setTextColor(ILI9341_YELLOW, ILI9341_BLACK);
    tft.print("Door unlocked");

    digitalWrite(RELAY_PIN, LOW);
    ServoMotor.write(180);                    // Unlock position
  }

  //  delay(50);            //Add some delay before next scan.
}


void boot_screen()
{
  //  320*240
  //  --------------------
  //  -     BIOMETRIC    -
  //  -       DOOR       -
  //  -      LOCKING     -
  //  -      SYSTEM      -
  //  --------------------

  tft.setTextColor(ILI9341_WHITE);  tft.setTextSize(5);
  tft.setCursor(15, 25);
  tft.println("BIOMETRIC");
  tft.setCursor(90, 75);
  tft.println("DOOR");
  tft.setCursor(45, 125);
  tft.println("LOCKING");
  tft.setCursor(60, 175);
  tft.println("SYSTEM");

}

void tft_diagnostics()
{
  // read diagnostics (optional but can help debug problems)
  uint8_t x = tft.readcommand8(ILI9341_RDMODE);
  Serial.print("Display Power Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDMADCTL);
  Serial.print("MADCTL Mode: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDPIXFMT);
  Serial.print("Pixel Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDIMGFMT);
  Serial.print("Image Format: 0x"); Serial.println(x, HEX);
  x = tft.readcommand8(ILI9341_RDSELFDIAG);
  Serial.print("Self Diagnostic: 0x"); Serial.println(x, HEX);
}

void Setup_fingerprint_sensor()
{

  // set the data rate for the sensor serial port
  finger.begin(57600);
  delay(5);
  if (finger.verifyPassword()) {
    Serial.println("Found fingerprint sensor!");
  } else {
    Serial.println("Did not find fingerprint sensor :(");
    while (1) {
      delay(1);
    }
  }
}