FT-1 TPQ Al-Munawwarah

Firmware innoiti FT-1 untuk TPQ Al-Munawwarah, tidak ada batasan presensi harian

main7_NoBatas.ino INO FILE
#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_Fingerprint.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeSansBold12pt7b.h> // Font kustom
#include <Fonts/FreeSansBold9pt7b.h> // Font kustom
#include <Fonts/FreeSerif9pt7b.h> // Font kustom
#include <Fonts/FreeSans9pt7b.h> // Font kustom
#include <NTPClient.h>
#include <WiFiUdp.h> 
#include <Fonts/TomThumb.h>  // Menyertakan font TomThumb

#define MODEM_RX 16
#define MODEM_TX 17
#define mySerial Serial2 // gunakan untuk ESP32

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

#define BUZZER_PIN 5 // Pin untuk buzzer
#define LED_PIN 18 // Pin untuk buzzer

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&mySerial);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

// Tambahkan untuk NTP Client
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 25200, 60000); // GMT+7 (25200 detik)

// Struktur data untuk menyimpan ID dan nama
struct FingerprintData {
  uint16_t id;
  const char* name;
};

// Daftar ID dan nama
FingerprintData userData[] = {
  {1, "U. Zidan"},
  {2, "U. Andri"},
  {3, "U. Azril"},
  {4, "U. Zakka"},
  {5, "U. Wasis"},
  {6, "U. Tain"},
  {7, "U. Umrotul"},
  {8, "U. Rista"},
  {9, "U. Indah"},
  {10, "U. Arum"},
  {11, "U. Wulan"},
  {21, "Lonny"},
  {22, "Aini"},
  {23, "Ahmad"},
  {24, "Azzam"},
  {25, "Rifqi"},
  {26, "Nazwa"},
  {27, "Alby"},
  {28, "Vero"},
  {29, "Iyo"},
  {30, "Asya"},
  {31, "Calingga"},
  {32, "Kiran"},
  {33, "Elang"},
  {34, "Endra"},
  {35, "Rohit"},
  {36, "Asa"},
  {37, "Afa"},
  {38, "Kevin"},
  {39, "Keysha"},
  {40, "Neneng"},
  {41, "Laras"},
  {42, "Abror"},
  {43, "Ahsan"},
  {44, "Calief"},
  {45, "Hafy"},
  {46, "Haikal"},
  {47, "Rizqi"},
  {48, "Nanda"},
  {49, "Kaisa"},
  {50, "Nayla"},
  {51, "Novi"},
  {52, "Vica"},
  {53, "Nuril"},
  {54, "Fino"},
  {55, "Raffi"},
  {56, "Rafif"},
  {57, "Bahi"},
  {58, "Shofia"},
  {59, "Syahidah"},
  {60, "Alfath"},
  {61, "Syirin"},
  {62, "Uwais"},
  {63, "Vicko"},
  {64, "Yolla"},
  {65, "Niel"},
  {66, "Wihra"},
  {67, "Fina"},

  {120, "Zara"},
  {121, "Huda"},
  {122, "Kalya"}

};

const int userCount = sizeof(userData) / sizeof(userData[0]); // Hitung jumlah data

// Informasi Wi-Fi
const char* ssid = "CreativeNet";       // Ganti dengan nama Wi-Fi
const char* password = "Creanet123"; // Ganti dengan password Wi-Fi
const char* serverName = "http://zidcreative.com/simunawwarah/jurnalsantri/absensi/absensi.php"; // URL PHP server

// Variabel untuk menyimpan waktu absensi terakhir
unsigned long lastAttendanceTime[130] = {0}; // Menyimpan waktu absensi per ID pengguna

