Software apps and online services | ||||||
![]() |
|
Neha was wasting 10 minutes every lecture on manual attendance. She wanted a fast, reliable solution that prevents proxy attendance. Following YaranaIoT Guru’s guide, she built a system where students tap RFID cards and attendance is logged instantly to a secure server. The teacher now spends more time teaching and less time taking roll.
“One tap — attendance recorded — no fraud, no paper.” — Neha
“One tap — attendance recorded — no fraud, no paper.” — Neha
CREATE DATABASE attendance_system;
USE attendance_system;
-- Students table
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
student_id VARCHAR(32) UNIQUE NOT NULL, -- college roll / unique id
name VARCHAR(100) NOT NULL,
card_uid VARCHAR(64) UNIQUE, -- RFID UID
pin_hash VARCHAR(255), -- optional hashed PIN
active TINYINT DEFAULT 1
);
-- Attendance logs
CREATE TABLE attendance_log (
id INT AUTO_INCREMENT PRIMARY KEY,
student_id VARCHAR(32) NOT NULL,
station_id VARCHAR(50) NOT NULL,
scan_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
method VARCHAR(20), -- 'card','card+pin'
raw_uid VARCHAR(64),
ip_address VARCHAR(45),
notes TEXT
);
-- Admin users (for dashboard)
CREATE TABLE admins (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE,
password_hash VARCHAR(255)
);
🔐 Secure API: PHP Endpoint (insert_attendance.php)
C/C++Security notes: Use HTTPS on server. Require an API key per station or sign the payload (HMAC) with a station secret. Below example shows API key check + prepared statements.
<?php
// insert_attendance.php
// POST params: api_key, station_id, card_uid, student_id (optional), method, pin_hash (optional)
$CONFIG_API_KEYS = [
'STATION_01' => 'your_station_api_key_here' // store securely, rotate periodically
];
$servername = "localhost";
$dbuser = "root";
$dbpass = "";
$dbname = "attendance_system";
$input = $_POST;
// Basic validation
if (!isset($input['api_key'], $input['station_id'], $input['card_uid'])) {
http_response_code(400);
echo json_encode(['status'=>'error','msg'=>'Missing parameters']);
exit;
}
$api_key = $input['api_key'];
$station_id = $input['station_id'];
$card_uid = $input['card_uid'];
$method = isset($input['method']) ? $input['method'] : 'card';
$pin_hash = isset($input['pin_hash']) ? $input['pin_hash'] : null;
// Verify API key -> station mapping
$valid = false;
foreach ($CONFIG_API_KEYS as $sid => $key) {
if ($sid === $station_id && hash_equals($key, $api_key)) { $valid = true; break; }
}
if (!$valid) {
http_response_code(403);
echo json_encode(['status'=>'error','msg'=>'Invalid API key']);
exit;
}
// DB connect
$conn = new mysqli($servername, $dbuser, $dbpass, $dbname);
if ($conn->connect_error) {
http_response_code(500);
echo json_encode(['status'=>'error','msg'=>'DB connection failed']);
exit;
}
// Find student by card_uid
$stmt = $conn->prepare("SELECT student_id, name, pin_hash FROM students WHERE card_uid = ? AND active = 1 LIMIT 1");
$stmt->bind_param("s", $card_uid);
$stmt->execute();
$res = $stmt->get_result();
if ($res->num_rows === 0) {
// Unknown card
echo json_encode(['status'=>'unknown','msg'=>'Card not registered']);
$stmt->close();
$conn->close();
exit;
}
$row = $res->fetch_assoc();
$student_id = $row['student_id'];
$student_name = $row['name'];
$db_pin_hash = $row['pin_hash'];
$stmt->close();
// Optional: if method == 'card+pin', verify pin_hash matches stored hash
if ($method === 'card+pin') {
if (!$pin_hash || !password_verify($pin_hash, $db_pin_hash)) {
echo json_encode(['status'=>'error','msg'=>'Invalid PIN']);
$conn->close();
exit;
}
}
// Insert attendance log
$ip = $_SERVER['REMOTE_ADDR'];
$stmt2 = $conn->prepare("INSERT INTO attendance_log (student_id, station_id, method, raw_uid, ip_address, notes) VALUES (?, ?, ?, ?, ?, ?)");
$notes = "Name: " . $student_name;
$stmt2->bind_param("ssssss", $student_id, $station_id, $method, $card_uid, $ip, $notes);
$ok = $stmt2->execute();
$stmt2->close();
$conn->close();
if ($ok) {
echo json_encode(['status'=>'ok','msg'=>'Attendance recorded','student'=> $student_name, 'student_id'=>$student_id]);
} else {
http_response_code(500);
echo json_encode(['status'=>'error','msg'=>'DB insert failed']);
}
?>
🧠 ESP32 Code (Read RFID & send secure POST)
C/C++This example:
Reads RFID UID,
Computes short HMAC signature (station secret) for authenticity,
Sends POST to API.
Reads RFID UID,
Computes short HMAC signature (station secret) for authenticity,
Sends POST to API.
/*
Secure Attendance - ESP32 + RC522
Author: YaranaIoT Guru
*/
#include <WiFi.h>
#include <HTTPClient.h>
#include <MFRC522.h>
#include <SPI.h>
#include <mbedtls/md.h> // for HMAC (ESP32 core includes mbedtls)
#define RST_PIN 22
#define SS_PIN 21
// Edit these
const char* ssid = "YourWiFi";
const char* password = "YourPassword";
const char* serverUrl = "https://yourserver.com/attendance/insert_attendance.php";
const char* stationId = "STATION_01";
const char* stationApiKey = "your_station_api_key_here"; // used for simple API key auth
MFRC522 mfrc522(SS_PIN, RST_PIN);
void setup() {
Serial.begin(115200);
SPI.begin();
mfrc522.PCD_Init();
delay(100);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
Serial.println("\nConnected: " + WiFi.localIP().toString());
Serial.println("Ready, scan card...");
}
String uidToString(MFRC522::Uid uid) {
String s = "";
for (byte i=0; i < uid.size; i++) {
if(uid.uidByte[i] < 0x10) s += "0";
s += String(uid.uidByte[i], HEX);
}
s.toUpperCase();
return s;
}
// Optional: generate simple HMAC-SHA256 signature (if server expects it)
String hmac_sha256_hex(const String &key, const String &data) {
const unsigned char *keyBuf = (const unsigned char *)key.c_str();
size_t keyLen = key.length();
const unsigned char *dataBuf = (const unsigned char *)data.c_str();
size_t dataLen = data.length();
unsigned char output[32];
mbedtls_md_context_t ctx;
const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
mbedtls_md_init(&ctx);
mbedtls_md_setup(&ctx, md_info, 1);
mbedtls_md_hmac_starts(&ctx, keyBuf, keyLen);
mbedtls_md_hmac_update(&ctx, dataBuf, dataLen);
mbedtls_md_hmac_finish(&ctx, output);
mbedtls_md_free(&ctx);
// convert to hex
char hexStr[65];
for (int i=0; i<32; i++) sprintf(hexStr + (i*2), "%02x", output[i]);
hexStr[64]=0;
return String(hexStr);
}
void loop() {
// Look for new cards
if ( ! mfrc522.PICC_IsNewCardPresent()) return;
if ( ! mfrc522.PICC_ReadCardSerial()) return;
String uid = uidToString(mfrc522.uid);
Serial.println("Card UID: " + uid);
// payload data; include timestamp if desired
String payload = "station_id=" + String(stationId) + "&card_uid=" + uid;
// Option A: simple API key auth (POST field)
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
String postData = "api_key=" + String(stationApiKey) + "&station_id=" + String(stationId) + "&card_uid=" + uid + "&method=card";
int httpCode = http.POST(postData);
if (httpCode > 0) {
String resp = http.getString();
Serial.println("Server response: " + String(httpCode) + " - " + resp);
} else {
Serial.println("HTTP failed: " + String(httpCode));
}
http.end();
// feedback
// buzzer/LED logic here
delay(1500); // debounce
}
15 projects • 0 followers
Yarana Iot Guru
Yarana IoT Guru: Arduino,
ESP32, GSM, NodeMCU & more.
Projects, Tutorials & App Development. Innovate with us!
Thanks to YaranaIoT Guru.
Comments