Simple 2fa Access System

About the project

We will build an access system that doesn't need any external devices( you can use an 13.56 Mhz RFID tag if you want), and that uses a private-public key system so password stealing is much harder, thus making your application more secure.

Project info

Difficulty: Difficult

Platforms: Linux

Estimated time: 1 day

License: GNU General Public License, version 3 or later (GPL3+)

Items used in this project

Hardware components

Giant Board Giant Board x 1
Arduino Uno - R3 Arduino Uno - R3 x 1
20X4 I2C LCD Screen 20X4 I2C LCD Screen x 1
Membrane 3x4 Matrix Keypad Membrane 3x4 Matrix Keypad I recommend a metal one x 1
Servo - Generic (Sub-Micro Size) Servo - Generic (Sub-Micro Size) x 1
Arduino Jumper Cables High Quality Arduino Jumper Cables High Quality You can solder all the connections x 1
ASUS ZenPower powerbank ASUS ZenPower powerbank You can use another power bank but it won't fit as nice in the 3D print. x 1
USB A/Micro Cable - 2m USB A/Micro Cable - 2m x 1
USB Power Supply Wall Adapter 5V@2.5A (EU Standard) USB Power Supply Wall Adapter 5V@2.5A (EU Standard) You can use any decent usb wall plug x 1
M2.5 6.0mm Screw Zinc Plated Steel M2.5 6.0mm Screw Zinc Plated Steel x 12
MFRC522 RFID Reader/Writer MFRC522 RFID Reader/Writer x 1

View all

Software apps and online services

Linux Linux
Arduino IDE Arduino IDE
Pycharm Pycharm We use this to test the python scripts
Putty Putty We use it to connect to the Giant Board

Hand tools and fabrication machines

3D printer 3D printer Or you can use any 3D printing service x 1
Soldering iron Soldering iron x 1
Screwdriver set Screwdriver set x 1

Story

Idea

I got the idea to build such a system, after looking at numerous tutorials, and often finding different problems that were dealbreakers for me, I wanted to build and design a system that can offer all the functionality of a commercial one at a lower price, and that doesn't skimp on security, using only standard hardware, using 2FA.

This tutorial has 3 chapters:

  • Firstly, we will talk about the hardware construction and how it all fits together.
  • Secondly, we will discuss how the software works and how to install it and configure the Giant board/ Arduino
  • Thirdly, we will talk about the advantages and disadvantages of such systems, comparing it to off-the-shelf systems and also to DIY ones.

Hardware

Front panel construction

Hardware construction

We will 3D print the Front panel body, then we will remove the supports and we are going to prepare it for the next steps:

Then we are going to attach all the necessary modules to complete the build:

  1. Lcd screen mounts to the upper 4 screws with M2.5 screws
  2. RC-522 sensor is mounted under the Arduino
  3. Membrane keypad is mounted on the front panel with the cable entering thru the small slot
  4. Arduino is mounted on the 4 lower screws and secures RFID module
  5. The whole unit will be mounted on the wall with 4 screws, one in each corner, taking care that the wires need to pass thru the wall to the back unit

Wiring

Below is attached a wiring diagram(*Sorry for not using Fritzing, not all components I needed were included)

The components are connected as follows:

  • LCD GND to Arduino GND
  • LCD VCC to Arduino 5V
  • LCD SDA to Arduino A4
  • LCD SCL to Arduino A5
  • KEYPAD Pin 1 to Arduino A0
  • KEYPAD Pin 2 to Arduino A1
  • KEYPAD Pin 3 to Arduino A2
  • KEYPAD Pin 4 to Arduino A4
  • KEYPAD Pin 5 to Arduino D5
  • KEYPAD Pin 6 to Arduino D6
  • KEYPAD Pin 7 to Arduino D7
  • RC522 GND to Arduino GND
  • RC522 3.3V to Arduino 3.3V
  • RC522 RST to Arduino D9
  • RC522 MISO to Arduino D12
  • RC522 MOSI to Arduino D11
  • RC522 SCK to Arduino D13
  • RC522 SDA to Arduino D10