void setup() {
  Serial.begin(9600);
  while (!Serial);
  delay(100);
  Serial.println("\n\nzidCreative Innoiti TF 1 Verifikasi");

  // Koneksi Wi-Fi
  Serial.print("Menghubungkan ke Wi-Fi");
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWi-Fi Terhubung!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Mulai komunikasi dengan sensor sidik jari
  finger.begin(57600);
  if (finger.verifyPassword()) {
    Serial.println("Sensor sidik jari ditemukan!");
  } else {
    Serial.println("Sensor sidik jari tidak ditemukan :(");
    while (1) { delay(1); }
  }

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);
  }
  display.clearDisplay();
  display.setFont(&FreeSansBold12pt7b); // Menggunakan font kustom
  display.setTextColor(WHITE);
  display.setCursor(5, 20);
  display.println("Innoiti");
  display.setCursor(5, 45);
  display.println("FT1");
  display.display();

  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(BUZZER_PIN, LOW);
  digitalWrite(LED_PIN, LOW);

  timeClient.begin();
}

void loop() {
  // Tunggu sidik jari
  uint8_t result = getFingerprintID();
  if (result == FINGERPRINT_OK) {
    handleAttendance(); // Tangani absensi
  } else if (result == FINGERPRINT_NOTFOUND) {
    displayError("Siapa Ya?");
    playErrorSound();
  } else {
    displayTime();
  }
  delay(1000); // Tunggu 1 detik sebelum mencoba lagi
}

void handleAttendance() {
  // Periksa apakah sudah absen hari ini
  int userID = finger.fingerID;
  unsigned long currentTime = timeClient.getEpochTime();
  unsigned long currentDay = currentTime / 86400; // Hari sejak 1 Jan 1970

  //if (currentDay == lastAttendanceTime[userID]) {
    // Jika sudah absen hari ini
    //displaySudahAbsen();
    //playErrorSound();
    //return;
  //}

  // Proses absensi jika belum absen hari ini
  lastAttendanceTime[userID] = currentDay; // Simpan waktu absensi
  displayFingerprintID(); // Tampilkan ID di OLED
  playSuccessSound();     // Bunyi sukses
}

// Fungsi untuk menampilkan pesan kesalahan
void displayError(String errorMsg) {
  display.clearDisplay();
  display.setFont(&FreeSansBold12pt7b);
  display.setTextColor(WHITE);

  display.setCursor(0, 40);
  display.println(errorMsg);
  display.display();
}

// Fungsi untuk menampilkan pesan kesalahan
void displaySudahAbsen() {
  display.clearDisplay();
  display.setFont(&FreeSansBold9pt7b);
  display.setTextColor(WHITE);

  display.setCursor(5, 20);
  display.println("Kamu sudah");
  display.setCursor(5, 40);
  display.println("absen hari ini");
  display.setCursor(5, 60);
  display.println("Besok lagi ya...");
  display.display();
}

uint8_t getFingerprintID() {
  uint8_t p = finger.getImage();
  if (p != FINGERPRINT_OK) {
    if (p == FINGERPRINT_NOFINGER) {
      Serial.println("Tidak ada jari yang terdeteksi.");
    }
    return p;
  }

  p = finger.image2Tz();
  if (p != FINGERPRINT_OK) {
    Serial.println("Gagal mengonversi gambar menjadi template.");
    return p;
  }

  p = finger.fingerFastSearch();
  if (p == FINGERPRINT_OK) {
    Serial.print("Sidik jari ditemukan dengan ID: ");
    Serial.println(finger.fingerID);
    Serial.print("Confidence: ");
    Serial.println(finger.confidence);
  }
  return p;
}

const char* getNameByID(uint16_t id) {
  for (int i = 0; i < userCount; i++) {
    if (userData[i].id == id) {
      return userData[i].name;
    }
  }
  return "-";
}

void displayFingerprintID() {
  display.clearDisplay();
  display.setFont(&FreeSansBold12pt7b);
  display.setTextColor(WHITE);

  const char* userName = getNameByID(finger.fingerID);

  display.setCursor(5, 20);
  display.println("************");
  display.setCursor(5, 35);
  display.println("Tunggu");
  display.setCursor(5, 62);
  display.println("************");
  display.display();

  sendData(finger.fingerID, userName);

  Serial.print("ID: ");
  Serial.print(finger.fingerID);
  Serial.print(", Nama: ");
  Serial.println(userName);
}

