Mode 7 Hari

This commit is contained in:
2025-12-22 12:22:49 +08:00
parent 034ad6f9a3
commit 179d586cf8

View File

@@ -76,6 +76,15 @@ bool ledState = false;
unsigned long lastBuzzerBeep = 0;
bool buzzerState = false;
// MP3 playback error detection (via DFPlayer serial messages)
bool playbackError = false;
unsigned long playbackErrorEndTime = 0;
// DFPlayer auto-recovery
bool dfPlayerNeedsRecovery = false;
unsigned long lastRecoveryAttempt = 0;
const unsigned long RECOVERY_INTERVAL_MS = 5000; // Try recovery every 5 seconds
// Admin reset blinking effect
bool adminResetBlinking = false;
unsigned long adminResetEndTime = 0;
@@ -230,12 +239,117 @@ void saveSchedules() {
//////////////////////////////////////////////////////////////////////////
// DFPlayer
//////////////////////////////////////////////////////////////////////////
// Parse DFPlayer messages and return error description
String getDFPlayerError(uint8_t type, int value) {
switch (type) {
case DFPlayerError:
switch (value) {
case Busy: return "Card not found";
case Sleeping: return "Sleeping";
case SerialWrongStack: return "Wrong Stack";
case CheckSumNotMatch: return "Checksum Error";
case FileIndexOut: return "File Index Out";
case FileMismatch: return "File Mismatch";
case Advertise: return "In Advertise";
default: return "Unknown Error";
}
default:
return "";
}
}
// Flag to prevent CardInserted loop after recovery
bool recoveryJustDone = false;
// Check DFPlayer for messages and handle errors
void checkDFPlayerMessage() {
static bool sdCardPresent = true; // Assume present at start
if (myDFPlayer.available()) {
uint8_t type = myDFPlayer.readType();
int value = myDFPlayer.read();
if (type == DFPlayerError) {
String errorMsg = getDFPlayerError(type, value);
Serial.printf("[MP3] DFPlayer Error: %s (code: %d)\n", errorMsg.c_str(), value);
// Trigger error state for SD card related errors
if (value == Busy || value == FileIndexOut || value == FileMismatch) {
playbackError = true;
dfPlayerNeedsRecovery = true;
playbackErrorEndTime = millis() + 10000UL;
sdCardPresent = false;
// Notify via WebSocket
DynamicJsonDocument d(256);
d["type"] = "log";
d["msg"] = "⚠️ DFPlayer Error: " + errorMsg;
sendJsonWs(d);
}
} else if (type == DFPlayerCardInserted) {
Serial.println("[MP3] SD Card inserted");
// Skip if recovery was just done (to prevent loop from begin())
if (recoveryJustDone) {
recoveryJustDone = false;
Serial.println("[MP3] Ignoring CardInserted after recovery");
} else if (!sdCardPresent || playbackError) {
// Only trigger recovery if card was previously removed or there's an error
dfPlayerNeedsRecovery = true;
DynamicJsonDocument d(256);
d["type"] = "log";
d["msg"] = "💾 SD Card terdeteksi, mencoba recovery...";
sendJsonWs(d);
}
sdCardPresent = true;
} else if (type == DFPlayerCardRemoved) {
Serial.println("[MP3] SD Card removed");
sdCardPresent = false;
playbackError = true;
dfPlayerNeedsRecovery = true;
playbackErrorEndTime = millis() + 10000UL;
DynamicJsonDocument d(256);
d["type"] = "log";
d["msg"] = "⚠️ SD Card dilepas!";
sendJsonWs(d);
} else if (type == DFPlayerPlayFinished) {
Serial.printf("[MP3] Track %d finished\n", value);
isPlaying = false;
}
}
}
void initDFPlayer() {
dfSerial.begin(9600, SERIAL_8N1, DFPLAYER_RX_PIN, DFPLAYER_TX_PIN);
vTaskDelay(pdMS_TO_TICKS(200));
myDFPlayer.setTimeOut(600); // Fix for clone MP3 players
if (myDFPlayer.begin(dfSerial)) {
myDFPlayer.volume(30); // 0..30 (Max volume)
dfPlayerNeedsRecovery = false;
Serial.println("[MP3] DFPlayer initialized successfully");
} else {
dfPlayerNeedsRecovery = true;
Serial.println("[MP3] DFPlayer initialization failed");
}
}
void recoverDFPlayer() {
Serial.println("[MP3] Attempting DFPlayer recovery...");
myDFPlayer.setTimeOut(600);
if (myDFPlayer.begin(dfSerial)) {
myDFPlayer.volume(30);
dfPlayerNeedsRecovery = false;
playbackError = false;
recoveryJustDone = true; // Set flag to ignore next CardInserted event
Serial.println("[MP3] DFPlayer recovery successful!");
// Notify via WebSocket
DynamicJsonDocument d(256);
d["type"] = "log";
d["msg"] = "✅ DFPlayer pulih! Sistem siap kembali.";
sendJsonWs(d);
} else {
Serial.println("[MP3] DFPlayer recovery failed");
}
}
@@ -250,8 +364,11 @@ void playTrack(uint16_t track, const char* desc) {
relayHoldUntil = millis() + 5000UL;
}
myDFPlayer.playMp3Folder(track); // as requested
myDFPlayer.playMp3Folder(track);
isPlaying = true;
playbackError = false; // Reset error state
dfPlayerNeedsRecovery = false; // Reset recovery flag for new playback attempt
// notify
DynamicJsonDocument doc(256);
doc["type"] = "log";
@@ -797,6 +914,9 @@ void loop(){
testButton.tick();
resetButton.tick();
// Check for DFPlayer messages (errors, card insert/remove, etc.)
checkDFPlayerMessage();
// Process TEST_BUTTON click: toggle relay manually
if (testBtnClickPending) {
testBtnClickPending = false;
@@ -920,8 +1040,18 @@ void loop(){
relayOn = false;
}
// Buzzer warning if date < 2025
if (now.year() < 2025) {
// DFPlayer auto-recovery: reset and set volume after error
if (dfPlayerNeedsRecovery && millis() - lastRecoveryAttempt >= RECOVERY_INTERVAL_MS) {
lastRecoveryAttempt = millis();
recoverDFPlayer();
// Recovery done - stop buzzer
playbackError = false;
playbackErrorEndTime = 0;
}
// Buzzer warning if date < 2025 OR playback error
bool buzzerCondition = (now.year() < 2025) || (playbackError && millis() < playbackErrorEndTime);
if (buzzerCondition) {
if (millis() - lastBuzzerBeep >= 2000) {
lastBuzzerBeep = millis();
buzzerState = true;