This is how it should look when assembled, you can desolder the pins from the components if you want, then solder wires directly if you would like, it will make it more resistant to shocks and also look nicer.

Back lock assembly

Hardware construction

We will 3D print the back body, then we will remove the supports and we are going to prepare it for the next steps:

We are going to attach the necessary components next:

  1. The Giant Board sits on the bottom 4 screws with the USB port facing right, this is very important
  2. The ServoMotor will be mounted with 2 screws, and with the output shaft facing downwards
  3. the Asus ZenPower batter will be mounted with the USB ports facing to the right

Wiring

The components are connected as follows:

  • ServoMotor SIGNAL pin to Giant Board PWM1
  • ServoMotor VCC pin to 5V rail
  • ServoMotor GND pin to GND rail
  • Giant Board Micro-USB port to 5V cable connected to the power bank
  • Giant Board AD3 to Arduino D0
  • Giant Board AD2 to Arduino D1
  • Arduino VIN to 5V rail
  • Arduino GND to GND rail

This is how it should look like, I would suggest making the locking bar from steel(the blue highlighted piece):

Mounting the pieces on a door

The Front Panel and the Lock Body need to communicate so they have to near each other, the front panel will be placed on the insecure parts of the door, while the lock will be placed on the secure side, they will be fixed, each with four screws, the locking bar will lock the door from moving as in the image below:

Software

Configuring the Giant Board

Installing necessary software

Firstly, we need to install a terminal emulation app, I'm using windows, so I chose Putty, you can get it at https://putty.org/. Once you have installed it, you will be greeted with this window:

We need to select the Serial tab and enter the serial port associated with our Giant Board, if you don't know it, you can find it at Device manager, under COM ports. After we have selected it, we need to set the baud rate to 115200, then we press Open. If it doesn't work first, wait for a bit so the Giant Board has time to boot.

Configuring the controller

The default username name is debian and the default password is temppwd. Once you type that in you will be greeted by the Giant Board console!. It is recommended that you change the password with the passwd command.

First, we need to configure the network. We enter the command sudo connmanctl, it will ask for your password, enter it. You will be greeted with a prompt like this:

Enter the command services, it will give you a list of one device, with a name like         gadget_5e70b6158b61_usb,  copy it, then type connect and paste the string, you paste with right-click. you will be greeted with Connected gadget_5e70b6158b61_usb,  if this is the case, then you are ready to go, if you encounter difficulties, the Giant Board documentation can be very helpful at https://groboards.com/docs/

Then we need to configure it inside Windows, go to Network and Sharing centre in the control panel, you should see something like this:

Click on the connection that has internet, in my case (Wi-Fi 2), and then go to Properties. Once you get there go to the Sharing tab and enable Sharing, this will make you select a network, select the network created by the Giant Board, in my case (Ethernet 6), once you did this, you will have Internet on your Giant Board.

The giant board uses Overlays to define hardware connectivity. You need to go enter sudo nano /boot/uboot/uEnv.txt,  then you need to uncomment the line: 

  1. enable_uboot_overlays=1

Then, you need to add to two of the overlay lines:

  1. GB-UART2-FLX4-AD2-AD3.dtbo
  2. GB-PWM1.dtbo

The first enables UART which will be used to communicate with the Arduino and the second enables PWM to control the Servo

We need to install the libraries for controlling the motor and the UART serial line and random number generation:

  1. pip install Adafruit-Blinka
  1. pip install pyserial
  1. pip install random2

Writing the main script

Now we are going to write the main control script for the giant board, we will discuss it in parts, but the whole code can be copied from the Attachments.First, we need to create a file named backend.py at the bin directory, we do this by using the following command:

  1. sudo nano bin/backend.py

This will open the text editor nano, it should look like this:

The shortcuts are in the lower part of the screen.Now we can get to writing the main script, first we add all the necessary libraries:

  1. import serial
  2. import random
  3. import time
  4. import board
  5. import pulseio
  6. from adafruit_motor import servo

