Arduino Time-Based One-Time Door Password Lock - Use Google Authenticator for Your Lock!

by Progetto Company in Circuits > Arduino

27 Views, 2 Favorites, 0 Comments

Arduino Time-Based One-Time Door Password Lock - Use Google Authenticator for Your Lock!

totp_lock_thumbnail.jpg
Build an Arduino Smart Lock with Google Authenticator (TOTP) #arduino #arduinoproject

DISCLAIMER: CERTAIN COMPONENTS USED IN THIS TUTORIAL ARE FOR SALE BY THE AUTHOR

During this tutorial, you'll build a secure, time-based password lock using an Arduino, a TFT display, a keypad and an RTC module. The lock generates a new code every 30 seconds based on the current time, just like the codes used in Google Authenticator and other 2FA apps. You'll scan a QR code to add the lock to your app, and from then on, the current TOTP code on your phone will unlock it.

All the code for this project is open source, and we'll walk through it step by step so you can learn how it works and customize it for your own use. Be sure to check out the video above for a full demo!

Supplies

parts.jpg

To build this project, you’ll need:

  1. An Arduino board
  2. I'm using an Arduino Nano, but any Arduino with at least as much Flash and SRAM as the ATMega328p should work.
  3. ⚠️ This project uses over 99% of the ATMega328p's Flash and most of its SRAM.
  4. Jumper wires
  5. 15× male-to-male jumper wires
  6. 5× male-to-female jumper wires
  7. A half-pint breadboard or larger
  8. One Pin Keypad Module + 4x4 Keypad
  9. Available here: One Pin Keypad on Tindie
  10. DS3231 RTC (Real-Time Clock) Module
  11. Example on AliExpress
  12. Be sure to install a CR2032 coin cell to maintain timekeeping!
  13. A solenoid and matching power supply
  14. Sol-EZ Solenoid Driver Kit
  15. I'm using the high-power version, which requires a 5V microcontroller.
  16. If your microcontroller runs at 3.3V, use the logic level shifter below.
  17. Available here: Sol-EZ Solenoid Driver Kit on Tindie
  18. TFT Display
  19. Mine is a 1.54" SPI TFT, 240×240 resolution, using the ST7789 driver.
  20. Here’s a similar option: ST7789 TFT on AliExpress
  21. ✅ Make sure the display is large and high-resolution enough to display a scannable QR code.
  22. ⚠️ If using a different display, you’ll need to modify the code (especially UI pixel coordinates).
  23. Logic level shifter (optional)
  24. Needed if your TFT display uses a different voltage than your Arduino
  25. Available here: 4-Channel Logic Level Converter on Tindie

Wiring

schematic.jpg
wiring.jpg
IMG_20191221_171026.jpg

The wiring for this project is fairly involved, as it connects several devices. However, you don't need to wire everything all at once, the tutorial will introduce each component step by step, adding its corresponding code as we go. This iterative approach makes it easier to test and debug as you build. ALWAYS CHECK FOR SHORTS!

Don't forget the diode across the terminals of the solenoid driver, see photos.

📷 Refer to the wiring diagram above for a full overview of how everything connects.

🔌 Power Notes:

  1. The Arduino itself can be powered via its USB port, which is sufficient for most of the components.
  2. The solenoid, however, requires external power, which should match the solenoid's rated voltage and current. Make sure to power it separately through the Sol-EZ driver circuit.

(Optional) PlatformIO Setup

PIO.jpg

The code used in this project is a bit more involved than any of our previous projects, and I wanted to split it into multiple files to keep the code tidy. To make things easier on myself, I decided to use Visual Studio Code for this project with the PlatformIO extension.

  1. Please follow this link to install Visual Studio Code: https://code.visualstudio.com/download
  2. Then, set up the Platform IO Extension: https://docs.platformio.org/en/stable/integration/ide/vscode.html#

If you're using a different Arduino board, you'll have to edit platform.ini; see here for details: https://docs.platformio.org/page/projectconf.html

If you prefer the Arduino IDE, you should be able to move the files from the lib/Maze directory to your Arduino Libraries folder and rename the main .cpp file you wish to run in src to a .ino file and install the libraries using the Arduino IDE. For more details and a potentially automated way to do this on Linux (I have not tested it), see this link: https://runningdeveloper.com/blog/platformio-project-to-arduino-ide/

Download & Open the Code

github.jpg
import_project.jpg

This project's code is open source and can be found on GitHub: https://github.com/ProgettoCompany/TOTPLock

Please download or clone the code (as is your preference) and import it into PlatformIO:

  1. Start PlatformIO in Visual Studio Code (click on the extension on the left bar and click Open under Quick Access > PIO Home)
  2. Click Projects in PIO Home
  3. Click Add Existing and navigate to where you downloaded the code from GitHub


Set the RTC Time

serial_monitor.jpg
step_4.jpg

Open main.cpp in the src folder and open step_4.cpp in the steps folder. Replace all of the code in main.cpp with the code from step_4.cpp.

To use the RTC with an Arduino requires installing RTCLib; this library and the others required for this project should be automatically installed by PlatformIO when you open the project.