void sendData(uint16_t id_jari, const char* name) {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi tidak terhubung! Mencoba reconnect...");
    WiFi.disconnect();
    WiFi.reconnect();
    delay(5000); // Tunggu 5 detik sebelum mencoba lagi
    if (WiFi.status() != WL_CONNECTED) {
      Serial.println("WiFi gagal terhubung. Data tidak dikirim.");
      displayError("WiFi Error!");
      return;
    }
  }

  HTTPClient http;
  http.begin(serverName);
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");

  String postData = "id_jari=" + String(id_jari) + "&name=" + String(name);
  
  // Kirim data hanya 1 kali
  int httpResponseCode = http.POST(postData);
  
  if (httpResponseCode > 0) {
    Serial.print("Data berhasil dikirim! HTTP Response: ");
    Serial.println(httpResponseCode);

    // Tambahkan notifikasi OLED
    const char* userName = getNameByID(finger.fingerID);
    displaySuccess(userName);
    
  } else {
    Serial.println("Gagal mengirim data.");
    displayError("restart!");
    playErrorSound();
  }

  http.end(); // Tutup HTTPClient
}

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();
  timeClient.update();
  String formattedTime = timeClient.getFormattedTime();

  display.setCursor(2, 15);
  display.setFont(&FreeSerif9pt7b);
  display.println("Al-Munawwarah");

  display.setCursor(15, 42);
  display.setFont(&FreeSansBold12pt7b);
  display.println(formattedTime);

  display.setCursor(7, 60);
  display.setFont(&FreeSansBold9pt7b);
  display.println(">>>>>>>>>>");
  

  display.display();
}

void displaySuccess(const char* message) {
  display.clearDisplay();

  int centerX = display.width() / 6;
  int centerY = display.height() / 4;
  
  // Gambar lingkaran putih lebih kecil sebagai background
  display.fillCircle(centerX, centerY, 12, WHITE);  
  display.drawCircle(centerX, centerY, 12, BLACK); // Garis luar hitam

  display.display();
  delay(100);

  // Animasi menggambar tanda centang lebih tebal
  for (int i = 0; i <= 10; i++) {
    display.fillCircle(centerX, centerY, 10, WHITE);  
    display.drawCircle(centerX, centerY, 10, BLACK); // Garis luar hitam

    int startX = centerX - 5;
    int startY = centerY;
    int midX = centerX - 2;
    int midY = centerY + 4;
    int endX = centerX + 6;
    int endY = centerY - 6;

    int drawMidX = startX + (midX - startX) * i / 10;
    int drawMidY = startY + (midY - startY) * i / 10;

    // Gambar bagian pertama centang (garis ke tengah) lebih tebal
    for (int j = -1; j <= 1; j++) {  
      display.drawLine(startX, startY + j, drawMidX, drawMidY + j, BLACK);
    }

    if (i > 5) {
      int drawEndX = midX + (endX - midX) * (i - 5) / 5;
      int drawEndY = midY + (endY - midY) * (i - 5) / 5;

      // Gambar bagian kedua centang (garis dari tengah ke ujung) lebih tebal
      for (int j = -1; j <= 1; j++) {  
        display.drawLine(drawMidX, drawMidY + j, drawEndX, drawEndY + j, BLACK);
      }
    }

    display.display();
    delay(50);
  }

  // Tampilkan pesan sukses setelah animasi selesai
  display.setCursor(centerX + 15, centerY + 14);
  display.println("-----------");
  display.setCursor(13, centerY + 35); // Pesan lebih ke bawah
  display.setTextColor(WHITE);
  display.println(message);
  display.display();
}

void displayError(const char* message) {
  display.clearDisplay();
  display.setFont(&FreeSansBold9pt7b);
  display.setTextColor(WHITE);
  display.setCursor(10, 15);
  display.println("Gagal!");
  display.setCursor(10, 35);
  display.println("--------");
  display.setCursor(10, 40);
  display.println(message);
  display.display();
}