Then we create the necessary objects such as the servo motor and the Serial Connection (UART):

  1. # create a PWMOut object on Pin PWM1.
  2. pwm = pulseio.PWMOut(board.PWM1, duty_cycle=2 ** 15, frequency=50)
  3. # Create a servo object, my_servo.
  4. my_servo = servo.Servo(pwm)
  5.  
  6. serialPort = serial.Serial(port = "/dev/ttyS1", baudrate=115200,bytesize=8, timeout=2, stopbits=serial.STOPBITS_ONE) # Here you add Arduino parameters, those are default
  7. serialString = "" # Used to hold data coming over UART

Now we initialize the servo motor to the closed position:

  1. for angle in range(180, 0, -5): # 180 - 0 degrees, 5 degrees at a time.
  2. my_servo.angle = angle
  3. time.sleep(0.05)

We create the function that unlocks the door so we can call it later if the correct credentials are supplied:

  1. def unlock():
  2. for angle in range(0, 180, 5): # 0 - 180 degrees, 5 degrees at a time.
  3. my_servo.angle = angle
  4. time.sleep(0.05)
  5. time.sleep(2)
  6. for angle in range(180, 0, -5): # 0 - 180 degrees, 5 degrees at a time.
  7. my_servo.angle = angle
  8. time.sleep(0.05)

If your motor is backward change 0 to 180, 180 to 0, 5 to -5, and -5 to 5 in the parameters of range.

Now we add the function that defines ourselves (the user):

  1. # this is the secure info of user "me"
  2. def me(type, token):
  3. # Here you put the passcode
  4. if (type == 1):
  5. return "111111"
  6. # Here you put the RFID tag info
  7. if (type == 2):
  8. return "66949828"
  9. if (type == 3):
  10. d1 = token[0]
  11. d2 = token[1]
  12. d3 = token[2]
  13. d4 = token[3]
  14. d5 = token[4]
  15. d6 = token[5]
  16. d7 = token[6]
  17. d8 = token[7]
  18. # here you write your 2FA rule
  19. result = ''
  20. result += str((d1 + 1) % 10)
  21. result += str((d2 + 2) % 10)
  22. result += str((d3 + 3) % 10)
  23. result += str((d4 + 4) % 10)
  24. result += str((d5 + 5) % 10)
  25. result += str((d6 + 6) % 10)
  26. result += str((d7 + 7) % 10)
  27. result += str((d8 + 8) % 10)
  28. return result

In the first 'if', we add our passcode, in the second, our RFID tag and in the third our 2FA rule, in this case, I take every digit and add 1 to the first digit 2 to the second, etc, taking only the last digit so we get an array with an identical number of digits.