If you're using the Arduino IDE, see lib_deps in platformio.ini for the list of required libraries.

Using https://www.unixtimestamp.com/, set the RTC's timestamp using the Serial Monitor. You can open the Serial Monitor by clicking the 🔌 looking icon in the top right of the VS Code Editor.

While the Arduino can measure the time elapsed since the program started executing, it has no concept of time beyond this millis() value. To generate the time-based one-time (TOTP) password, we need an external time source. It's worth noting that we could have used an external NTP (Network Time Protocol) server instead if our microcontroller had internet access, but I thought a lock shouldn't need internet access (insert `smart` toaster joke here).


For more info on how to use the DS3231 RTC with an Arduino, see: https://www.circuitbasics.com/how-to-use-a-real-time-clock-module-with-the-arduino/

A Quick Note on F Strings

memory_usage.jpg

Arduino boards utilize three types of memory:

  1. Flash Memory: Non-volatile storage for your program code.
  2. SRAM (Static RAM): Volatile memory used for variables and runtime data.
  3. EEPROM: Non-volatile memory for storing small amounts of data that must be saved when power is removed.

SRAM is particularly limited (e.g., only 2KB on the Arduino Nano), so conserving it is crucial. By default, string literals (like those used in Serial.print()) are stored in SRAM, consuming valuable space. When you compile main.cpp, you'll notice we use only half of the SRAM; however, to the best of my knowledge, that does not include dynamically allocated memory used by the libraries. Without F-strings, the program will hang during void setup() and reset automatically.

To optimize SRAM usage, we use the F() macro to store string literals in Flash memory instead. For example:

Serial.println(F("This string is stored in Flash, not SRAM."));

This approach helps prevent SRAM overflows, especially in programs with many Serial print statements.

For more details on Arduino memory management and the F() macro, check out this fantastic guide by Adafruit: https://learn.adafruit.com/memories-of-an-arduino/optimizing-sram

Display the TOTP QR Code

step_6.JPG
qr_code.jpg

Open main.cpp in the src folder and open step_6.cpp in the steps folder. Replace all of the code in main.cpp with the code from step_6.cpp.

Note that you can generate a new hmacKey using a website created by the author of the TOTP library used in this project: https://www.lucadentella.it/OTP/. If you increase the length of the TOTP code, you'll have to update the call to base32Encode(), the constructor for TOTP, which includes the key length and the buffer for allocating the base32 encoded string. I have tried with a 16-character code, but Google Authenticator was unable to scan it, so your mileage may vary.

While this project was inspired by this post: https://eddmann.com/posts/building-a-2fa-totp-generator-using-a-raspberry-pi-pico-and-micropython/, it is worth noting that Luca Dentella created a project similar to this one back in 2013: https://www.lucadentella.it/2013/09/14/serratura-otp/2/

If you're using the Arduino IDE, install the TOTP, Adafruit GFX, Adafruit ST7735 and ST7789 and QRCode libraries for this part.

Calibrate the One Pin Keypad

opk.jpg

As detailed in https://www.instructables.com/Meet-One-Pin-Keypad/, calibrate your One Pin Keypad module and copy the resulting myThresholds array, ex:

int myThresholds[16] = {36, 104, 166, 218, 263, 307, 345, 379, 406, 436, 463, 486, 514, 525, 547, 562};

While it's a shameless plug, it's worth noting here that without the One Pin Keypad, we would not have had enough digital pins on the Arduino Nano for this project.

Code Entry Using the Keypad

step_8.jpg

Open main.cpp in the src folder and open step_8.cpp in the steps folder. Replace all of the code in main.cpp with the code from step_8.cpp.

At this point, we basically have a fully functioning lock with code entry, the entered code is displayed on the screen and verified against the TOTP code generated in step 6. We store the 6-digit code in an array as we read it from the keypad and have a 10 second timeout for user input.

Add the Solenoid

step_9.jpg

Open main.cpp in the src folder and open step_8.cpp in the steps folder. Replace all of the code in main.cpp with the code from step_8.cpp.

Add Timezone Support

step_9.jpg

Open main.cpp in the src folder and open step_10.cpp in the steps folder. Replace all of the code in main.cpp with the code from step_10.cpp. Note that this code is also the same as the code from the original main.cpp.

This is a relatively minor enhancement. Since the RTC does not set your timezone, the displayed time is incorrect unless you live in the UTC timezone. To fix this, I added a simple screen that allows you to adjust the timezone by half-hour increments and store it in EEPROM for persistence. An interesting little easter egg is that originally I planned to allow the user to enter the time zone numerically, but ran out of flash for the implementation.

Conclusion & Next Steps

cover.jpg

Congratulations, you have created a TOTP lock! Feel free to remix and improve this project to make it your own! Maybe add a case, an actual locking mechanism, or make the circuit into a PCB. If you're feeling especially ambitious and have a more powerful microcontroller (with more flash and SRAM), try using a security chip to store the HMAC key and generate the TOTP codes without the microcontroller having access to the HMAC key. I am not honestly sure how this would work, but it would be an interesting challenge.

If you have any questions, comments or concerns, feel free to email me at progettocompany@gmail.com

Happy hacking!

John Wolf

Progetto Company