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!

 #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

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



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:
- The Arduino itself can be powered via its USB port, which is sufficient for most of the components.
- 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

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.
- Please follow this link to install Visual Studio Code: https://code.visualstudio.com/download
- 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


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:
- Start PlatformIO in Visual Studio Code (click on the extension on the left bar and click Open under Quick Access > PIO Home)
- Click Projects in PIO Home
- Click Add Existing and navigate to where you downloaded the code from GitHub
Set the RTC Time


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

Arduino boards utilize three types of memory:
- Flash Memory: Non-volatile storage for your program code.
- SRAM (Static RAM): Volatile memory used for variables and runtime data.
- 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:
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


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

As detailed in https://www.instructables.com/Meet-One-Pin-Keypad/, calibrate your One Pin Keypad module and copy the resulting myThresholds array, ex:
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

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

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

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

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