Mode 7 Hari
This commit is contained in:
136
src/main.cpp
136
src/main.cpp
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user