Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
make2explore
Published © CC BY-NC-SA

IoT Based Smart and Secure Lock V2.0

In this project we've built IoT based smart and secure lock which have 4 layers of access. RFID + PIN + Fingerprint + OTP.

IntermediateFull instructions provided10 hours3,907

Things used in this project

Hardware components

Espressif ESP32 Development Board - Developer Edition
Espressif ESP32 Development Board - Developer Edition
×1
Nextion NX4832T035 - 3.5" HMI TFT LCD Touch Display Module
Itead Nextion NX4832T035 - 3.5" HMI TFT LCD Touch Display Module
×1
Fingerprint Sensor
DFRobot Fingerprint Sensor
×1
MB102 Breadboard Power Supply module
×1
12V Solenoid Lock
×1
2 Channel Relay Board 5V
×1
Batteries - 7.4V LiPo, 11.1V LiPo and Power Bank.
×1

Software apps and online services

VS Code
Microsoft VS Code
PlatformIO IDE
PlatformIO IDE
Arduino IDE
Arduino IDE

Story

Read more

Schematics

IoT_Lock_V2_Circuit_Diagrams

Code

IoT_based_Smart_Secure_Lock_V2

C/C++
// ---------------------------------- make2explore.com----------------------//
// Project           - IoT Based Smart Lock- RFID + Fingerprint + PIN + OTP + MySQL DB
// Created By        - blog@make2explore.com
// Version - 1.0
// Last Modified     - 07/08/2021 15:00:00 @admin
// Software          - C/C++, Arduino IDE, ESP32 SDK, Libraries
// Hardware          - NodeMCU ESP32S, RC522 RFID Reader, FPM10A Fingerprint Sensor, Nextion Display, Solenoid Lock              
// Sensors Used      - RC522 RFID Reader, FPM10A Fingerprint Sensor
// Source Repo       - github.com/make2explore
// -------------------------------------------------------------------------//

#include <WiFi.h>                   // include wifi related libraries
#include <NTPClient.h>              // Required for fetching current time
#include <HTTPClient.h>             // Required for HTTP POST/GET request, functions
#include <UniversalTelegramBot.h>   // Telegram BOT API library

#include <SPI.h>                    // Library required for RC522 RFID Reader
#include <MFRC522.h>                // Library of RC522 RFID Reader
#include "Nextion.h"                // Library of Nextion Display
#include <Adafruit_Fingerprint.h>   // Library of Fingerprint Sensor

#define SS_PIN 21                   // SDA/SS Pin of RFID Reader
#define RST_PIN 22                  // RESET Pin of RFID Reader
#define LockerPin 33                // Relay driving Solenoid lock is connected to this pin (Active Low)

// Replace with your network credentials
const char* ssid = "XXXXXXXXXXXXXX";
const char* password = "XXXXXXXXXXXXX";

// Website Details
// REPLACE with your Domain name and URL path or IP address with path
const char* serverName = "http://example.com/post_data.php";

// Keep this API Key value to be compatible with the PHP code provided in the Github. 
// If you change the apiKeyValue value, the PHP file /post-data.php also needs to have the same key 
String apiKeyValue = "XXXXXXXXXXX";

// Initialize Telegram BOT
#define BOTtoken "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"  // your Bot Token (Got from Botfather)

// Use @myidbot or @userinfobot to find out the chat ID of an individual or a group
// Also note that you need to click "start" on a bot before it can message you
#define CHAT_ID "XXXXXXXXXXX"

WiFiClientSecure client;
UniversalTelegramBot bot(BOTtoken, client);

MFRC522 mfrc522(SS_PIN, RST_PIN);            // Create MFRC522 instance.
String user="";                              // String variable For Username
String data="";                              // String variable For PIN data from Nextion
String branchName = "Secure Co-Op Bank";
String userName ="";

// Define NTP Client to get time
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org");


