feat: Add restart button functionality and motion calibration
- Implemented a restart button with debounce handling and long-press detection in App.cpp. - Added motion calibration settings to Settings.cpp and Settings.h, allowing for roll and pitch zero offsets. - Enhanced WebUI to include motion calibration controls and a restart option. - Updated FaceRenderer to adjust eye and mouth positions based on screen dimensions. - Introduced deadzone handling for motion sensor readings to improve stability.
This commit is contained in:
@@ -42,6 +42,12 @@ static unsigned long nextTimeCheckMs = 0;
|
||||
static bool lastScheduleSleep = false;
|
||||
static String lastConfiguredTz;
|
||||
static unsigned long motionWakeUntilMs = 0;
|
||||
static bool restartButtonEnabled = true;
|
||||
static bool restartButtonLastRaw = true;
|
||||
static bool restartButtonStable = true;
|
||||
static unsigned long restartButtonLastEdgeMs = 0;
|
||||
static unsigned long restartButtonPressedSinceMs = 0;
|
||||
static bool restartButtonArmed = true;
|
||||
|
||||
static constexpr float DIM_LUX_MIN = 0.0f;
|
||||
static constexpr float DIM_LUX_MAX = 300.0f;
|
||||
@@ -49,6 +55,9 @@ static constexpr uint8_t DIM_CONTRAST_MIN = 0x10;
|
||||
static constexpr uint8_t DIM_CONTRAST_MAX = 0xFF;
|
||||
static constexpr int ROUTINE_WINDOW_MIN = 5;
|
||||
static constexpr unsigned long MOTION_WAKE_MS = 30000UL;
|
||||
static constexpr int PIN_RESTART_BUTTON = 2; // Active-low button to GND
|
||||
static constexpr unsigned long BUTTON_DEBOUNCE_MS = 30UL;
|
||||
static constexpr unsigned long BUTTON_HOLD_RESTART_MS = 1200UL;
|
||||
|
||||
static PlantEventType moodToEvent(FaceRenderer::Mood m) {
|
||||
if (m == FaceRenderer::DRY) return EVT_DRY;
|
||||
@@ -72,6 +81,56 @@ static uint8_t luxToContrast(float lux) {
|
||||
return (uint8_t)value;
|
||||
}
|
||||
|
||||
static void initRestartButton() {
|
||||
pinMode(PIN_RESTART_BUTTON, INPUT_PULLUP);
|
||||
bool raw = digitalRead(PIN_RESTART_BUTTON);
|
||||
restartButtonLastRaw = raw;
|
||||
restartButtonStable = raw;
|
||||
restartButtonLastEdgeMs = millis();
|
||||
restartButtonPressedSinceMs = 0;
|
||||
restartButtonArmed = true;
|
||||
|
||||
Serial.print("[Button] Restart button on GPIO ");
|
||||
Serial.print(PIN_RESTART_BUTTON);
|
||||
Serial.print(" (active-low), initial=");
|
||||
Serial.println(raw ? "released" : "pressed");
|
||||
}
|
||||
|
||||
static void handleRestartButton() {
|
||||
if (!restartButtonEnabled) return;
|
||||
|
||||
unsigned long now = millis();
|
||||
bool raw = digitalRead(PIN_RESTART_BUTTON);
|
||||
|
||||
if (raw != restartButtonLastRaw) {
|
||||
restartButtonLastRaw = raw;
|
||||
restartButtonLastEdgeMs = now;
|
||||
}
|
||||
|
||||
if ((now - restartButtonLastEdgeMs) >= BUTTON_DEBOUNCE_MS && restartButtonStable != raw) {
|
||||
restartButtonStable = raw;
|
||||
bool pressed = !restartButtonStable; // active-low
|
||||
|
||||
if (pressed) {
|
||||
restartButtonPressedSinceMs = now;
|
||||
Serial.println("[Button] Restart button pressed");
|
||||
} else {
|
||||
Serial.println("[Button] Restart button released");
|
||||
restartButtonPressedSinceMs = 0;
|
||||
restartButtonArmed = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool pressed = !restartButtonStable;
|
||||
if (pressed && restartButtonArmed && restartButtonPressedSinceMs != 0 &&
|
||||
(now - restartButtonPressedSinceMs) >= BUTTON_HOLD_RESTART_MS) {
|
||||
restartButtonArmed = false;
|
||||
Serial.println("[Button] Restart hold detected - rebooting");
|
||||
delay(50);
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
|
||||
struct ScheduleState {
|
||||
bool hasTime = false;
|
||||
bool sleeping = false;
|
||||
@@ -234,6 +293,7 @@ void App::setup() {
|
||||
|
||||
display.begin();
|
||||
display.showStatus("FacePlant", "Starting...");
|
||||
initRestartButton();
|
||||
|
||||
wifi.begin(settings, forceSetup);
|
||||
|
||||
@@ -245,7 +305,12 @@ void App::setup() {
|
||||
|
||||
webhook.begin(settings);
|
||||
|
||||
web.begin(settings, wifi, moisture, face, webhook, bootMs);
|
||||
{
|
||||
MotionCalibration mc = settings.motionCalibration();
|
||||
motion.setZeroOffsets(mc.rollZeroDeg, mc.pitchZeroDeg);
|
||||
}
|
||||
|
||||
web.begin(settings, wifi, moisture, motion, face, webhook, bootMs);
|
||||
ota.begin(web.server(), &display);
|
||||
|
||||
lastMood = face.mood();
|
||||
@@ -259,6 +324,7 @@ void App::loop() {
|
||||
static unsigned long lastDisplayUpdate = 0;
|
||||
|
||||
BootTrigger::clearAfterStableUptime();
|
||||
handleRestartButton();
|
||||
|
||||
wifi.loop();
|
||||
web.loop();
|
||||
|
||||
Reference in New Issue
Block a user