#include <WiFi.h>
#include <HTTPClient.h>
#include "time.h"
// Wi-Fi credentials for Wokwii
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// ThingSpeak settings
String apiKey = "9H07YXCDRDA5NARD";
const char* server = "http://api.thingspeak.com/update";
// Pins
const int attendanceButtonPin = 15; // Button to mark attendance
const int resetButtonPin = 16; // Button to reset session
const int ledPin = 2; // Confirmation LED
const int buzzerPin = 4; // Confirmation buzzer
// System variables
bool attendanceMarked = false;
int attendanceCount = 0;
const int expectedStudents = 5; // Simulated class size for percentage calculation
// Button state tracking for edge detection
int lastAttendanceButtonState = HIGH;
int lastResetButtonState = HIGH;
// Time settings for Uganda
const long gmtOffset_sec = 3 * 3600;
const int daylightOffset_sec = 0;
// Send heartbeat data every 20 seconds
unsigned long lastSendTime = 0;
const unsigned long sendInterval = 20000;
// Connect to Wi-Fi
void connectWiFi() {
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
// Sync time using NTP
void syncTime() {
configTime(gmtOffset_sec, daylightOffset_sec, "pool.ntp.org", "time.nist.gov");
struct tm timeinfo;
while (!getLocalTime(&timeinfo)) {
Serial.println("Waiting for time sync...");
delay(1000);
}
Serial.println("Time synchronized");
}
// Get current hour and minute
bool getCurrentTime(int &hourNow, int &minuteNow) {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
return false;
}
hourNow = timeinfo.tm_hour;
minuteNow = timeinfo.tm_min;
return true;
}
// Simple rule-based "AI" risk score
int calculateRiskScore() {
int hourNow, minuteNow;
if (!getCurrentTime(hourNow, minuteNow)) {
return 0; // If time is unavailable, keep it safe
}
float attendanceRate = (attendanceCount * 100.0) / expectedStudents;
// Example class schedule: 8:00 AM
if (hourNow < 8) {
return 0; // Class has not started
}
if (hourNow == 8 && minuteNow <= 15) {
return (attendanceRate < 60.0) ? 1 : 0;
}
if (hourNow == 8 && minuteNow > 15) {
return (attendanceRate < 80.0) ? 1 : 0;
}
if (hourNow > 8 && hourNow < 10) {
return (attendanceRate < 80.0) ? 1 : 0;
}
return (attendanceRate < 60.0) ? 1 : 0;
}
// Send data to ThingSpeak
void sendToThingSpeak(int riskScore) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi not connected");
return;
}
float attendanceRate = (attendanceCount * 100.0) / expectedStudents;
int hourNow, minuteNow;
getCurrentTime(hourNow, minuteNow);
HTTPClient http;
String url = String(server) +
"?api_key=" + apiKey +
"&field1=" + String(attendanceCount) +
"&field2=" + String(attendanceRate, 1) +
"&field3=" + String(riskScore) +
"&field4=" + String(hourNow * 100 + minuteNow);
http.begin(url);
int httpResponseCode = http.GET();
Serial.print("ThingSpeak HTTP response: ");
Serial.println(httpResponseCode);
http.end();
}
void setup() {
Serial.begin(115200);
pinMode(attendanceButtonPin, INPUT_PULLUP);
pinMode(resetButtonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
digitalWrite(ledPin, LOW);
digitalWrite(buzzerPin, LOW);
connectWiFi();
syncTime();
Serial.println("System ready");
sendToThingSpeak(0); // send initial status
}
void loop() {
int attendanceButtonState = digitalRead(attendanceButtonPin);
int resetButtonState = digitalRead(resetButtonPin);
// Attendance button: detect new press only
if (attendanceButtonState == LOW && lastAttendanceButtonState == HIGH) {
if (!attendanceMarked) {
attendanceMarked = true;
attendanceCount++;
digitalWrite(ledPin, HIGH);
digitalWrite(buzzerPin, HIGH);
delay(200);
digitalWrite(buzzerPin, LOW);
Serial.println("Attendance Marked");
int riskScore = calculateRiskScore();
sendToThingSpeak(riskScore);
} else {
Serial.println("Duplicate Ignored");
}
}
// Reset button: start a new class/day
if (resetButtonState == LOW && lastResetButtonState == HIGH) {
attendanceMarked = false;
attendanceCount = 0;
digitalWrite(ledPin, LOW);
Serial.println("New session started");
int riskScore = calculateRiskScore();
sendToThingSpeak(riskScore);
}
// Heartbeat update every 20 seconds
if (millis() - lastSendTime >= sendInterval) {
lastSendTime = millis();
int riskScore = calculateRiskScore();
sendToThingSpeak(riskScore);
}
lastAttendanceButtonState = attendanceButtonState;
lastResetButtonState = resetButtonState;
delay(20);
}