feat: implement initial ESP32 school bell system with web UI, DFPlayer control, RTC, LittleFS, and OTA.
This commit is contained in:
113
src/main.cpp
113
src/main.cpp
@@ -1,15 +1,16 @@
|
|||||||
// src/main.cpp
|
// src/main.cpp
|
||||||
// Bel Sekolah ESP32 - final version
|
// Bel Sekolah ESP32 - final version
|
||||||
// Pins:
|
// Pins:
|
||||||
// RESET_PIN = 5 (hold >15s -> reset admin credentials)
|
// TEST_BUTTON = 18 (click -> toggle relay, long press -> play test MP3)
|
||||||
// STATUS_LED_PIN = 6
|
// RESET_BUTTON = 0 (long press >15s -> reset admin credentials)
|
||||||
// RELAY_PIN = 7 (active LOW)
|
// STATUS_LED_PIN = 26
|
||||||
// DFPLAYER_RX_PIN = 15
|
// RELAY_PIN = 19 (active LOW)
|
||||||
// DFPLAYER_TX_PIN = 16
|
// DFPLAYER_RX_PIN = 16
|
||||||
// BUSY_PIN = 17 (LOW = busy)
|
// DFPLAYER_TX_PIN = 17
|
||||||
//esp32 sda 21
|
// BUSY_PIN = 5 (LOW = busy)
|
||||||
//esp32 scl 22
|
// esp32 sda 21
|
||||||
//MCU adalah Wemos ESP32 mini
|
// esp32 scl 22
|
||||||
|
// MCU adalah Wemos ESP32 mini
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
@@ -35,7 +36,8 @@
|
|||||||
#define DFPLAYER_TX_PIN 17 //2 df
|
#define DFPLAYER_TX_PIN 17 //2 df
|
||||||
#define RELAY_PIN 19
|
#define RELAY_PIN 19
|
||||||
#define BUSY_PIN 5 //must high at boot (strapping pin)
|
#define BUSY_PIN 5 //must high at boot (strapping pin)
|
||||||
#define RESET_PIN 18
|
#define TEST_BUTTON 18
|
||||||
|
#define RESET_BUTTON 0
|
||||||
#define BUZZER_PIN 23
|
#define BUZZER_PIN 23
|
||||||
|
|
||||||
#define RESET_HOLD_MS 15000UL
|
#define RESET_HOLD_MS 15000UL
|
||||||
@@ -74,12 +76,19 @@ bool buzzerState = false;
|
|||||||
bool adminResetBlinking = false;
|
bool adminResetBlinking = false;
|
||||||
unsigned long adminResetEndTime = 0;
|
unsigned long adminResetEndTime = 0;
|
||||||
|
|
||||||
// Button flags
|
// Button flags for TEST_BUTTON
|
||||||
volatile bool btnClickPending = false;
|
volatile bool testBtnClickPending = false;
|
||||||
volatile bool btnLongPressPending = false;
|
volatile bool testBtnLongPressPending = false;
|
||||||
|
|
||||||
// OneButton instance for RESET_PIN
|
// Button flags for RESET_BUTTON
|
||||||
OneButton button(RESET_PIN, true);
|
volatile bool resetBtnLongPressPending = false;
|
||||||
|
|
||||||
|
// Manual relay toggle state (separate from automatic relay control)
|
||||||
|
bool manualRelayOn = false;
|
||||||
|
|
||||||
|
// OneButton instances
|
||||||
|
OneButton testButton(TEST_BUTTON, true);
|
||||||
|
OneButton resetButton(RESET_BUTTON, true);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// WiFi Channel Selection
|
// WiFi Channel Selection
|
||||||
@@ -659,7 +668,8 @@ void setup(){
|
|||||||
pinMode(RELAY_PIN, OUTPUT);
|
pinMode(RELAY_PIN, OUTPUT);
|
||||||
digitalWrite(RELAY_PIN, HIGH); // relay active LOW, so HIGH = off
|
digitalWrite(RELAY_PIN, HIGH); // relay active LOW, so HIGH = off
|
||||||
pinMode(BUSY_PIN, INPUT_PULLUP); // busy pin input (LOW when busy)
|
pinMode(BUSY_PIN, INPUT_PULLUP); // busy pin input (LOW when busy)
|
||||||
pinMode(RESET_PIN, INPUT_PULLUP);
|
pinMode(TEST_BUTTON, INPUT_PULLUP);
|
||||||
|
pinMode(RESET_BUTTON, INPUT_PULLUP);
|
||||||
pinMode(BUZZER_PIN, OUTPUT);
|
pinMode(BUZZER_PIN, OUTPUT);
|
||||||
digitalWrite(BUZZER_PIN, LOW);
|
digitalWrite(BUZZER_PIN, LOW);
|
||||||
|
|
||||||
@@ -732,16 +742,19 @@ void setup(){
|
|||||||
ArduinoOTA.begin();
|
ArduinoOTA.begin();
|
||||||
|
|
||||||
|
|
||||||
// Setup OneButton callbacks
|
// Setup TEST_BUTTON callbacks (click=toggle relay, long press=play test MP3)
|
||||||
button.setPressMs(15000); // Set long press to 15 seconds
|
testButton.setPressMs(2000); // 2 seconds for test MP3 play
|
||||||
button.attachClick([]() {
|
testButton.attachClick([]() {
|
||||||
// Just set flag, don't do heavy work here
|
testBtnClickPending = true;
|
||||||
btnClickPending = true;
|
});
|
||||||
|
testButton.attachLongPressStart([]() {
|
||||||
|
testBtnLongPressPending = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
button.attachLongPressStart([]() {
|
// Setup RESET_BUTTON callbacks (long press=reset admin credentials)
|
||||||
// Just set flag
|
resetButton.setPressMs(15000); // 15 seconds for admin reset
|
||||||
btnLongPressPending = true;
|
resetButton.attachLongPressStart([]() {
|
||||||
|
resetBtnLongPressPending = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -754,21 +767,45 @@ void setup(){
|
|||||||
void loop(){
|
void loop(){
|
||||||
ArduinoOTA.handle();
|
ArduinoOTA.handle();
|
||||||
|
|
||||||
ws.cleanupClients();
|
// Handle OneButton instances
|
||||||
|
testButton.tick();
|
||||||
|
resetButton.tick();
|
||||||
|
|
||||||
// Handle OneButton
|
// Process TEST_BUTTON click: toggle relay manually
|
||||||
button.tick();
|
if (testBtnClickPending) {
|
||||||
|
testBtnClickPending = false;
|
||||||
// Process button events outside of callback
|
manualRelayOn = !manualRelayOn;
|
||||||
if (btnClickPending) {
|
if (manualRelayOn) {
|
||||||
btnClickPending = false;
|
digitalWrite(RELAY_PIN, LOW); // relay active LOW
|
||||||
Serial.println("[BUTTON] Click detected: playing track 1000");
|
relayOn = true;
|
||||||
playTrack(1000, "Manual Click");
|
Serial.println("[BUTTON] Manual relay ON");
|
||||||
|
DynamicJsonDocument d(256);
|
||||||
|
d["type"] = "log";
|
||||||
|
d["msg"] = "🔊 Relay dinyalakan manual";
|
||||||
|
sendJsonWs(d);
|
||||||
|
} else {
|
||||||
|
digitalWrite(RELAY_PIN, HIGH); // relay off
|
||||||
|
relayOn = false;
|
||||||
|
Serial.println("[BUTTON] Manual relay OFF");
|
||||||
|
DynamicJsonDocument d(256);
|
||||||
|
d["type"] = "log";
|
||||||
|
d["msg"] = "🔇 Relay dimatikan manual";
|
||||||
|
sendJsonWs(d);
|
||||||
|
}
|
||||||
|
broadcastStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (btnLongPressPending) {
|
// Process TEST_BUTTON long press: play test MP3
|
||||||
btnLongPressPending = false;
|
if (testBtnLongPressPending) {
|
||||||
Serial.println("[BUTTON] Long press detected: resetting admin credentials");
|
testBtnLongPressPending = false;
|
||||||
|
Serial.println("[BUTTON] Long press detected: playing track 1000");
|
||||||
|
playTrack(1000, "Manual Test");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process RESET_BUTTON long press: reset admin credentials
|
||||||
|
if (resetBtnLongPressPending) {
|
||||||
|
resetBtnLongPressPending = false;
|
||||||
|
Serial.println("[BUTTON] Reset button long press: resetting admin credentials");
|
||||||
resetAdminToDefault();
|
resetAdminToDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -842,8 +879,8 @@ void loop(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// release relay if conditions met
|
// release relay if conditions met (but not if manual mode is active)
|
||||||
if (!busy && relayOn && millis() > relayHoldUntil) {
|
if (!busy && relayOn && millis() > relayHoldUntil && !manualRelayOn) {
|
||||||
digitalWrite(RELAY_PIN, HIGH); // OFF
|
digitalWrite(RELAY_PIN, HIGH); // OFF
|
||||||
relayOn = false;
|
relayOn = false;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user