The rest of the script is just validation:

  1. def genrand():
  2. # here we generate a random token
  3. s1 = random.randint(0, 10)
  4. s2 = random.randint(0, 10)
  5. s3 = random.randint(0, 10)
  6. s4 = random.randint(0, 10)
  7. s5 = random.randint(0, 10)
  8. s6 = random.randint(0, 10)
  9. s7 = random.randint(0, 10)
  10. s8 = random.randint(0, 10)
  11. return [s1,s2,s3,s4,s5,s6,s7,s8], str(s1)+str(s2)+str(s3)+str(s4)+str(s5)+str(s6)+str(s7)+str(s8)
  12.  
  13.  
  14. while(1):
  15.  
  16. # Wait until there is data waiting in the serial buffer
  17. if(serialPort.in_waiting > 0):
  18. # Read data out of the buffer until a carraige return / new line is found
  19. serialString = serialPort.readline()
  20. # Print the contents of the serial data
  21. comm = serialString.decode('Ascii')
  22. comm = comm.strip()
  23. # Separate string into 2 parts delimited by '|'
  24. str1, str2 = comm.split('|')
  25. # Verify if the connection started
  26. if (str1 == 'COMM' and str2 == 'START'):
  27. print("Connection succesfull!")
  28.  
  29. if (str1 == 'PASS'):
  30. print('PASS ==> ' + str2)
  31. if (me(1, '') == str2):
  32. print ("PASS OK")
  33. serialPort.write(b"MODE|SQRFIDn")
  34. exit = False
  35. while exit == False:
  36. if (serialPort.in_waiting > 0):
  37. exit = True
  38. # Read data out of the buffer until a carraige return / new line is found
  39. serialString = serialPort.readline()
  40. # Print the contents of the serial data
  41. comm = serialString.decode('Ascii')
  42. comm = comm.strip()
  43. # Separate string into 2 parts delimited by '|'
  44. str1, str2 = comm.split('|')
  45. if (str1 == 'RFID'):
  46. if (me(2, '') == str2):
  47. print('RFID OK')
  48. serialPort.write(b"MODE|SQ2FAn")
  49. exit1 = False
  50. while exit1 == False:
  51. if (serialPort.in_waiting > 0):
  52. exit1 = True
  53. # Read data out of the buffer until a carraige return / new line is found
  54. serialString = serialPort.readline()
  55. # Print the contents of the serial data
  56. comm = serialString.decode('Ascii')
  57. comm = comm.strip()
  58. # Separate string into 2 parts delimited by '|'
  59. str1, str2 = comm.split('|')
  60. if (str1 == 'MODE'):
  61. token, tokenstr = genrand()
  62. tokenstr = tokenstr[0:8]
  63. serialPort.write(bytes((tokenstr + 'n').encode()))
  64. exit2 = False
  65. while exit2 == False:
  66. if (serialPort.in_waiting > 0):
  67. exit2 = True
  68. # Read data out of the buffer until a carraige return / new line is found
  69. serialString = serialPort.readline()
  70. # Print the contents of the serial data
  71. comm = serialString.decode('Ascii')
  72. comm = comm.strip()
  73. # Separate string into 2 parts delimited by '|'
  74. str1, str2 = comm.split('|')
  75. if (str2 == me(3,token)):
  76. print("2FA OK")
  77. serialPort.write(b"ACC|GRANTn")
  78. unlock () # unlock
  79. else:
  80. print("2FA FALSE")
  81. serialPort.write(b"ACC|INTRn")
  82. else:
  83. print("RFID FALSE")
  84. serialPort.write(b"ACC|INTRn")
  85. else:
  86. print("PASS FALSE")
  87. serialPort.write(b"ACC|INTRn")
  88.  
  89. if (str1 == 'RFID'):
  90. print('RFID ==> ' + str2)
  91. if (me(2, '') == str2):
  92. print("RFID OK")
  93. serialPort.write(b"MODE|SQPASSn")
  94. exit = False
  95. while exit == False:
  96. if (serialPort.in_waiting > 0):
  97. exit = True
  98. # Read data out of the buffer until a carraige return / new line is found
  99. serialString = serialPort.readline()
  100. # Print the contents of the serial data
  101. comm = serialString.decode('Ascii')
  102. comm = comm.strip()
  103. # Separate string into 2 parts delimited by '|'
  104. str1, str2 = comm.split('|')
  105. if (str1 == 'PASS'):
  106. if (me(1, '') == str2):
  107. print('PASS OK')
  108. serialPort.write(b"MODE|SQ2FAn")
  109. exit1 = False
  110. while exit1 == False:
  111. if (serialPort.in_waiting > 0):
  112. exit1 = True
  113. # Read data out of the buffer until a carraige return / new line is found
  114. serialString = serialPort.readline()
  115. # Print the contents of the serial data
  116. comm = serialString.decode('Ascii')
  117. comm = comm.strip()
  118. # Separate string into 2 parts delimited by '|'
  119. str1, str2 = comm.split('|')
  120. if (str1 == 'MODE'):
  121. token, tokenstr = genrand()
  122. tokenstr = tokenstr[0:8]
  123. serialPort.write(bytes((tokenstr + 'n').encode()))
  124. exit2 = False
  125. while exit2 == False:
  126. if (serialPort.in_waiting > 0):
  127. exit2 = True
  128. # Read data out of the buffer until a carraige return / new line is found
  129. serialString = serialPort.readline()
  130. # Print the contents of the serial data
  131. comm = serialString.decode('Ascii')
  132. comm = comm.strip()
  133. # Separate string into 2 parts delimited by '|'
  134. str1, str2 = comm.split('|')
  135. if (str2 == me(3, token)):
  136. print("2FA OK")
  137. serialPort.write(b"ACC|GRANTn")
  138. unlock() # unlock
  139. else:
  140. print("2FA FALSE")
  141. serialPort.write(b"ACC|INTRn")
  142. else:
  143. print("PASS FALSE")
  144. serialPort.write(b"ACC|INTRn")
  145. else:
  146. print("RFID FALSE")
  147. serialPort.write(b"ACC|INTRn")

