feat(doorbell): add staged boot sequence and refactor main loop
This commit is contained in:
@@ -22,6 +22,11 @@
|
||||
#define HINT_MIN_BRIGHTNESS 30
|
||||
#define HINT_MAX_BRIGHTNESS 60
|
||||
|
||||
// ── Loop yield (prevents Task Watchdog on ESP32) ──
|
||||
#ifndef LOOP_YIELD_MS
|
||||
#define LOOP_YIELD_MS 10
|
||||
#endif
|
||||
|
||||
// ── WiFi credential struct (populated in each board's secrets.h) ──
|
||||
struct WiFiCred {
|
||||
const char* ssid;
|
||||
|
||||
@@ -26,12 +26,22 @@ void DoorbellLogic::begin(
|
||||
Serial.println(F(" *** DEBUG MODE — _test topics ***"));
|
||||
Serial.println(F("========================================\n"));
|
||||
|
||||
// Display
|
||||
// Stage 1: Display init
|
||||
setBootStage(BootStage::INIT_DISPLAY);
|
||||
{
|
||||
ScreenState temp;
|
||||
temp.bootStage = BootStage::SPLASH;
|
||||
_display->render(temp);
|
||||
}
|
||||
_display->begin();
|
||||
delay(LOOP_YIELD_MS);
|
||||
|
||||
// Network
|
||||
// Stage 2: Network init
|
||||
setBootStage(BootStage::INIT_NETWORK);
|
||||
_net.begin(creds, credCount);
|
||||
|
||||
// Stage 3: WiFi connect
|
||||
setBootStage(BootStage::CONNECTING_WIFI);
|
||||
if(_net.isConnected()) {
|
||||
_net.syncNTP();
|
||||
Serial.printf("[NET] WiFi:%s RSSI:%d IP:%s\n", _net.getSSID().c_str(), _net.getRSSI(),
|
||||
@@ -51,9 +61,16 @@ void DoorbellLogic::begin(
|
||||
Serial.printf("[CONFIG] SILENCE_URL: %s\n", _silenceUrl.c_str());
|
||||
Serial.printf("[CONFIG] ADMIN_URL: %s\n", _adminUrl.c_str());
|
||||
|
||||
// Stage 4: Ready
|
||||
setBootStage(BootStage::READY);
|
||||
delay(LOOP_YIELD_MS);
|
||||
|
||||
// Boot status
|
||||
flushStatus(String("BOOTED — ") + _net.getSSID() + " " + _net.getIP()
|
||||
+ " RSSI:" + String(_net.getRSSI()));
|
||||
|
||||
// Stage 5: Done (transition to OFF happens in finishBoot)
|
||||
setBootStage(BootStage::DONE);
|
||||
}
|
||||
|
||||
void DoorbellLogic::finishBoot() {
|
||||
@@ -304,3 +321,49 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ── Hold gesture for silencing ─────────────────────────────────
|
||||
|
||||
bool DoorbellLogic::updateHold(const TouchEvent& evt) {
|
||||
if(_state.deviceState != DeviceState::ALERTING)
|
||||
return false;
|
||||
|
||||
static int holdStartX = -1;
|
||||
static int holdStartY = -1;
|
||||
|
||||
HoldState h = _display->updateHold(HOLD_TO_SILENCE_MS);
|
||||
|
||||
if(h.completed) {
|
||||
silenceAlert();
|
||||
holdStartX = -1;
|
||||
holdStartY = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(h.started) {
|
||||
holdStartX = evt.x;
|
||||
holdStartY = evt.y;
|
||||
}
|
||||
|
||||
if(holdStartX >= 0) {
|
||||
_display->updateHint(holdStartX, holdStartY, h.active);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// ── Serial console helper ───────────────────────────────────────
|
||||
|
||||
void DoorbellLogic::processSerial() {
|
||||
if(Serial.available()) {
|
||||
String cmd = Serial.readStringUntil('\n');
|
||||
cmd.trim();
|
||||
if(cmd.length() > 0)
|
||||
onSerialCommand(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
void DoorbellLogic::setBootStage(BootStage stage) {
|
||||
_state.bootStage = stage;
|
||||
_display->render(_state);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ public:
|
||||
void finishBoot();
|
||||
/// Serial debug console.
|
||||
void onSerialCommand(const String& cmd);
|
||||
/// Process Serial input — call each loop iteration.
|
||||
void processSerial();
|
||||
|
||||
const ScreenState& getScreenState() const { return _state; }
|
||||
|
||||
@@ -27,6 +29,12 @@ public:
|
||||
void setScreen(ScreenID s);
|
||||
/// Handle touch input — returns dashboard tile index if tapped, or -1.
|
||||
int handleTouch(const TouchEvent& evt);
|
||||
/// Handle hold gesture for silencing — call each loop iteration when alerting.
|
||||
/// Returns true if hold completed and alert was silenced.
|
||||
bool updateHold(const TouchEvent& evt);
|
||||
|
||||
/// Set current boot stage (for staged boot sequence).
|
||||
void setBootStage(BootStage stage);
|
||||
|
||||
private:
|
||||
void pollTopics();
|
||||
|
||||
@@ -5,9 +5,12 @@ enum class DeviceState { BOOTED, SILENT, ALERTING, SILENCED };
|
||||
|
||||
enum class ScreenID { BOOT, OFF, ALERT, DASHBOARD };
|
||||
|
||||
enum class BootStage { SPLASH, INIT_DISPLAY, INIT_NETWORK, CONNECTING_WIFI, READY, DONE };
|
||||
|
||||
struct ScreenState {
|
||||
DeviceState deviceState = DeviceState::BOOTED;
|
||||
ScreenID screen = ScreenID::BOOT;
|
||||
BootStage bootStage = BootStage::SPLASH;
|
||||
|
||||
String alertTitle;
|
||||
String alertBody;
|
||||
@@ -52,3 +55,21 @@ inline const char* screenIdStr(ScreenID s) {
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
inline const char* bootStageStr(BootStage s) {
|
||||
switch(s) {
|
||||
case BootStage::SPLASH:
|
||||
return "SPLASH";
|
||||
case BootStage::INIT_DISPLAY:
|
||||
return "INIT_DISPLAY";
|
||||
case BootStage::INIT_NETWORK:
|
||||
return "INIT_NETWORK";
|
||||
case BootStage::CONNECTING_WIFI:
|
||||
return "CONNECTING_WIFI";
|
||||
case BootStage::READY:
|
||||
return "READY";
|
||||
case BootStage::DONE:
|
||||
return "DONE";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user