#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// ==================================================
// WiFi Configuration
// ==================================================
String wifiSsid = "Wokwi-GUEST";
String wifiPassword = "";
// ==================================================
// API Configuration
// ==================================================
String attendanceUrl =
"https://prathammardhekar.pythonanywhere.com/api/v1/iot/attendance?device=device01-lab&fp=1&token=zpMqrlsmT5gsQaByloKCgIHCZGkWLIxz";
String heartbeatUrl =
"https://prathammardhekar.pythonanywhere.com/api/v1/iot/heartbeat?device=device01-lab&token=zpMqrlsmT5gsQaByloKCgIHCZGkWLIxz";
// ==================================================
// Pin Configuration
// ==================================================
const int blinkLedPin = 18;
const int greenLedPin = 4;
const int pushButtonPin = 5;
// ==================================================
// LCD Configuration
// ==================================================
const int lcdAddress = 0x27;
const int lcdColumns = 16;
const int lcdRows = 2;
LiquidCrystal_I2C lcd(
lcdAddress,
lcdColumns,
lcdRows
);
// ==================================================
// Display BioTrack
// ==================================================
/**
* Displays the default BioTrack ready screen.
*/
void displayBioTrack() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("BioTrack");
lcd.setCursor(0, 1);
lcd.print("Ready...");
}
// ==================================================
// Display Fingerprint Triggered
// ==================================================
/**
* Displays fingerprint trigger status.
*/
void displayFingerprintTriggered() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Fingerprint");
lcd.setCursor(0, 1);
lcd.print("Triggered!");
}
// ==================================================
// Extract JSON String Value
// ==================================================
/**
* Extracts a simple string value from JSON.
*/
String extractJsonValue(String response, String key) {
String searchKey = "\"" + key + "\":\"";
int startPosition = response.indexOf(searchKey);
if (startPosition < 0) {
return "N/A";
}
startPosition += searchKey.length();
int endPosition = response.indexOf(
"\"",
startPosition
);
if (endPosition < 0) {
return "N/A";
}
return response.substring(
startPosition,
endPosition
);
}
// ==================================================
// WiFi Connection
// ==================================================
/**
* Connects the ESP32 to the configured WiFi network.
*/
void connectToWiFi() {
Serial.println();
Serial.println("Connecting to WiFi...");
WiFi.begin(
wifiSsid,
wifiPassword
);
int retryCount = 0;
while (
WiFi.status() != WL_CONNECTED &&
retryCount < 30
) {
delay(500);
Serial.print(".");
retryCount++;
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("WiFi connection failed");
}
}
// ==================================================
// Attendance API Request
// ==================================================
/**
* Sends attendance request to the PythonAnywhere API.
*/
void sendAttendanceRequest() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println(
"Attendance: WiFi not connected"
);
return;
}
Serial.println();
Serial.println("========== ATTENDANCE ==========");
Serial.println("Request URL:");
Serial.println(attendanceUrl);
HTTPClient http;
http.begin(attendanceUrl);
int httpCode = http.GET();
Serial.print("HTTP Code : ");
Serial.println(httpCode);
if (httpCode > 0) {
String response = http.getString();
Serial.println("Raw API Response:");
Serial.println(response);
if (httpCode == 200) {
Serial.println("Status : SUCCESS");
} else {
Serial.println("Status : HTTP RESPONSE RECEIVED");
}
} else {
Serial.println("Status : REQUEST FAILED");
Serial.print("Error : ");
Serial.println(
http.errorToString(httpCode)
);
}
Serial.println("================================");
http.end();
}
// ==================================================
// Heartbeat API Request
// ==================================================
/**
* Sends heartbeat request and formats the expected API response.
*/
void sendHeartbeatRequest() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println(
"Heartbeat: WiFi not connected"
);
return;
}
Serial.println();
Serial.println("========== HEARTBEAT ==========");
Serial.println("Request URL:");
Serial.println(heartbeatUrl);
HTTPClient http;
http.begin(heartbeatUrl);
int httpCode = http.GET();
Serial.print("HTTP Code : ");
Serial.println(httpCode);
if (httpCode > 0) {
String response = http.getString();
Serial.println("Raw API Response:");
Serial.println(response);
// ------------------------------------------
// Expected API response:
//
// {
// "code": "heartbeat",
// "device": "device01-lab",
// "ok": true,
// "serverTime": "2026-10-04 19:50:45",
// "timezone": "UTC"
// }
// ------------------------------------------
String code = extractJsonValue(
response,
"code"
);
String device = extractJsonValue(
response,
"device"
);
String serverTime = extractJsonValue(
response,
"serverTime"
);
String timezone = extractJsonValue(
response,
"timezone"
);
// ------------------------------------------
// Check actual heartbeat response
// ------------------------------------------
if (
httpCode == 200 &&
code == "heartbeat" &&
response.indexOf("\"ok\":true") >= 0
) {
Serial.println();
Serial.println("Status : SUCCESS");
Serial.print("Code : ");
Serial.println(code);
Serial.print("Device : ");
Serial.println(device);
Serial.println("OK : true");
Serial.print("ServerTime: ");
Serial.println(serverTime);
Serial.print("Timezone : ");
Serial.println(timezone);
} else {
Serial.println();
Serial.println("Status : UNEXPECTED RESPONSE");
Serial.print("Code : ");
Serial.println(code);
Serial.print("Device : ");
Serial.println(device);
Serial.print("ServerTime: ");
Serial.println(serverTime);
Serial.print("Timezone : ");
Serial.println(timezone);
}
} else {
Serial.println("Status : REQUEST FAILED");
Serial.print("Error : ");
Serial.println(
http.errorToString(httpCode)
);
}
Serial.println("================================");
http.end();
}
// ==================================================
// Push Button Handler
// ==================================================
/**
* Detects button press and sends attendance once per press.
*/
void handlePushButton() {
static bool buttonPressed = false;
int currentButtonState =
digitalRead(pushButtonPin);
// ------------------------------------------
// Button Pressed
// ------------------------------------------
if (currentButtonState == LOW) {
if (!buttonPressed) {
buttonPressed = true;
// Green LED ON
digitalWrite(
greenLedPin,
HIGH
);
// LCD
displayFingerprintTriggered();
// Serial
Serial.println(
"Fingerprint triggered"
);
// Send attendance
sendAttendanceRequest();
// Small debounce delay
delay(200);
}
}
// ------------------------------------------
// Button Released
// ------------------------------------------
else {
if (buttonPressed) {
buttonPressed = false;
// Green LED OFF
digitalWrite(
greenLedPin,
LOW
);
// LCD
displayBioTrack();
// Serial
Serial.println(
"Fingerprint released"
);
}
}
}
// ==================================================
// Setup
// ==================================================
void setup() {
// ------------------------------------------
// Serial
// ------------------------------------------
Serial.begin(115200);
// ------------------------------------------
// GPIO
// ------------------------------------------
pinMode(
blinkLedPin,
OUTPUT
);
pinMode(
greenLedPin,
OUTPUT
);
pinMode(
pushButtonPin,
INPUT_PULLUP
);
// ------------------------------------------
// Initial LED State
// ------------------------------------------
digitalWrite(
blinkLedPin,
LOW
);
digitalWrite(
greenLedPin,
LOW
);
// ------------------------------------------
// I2C
// ------------------------------------------
Wire.begin();
// ------------------------------------------
// LCD
// ------------------------------------------
lcd.init();
lcd.backlight();
// ------------------------------------------
// Startup Screen
// ------------------------------------------
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("BioTrack");
lcd.setCursor(0, 1);
lcd.print("Starting...");
// ------------------------------------------
// Startup LED
// ------------------------------------------
delay(100);
digitalWrite(
blinkLedPin,
HIGH
);
delay(1000);
digitalWrite(
blinkLedPin,
LOW
);
delay(1000);
// ------------------------------------------
// WiFi
// ------------------------------------------
connectToWiFi();
// ------------------------------------------
// Ready
// ------------------------------------------
displayBioTrack();
Serial.println();
Serial.println("BioTrack started");
Serial.println("Heartbeat monitoring active");
}
// ==================================================
// Main Loop
// ==================================================
void loop() {
// ------------------------------------------
// Check Push Button
// ------------------------------------------
handlePushButton();
// ------------------------------------------
// Heartbeat LED ON
// ------------------------------------------
digitalWrite(
blinkLedPin,
HIGH
);
// ------------------------------------------
// Send Heartbeat
// ------------------------------------------
sendHeartbeatRequest();
// ------------------------------------------
// Keep LED ON
// ------------------------------------------
delay(500);
// ------------------------------------------
// Heartbeat LED OFF
// ------------------------------------------
digitalWrite(
blinkLedPin,
LOW
);
// ------------------------------------------
// Wait Before Next Heartbeat
// ------------------------------------------
delay(10000);
}