After the script is written we can make it start at the boot of the Giant Board, to do this we need to add a new crontab:

  1. sudo crontab -e

Then we need to specify our script, we add this line to the bottom of the file, after all the #'s:

  1. @reboot python /bin/your_script.py &

Then we can reboot our board with sudo reboot.

Configuring the Arduino

Installing necessary software

We need the Arduino IDE to send programs to our Arduino, we can get it at https://www.arduino.cc/en/Main/Software

After we have downloaded it we will be greeted with a page that looks like this:

Now we are ready to add the necessary code so our Arduino becomes a frontend, like our python script, we first add the necessary libraries:

  1. #include <Wire.h>
  2. #include <LiquidCrystal_I2C.h>
  3. #include <SPI.h>
  4. #include <MFRC522.h>

Then we add variables and define some instances for the RFID reader and the LCD screen:

  1. // Variables for the main program
  2. const int tokensize = 8;
  3. int mode = 1; // 1 = can read rfid + passcode 2 = rfid 3 = passcode 4 = 2FA
  4. String command;
  5. String token;
  6.  
  7. // RFID reader pins and variables
  8. #define SS_PIN 10
  9. #define RST_PIN 9
  10. MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
  11. MFRC522::MIFARE_Key key;
  12. byte uid[4];
  13.  
  14. //Keypad characters
  15. char digits[10];
  16. int keychar, cont;
  17. int keypressed = 0;
  18. char characters[] = {' ','3','6','9','#','2','5','8','0','1','4','7','*'}; // characters on the keypad
  19.  
  20. //LCD screen I2C address (0x3F)
  21. LiquidCrystal_I2C lcd(0x3F, 20, 4);

Now we enter the setup part of the script, this tells the microcontroller, in this case, the Atmega328p what to do when first starting up, here we set up pins and start the RFID reader, the UART interface and the LCD interface:

  1. void setup() {
  2. // setting up pins for the 3 X 4 matrix keypad
  3. pinMode(5, OUTPUT);
  4. pinMode(6, OUTPUT);
  5. pinMode(7, OUTPUT);
  6. pinMode(A0, INPUT_PULLUP);
  7. pinMode(A1, INPUT_PULLUP);
  8. pinMode(A2, INPUT_PULLUP);
  9. pinMode(A3, INPUT_PULLUP);
  10.  
  11. // starting a serial connection for monitoring
  12. Serial.begin(115200);
  13. //Serial.println("AS-Frontend-v-1.1");
  14. Serial.println("COMM|START");
  15.  
  16. // starting SPI bus for RFID reader
  17. SPI.begin(); // Init SPI bus
  18. rfid.PCD_Init(); // Init MFRC522
  19. for (byte i = 0; i < 6; i++) {
  20. key.keyByte[i] = 0xFF;
  21. }
  22.  
  23. // printing info on the lcd
  24. lcd.begin();
  25. lcd.print(" Access system");
  26. lcd.print(" Rev 1.1");
  27. delay(100);
  28. lcdstd();
  29. // it needs to read RFID + Passcodes
  30. mode = 1;
  31. }

The Arduino communicates with the Giant Board with short messages like COMM|START for starting the bus.

We now get into the different functions that make all of this to work

