#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Keypad.h>
#include <RTClib.h>
#include <SPI.h>
#include <SD.h>
#include <ESP32Servo.h>
// ======================= OLED CONFIG =======================
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ======================= RTC CONFIG ========================
RTC_DS1307 rtc;
// ======================= SERVO CONFIG ======================
Servo gateServo;
#define SERVO_PIN 14
#define SERVO_OPEN 90
#define SERVO_CLOSED 0
// ======================= SD CARD CONFIG ====================
#define SD_CS 5
// ======================= KEYPAD CONFIG =====================
const byte ROWS = 4;
const byte COLS = 4;
// Keypad layout
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
// Updated safe GPIO mapping for ESP32
byte rowPins[ROWS] = {26, 27, 25, 15}; // R1, R2, R3, R4
byte colPins[COLS] = {16, 17, 34, 35}; // C1, C2, C3, C4 (input only)
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// ======================= GLOBAL VARIABLES ==================
String lastRFID = ""; // To store simulated RFID input
bool adminMode = false; // Admin mode toggle
// ======================= FUNCTIONS =========================
// Display message on OLED
void displayMessage(String line1, String line2) {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.println(line1);
display.setCursor(0, 20);
display.println(line2);
display.display();
}
// Log attendance to SD card
void logAttendance(String rfidTag) {
if (!rtc.isrunning()) {
displayMessage("RTC ERROR!", "Check DS1307");
return;
}
DateTime now = rtc.now();
String timestamp = String(now.year()) + "-" +
String(now.month()) + "-" +
String(now.day()) + " " +
String(now.hour()) + ":" +
String(now.minute()) + ":" +
String(now.second());
File file = SD.open("/attendance.txt", FILE_APPEND);
if (file) {
file.println(rfidTag + "," + timestamp);
file.close();
displayMessage("Access Granted", "Logged Successfully");
Serial.println("Logged: " + rfidTag + " at " + timestamp);
} else {
displayMessage("SD ERROR!", "Check SD Card");
}
}
// Open and close servo gate
void openGate() {
gateServo.write(SERVO_OPEN);
delay(2000); // Keep gate open for 2 seconds
gateServo.write(SERVO_CLOSED);
}
// Reset attendance data
void resetAttendanceData() {
if (SD.exists("/attendance.txt")) {
SD.remove("/attendance.txt");
displayMessage("Admin Mode", "Data Reset Done");
Serial.println("Attendance log file deleted.");
} else {
displayMessage("Admin Mode", "No Data Found");
Serial.println("No data to reset.");
}
delay(1500);
}
// View logs in serial monitor
void viewLogs() {
displayMessage("Logs:", "Check Serial Monitor");
File file = SD.open("/attendance.txt");
if (file) {
Serial.println("----- Attendance Logs -----");
while (file.available()) {
Serial.write(file.read());
}
Serial.println("\n----------------------------");
file.close();
} else {
Serial.println("No logs found.");
}
delay(2000);
}
// ======================= SETUP =============================
void setup() {
Serial.begin(115200);
// OLED initialization
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("SSD1306 allocation failed");
for (;;); // Stop here if OLED fails
}
displayMessage("Initializing...", "");
// RTC initialization
if (!rtc.begin()) {
displayMessage("RTC ERROR", "Check DS1307");
Serial.println("Couldn't find RTC module!");
while (1);
}
if (!rtc.isrunning()) {
rtc.adjust(DateTime(F(__DATE__), F(__TIME__))); // Set to compile time
}
// Servo initialization
gateServo.attach(SERVO_PIN);
gateServo.write(SERVO_CLOSED);
// SD Card initialization
if (!SD.begin(SD_CS)) {
displayMessage("SD ERROR", "Check wiring");
Serial.println("SD Card initialization failed!");
} else {
Serial.println("SD Card initialized successfully.");
}
displayMessage("System Ready", "Scan Your RFID");
Serial.println("System initialized and ready.");
}
// ======================= LOOP ==============================
void loop() {
char key = keypad.getKey();
if (key) {
Serial.print("Key Pressed: ");
Serial.println(key);
if (adminMode) {
// Admin Mode Menu
if (key == 'A') {
viewLogs();
} else if (key == 'B') {
resetAttendanceData();
} else if (key == 'C') {
adminMode = false;
displayMessage("Admin Mode", "Exited");
delay(1000);
}
} else {
// Normal User Mode
if (key == '#') {
adminMode = true;
displayMessage("Admin Mode", "A:View B:Reset C:Exit");
} else {
// Simulate RFID scan using keypad input
lastRFID += key;
displayMessage("Scanning...", lastRFID);
// Assuming a valid tag has 4 digits
if (lastRFID.length() >= 4) {
logAttendance(lastRFID);
openGate();
lastRFID = ""; // Reset for next scan
displayMessage("System Ready", "Scan Next");
delay(1000);
}
}
}
}
}