String RealT = "";
//Week Days
String weekDays[7]={"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};

//Month names
String months[12]={"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};


Adafruit_Fingerprint finger = Adafruit_Fingerprint(&Serial2);        //Fingerprint sensor is connected to Serial port 2

// Prototypes of CallBack Functions

/*
 *******************************************************************
   Nextion component for page:  Home
 *******************************************************************
*/

NexText DateTimeH = NexText(0, 2, "DateTimeH");

/*
 *******************************************************************
   Nextion component for page:   ValidRFID
 *******************************************************************
*/
NexText DateTimeV = NexText(1, 2, "DateTimeV");
NexText ValNM = NexText(0, 1, "ValNM");


/*
 *******************************************************************
   Nextion component for page:   InvalidRFID
 *******************************************************************
*/
NexText DateTimeI = NexText(2, 2, "DateTimeI");
NexText InvalNM = NexText(2, 1, "InvalNM");

/*
 *******************************************************************
   Nextion component for page:   About
 *******************************************************************
*/
NexText DateTimeA = NexText(3, 2, "DateTimeA");

/*
 *******************************************************************
   Nextion component for page:   PinEnter
 *******************************************************************
*/
NexText DateTimeP = NexText(4, 21, "DateTimeP");
NexText PinDM1 = NexText(4, 19, "PinDM1");
NexText PinDM2 = NexText(4, 20, "PinDM2");

NexText PinT0 = NexText(4, 14, "PinT0");
NexText PinT1 = NexText(4, 15, "PinT1");
NexText PinT2 = NexText(4, 16, "PinT2");
NexText PinT3 = NexText(4, 17, "PinT3");

NexButton PinE = NexButton(4, 12, "PinE");

/*
 *******************************************************************
   Nextion component for page:   otpEnter
 *******************************************************************
*/
NexText DateTimeO = NexText(5, 21, "DateTimeO");
NexText otpDM1 = NexText(5, 19, "otpDM1");
NexText otpDM2 = NexText(5, 20, "otpDM2");

NexText otpT0 = NexText(5, 14, "otpT0");
NexText otpT1 = NexText(5, 15, "otpT1");
NexText otpT2 = NexText(5, 16, "otpT2");
NexText otpT3 = NexText(5, 17, "otpT3");

NexButton otpE = NexButton(5, 12, "PinE");

/*
 *******************************************************************
   Nextion component for page:   Welcome
 *******************************************************************
*/
NexText DateTimeW = NexText(6, 2, "DateTimeW");
NexText wTxt = NexText(6, 1, "wTxt");

/*
 *******************************************************************
   Nextion component for page:   Finger
 *******************************************************************
*/
NexText DateTimeFH = NexText(7, 1, "DateTimeFH");

/*
 *******************************************************************
   Nextion component for page:   FingerScan
 *******************************************************************
*/
NexText DateTimeFS = NexText(8, 1, "DateTimeFS");

/*
 *******************************************************************
   Nextion component for page:   ValidFinger
 *******************************************************************
*/
NexText DateTimeVF = NexText(9, 1, "DateTimeVF");

/*
 *******************************************************************
   Nextion component for page:   InvalidFinger
 *******************************************************************
*/
NexText DateTimeIF = NexText(10, 1, "DateTimeIF");



void PinEPopCallback(void *ptr);
void otpEPopCallback(void *ptr);


// Declare a Page objects 
NexPage Home         = NexPage(0, 0, "Home");
NexPage ValidRFID    = NexPage(1, 0, "ValidRFID");
NexPage InvalidRFID  = NexPage(2, 0, "InvalidRFID");
NexPage About        = NexPage(3, 0, "About");
NexPage PinEnter     = NexPage(4, 0, "PinEnter");
NexPage otpEnter     = NexPage(5, 0, "otpEnter");
NexPage Welcome      = NexPage(6, 0, "Welcome");
NexPage Finger       = NexPage(7, 0, "Finger");
NexPage FingerScan   = NexPage(8, 0, "FingerScan");
NexPage ValidFinger  = NexPage(9, 0, "ValidFinger");
NexPage InvalidFinger = NexPage(10, 0, "InvalidFinger");


char buffer[10] = {0};   // Buffer for collecting text values

// Register all objects to the touch event list.  

NexTouch *nex_listen_list[] = 
{
    &PinE,
    &otpE,
    NULL
};


//************send data to the website*************
void SendDataToWebsite(){
  //Check WiFi connection status
  Serial.println("Sending Data to Website");
  if(WiFi.status()== WL_CONNECTED){
    WiFiClient client;
    HTTPClient http;    //Declare object of class HTTPClient
    
    GetDateTime();
    
    // Your Domain name with URL path or IP address with path
    http.begin(client, serverName);
    
    // Specify content-type header
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    
    // Prepare your HTTP POST request data
    String httpRequestData = "api_key=" + apiKeyValue + "&userID=" + user  + "&userName=" + userName + "&branchName=" + branchName + "";
                          
                          
    Serial.print("httpRequestData: ");
    Serial.println(httpRequestData);

    
    // Send HTTP POST request
    int httpResponseCode = http.POST(httpRequestData);
    
    
    if (httpResponseCode>0) {
      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);
    }
    else {
      Serial.print("Error code: ");
      Serial.println(httpResponseCode);
    }
    // Free resources
    http.end();
  }
  else {
    Serial.println("WiFi Disconnected");
  }
}
//*****************send data to the website*********



//  Button components pop callback functions - for PinEntry

void PinEPopCallback(void *ptr)
{
    mfrc522.PICC_HaltA(); // Stop reading
    String s = "";

    memset(buffer, 0, sizeof(buffer));
    
    PinT0.getText(buffer, sizeof(buffer));
    s += buffer;
    PinT1.getText(buffer, sizeof(buffer));
    s += buffer;
    PinT2.getText(buffer, sizeof(buffer));
    s += buffer;
    PinT3.getText(buffer, sizeof(buffer));
    s += buffer;

    Serial.print("Entered Pin = ");
    Serial.println(s);

    if (s == "1234" && user == "user1"){
      PinDM1.setText("Entered PIN is : VALID");
      PinDM2.setText("Now You'll Receive OTP on Telegram");

      int randNumber = random(1000, 9999);
      data = String(randNumber);
      String msg = "OTP for IoT Based Smart Locker -" + data + "\n";
      msg += "valid for one Time only";
      bot.sendMessage(CHAT_ID, msg, "");
      //OTP for IoT Based Smart Locker - {{PARTICLE_EVENT_VALUE}} valid for one Time only
      delay(1000);

      otpEnter.show();
      GetDateTime();
      DateTimeO.setText(RealT.c_str());
      delay(1000);
    }
    else if (s == "5678" && user == "user2"){
      PinDM1.setText("Entered PIN is : VALID");
      PinDM2.setText("Now You'll Receive OTP on Telegram");

      int randNumber = random(1000, 9999);
      data = String(randNumber);
      String msg = "OTP for IoT Based Smart Locker -" + data + "\n";
      msg += "valid for one Time only";
      bot.sendMessage(CHAT_ID, msg, "");
      //Particle.publish("telegramWebhook", data, PRIVATE);
      delay(1000);

      otpEnter.show();
      GetDateTime();
      DateTimeO.setText(RealT.c_str());
      delay(1000);
    }
    else {
      PinDM2.setText("Invalid PIN : Access Denied");
      delay(2000);
      printNormalModeMessage(); 
    }
}

//  Button components pop callback functions - for otpEntry

void otpEPopCallback(void *ptr){

    mfrc522.PICC_HaltA(); // Stop reading
    String o = "";

    memset(buffer, 0, sizeof(buffer));
    
    otpT0.getText(buffer, sizeof(buffer));
    o += buffer;
    otpT1.getText(buffer, sizeof(buffer));
    o += buffer;
    otpT2.getText(buffer, sizeof(buffer));
    o += buffer;
    otpT3.getText(buffer, sizeof(buffer));
    o += buffer;

    
    if (o == data && user == "user1"){
      otpDM1.setText("Step III passed : Valid OTP");
      otpDM2.setText("User : Access Granted");
      delay(2000);
      digitalWrite(LockerPin, LOW);
      Welcome.show();
      GetDateTime();
      DateTimeW.setText(RealT.c_str());
      wTxt.setText("Hello Aakash Gagan");
      userName = "Aakash Gagan";
      //char buf[128];
      //snprintf(buf, sizeof(buf), "[\"%s\",\"%s\"]", "User ID : 1", "Jason"); 
      SendDataToWebsite();
      delay(5000);
      digitalWrite(LockerPin, HIGH);
      printNormalModeMessage();
    }
    else if (o == data && user == "user2"){
      otpDM1.setText("Step III passed : Valid OTP");
      otpDM2.setText("User : Access Granted");
      delay(2000);
      digitalWrite(LockerPin, LOW);
      Welcome.show();
      GetDateTime();
      DateTimeW.setText(RealT.c_str());
      wTxt.setText("Hello Ravi Bhaskar");
      userName = "Ravi Bhaskar";
      //char buf[128];
      //snprintf(buf, sizeof(buf), "[\"%s\",\"%s\"]", "User ID : 2", "Ravi"); 
      SendDataToWebsite();
      delay(5000);
      digitalWrite(LockerPin, HIGH);
      printNormalModeMessage();
    }
    else {
      otpDM1.setText("Invalid OTP : Access Denied");
      otpDM2.setText("Try Again");
      delay(3000);
      printNormalModeMessage(); 
    }

    digitalWrite(LockerPin, HIGH);

}

void initRFID(){
  SPI.begin();      // Init SPI bus
  mfrc522.PCD_Init(); // Init MFRC522 card
}


void initFingerSensor(){
  
  // 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); }

  finger.getTemplateCount();

  if (finger.templateCount == 0) {
    Serial.print("Sensor doesn't contain any fingerprint data. Please run the 'enroll' example.");
  }
  else {
    Serial.println("Waiting for valid finger...");
      Serial.print("Sensor contains "); Serial.print(finger.templateCount); Serial.println(" templates");
  }
 }
}
/* Function which Scans RFID Tags/Cards and Identify the User */

