From 08960c9eeccf89c907c0bc5243b7fb45f4b34d1d Mon Sep 17 00:00:00 2001 From: Thomas Faour Date: Mon, 27 Jul 2026 22:40:44 +0000 Subject: [PATCH] Swap combo button tiers: quick press resets, ~3s hold shows menu Quick reset is now the fast/default action; summoning the management menu takes a deliberate hold. Factory reset at ~15s is unchanged. Renamed FRAME_COMBO_SOFT_RESET_HOLD_MS -> FRAME_COMBO_MENU_HOLD_MS to match its new meaning. Bumps firmware to 1.4.1. --- CLAUDE.md | 2 +- docs/architecture.md | 6 +++--- docs/hardware.md | 8 ++++---- firmware/README.md | 23 ++++++++++++----------- firmware/main/Kconfig.projbuild | 25 ++++++++++++------------- firmware/main/combo_button.c | 14 +++++++------- firmware/main/combo_button.h | 8 ++++---- firmware/version.txt | 2 +- 8 files changed, 44 insertions(+), 44 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 81cd932..c5e3dc6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,7 @@ photos/calendar/whiteboard/weather widget system to the device. CURRENT TODO -sharing layouts with linked users -a "coming up this week" widget --switch button reset action? and on reset dismiss the menu. +-on reset dismiss the menu. Start here, don't re-derive from scratch: - [`docs/architecture.md`](docs/architecture.md) -- how firmware and diff --git a/docs/architecture.md b/docs/architecture.md index a95c5c6..3eef6c2 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -102,9 +102,9 @@ placement grid, and button-action dispatch. - Deep sleep for the server-configured interval on success, or a shorter retry interval on any failure. - The menu/reset button's soft-reset and factory-reset tiers (held ~3s - or ~15s) are handled earlier, before any of this, and never return -- - see [`firmware/README.md`](../firmware/README.md#managing-the-queue-soft-resetting-and-factory-resetting). + The menu/reset button's soft-reset (quick press) and factory-reset + (held ~15s) tiers are handled earlier, before any of this, and never + return -- see [`firmware/README.md`](../firmware/README.md#managing-the-queue-soft-resetting-and-factory-resetting). See [`docs/hardware.md`](hardware.md) for wiring and [`server/README.md`](../server/README.md) for the server side. diff --git a/docs/hardware.md b/docs/hardware.md index ab4358d..374c6f2 100644 --- a/docs/hardware.md +++ b/docs/hardware.md @@ -40,10 +40,10 @@ pressed): photo; see [`firmware/README.md`](../firmware/README.md#going-back-to-the-previous-photo). - **Menu / reset (GPIO1)**: one button, three actions by hold duration -- - a quick press overlays a "scan to manage" QR code on the current photo - for 30 seconds; holding ~3s then releasing soft-resets the device - (config kept); holding ~15s factory-resets it (clears WiFi/server - config, reprovisions); see + a quick press soft-resets the device (config kept); holding ~3s then + releasing overlays a "scan to manage" QR code on the current photo for + 30 seconds; holding ~15s factory-resets it (clears WiFi/server config, + reprovisions); see [`firmware/README.md`](../firmware/README.md#managing-the-queue-soft-resetting-and-factory-resetting). All three pins were picked because they're within GPIO 0-7 -- the only diff --git a/firmware/README.md b/firmware/README.md index 60b1c31..3dd62aa 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -66,7 +66,7 @@ Under **ESPresso Frame Configuration**: | `FRAME_NEXT_BUTTON_GPIO` | 2 | Next-photo button GPIO (-1 to disable). Must be 0-7 (ESP32-C6's deep-sleep-wakeup-capable pins) | | `FRAME_BACK_BUTTON_GPIO` | 0 | Back-photo button GPIO (-1 to disable). Must be 0-7 | | `FRAME_COMBO_BUTTON_GPIO` | 1 | Menu/reset button GPIO (-1 to disable). Must be 0-7 | -| `FRAME_COMBO_SOFT_RESET_HOLD_MS` | 3000 | How long the combo button must be held (then released) to soft-reset | +| `FRAME_COMBO_MENU_HOLD_MS` | 3000 | How long the combo button must be held (then released) to show the management menu | | `FRAME_COMBO_FACTORY_RESET_HOLD_MS` | 15000 | How long the combo button must be held to factory-reset | | `FRAME_HOLD_ACTION_MS` | 3000 | **Fallback only** -- how long NEXT/BACK must be held to trigger a global action instead of a short press; see below | | `FRAME_BATTERY_ADC_GPIO` | -1 (disabled) | Battery voltage-divider ADC GPIO; see the Battery section below | @@ -294,9 +294,13 @@ One more button, wired between GPIO1 and GND (same wiring style as the other buttons), covers three actions -- disambiguated purely by how long it's held: -**A quick press** wakes the device and overlays several corners of -whatever photo is currently showing, leaving the middle of the photo -visible and unchanged: +**A quick press** soft-resets the device -- `esp_restart()`, keeping the +stored WiFi/server config. Useful for recovering a hung device without +losing setup. + +**Holding it ~3 seconds, then releasing** wakes the device (if asleep) +and overlays several corners of whatever photo is currently showing, +leaving the middle of the photo visible and unchanged: - **Top-right**: a QR code -- "SCAN TO MANAGE" -- linking to the server's config page. @@ -315,8 +319,9 @@ for faces Immich hasn't been told a name for; no face detection happens on the device or the server, this is entirely Immich's own People feature). A third press exits immediately rather than waiting out the 30-second timer. Holding the button during this stage doesn't trigger -either reset tier below -- the hold-duration read only ever happens -once, right when the device first wakes, before any menu is shown. +the factory-reset tier below -- the hold-duration read only ever +happens once, right when the device first wakes, before any menu is +shown. The device stays awake for the whole menu interaction (up to three physical refreshes: the base overlay, the escalated one, and @@ -324,17 +329,13 @@ reverting), so this costs meaningfully more power than a normal wake -- expected for a deliberate, occasional action, same tradeoff as the other buttons. -**Holding it ~3 seconds, then releasing** soft-resets the device -- -`esp_restart()`, keeping the stored WiFi/server config. Useful for -recovering a hung device without losing setup. - **Holding it ~15 seconds** (whether or not you're still holding it -- this fires immediately, it doesn't wait for release) clears the stored WiFi/server config and restarts into provisioning. From either power-on or while the device is deep-asleep, since this GPIO is armed as a wakeup source. -See `FRAME_COMBO_BUTTON_GPIO`, `FRAME_COMBO_SOFT_RESET_HOLD_MS`, and +See `FRAME_COMBO_BUTTON_GPIO`, `FRAME_COMBO_MENU_HOLD_MS`, and `FRAME_COMBO_FACTORY_RESET_HOLD_MS` above to change the pin or hold durations, or disable all three actions. diff --git a/firmware/main/Kconfig.projbuild b/firmware/main/Kconfig.projbuild index d0a020b..55ec780 100644 --- a/firmware/main/Kconfig.projbuild +++ b/firmware/main/Kconfig.projbuild @@ -154,13 +154,12 @@ menu "ESPresso Frame Configuration" Button wired between this GPIO and GND (active-low, internal pull-up enabled in firmware -- no external resistor needed). One pin, three actions depending on how long it's held: - a quick press shows the management menu (same as before); - holding it FRAME_COMBO_SOFT_RESET_HOLD_MS then releasing - soft-resets the device (reboots, keeps the stored WiFi/ - server config); holding it all the way to - FRAME_COMBO_FACTORY_RESET_HOLD_MS clears the stored config - and restarts into provisioning, regardless of whether it's - released yet. Must be GPIO 0-7 for the same deep-sleep- + a quick press soft-resets the device (reboots, keeps the + stored WiFi/server config); holding it FRAME_COMBO_MENU_HOLD_MS + then releasing shows the management menu; holding it all the + way to FRAME_COMBO_FACTORY_RESET_HOLD_MS clears the stored + config and restarts into provisioning, regardless of whether + it's released yet. Must be GPIO 0-7 for the same deep-sleep- wakeup reason as FRAME_NEXT_BUTTON_GPIO above; defaults to a different pin than the other buttons. Set to -1 to disable the feature entirely (also disables the management @@ -168,14 +167,14 @@ menu "ESPresso Frame Configuration" reconfiguring then only works by erasing NVS over USB, see firmware/README.md). - config FRAME_COMBO_SOFT_RESET_HOLD_MS - int "Soft-reset hold duration (ms)" + config FRAME_COMBO_MENU_HOLD_MS + int "Management-menu hold duration (ms)" default 3000 depends on FRAME_COMBO_BUTTON_GPIO >= 0 help How long the menu/reset button must be held before releasing - it triggers a soft reset (reboot, config kept). Long enough - to be clearly distinct from a quick menu-opening press. + it shows the management menu instead of soft-resetting. Long + enough to be clearly distinct from a quick reset tap. config FRAME_COMBO_FACTORY_RESET_HOLD_MS int "Factory-reset hold duration (ms)" @@ -185,8 +184,8 @@ menu "ESPresso Frame Configuration" How long the menu/reset button must be held continuously before the device clears its stored config and reboots into provisioning, regardless of release. Comfortably longer than - FRAME_COMBO_SOFT_RESET_HOLD_MS so the two tiers can't be - confused for each other. + FRAME_COMBO_MENU_HOLD_MS so the two tiers can't be confused + for each other. config FRAME_HOLD_ACTION_MS int "Next/back hold-for-global-action duration (ms)" diff --git a/firmware/main/combo_button.c b/firmware/main/combo_button.c index bcd7b21..c9cae62 100644 --- a/firmware/main/combo_button.c +++ b/firmware/main/combo_button.c @@ -53,8 +53,8 @@ bool combo_button_check(void) return false; /* not pressed, and didn't cause this wake either */ } - ESP_LOGI(TAG, "Combo button held -- quick press for menu, %dms for soft reset, %dms for factory reset", - CONFIG_FRAME_COMBO_SOFT_RESET_HOLD_MS, CONFIG_FRAME_COMBO_FACTORY_RESET_HOLD_MS); + ESP_LOGI(TAG, "Combo button held -- quick press for soft reset, %dms for menu, %dms for factory reset", + CONFIG_FRAME_COMBO_MENU_HOLD_MS, CONFIG_FRAME_COMBO_FACTORY_RESET_HOLD_MS); int elapsed_ms = 0; while (gpio_get_level(COMBO_BUTTON_GPIO) == 0) { @@ -70,13 +70,13 @@ bool combo_button_check(void) } } - if (elapsed_ms >= CONFIG_FRAME_COMBO_SOFT_RESET_HOLD_MS) { - ESP_LOGW(TAG, "Held %dms and released, soft-restarting (config kept)", elapsed_ms); - esp_restart(); + if (elapsed_ms >= CONFIG_FRAME_COMBO_MENU_HOLD_MS) { + ESP_LOGI(TAG, "Held %dms and released, showing management menu", elapsed_ms); + return true; } - ESP_LOGI(TAG, "Quick press (%dms), showing management menu", elapsed_ms); - return true; + ESP_LOGW(TAG, "Quick press (%dms), soft-restarting (config kept)", elapsed_ms); + esp_restart(); } bool combo_button_is_pressed(void) diff --git a/firmware/main/combo_button.h b/firmware/main/combo_button.h index 1f66300..effbd64 100644 --- a/firmware/main/combo_button.h +++ b/firmware/main/combo_button.h @@ -16,11 +16,11 @@ void combo_button_init(void); * Checks the combined menu/reset button and acts on how long it was * held, evaluated once per wake: * - Not pressed: returns false immediately. - * - Released before CONFIG_FRAME_COMBO_SOFT_RESET_HOLD_MS (a quick - * press): returns true -- caller should show the management menu. - * - Released between the soft-reset and factory-reset thresholds: a - * soft reset (esp_restart(), stored WiFi/server config kept) -- + * - Released before CONFIG_FRAME_COMBO_MENU_HOLD_MS (a quick press): + * a soft reset (esp_restart(), stored WiFi/server config kept) -- * never returns. + * - Released between the menu and factory-reset thresholds: returns + * true -- caller should show the management menu. * - Held through CONFIG_FRAME_COMBO_FACTORY_RESET_HOLD_MS: a factory * reset (frame_config_clear() + esp_restart(), fires immediately * without waiting for release) -- never returns. diff --git a/firmware/version.txt b/firmware/version.txt index 88c5fb8..347f583 100644 --- a/firmware/version.txt +++ b/firmware/version.txt @@ -1 +1 @@ -1.4.0 +1.4.1