diff --git a/boards/esp32-32e-4/board-config.sh b/boards/esp32-32e-4/board-config.sh new file mode 100644 index 0000000..ed7d51e --- /dev/null +++ b/boards/esp32-32e-4/board-config.sh @@ -0,0 +1,4 @@ +FQBN="esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" +PORT="/dev/ttyUSB0" +LIBS="--libraries ./vendor/esp32-32e-4/TFT_eSPI" +OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM" diff --git a/boards/esp32-32e/board-config.sh b/boards/esp32-32e/board-config.sh new file mode 100644 index 0000000..aa3d5eb --- /dev/null +++ b/boards/esp32-32e/board-config.sh @@ -0,0 +1,4 @@ +FQBN="esp32:esp32:esp32:FlashSize=4M,PartitionScheme=default" +PORT="/dev/ttyUSB0" +LIBS="--libraries ./vendor/esp32-32e/TFT_eSPI" +OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM" diff --git a/boards/esp32-s3-lcd-43/board-config.sh b/boards/esp32-s3-lcd-43/board-config.sh new file mode 100644 index 0000000..77e0f15 --- /dev/null +++ b/boards/esp32-s3-lcd-43/board-config.sh @@ -0,0 +1,4 @@ +FQBN="esp32:esp32:waveshare_esp32_s3_touch_lcd_43:PSRAM=enabled,FlashSize=16M,USBMode=hwcdc,PartitionScheme=app3M_fat9M_16MB" +PORT="/dev/ttyACM0" +LIBS="--libraries ./vendor/esp32-s3-lcd-43/LovyanGFX" +OPTS="-DDEBUG_MODE -DBOARD_HAS_PSRAM -DLGFX_USE_V1" diff --git a/libraries/KlubhausCore/src/DoorbellLogic.cpp b/libraries/KlubhausCore/src/DoorbellLogic.cpp index 45a1c76..d9a7d0c 100644 --- a/libraries/KlubhausCore/src/DoorbellLogic.cpp +++ b/libraries/KlubhausCore/src/DoorbellLogic.cpp @@ -133,7 +133,8 @@ void DoorbellLogic::update() { 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"); + Serial.printf("[%lu] [STATE] Inactivity timeout (%lu ms) → OFF\n", + millis(), now - _lastActivityMs); _state.screen = ScreenID::OFF; _display->setBacklight(false); _state.backlightOn = false; @@ -229,10 +230,12 @@ void DoorbellLogic::onAdmin(const String& cmd) { delay(500); ESP.restart(); } else if(cmd == "dashboard") { + Serial.printf("[%lu] [ADMIN] dashboard\n", millis()); _state.screen = ScreenID::DASHBOARD; _display->setBacklight(true); _state.backlightOn = true; } else if(cmd == "off") { + Serial.printf("[%lu] [ADMIN] off\n", millis()); _state.screen = ScreenID::OFF; _display->setBacklight(false); _state.backlightOn = false; @@ -312,7 +315,7 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) { _lastActivityMs = millis(); if(_state.screen == ScreenID::OFF) { - Serial.println("[TOUCH] OFF → DASHBOARD"); + Serial.printf("[%lu] [TOUCH] OFF → DASHBOARD\n", millis()); setScreen(ScreenID::DASHBOARD); return -1; } diff --git a/mise.toml b/mise.toml index cf88626..95c0ea9 100644 --- a/mise.toml +++ b/mise.toml @@ -6,70 +6,41 @@ [tools] hk = "latest" pkl = "latest" +# zellij = "latest" # Install manually if needed (brew install zellij) # Usage: # 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 +# BOARD=esp32-32e-4 mise run monitor-screen # shows tio command to run manually # -# Valid BOARD: esp32-32e, esp32-32e-4, esp32-s3-43 +# Valid BOARD: esp32-32e, esp32-32e-4, esp32-s3-lcd-43 +# Board config lives in: boards/{BOARD}/board-config.sh [tasks.compile] description = "Compile (uses BOARD env var)" run = """ -case "$BOARD" in - 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 +source ./boards/$BOARD/board-config.sh 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 = """ -# Kill any screen session holding the port -screen -X -S doorbell quit 2>/dev/null || true -sleep 1 +source ./boards/$BOARD/board-config.sh -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 -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 +LOCKFILE="/tmp/doorbell-$BOARD.lock" +if [ -f "$LOCKFILE" ]; then + echo "Error: Another instance is running (lockfile exists: $LOCKFILE)" + echo "Remove with: rm $LOCKFILE" + exit 1 +fi +trap 'rm -f "$LOCKFILE"' EXIT +touch "$LOCKFILE" + +echo "Acquired lock: $LOCKFILE" + +PORT="${PORT:-$PORT}" 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 """ @@ -77,42 +48,37 @@ arduino-cli upload --fqbn "$FQBN" --port "$PORT" ./boards/$BOARD [tasks.monitor] description = "Monitor (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 +source ./boards/$BOARD/board-config.sh +PORT="${PORT:-$PORT}" 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)" +[tasks.monitor-tio] +description = "Show tio command to run in separate terminal" 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 +source ./boards/$BOARD/board-config.sh + +LOCKFILE="/tmp/doorbell-$BOARD.lock" +if [ -f "$LOCKFILE" ]; then + echo "Error: Another instance is running (lockfile exists: $LOCKFILE)" + echo "Remove with: rm $LOCKFILE" + exit 1 +fi +trap 'rm -f "$LOCKFILE"' EXIT +touch "$LOCKFILE" + +echo "Acquired lock: $LOCKFILE (Ctrl+C to release)" + +PORT="${PORT:-$PORT}" 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" +tio --map INLCRNL "$TARGET" -e """ [tasks.monitor-screen-kill] -description = "Kill screen-based monitor" +description = "Kill tio (Ctrl+C in the terminal)" run = """ -screen -X -S doorbell quit 2>/dev/null && echo "Killed screen session 'doorbell'" || echo "No session found" +echo "Press Ctrl+C in the tio terminal to exit" """ [tasks.install-libs-shared] @@ -197,7 +163,12 @@ echo "[OK] LovyanGFX vendored" [tasks.install-libs] description = "Install all libraries (shared + vendored)" -depends = ["install-libs-shared", "install-libs-32e", "install-libs-32e-4", "install-libs-s3-43"] +depends = [ + "install-libs-shared", + "install-libs-32e", + "install-libs-32e-4", + "install-libs-s3-43", +] # Convenience @@ -211,6 +182,23 @@ rm -rf boards/esp32-s3-lcd-43/build echo "[OK] Build artifacts cleaned" """ +[tasks.arduino-clean] +description = "Clean Arduino CLI cache (staging + packages)" +run = """ +echo "Checking ~/.arduino15..." +du -sh ~/.arduino15/staging 2>/dev/null || echo "No staging folder" +du -sh ~/.arduino15/packages 2>/dev/null || echo "No packages folder" +read -p "Delete staging + packages folders? [y/N] " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + rm -rf ~/.arduino15/staging + rm -rf ~/.arduino15/packages + echo "[OK] Arduino staging + packages cleared" +else + echo "Aborted" +fi +""" + [tasks.format] run = """ clang-format -i --style=file \