void ScanRFID(){

    if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue
      return;
    }
    if ( ! mfrc522.PICC_ReadCardSerial()) {   //Since a PICC placed get Serial and continue
      return;
    }

    String content= "";
    user="";
    for (byte i = 0; i < mfrc522.uid.size; i++) 
    {
      content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
      content.concat(String(mfrc522.uid.uidByte[i], HEX));
    }

    content.toUpperCase();
    mfrc522.PICC_HaltA(); // Stop reading

    if (content.substring(1) == "B9 C7 3D 8D") //change here the UID of the card/cards that you want to give access
    {
      user = "user1";
      ValidRFID.show();
      GetDateTime();
      DateTimeV.setText(RealT.c_str());
      ValNM.setText("Welcome Aakash !");
      delay(3000);
      Finger.show();
      DateTimeFH.setText(RealT.c_str());
      delay(2000);
      int fingerID = getFingerprintID();
      
      if((fingerID == 1) || (fingerID == 2) || (fingerID == 3) || (fingerID == 4)){
        ValidFinger.show();
        DateTimeVF.setText(RealT.c_str());
        delay(2000);
        PinEnter.show();
        DateTimeP.setText(RealT.c_str());
      }else{
        InvalidFinger.show();
        DateTimeIF.setText(RealT.c_str());
        delay(2000);
        printNormalModeMessage();       
      }
    }
    else if(content.substring(1) == "FE CB 37 5B"){
      user = "user2";
      ValidRFID.show();
      GetDateTime();
      DateTimeV.setText(RealT.c_str());
      ValNM.setText("Welcome ravi !");
      delay(3000);
      Finger.show();
      DateTimeFH.setText(RealT.c_str());
      delay(2000);
      int fingerID = getFingerprintID();
      
      if((fingerID == 5) || (fingerID == 6) || (fingerID == 7) || (fingerID == 8)){
        ValidFinger.show();
        DateTimeVF.setText(RealT.c_str());
        delay(2000);
        PinEnter.show();
        DateTimeP.setText(RealT.c_str());
      }else{
        InvalidFinger.show();
        DateTimeIF.setText(RealT.c_str());
        delay(2000);
        printNormalModeMessage();       
      }
    }
    else {
      InvalidRFID.show();
      DateTimeI.setText(RealT.c_str());
      InvalNM.setText("Access Denied !!");
      delay(3000);
      printNormalModeMessage();
    }

}

