Program Utama innoiti CT1 (Tinggal ganti SSID)
#include <WiFi.h>
#include <HTTPClient.h>
#include <SPI.h>
#include <MFRC522.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSansBold12pt7b.h>
#include <Fonts/FreeSansBold9pt7b.h>
#include <Fonts/FreeSerif9pt7b.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Pin definitions for ESP32 (disarankan)
#define RST_PIN 27 // Reset pin untuk RC522
#define SS_PIN 5 // SS/CS RC522
#define BUZZER_PIN 4 // Buzzer
#define LED_PIN 16 // LED indikator
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::MIFARE_Key key;
MFRC522::StatusCode status;
// WiFi configuration
const char* ssid = "TPQ Jabal Rohmah";
const char* password = "lamongan";
const char* serverUrl = "http://zidcreative.com/innoiti/cust/cust_6/php/absensi.php";
// NTP Client configuration
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 25200, 60000); // GMT+7 (25200 seconds)
// Variables for attendance tracking
int dailyAttendanceCount = 0;
unsigned long currentAttendanceDay = 0;
float currentSpeedKBps = 0;
unsigned long lastSpeedTestTime = 0;
const long speedTestInterval = 10000; // Measure speed every 10 seconds
void setup() {
Serial.begin(9600);
SPI.begin();
// Initialize RFID reader
mfrc522.PCD_Init();
for (byte i = 0; i < 6; i++) key.keyByte[i] = 0xFF; // Default key
// Initialize OLED
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setFont(&FreeSansBold12pt7b);
display.setTextColor(WHITE);
display.setCursor(5, 20);
display.println("Innoiti");
display.setCursor(5, 45);
display.println("CT-1");
display.display();
// Initialize buzzer and LED
pinMode(BUZZER_PIN, OUTPUT);
pinMode(LED_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
// Play intro sound
playIntro();
// Connect to WiFi
Serial.print("Connecting to WiFi");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Connected!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// Initialize NTP client
timeClient.begin();
}
void loop() {
measureNetworkSpeed();
timeClient.update();
// Display time and status
displayTime();
// Check for RFID card
if (!mfrc522.PICC_IsNewCardPresent()) return;
if (!mfrc522.PICC_ReadCardSerial()) return;
Serial.println("\nReading RFID data...");
handleRFIDCard();
// Halt communication with card
mfrc522.PICC_HaltA();
mfrc522.PCD_StopCrypto1();
}
void handleRFIDCard() {
displayProcessing();
// Read data from blocks
byte buffer[18];
byte bufferSize = sizeof(buffer);
String id_jari = "Unknown";
String name = "Unknown";
String kode = "Unknown";
// Read ID from block 5
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 5, &key, &(mfrc522.uid));
if (status == MFRC522::STATUS_OK) {
status = mfrc522.MIFARE_Read(5, buffer, &bufferSize);
if (status == MFRC522::STATUS_OK) {
id_jari = "";
for (byte i = 0; i < 16; i++) {
if (buffer[i] != 0x00) id_jari += (char)buffer[i];
}
id_jari.trim(); // Remove any whitespace
}
}
// Read name from block 4
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 4, &key, &(mfrc522.uid));
if (status == MFRC522::STATUS_OK) {
status = mfrc522.MIFARE_Read(4, buffer, &bufferSize);
if (status == MFRC522::STATUS_OK) {
name = "";
for (byte i = 0; i < 16; i++) {
if (buffer[i] != 0x00) name += (char)buffer[i];
}
name.trim(); // Remove any whitespace
}
}
// Read kode from block 6
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, 6, &key, &(mfrc522.uid));
if (status == MFRC522::STATUS_OK) {
status = mfrc522.MIFARE_Read(6, buffer, &bufferSize);
if (status == MFRC522::STATUS_OK) {
kode = "";
for (byte i = 0; i < 16; i++) {
if (buffer[i] != 0x00) kode += (char)buffer[i];
}
kode.trim(); // Remove any whitespace
}
}
// Validate data
if (id_jari.length() == 0 || id_jari == "Unknown" ||
name.length() == 0 || name == "Unknown" ||
kode.length() == 0 || kode == "Unknown") {
Serial.println("Invalid card data");
displayError("Ups Gagal");
playErrorSound();
return;
}
// Check if kode is "A"
if (kode != "A") {
Serial.println("Kartu ditolak - Kode tidak valid");
displayError("Tertolak");
playErrorSound();
return;
}
Serial.print("ID: "); Serial.println(id_jari);
Serial.print("Name: "); Serial.println(name);
Serial.print("Kode: "); Serial.println(kode);
// Handle attendance
unsigned long currentTime = timeClient.getEpochTime();
unsigned long currentDay = currentTime / 86400; // Days since 1 Jan 1970
// Reset counter if new day
if (currentDay != currentAttendanceDay) {
dailyAttendanceCount = 0;
currentAttendanceDay = currentDay;
}
// Process attendance
dailyAttendanceCount++;
sendData(id_jari, name);
}
void sendData(String id_jari, String name) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi not connected! Trying to reconnect...");
WiFi.disconnect();
WiFi.reconnect();
delay(5000);
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Failed to connect to WiFi");
displayError("WiFi Error!");
return;
}
}
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
String postData = "id_jari=" + id_jari + "&name=" + name;
int httpResponseCode = http.POST(postData);
if (httpResponseCode > 0) {
Serial.print("Data sent successfully! HTTP Response: ");
Serial.println(httpResponseCode);
displaySuccess(name.c_str());
playSuccessSound();
} else {
Serial.println("Failed to send data");
displayError("Coba Lagi");
playErrorSound();
}
http.end();
}
void playIntro() {
digitalWrite(LED_PIN, HIGH);
tone(BUZZER_PIN, 1000, 200);
delay(200);
tone(BUZZER_PIN, 1200, 200);
delay(200);
tone(BUZZER_PIN, 1500, 300);
delay(300);
noTone(BUZZER_PIN);
digitalWrite(LED_PIN, LOW);
}
void playSuccessSound() {
for (int i = 0; i < 2; i++) {
digitalWrite(BUZZER_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
delay(100);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
delay(100);
}
}
void playErrorSound() {
digitalWrite(BUZZER_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
delay(1000);
digitalWrite(BUZZER_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
void displayTime() {
display.clearDisplay();
// Display organization name
display.setFont(&FreeSerif9pt7b);
display.setTextColor(WHITE);
display.setCursor(2, 14);
display.println("- Jabal Rahmah -");
// Display time
display.setFont(&FreeSansBold12pt7b);
display.setCursor(17, 42);
display.println(timeClient.getFormattedTime());
// Additional functions (WiFi indicator and counter)
drawWifiIndicator();
drawAttendanceCounter();
display.display();
}
void displaySuccess(const char* message) {
display.clearDisplay();
// Animated circle
for(int i=0; i<=360; i+=30) {
display.clearDisplay();
drawAnimatedCircle(64, 20, 10, i);
display.display();
delay(20);
}
// Animated checkmark
drawAnimatedCheckmark(64, 20);
// Success message
display.setFont(&FreeSansBold9pt7b);
display.setTextColor(WHITE);
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds(message, 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w)/2, 50);
display.println(message);
display.drawFastHLine(10, 55, SCREEN_WIDTH-20, WHITE);
display.display();
}
void drawAnimatedCircle(int16_t x, int16_t y, int16_t r, int16_t angle) {
float rad = angle * PI / 180;
int16_t x2 = x + r * cos(rad);
int16_t y2 = y + r * sin(rad);
display.drawLine(x, y, x2, y2, WHITE);
}
void drawAnimatedCheckmark(int16_t x, int16_t y) {
display.fillCircle(x, y, 12, WHITE);
for(int i=0; i<=10; i++) {
display.fillCircle(x, y, 12, WHITE);
int16_t x1 = x - 8;
int16_t y1 = y;
int16_t x2 = x - 2;
int16_t y2 = y + 6;
int16_t drawX2 = x1 + (x2 - x1) * i / 10;
int16_t drawY2 = y1 + (y2 - y1) * i / 10;
display.drawLine(x1, y1, drawX2, drawY2, BLACK);
if(i > 5) {
int16_t x3 = x2;
int16_t y3 = y2;
int16_t x4 = x + 8;
int16_t y4 = y - 6;
int16_t drawX4 = x3 + (x4 - x3) * (i-5) / 5;
int16_t drawY4 = y3 + (y4 - y3) * (i-5) / 5;
display.drawLine(x3, y3, drawX4, drawY4, BLACK);
}
display.display();
delay(30);
}
}
void drawWifiIndicator() {
int rssi = WiFi.RSSI();
int bars;
if (rssi > -55) bars = 4;
else if (rssi > -65) bars = 3;
else if (rssi > -75) bars = 2;
else if (rssi > -85) bars = 1;
else bars = 0;
int x = 7;
int y = 61;
display.fillRect(x, y-10, 30, 12, BLACK);
display.drawPixel(x, y-2, WHITE);
display.drawPixel(x+1, y-2, WHITE);
display.drawPixel(x+2, y-3, WHITE);
display.drawPixel(x+3, y-3, WHITE);
display.drawPixel(x+4, y-4, WHITE);
display.drawPixel(x+5, y-4, WHITE);
for (int i = 0; i < bars; i++) {
display.fillRect(x + 8 + (i*5), y - 2 - (i*2), 3, 2 + (i*2), WHITE);
}
}
void drawAttendanceCounter() {
display.setFont(NULL);
display.setTextSize(1);
// Display network speed
display.setCursor(42, 55);
display.print(currentSpeedKBps, 1);
display.print("KB/s");
// Display attendance counter
display.setCursor(100, 55);
display.print("A:");
display.print(dailyAttendanceCount);
}
void measureNetworkSpeed() {
if (millis() - lastSpeedTestTime >= speedTestInterval) {
HTTPClient http;
const char* testUrl = "http://httpbin.org/stream-bytes/1024";
long fileSize = 1024;
http.begin(testUrl);
int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
long startTime = millis();
WiFiClient *stream = http.getStreamPtr();
while (stream->available()) {
stream->read();
}
long duration = millis() - startTime;
if (duration > 0) {
currentSpeedKBps = (fileSize / 1024.0) / (duration / 1000.0);
Serial.print("Speed: ");
Serial.print(currentSpeedKBps);
Serial.println(" KB/s");
}
}
http.end();
lastSpeedTestTime = millis();
}
}
void displayProcessing() {
display.clearDisplay();
static float angle = 0;
const int centerX = SCREEN_WIDTH/2;
const int centerY = SCREEN_HEIGHT/2 - 5;
const int radius = 12;
display.drawCircle(centerX, centerY, radius, WHITE);
int dotX = centerX + radius * cos(angle);
int dotY = centerY + radius * sin(angle);
display.fillCircle(dotX, dotY, 2, WHITE);
angle += 0.2;
if(angle > 2*PI) angle = 0;
display.setFont(&FreeSansBold9pt7b);
display.setTextColor(WHITE);
int16_t x1, y1;
uint16_t w, h;
display.getTextBounds("Memproses", 0, 0, &x1, &y1, &w, &h);
display.setCursor((SCREEN_WIDTH - w)/2, centerY + radius + 20);
display.println("Memproses");
display.display();
}
void displayError(String errorMsg) {
display.clearDisplay();
display.setFont(&FreeSansBold12pt7b);
display.setTextColor(WHITE);
display.setCursor(0, 40);
display.println(errorMsg);
display.display();
}