#include <Adafruit_SSD1306.h>
#include <Wire.h>
#include <Servo.h>
#include <Keypad.h>
// Constants
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET 4
#define SERVO_PIN 6
#define SERVO_LOCK_POS 20
#define SERVO_UNLOCK_POS 90
#define LOCK_DELAY 500
#define FEEDBACK_DELAY 100
#define MESSAGE_DELAY 1500
#define BUZZER_PIN 11
// Global objects
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Servo lockServo;
bool passwordSet = false;
String currentCode = ""; //EMPTY Default code
bool changingCode = false;
// Keypad settings
const byte KEYPAD_ROWS = 4;
const byte KEYPAD_COLS = 4;
byte rowPins[KEYPAD_ROWS] = {5, 4, 3, 2};
byte colPins[KEYPAD_COLS] = {7, 8, 9, 10};
char keys[KEYPAD_ROWS][KEYPAD_COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, KEYPAD_ROWS, KEYPAD_COLS);
// State enum
enum State { UNLOCKED, LOCKED };
State currentState = UNLOCKED;
// Functions
void lock() {
lockServo.write(SERVO_LOCK_POS);
currentState = LOCKED;
}
void unlock() {
lockServo.write(SERVO_UNLOCK_POS);
currentState = UNLOCKED;
}
void clearDisplay() {
display.clearDisplay();
display.setCursor(0, 0);
}
void showMessage(String message) {
clearDisplay();
display.print(message);
display.display();
delay(MESSAGE_DELAY);
}
String inputSecretCode() {
clearDisplay();
display.print("passcode---->");
display.display();
String result = "";
while (result.length() < 4) {
char key = keypad.getKey();
if (key >= '0' && key <= '9') {
display.print("* ");
display.display();
result += key;
delay(FEEDBACK_DELAY);
}
}
return result;
}
bool setNewCode() {
showMessage("Enter new passcode:");
String newCode = inputSecretCode();
showMessage("Confirm new passcode");
String confirmCode = inputSecretCode();
if (newCode.length() == 4 && confirmCode.length() == 4 && newCode == confirmCode) {
currentCode = newCode;
passwordSet = true;
changingCode = false;
return true;
} else {
showMessage("passCode mismatch");
showMessage("Safe not locked!");
return false;
}
}
void showUnlockMessage() {
String message = "Unlocking!";
for (byte i = 0; i < message.length(); i++) {
display.print(message[i]);
display.display();
delay(50);
}
delay(500);
}
void safeUnlockedLogic() {
showMessage("The Safe is Unlocked!");
clearDisplay();
display.print("Press # to lock Press A to set New Passcode");
display.display();
delay(MESSAGE_DELAY);
bool newCodeNeeded = !passwordSet;
char key;
while (true) {
key = keypad.getKey();
if (key == 'A' || key == '#') {
break;
}
}
bool readyToLock = true;
if (key == 'A' || newCodeNeeded) {
readyToLock = setNewCode();
}
if (readyToLock) {
clearDisplay();
tone(BUZZER_PIN, 1500, 100);
delay(50);
String message = "locking!";
for (byte i = 0; i < message.length(); i++) {
display.print(message[i]);
display.display();
delay(50);
}
delay(500);
lock();
delay(LOCK_DELAY);
}
}
void safeLockedLogic() {
String userCode = inputSecretCode();
bool unlockedSuccessfully = passwordSet && userCode == currentCode;
delay(200);
if (unlockedSuccessfully) {
tone(BUZZER_PIN, 1000, 100);
delay(150);
showUnlockMessage();
unlock();
} else {
tone(BUZZER_PIN, 900, 100);
delay(300);
tone(BUZZER_PIN, 900, 100);
delay(300);
tone(BUZZER_PIN, 900, 100);
delay(300);
showMessage("Access Denied!");
}
}
void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
lockServo.attach(SERVO_PIN);
pinMode(BUZZER_PIN, OUTPUT);
unlock();
tone(BUZZER_PIN, 1000, 100);
delay(150);
String message = "Welcome!";
for (byte i = 0; i < message.length(); i++) {
display.print(message[i]);
display.display();
delay(50);
}
delay(1000);
}
void loop() {
if (currentState == LOCKED) {
safeLockedLogic();
} else {
safeUnlockedLogic();
}
}