// This function is for Display default initial screen

void printNormalModeMessage() {
  Home.show();
  DateTimeH.setText(RealT.c_str());
  delay(150);
}


//********************Get the Fingerprint ID******************
int getFingerprintID() {
  checkAgain:
  uint8_t p = finger.getImage();
  switch (p) {
    case FINGERPRINT_OK:
      //Serial.println("Image taken");
      GetDateTime();
      FingerScan.show();
      DateTimeFS.setText(RealT.c_str());
      break;
    case FINGERPRINT_NOFINGER:
      //Serial.println("No finger detected");
      goto checkAgain;
      return 0;
    case FINGERPRINT_PACKETRECIEVEERR:
      //Serial.println("Communication error");
      return -2;
    case FINGERPRINT_IMAGEFAIL:
      //Serial.println("Imaging error");
      return -2;
    default:
      //Serial.println("Unknown error");
      return -2;
  }
  // OK success!
  p = finger.image2Tz();
  switch (p) {
    case FINGERPRINT_OK:
      //Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      //Serial.println("Image too messy");
      return -1;
    case FINGERPRINT_PACKETRECIEVEERR:
      //Serial.println("Communication error");
      return -2;
    case FINGERPRINT_FEATUREFAIL:
      //Serial.println("Could not find fingerprint features");
      return -2;
    case FINGERPRINT_INVALIDIMAGE:
      //Serial.println("Could not find fingerprint features");
      return -2;
    default:
      //Serial.println("Unknown error");
      return -2;
  }
  // OK converted!
  p = finger.fingerFastSearch();
  if (p == FINGERPRINT_OK) {
    //Serial.println("Found a print match!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    //Serial.println("Communication error");
    return -2;
  } else if (p == FINGERPRINT_NOTFOUND) {
    //Serial.println("Did not find a match");
    return -1;
  } else {
    //Serial.println("Unknown error");
    return -2;
  }   
  // found a match!
  Serial.print("Found ID #"); Serial.print(finger.fingerID); 
  Serial.print(" with confidence of "); Serial.println(finger.confidence); 
 
  return finger.fingerID;
}

