From 4c0991b8bdc70e3760698c10cd38c0fed277f698 Mon Sep 17 00:00:00 2001 From: David Gwilliam Date: Wed, 18 Feb 2026 01:12:36 -0800 Subject: [PATCH] feat(doorbell): add inactivity timeout to turn off screen --- libraries/KlubhausCore/src/Config.h | 1 + libraries/KlubhausCore/src/DoorbellLogic.cpp | 11 ++ libraries/KlubhausCore/src/DoorbellLogic.h | 1 + mise.toml | 182 ++++++++----------- 4 files changed, 91 insertions(+), 104 deletions(-) diff --git a/libraries/KlubhausCore/src/Config.h b/libraries/KlubhausCore/src/Config.h index 2299225..5be1acb 100644 --- a/libraries/KlubhausCore/src/Config.h +++ b/libraries/KlubhausCore/src/Config.h @@ -16,6 +16,7 @@ #define HOLD_TO_SILENCE_MS 3000 #define ALERT_TIMEOUT_MS 120000 #define SILENCE_DISPLAY_MS 10000 +#define INACTIVITY_TIMEOUT_MS 30000 #define WIFI_CONNECT_TIMEOUT_MS 15000 #define HTTP_TIMEOUT_MS 10000 #define HINT_ANIMATION_MS 2000 diff --git a/libraries/KlubhausCore/src/DoorbellLogic.cpp b/libraries/KlubhausCore/src/DoorbellLogic.cpp index 6839bbe..45a1c76 100644 --- a/libraries/KlubhausCore/src/DoorbellLogic.cpp +++ b/libraries/KlubhausCore/src/DoorbellLogic.cpp @@ -79,6 +79,7 @@ void DoorbellLogic::finishBoot() { _display->setBacklight(false); _state.backlightOn = false; _bootGraceEnd = millis() + BOOT_GRACE_MS; + _lastActivityMs = millis(); Serial.printf("[BOOT] Grace period: %d ms\n", BOOT_GRACE_MS); Serial.printf("[BOOT] Ready — monitoring %s\n", NTFY_SERVER); } @@ -130,6 +131,13 @@ void DoorbellLogic::update() { } break; default: + // Inactivity timeout: turn off screen after no activity + if(_state.screen != ScreenID::OFF && now - _lastActivityMs > INACTIVITY_TIMEOUT_MS) { + Serial.println("[STATE] Inactivity timeout → OFF"); + _state.screen = ScreenID::OFF; + _display->setBacklight(false); + _state.backlightOn = false; + } break; } } @@ -300,6 +308,9 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) { if(!evt.pressed) return -1; + // Reset inactivity timer on any touch + _lastActivityMs = millis(); + if(_state.screen == ScreenID::OFF) { Serial.println("[TOUCH] OFF → DASHBOARD"); setScreen(ScreenID::DASHBOARD); diff --git a/libraries/KlubhausCore/src/DoorbellLogic.h b/libraries/KlubhausCore/src/DoorbellLogic.h index c5a98ee..da56459 100644 --- a/libraries/KlubhausCore/src/DoorbellLogic.h +++ b/libraries/KlubhausCore/src/DoorbellLogic.h @@ -57,6 +57,7 @@ private: uint32_t _lastPollMs = 0; uint32_t _lastHeartbeatMs = 0; + uint32_t _lastActivityMs = 0; uint32_t _bootGraceEnd = 0; String _alertUrl; diff --git a/mise.toml b/mise.toml index 9e708d4..20fa897 100644 --- a/mise.toml +++ b/mise.toml @@ -8,43 +8,107 @@ hk = "latest" pkl = "latest" # Usage: -# BOARD=esp32-32e-4 mise run compile # compile for esp32-32e-4 -# BOARD=esp32-32e-4 mise run upload # upload to esp32-32e-4 -# BOARD=esp32-32e-4 mise run monitor # monitor esp32-32e-4 +# BOARD=esp32-32e-4 mise run compile # compile +# BOARD=esp32-32e-4 mise run upload # upload +# BOARD=esp32-32e-4 mise run monitor # monitor +# BOARD=esp32-32e-4 mise run monitor-screen # screen monitor with auto-reconnect # -# Valid BOARD values: esp32-32e, esp32-32e-4, esp32-s3-43 +# Valid BOARD: esp32-32e, esp32-32e-4, esp32-s3-43 [tasks.compile] description = "Compile (uses BOARD env var)" run = """ case "$BOARD" in - esp32-32e) mise run compile-32e ;; - esp32-32e-4) mise run compile-32e-4 ;; - esp32-s3-43) mise run compile-s3-43 ;; + esp32-32e) + FQBN="esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" + LIBS="--libraries ./vendor/esp32-32e/TFT_eSPI" + OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM" + ;; + esp32-32e-4) + FQBN="esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" + LIBS="--libraries ./vendor/esp32-32e-4/TFT_eSPI" + OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM" + ;; + esp32-s3-43) + FQBN="esp32:esp32:waveshare_esp32_s3_touch_lcd_43:PSRAM=enabled,FlashSize=16M,USBMode=hwcdc,PartitionScheme=app3M_fat9M_16MB" + LIBS="--libraries ./vendor/esp32-s3-lcd-43/LovyanGFX" + OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM -DLGFX_USE_V1" + ;; *) echo "Unknown BOARD: $BOARD" && exit 1 ;; esac +arduino-cli compile --fqbn "$FQBN" --libraries ./libraries $LIBS --build-property "compiler.cpp.extra_flags=$OPTS" --warnings default ./boards/$BOARD """ [tasks.upload] description = "Upload (uses BOARD env var)" run = """ case "$BOARD" in - esp32-32e) mise run upload-32e ;; - esp32-32e-4) mise run upload-32e-4 ;; - esp32-s3-43) mise run upload-s3-43 ;; + esp32-32e) PORT="${PORT:-/dev/ttyUSB0}" ;; + esp32-32e-4) PORT="${PORT:-/dev/ttyUSB0}" ;; + esp32-s3-43) PORT="${PORT:-/dev/ttyACM0}" ;; *) echo "Unknown BOARD: $BOARD" && exit 1 ;; esac +FQBN="" +case "$BOARD" in + esp32-32e) FQBN="esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" ;; + esp32-32e-4) FQBN="esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" ;; + esp32-s3-43) FQBN="esp32:esp32:waveshare_esp32_s3_touch_lcd_43:PSRAM=enabled,FlashSize=16M,USBMode=hwcdc,PartitionScheme=app3M_fat9M_16MB" ;; +esac +LIBS="" +case "$BOARD" in + esp32-32e) LIBS="--libraries ./vendor/esp32-32e/TFT_eSPI" ;; + esp32-32e-4) LIBS="--libraries ./vendor/esp32-32e-4/TFT_eSPI" ;; + esp32-s3-43) LIBS="--libraries ./vendor/esp32-s3-lcd-43/LovyanGFX" ;; +esac +OPTS="" +case "$BOARD" in + esp32-32e) OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM" ;; + esp32-32e-4) OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM" ;; + esp32-s3-43) OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM -DLGFX_USE_V1" ;; +esac +arduino-cli compile --fqbn "$FQBN" --libraries ./libraries $LIBS --build-property "compiler.cpp.extra_flags=$OPTS" --warnings default ./boards/$BOARD && \ +arduino-cli upload --fqbn "$FQBN" --port "$PORT" ./boards/$BOARD """ [tasks.monitor] description = "Monitor (uses BOARD env var)" run = """ case "$BOARD" in - esp32-32e) mise run monitor-32e ;; - esp32-32e-4) mise run monitor-32e-4 ;; - esp32-s3-43) mise run monitor-s3-43 ;; + esp32-32e) PORT="${PORT:-/dev/ttyUSB0}" ;; + esp32-32e-4) PORT="${PORT:-/dev/ttyUSB0}" ;; + esp32-s3-43) PORT="${PORT:-/dev/ttyACM0}" ;; *) echo "Unknown BOARD: $BOARD" && exit 1 ;; esac +TARGET="$(readlink -f "$PORT" 2>/dev/null || echo "$PORT")" +arduino-cli monitor -p "$TARGET" --config baudrate=115200 +""" + +[tasks.monitor-screen] +description = "Screen monitor with auto-reconnect (uses BOARD env var)" +run = """ +case "$BOARD" in + esp32-32e) PORT="${PORT:-/dev/ttyUSB0}" ;; + esp32-32e-4) PORT="${PORT:-/dev/ttyUSB0}" ;; + esp32-s3-43) PORT="${PORT:-/dev/ttyACM0}" ;; + *) echo "Unknown BOARD: $BOARD" && exit 1 ;; +esac +TARGET="$(readlink -f "$PORT" 2>/dev/null || echo "$PORT")" +screen -dmS doorbell bash -c " +while true; do + echo \"Connecting to $TARGET...\" + arduino-cli monitor -p \"$TARGET\" --config baudrate=115200 + echo \"Disconnected, retrying in 3s...\" + sleep 3 +done +" +echo "Screen session 'doorbell' started. Attach with: screen -r doorbell" +echo "Detach: Ctrl+A D" +""" + +[tasks.monitor-screen-kill] +description = "Kill screen-based monitor" +run = """ +screen -X -S doorbell quit 2>/dev/null && echo "Killed screen session 'doorbell'" || echo "No session found" """ [tasks.install-libs-shared] @@ -131,97 +195,7 @@ echo "[OK] LovyanGFX vendored" description = "Install all libraries (shared + vendored)" depends = ["install-libs-shared", "install-libs-32e", "install-libs-32e-4", "install-libs-s3-43"] -# ── ESP32-32E ──────────────────────────────────────────── - -[tasks.compile-32e] -description = "Compile ESP32-32E sketch" -depends = ["install-libs"] -run = """ -arduino-cli compile \ - --fqbn "esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" \ - --libraries ./libraries \ - --libraries ./vendor/esp32-32e/TFT_eSPI \ - --build-property "compiler.cpp.extra_flags=-DDEBUG_MODE -DBOARD_HAS_PSRAM" \ - --warnings default \ - ./boards/esp32-32e -""" - -[tasks.upload-32e] -description = "Upload to ESP32-32E" -run = """ -arduino-cli upload \ - --fqbn "esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" \ - --port "${PORT:-/dev/ttyUSB0}" \ - ./boards/esp32-32e -""" - -[tasks.monitor-32e] -description = "Serial monitor for ESP32-32E" -run = """ -arduino-cli monitor --port "${PORT:-/dev/ttyUSB0}" --config baudrate=115200 -""" - -# ── ESP32-32E-4 inch ───────────────────────────────────────── - -[tasks.compile-32e-4] -description = "Compile ESP32-32E-4 inch sketch (ST7796 320x480)" -depends = ["install-libs-32e-4"] -run = """ -arduino-cli compile \ - --fqbn "esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" \ - --libraries ./libraries \ - --libraries ./vendor/esp32-32e-4/TFT_eSPI \ - --build-property "compiler.cpp.extra_flags=-DDEBUG_MODE -DBOARD_HAS_PSRAM" \ - --warnings default \ - ./boards/esp32-32e-4 -""" - -[tasks.upload-32e-4] -description = "Upload to ESP32-32E-4\"" -run = """ -arduino-cli upload \ - --fqbn "esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" \ - --port "${PORT:-/dev/ttyUSB0}" \ - ./boards/esp32-32e-4 -""" - -[tasks.monitor-32e-4] -description = "Serial monitor for ESP32-32E 4 inch" -run = """ -arduino-cli monitor -p "${PORT:-/dev/ttyUSB0}" --config 115200 -""" - -# ── ESP32-S3-LCD-4.3 ──────────────────────────────────── - -[tasks.compile-s3-43] -description = "Compile ESP32-S3-LCD-4.3 sketch (Core 2.x)" -depends = ["install-libs"] -run = """ -arduino-cli compile \ - --fqbn "esp32:esp32:waveshare_esp32_s3_touch_lcd_43:PSRAM=enabled,FlashSize=16M,USBMode=hwcdc,PartitionScheme=app3M_fat9M_16MB" \ - --libraries ./libraries \ - --library ./vendor/esp32-s3-lcd-43/LovyanGFX \ - --build-property "compiler.cpp.extra_flags=-DDEBUG_MODE -DBOARD_HAS_PSRAM -DLGFX_USE_V1" \ - --warnings default \ - ./boards/esp32-s3-lcd-43 -""" - -[tasks.upload-s3-43] -description = "Upload to ESP32-S3-LCD-4.3" -run = """ -arduino-cli upload \ - --fqbn "esp32:esp32:waveshare_esp32_s3_touch_lcd_43:PSRAM=enabled,FlashSize=16M,USBMode=hwcdc,PartitionScheme=app3M_fat9M_16MB" \ - --port "${PORT:-/dev/ttyACM0}" \ - ./boards/esp32-s3-lcd-43 -""" - -[tasks.monitor-s3-43] -description = "Serial monitor for ESP32-S3-LCD-4.3" -run = """ -arduino-cli monitor --port "${PORT:-/dev/ttyACM0}" --config baudrate=115200 -""" - -# ── Convenience ────────────────────────────────────────── +# Convenience [tasks.clean] description = "Remove build artifacts"