We first have the function that reads from the keypad, I know that there are off the shelf alternatives from Adafruit but those use the digital pins, mine also uses the analog pins so we can use more stuff with our little microcontroller, I tried to comment the code as much as I can but if anyone would like to know something you can leave it in the comments down below.

  1. int keypad() {
  2. float a = 0, b = 0, c = 0, d = 0, thresh = 100.0;
  3. // here we iterate thru the rows and the columns to check whether there is any key pressed
  4. digitalWrite(5, LOW);
  5. digitalWrite(6, HIGH);
  6. digitalWrite(7, HIGH);
  7. a = analogRead(A0);
  8. b = analogRead(A1);
  9. c = analogRead(A2);
  10. d = analogRead(A3);
  11. if (a < thresh) {
  12. return 1;
  13. }
  14. if (b < thresh) {
  15. return 2;
  16. }
  17. if (c < thresh) {
  18. return 3;
  19. }
  20. if (d < thresh) {
  21. return 4;
  22. }
  23. digitalWrite(5, HIGH);
  24. digitalWrite(6, LOW);
  25. digitalWrite(7, HIGH);
  26. a = analogRead(A0);
  27. b = analogRead(A1);
  28. c = analogRead(A2);
  29. d = analogRead(A3);
  30. if (a < thresh) {
  31. return 5;
  32. }
  33. if (b < thresh) {
  34. return 6;
  35. }
  36. if (c < thresh) {
  37. return 7;
  38. }
  39. if (d < thresh) {
  40. return 8;
  41. }
  42. digitalWrite(5, HIGH);
  43. digitalWrite(6, HIGH);
  44. digitalWrite(7, LOW);
  45. a = analogRead(A0);
  46. b = analogRead(A1);
  47. c = analogRead(A2);
  48. d = analogRead(A3);
  49. if (a < thresh) {
  50. return 9;
  51. }
  52. if (b < thresh) {
  53. return 10;
  54. }
  55. if (c < thresh) {
  56. return 11;
  57. }
  58. if (d < thresh) {
  59. return 12;
  60. }
  61. return 0;
  62. }

Then we have some code to change the message on the display:

  1. void lcdstd()
  2. {
  3. lcd.begin();
  4. delay(100);
  5. lcd.print(" Scan RFID tag ------ Type passcode");
  6. }
  1. void lcdauth()
  2. {
  3. lcd.begin();
  4. lcd.backlight();
  5. delay(100);
  6. lcd.print(" Access Granted");
  7. delay(2000);
  8. lcdstd();
  9. }
  1. void lcdnauth()
  2. {
  3. lcd.begin();
  4. lcd.backlight();
  5. delay(100);
  6. lcd.print(" Access Restricted Try again");
  7. delay(2000);
  8. lcdstd();
  9. }

Now we need to read from the RC522 reader so we need to get the data from the SPI bus and format it so it can be read by our program using this script, if anyone is wondering, we use only the UID of the tag:

  1. bool card_reader()
  2. {
  3. bool card = false;
  4. if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial())
  5. {
  6. for (byte i = 0; i < 4; i++)
  7. {
  8. uid[i] = rfid.uid.uidByte[i];
  9. card = true;
  10. }
  11. }
  12. rfid.PICC_HaltA();
  13. rfid.PCD_StopCrypto1();
  14. return card;
  15. }