// Connect to Wi-Fi
void connectWifi(){
  // Connect to Wi-Fi
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
}

//Init NTPclient to get time
void initNTP(){
  // Initialize a NTPClient to get time
  timeClient.begin();
  // Set offset time in seconds to adjust for your timezone, for example:
  // GMT +1 = 1 * 60 * 60 = 3600
  // GMT +5 = 5 * 60 * 60 = 18000
  // GMT -1 = -1 *60 * 60 = -3600
  // GMT 0 = 0
  timeClient.setTimeOffset(19080);
}

/* Function which sets current date time */

void GetDateTime(){
  timeClient.update();

  unsigned long epochTime = timeClient.getEpochTime();
  
  String formattedTime = timeClient.getFormattedTime();

  String weekDay = weekDays[timeClient.getDay()];

  //Get a time structure
  struct tm *ptm = gmtime ((time_t *)&epochTime); 

  int monthDay = ptm->tm_mday;

  int currentMonth = ptm->tm_mon+1;

  String currentMonthName = months[currentMonth-1];

  int currentYear = ptm->tm_year+1900;

  RealT = weekDay + " " + currentMonthName + " " + String(monthDay) + " " + formattedTime + " " + String(currentYear);

  //Serial.println(RealT);
  delay(1000);
}

void setup() {
  Serial.begin(115200);
  Serial.println("IoT based Smart Lock V2.0");
  delay(1000);

  /* Initialize the display and other peripherals */
  Serial.println("Setting up WiFi");
  connectWifi();
  delay(500);

  Serial.println("Fetching Time");
  initNTP();
  delay(250);
 
  pinMode(LockerPin, OUTPUT);           // Seting Relay PIN as Output
  digitalWrite(LockerPin, HIGH);        // Relay PIN is active LOW

  Serial.println("Setting up RFID");
  initRFID();
  delay(500);

  Serial.println("Setting up FingerPrint Sensor");
  initFingerSensor();
  delay(500);

  Serial.println("Setting Up Telegram API");
  client.setCACert(TELEGRAM_CERTIFICATE_ROOT); // Add root certificate for api.telegram.org

  Serial.println("Setting up Nextion Display");
  nexInit();
  delay(500);

  /* Register the pop event callback function of the current button0 component. */
  PinE.attachPop(PinEPopCallback);
  otpE.attachPop(otpEPopCallback);

  printNormalModeMessage(); // Default initial screen
  GetDateTime();
  DateTimeH.setText(RealT.c_str());
  delay(1000);
}

void loop() {
    /*
     * When a pop or push event occured every time, 
     * the corresponding component[right page id and component id] in touch event list will be asked.
     */
  nexLoop(nex_listen_list);
  ScanRFID();
}
/*=====================info@make2explore.com ==============================*/

IoT_based_Smart_Secure_Lock_V2

Credits

make2explore
8 projects • 15 followers
Engineering Consultant, Tech Content Creator - #Electronics #EmbeddedSystems #IoT #AI #ML

Comments