TKK_E32230908/Iot_Nawasena/rfid_suara.ino

283 lines
7.6 KiB
C++

#include <SPI.h>
#include <MFRC522.h>
#include "DFRobotDFPlayerMini.h"
#include <WiFi.h>
#include <ArduinoJson.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PubSubClient.h>
/* ================= CONFIGURATION ================= */
const char* ssid = "OPPO A57";
const char* password = "11223344";
const char* mqtt_server = "192.168.254.121";
const int mqtt_port = 1883;
/* ================= OBJECTS & PINS ================= */
#define SS_PIN 5
#define RST_PIN 4
#define BUZZER_PIN 13
MFRC522 rfid(SS_PIN, RST_PIN);
HardwareSerial mySerial(2);
DFRobotDFPlayerMini dfplayer;
LiquidCrystal_I2C lcd(0x27, 16, 2);
WiFiClient espClient;
PubSubClient client(espClient);
int merah = 23, hijau = 22, biru = 21;
/* ================= STATE & TIMERS ================= */
String mode = "standby";
unsigned long lastWifiCheck = 0;
unsigned long lastHeartbeat = 0;
bool isAudioPlaying = false;
unsigned long audioStartTime = 0;
const unsigned long AUDIO_DURATION = 3500; // jeda 3 detik
String lastUID = "";
unsigned long lastScanTime = 0;
const unsigned long SCAN_DELAY = 3000; // jeda 3 detik
String scrollMessage = " NAWASENA SMART LIBRARY SYSTEM - BAKORWIL III MALANG ";
unsigned long lastScroll = 0;
int scrollCursor = 0;
/* ================= HELPERS ================= */
void setRGB(bool r, bool g, bool b) {
digitalWrite(merah, r);
digitalWrite(hijau, g);
digitalWrite(biru, b);
}
void beep(int duration) {
digitalWrite(BUZZER_PIN, HIGH);
delay(duration);
digitalWrite(BUZZER_PIN, LOW);
}
void playTrack(int track) {
if (isAudioPlaying) return;
Serial.print("🔊 Memutar Track: "); Serial.println(track);
dfplayer.play(track);
isAudioPlaying = true;
audioStartTime = millis();
}
void applyModeVisual() {
if (mode == "admin") setRGB(1, 1, 0);
else if (mode == "scan_member") setRGB(0, 1, 0);
else if (mode == "wait") setRGB(1, 0, 0);
else if (mode == "identified") setRGB(0, 1, 1);
else setRGB(0, 0, 1);
}
/* ================= MQTT CALLBACK ================= */
void callback(char* topic, byte* payload, unsigned int length) {
String message = "";
for (int i = 0; i < length; i++) message += (char)payload[i];
Serial.println("📥 MQTT Diterima [" + String(topic) + "]: " + message);
if (String(topic) == "rfid/mode/set") {
mode = message;
lcd.clear();
if (mode == "scan_member") playTrack(6);
else if (mode == "admin") playTrack(5);
applyModeVisual();
}
if (String(topic) == "rfid/status") {
lcd.clear();
if (message == "valid") {
mode = "identified";
lcd.setCursor(0, 0); lcd.print(" KARTU TERBACA ");
lcd.setCursor(0, 1); lcd.print(" SILAHKAN... ");
playTrack(4);
}
else if (message == "success" || message == "finish") {
setRGB(0, 1, 0);
lcd.setCursor(0, 0); lcd.print(" TRANSAKSI OK ");
lcd.setCursor(0, 1); lcd.print(" TERIMA KASIH ");
playTrack(8);
delay(2500);
mode = "standby";
}
else if (message == "registered") {
setRGB(0, 1, 0);
lcd.setCursor(0, 0); lcd.print(" REGISTRASI OK ");
lcd.setCursor(0, 1); lcd.print(" KARTU TERTAUT ");
playTrack(7);
delay(2500);
mode = "standby";
}
else if (message == "error" || message == "failed") {
setRGB(1, 0, 0);
lcd.setCursor(0, 0); lcd.print(" AKSES DITOLAK ");
lcd.setCursor(0, 1); lcd.print(" COBA LAGI... ");
playTrack(3);
delay(2500);
}
lcd.clear();
applyModeVisual();
}
}
void reconnectMQTT() {
while (!client.connected()) {
Serial.print("🔄 Menghubungkan MQTT...");
String clientId = "ESP32_Nawasena_" + String(random(0xffff), HEX);
if (client.connect(clientId.c_str(), NULL, NULL, "rfid/device/status", 1, true, "offline")) {
Serial.println("TERHUBUNG!");
client.subscribe("rfid/mode/set");
client.subscribe("rfid/status");
client.subscribe("rfid/scan/admin");
client.publish("rfid/device/status", "online", true);
} else {
Serial.print("Gagal, rc="); Serial.print(client.state());
delay(5000);
}
}
}
/* ================= CORE FUNCTIONS ================= */
void handleRFID() {
String uid = "";
for (byte i = 0; i < rfid.uid.size; i++) {
uid += (rfid.uid.uidByte[i] < 0x10 ? "0" : "");
uid += String(rfid.uid.uidByte[i], HEX);
}
uid.toUpperCase();
if (uid == lastUID && (millis() - lastScanTime < SCAN_DELAY)) {
// Sesi dihentikan dengan aman jika kartu yang sama di-tap berulang kali
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
return;
}
// Perbarui waktu scan terakhir yang sukses
lastUID = uid;
lastScanTime = millis();
Serial.println("🆔 UID Terdeteksi: " + uid);
beep(150);
setRGB(1, 0, 1);
lcd.clear();
lcd.setCursor(0, 0); lcd.print(" MEMPROSES ");
lcd.setCursor(0, 1); lcd.print(" MOHON TUNGGU.. ");
// Publikasikan data murni berdasarkan mode via MQTT saja (API Dihapus)
if (mode == "admin") {
client.publish("rfid/scan/admin", uid.c_str());
}
else if (mode == "scan_member") {
client.publish("rfid/scan/member", uid.c_str());
}
else {
// Default fallback jika standby atau mode lainnya ke topic umum
client.publish("rfid/scan/general", uid.c_str());
}
delay(500);
applyModeVisual();
rfid.PICC_HaltA();
rfid.PCD_StopCrypto1();
}
void updateScrollText() {
if (millis() - lastScroll > 350) {
lastScroll = millis();
lcd.setCursor(0, 1);
String displayMsg = scrollMessage.substring(scrollCursor, scrollCursor + 16);
if (displayMsg.length() < 16) {
displayMsg += scrollMessage.substring(0, 16 - displayMsg.length());
}
lcd.print(displayMsg);
scrollCursor++;
if (scrollCursor >= scrollMessage.length()) scrollCursor = 0;
}
}
/* ================= MAIN PROGRAM ================= */
void setup() {
Serial.begin(115200);
pinMode(merah, OUTPUT); pinMode(hijau, OUTPUT); pinMode(biru, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
setRGB(1, 1, 1);
Wire.begin(32, 33);
lcd.init(); lcd.backlight();
lcd.setCursor(0, 0); lcd.print(" NAWASENA SMART ");
lcd.setCursor(0, 1); lcd.print(" BOOTING... ");
mySerial.begin(9600, SERIAL_8N1, 25, 26);
if (dfplayer.begin(mySerial)) {
dfplayer.volume(30);
}
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); }
client.setServer(mqtt_server, mqtt_port);
client.setCallback(callback);
SPI.begin(18, 15, 19, 5);
rfid.PCD_Init();
delay(1000);
playTrack(1);
lcd.clear();
applyModeVisual();
}
void loop() {
if (!client.connected()) {
reconnectMQTT();
}
client.loop();
if (millis() - lastHeartbeat > 30000) {
lastHeartbeat = millis();
if(client.connected()) {
client.publish("rfid/device/status", "online", true);
}
}
if (isAudioPlaying && (millis() - audioStartTime >= AUDIO_DURATION)) {
isAudioPlaying = false;
}
// Logika Tampilan LCD
if (mode != "identified" && mode != "wait") {
lcd.setCursor(0, 0);
if (mode == "scan_member") {
lcd.print(" TAP KARTU ANDA ");
lcd.setCursor(0, 1);
lcd.print(" ( ANGGOTA ) ");
} else if (mode == "admin") {
lcd.print(" MODE REGISTRASI");
lcd.setCursor(0, 1);
lcd.print(" SCAN KARTU... ");
} else {
lcd.print(" NAWASENA READY ");
updateScrollText();
}
}
if (!isAudioPlaying) {
if (rfid.PICC_IsNewCardPresent()) {
if (rfid.PICC_ReadCardSerial()) {
handleRFID();
}
}
}
}