Finally, we get to the main loop, which just verifies if any code or any tag is provided to the reader and if so it sends them to the Giant Board for verification:

  1. void loop()
  2. {
  3. if(card_reader() && mode != 2 && mode != 4)
  4. {
  5. Serial.print("RFID|");
  6. for (byte i = 0; i < 4; i++)
  7. {
  8. Serial.print(uid[i]);
  9. }
  10. //Serial.println("|");
  11. lcd.setCursor(7,2);
  12. lcd.print("******");
  13. lcdstd();
  14. mode = 0;
  15. }
  16. keychar = keypad();
  17. if(keychar!=keypressed && mode != 3 )
  18. {
  19. keypressed = keychar;
  20. lcd.setCursor(7,2);
  21. if(mode==4){
  22. lcd.setCursor(6,2);
  23. }
  24. //lcd.print(characters[keychar]);
  25. cont = true;
  26. int i=0;
  27. int m = 5;
  28. if(mode == 4){
  29. m = tokensize - 1;
  30. }
  31. while(i <= m) // stops after 6 digits
  32. {
  33. delay(50);
  34. keychar=keypad();
  35. if(keychar == 0)
  36. {
  37. cont = true;
  38. }
  39. if(keychar != 0 && cont == true)
  40. {
  41. //lcd.print(characters[keychar]); //uncomment this if you want the passcode to be visible when written
  42. digits[i]=characters[keychar];
  43. i++;
  44. lcd.print('*');
  45. cont = false;
  46. }
  47. }
  48. if(mode != 4){
  49. Serial.print("PASS|");
  50. }
  51. else{
  52. Serial.print("2FAS|");
  53. }
  54. for(int i=0;i<=m;i++){
  55. Serial.print(digits[i]);
  56. }
  57. //Serial.println("|");
  58. lcdstd();
  59. keypressed=0;
  60. mode = 0;
  61. }
  62. while(Serial.available() > 0)
  63. {
  64. command = Serial.readString();
  65. if(command == "MODE|SQPASSn")
  66. {
  67. //Serial.println("MODE|PASS");
  68. mode = 2;
  69. lcd.setCursor(3,1);
  70. lcd.print("Enter Passcode ");
  71. lcd.setCursor(3,0);
  72. lcd.print(" ");
  73. }
  74. if(command == "MODE|SQRFIDn")
  75. {
  76. //Serial.println("MODE|RFID");
  77. mode = 3;
  78. lcd.setCursor(3,1);
  79. lcd.print("Scan RFID tag ");
  80. lcd.setCursor(3,0);
  81. lcd.print(" ");
  82. }
  83. if(command == "MODE|SQ2FAn")
  84. {
  85. Serial.println("MODE|2FAPASS");
  86. mode = 4;
  87. while(Serial.available() == 0){}
  88. token = Serial.readString();
  89. token[tokensize]=' ';
  90. lcd.setCursor(3,0);
  91. lcd.print("Enter 2FA token");
  92. lcd.setCursor(3,1);
  93. lcd.print(" ");
  94. lcd.setCursor(6,1);
  95. lcd.print(token);
  96. lcd.setCursor(6,2);
  97. lcd.print("--------");
  98. }
  99. if(command == "ACC|GRANTn")
  100. {
  101. Serial.println("ACCESS|OK");
  102. lcdauth();
  103. }
  104. if(command == "ACC|INTRn")
  105. {
  106. Serial.println("ACCESS|NO");
  107. lcdnauth();
  108. }
  109. }
  110. }

And now, we have officially finished the hardware and software, we can talk about the cons and the post to such a system:

Pros and Cons

Pros:

  • It doesn't use any external device(RFID can be removed), unlike other systems that depend on your phone to verify, those systems prove useless if the said device runs out of battery, which in our world could easily happen.
  • It doesn't rely on other services to process data, like AWS or Google Cloud, or any other IoT service, this makes it more secure and independent of said services.
  • It doesn't have the flaw that many systems have, which is that the part that opens the door is on the insecure side, thus making it practically useless, requiring basic skills to open, these flaws are easily exploitable by using an external battery to open the solenoid or the motor
  • The power bank acts as a UPS "Uninterruptable Power Supply", that makes it work even if the power is down in your respective place.
  • It is cheap to build and I think it looks relatively nice 
  • There is room for integration with more of these systems, to have a centralized database on your home server that keeps all the events.

Cons:

  • Takes getting used to the 2FA code
  • 3D printed parts are not extremely durable, this can be improved by milling them with a CNC out of aluminum.
  • The lock body with the servo is vulnerable to brute force attacks, this can be easily solved with an external solenoid, I just couldn't find one near where I live.
  • Is not waterproof.

Final prototype

This is how it looks when the correct codes and RFID key are entered:

This is how it looks when an incorrect RFID tag is placed:

That is it, I hope you like it and maybe it inspired you to build something like this, if you have any idea, share it with us in the comments below!

Schematics, diagrams and documents

General diagram

Front panel diagram

CAD, enclosures and custom parts

Lock body

Front panel

Locking bar

Code

Frontend

This runs on the Arduino UNO R3

Backend

This code runs on the GiantBoard

Credits

Photo of sabinandrei

sabinandrei

I am a student that likes programming and robotics.

   

Leave your feedback...