Swap combo button tiers: quick press resets, ~3s hold shows menu
Firmware build check / build-check (push) Successful in 2m45s
Build and release firmware / build-and-release (push) Successful in 2m45s

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.
This commit is contained in:
2026-07-27 22:40:44 +00:00
parent f0c21af220
commit 08960c9eec
8 changed files with 44 additions and 44 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ photos/calendar/whiteboard/weather widget system to the device.
CURRENT TODO CURRENT TODO
-sharing layouts with linked users -sharing layouts with linked users
-a "coming up this week" widget -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: Start here, don't re-derive from scratch:
- [`docs/architecture.md`](docs/architecture.md) -- how firmware and - [`docs/architecture.md`](docs/architecture.md) -- how firmware and
+3 -3
View File
@@ -102,9 +102,9 @@ placement grid, and button-action dispatch.
- Deep sleep for the server-configured interval on success, or a - Deep sleep for the server-configured interval on success, or a
shorter retry interval on any failure. shorter retry interval on any failure.
The menu/reset button's soft-reset and factory-reset tiers (held ~3s The menu/reset button's soft-reset (quick press) and factory-reset
or ~15s) are handled earlier, before any of this, and never return -- (held ~15s) tiers are handled earlier, before any of this, and never
see [`firmware/README.md`](../firmware/README.md#managing-the-queue-soft-resetting-and-factory-resetting). 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 See [`docs/hardware.md`](hardware.md) for wiring and
[`server/README.md`](../server/README.md) for the server side. [`server/README.md`](../server/README.md) for the server side.
+4 -4
View File
@@ -40,10 +40,10 @@ pressed):
photo; see photo; see
[`firmware/README.md`](../firmware/README.md#going-back-to-the-previous-photo). [`firmware/README.md`](../firmware/README.md#going-back-to-the-previous-photo).
- **Menu / reset (GPIO1)**: one button, three actions by hold duration -- - **Menu / reset (GPIO1)**: one button, three actions by hold duration --
a quick press overlays a "scan to manage" QR code on the current photo a quick press soft-resets the device (config kept); holding ~3s then
for 30 seconds; holding ~3s then releasing soft-resets the device releasing overlays a "scan to manage" QR code on the current photo for
(config kept); holding ~15s factory-resets it (clears WiFi/server 30 seconds; holding ~15s factory-resets it (clears WiFi/server config,
config, reprovisions); see reprovisions); see
[`firmware/README.md`](../firmware/README.md#managing-the-queue-soft-resetting-and-factory-resetting). [`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 All three pins were picked because they're within GPIO 0-7 -- the only
+12 -11
View File
@@ -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_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_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_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_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_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 | | `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 other buttons), covers three actions -- disambiguated purely by how
long it's held: long it's held:
**A quick press** wakes the device and overlays several corners of **A quick press** soft-resets the device -- `esp_restart()`, keeping the
whatever photo is currently showing, leaving the middle of the photo stored WiFi/server config. Useful for recovering a hung device without
visible and unchanged: 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 - **Top-right**: a QR code -- "SCAN TO MANAGE" -- linking to the
server's config page. 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 on the device or the server, this is entirely Immich's own People
feature). A third press exits immediately rather than waiting out the feature). A third press exits immediately rather than waiting out the
30-second timer. Holding the button during this stage doesn't trigger 30-second timer. Holding the button during this stage doesn't trigger
either reset tier below -- the hold-duration read only ever happens the factory-reset tier below -- the hold-duration read only ever
once, right when the device first wakes, before any menu is shown. 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 The device stays awake for the whole menu interaction (up to three
physical refreshes: the base overlay, the escalated one, and 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 expected for a deliberate, occasional action, same tradeoff as the
other buttons. 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 -- **Holding it ~15 seconds** (whether or not you're still holding it --
this fires immediately, it doesn't wait for release) clears the stored this fires immediately, it doesn't wait for release) clears the stored
WiFi/server config and restarts into provisioning. From either power-on 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 or while the device is deep-asleep, since this GPIO is armed as a
wakeup source. 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 `FRAME_COMBO_FACTORY_RESET_HOLD_MS` above to change the pin or hold
durations, or disable all three actions. durations, or disable all three actions.
+12 -13
View File
@@ -154,13 +154,12 @@ menu "ESPresso Frame Configuration"
Button wired between this GPIO and GND (active-low, internal Button wired between this GPIO and GND (active-low, internal
pull-up enabled in firmware -- no external resistor needed). pull-up enabled in firmware -- no external resistor needed).
One pin, three actions depending on how long it's held: One pin, three actions depending on how long it's held:
a quick press shows the management menu (same as before); a quick press soft-resets the device (reboots, keeps the
holding it FRAME_COMBO_SOFT_RESET_HOLD_MS then releasing stored WiFi/server config); holding it FRAME_COMBO_MENU_HOLD_MS
soft-resets the device (reboots, keeps the stored WiFi/ then releasing shows the management menu; holding it all the
server config); holding it all the way to way to FRAME_COMBO_FACTORY_RESET_HOLD_MS clears the stored
FRAME_COMBO_FACTORY_RESET_HOLD_MS clears the stored config config and restarts into provisioning, regardless of whether
and restarts into provisioning, regardless of whether it's it's released yet. Must be GPIO 0-7 for the same deep-sleep-
released yet. Must be GPIO 0-7 for the same deep-sleep-
wakeup reason as FRAME_NEXT_BUTTON_GPIO above; defaults to wakeup reason as FRAME_NEXT_BUTTON_GPIO above; defaults to
a different pin than the other buttons. Set to -1 to a different pin than the other buttons. Set to -1 to
disable the feature entirely (also disables the management 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 reconfiguring then only works by erasing NVS over USB, see
firmware/README.md). firmware/README.md).
config FRAME_COMBO_SOFT_RESET_HOLD_MS config FRAME_COMBO_MENU_HOLD_MS
int "Soft-reset hold duration (ms)" int "Management-menu hold duration (ms)"
default 3000 default 3000
depends on FRAME_COMBO_BUTTON_GPIO >= 0 depends on FRAME_COMBO_BUTTON_GPIO >= 0
help help
How long the menu/reset button must be held before releasing How long the menu/reset button must be held before releasing
it triggers a soft reset (reboot, config kept). Long enough it shows the management menu instead of soft-resetting. Long
to be clearly distinct from a quick menu-opening press. enough to be clearly distinct from a quick reset tap.
config FRAME_COMBO_FACTORY_RESET_HOLD_MS config FRAME_COMBO_FACTORY_RESET_HOLD_MS
int "Factory-reset hold duration (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 How long the menu/reset button must be held continuously
before the device clears its stored config and reboots into before the device clears its stored config and reboots into
provisioning, regardless of release. Comfortably longer than provisioning, regardless of release. Comfortably longer than
FRAME_COMBO_SOFT_RESET_HOLD_MS so the two tiers can't be FRAME_COMBO_MENU_HOLD_MS so the two tiers can't be confused
confused for each other. for each other.
config FRAME_HOLD_ACTION_MS config FRAME_HOLD_ACTION_MS
int "Next/back hold-for-global-action duration (ms)" int "Next/back hold-for-global-action duration (ms)"
+7 -7
View File
@@ -53,8 +53,8 @@ bool combo_button_check(void)
return false; /* not pressed, and didn't cause this wake either */ 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", ESP_LOGI(TAG, "Combo button held -- quick press for soft reset, %dms for menu, %dms for factory reset",
CONFIG_FRAME_COMBO_SOFT_RESET_HOLD_MS, CONFIG_FRAME_COMBO_FACTORY_RESET_HOLD_MS); CONFIG_FRAME_COMBO_MENU_HOLD_MS, CONFIG_FRAME_COMBO_FACTORY_RESET_HOLD_MS);
int elapsed_ms = 0; int elapsed_ms = 0;
while (gpio_get_level(COMBO_BUTTON_GPIO) == 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) { if (elapsed_ms >= CONFIG_FRAME_COMBO_MENU_HOLD_MS) {
ESP_LOGW(TAG, "Held %dms and released, soft-restarting (config kept)", elapsed_ms); ESP_LOGI(TAG, "Held %dms and released, showing management menu", elapsed_ms);
esp_restart(); return true;
} }
ESP_LOGI(TAG, "Quick press (%dms), showing management menu", elapsed_ms); ESP_LOGW(TAG, "Quick press (%dms), soft-restarting (config kept)", elapsed_ms);
return true; esp_restart();
} }
bool combo_button_is_pressed(void) bool combo_button_is_pressed(void)
+4 -4
View File
@@ -16,11 +16,11 @@ void combo_button_init(void);
* Checks the combined menu/reset button and acts on how long it was * Checks the combined menu/reset button and acts on how long it was
* held, evaluated once per wake: * held, evaluated once per wake:
* - Not pressed: returns false immediately. * - Not pressed: returns false immediately.
* - Released before CONFIG_FRAME_COMBO_SOFT_RESET_HOLD_MS (a quick * - Released before CONFIG_FRAME_COMBO_MENU_HOLD_MS (a quick press):
* press): returns true -- caller should show the management menu. * a soft reset (esp_restart(), stored WiFi/server config kept) --
* - Released between the soft-reset and factory-reset thresholds: a
* soft reset (esp_restart(), stored WiFi/server config kept) --
* never returns. * 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 * - Held through CONFIG_FRAME_COMBO_FACTORY_RESET_HOLD_MS: a factory
* reset (frame_config_clear() + esp_restart(), fires immediately * reset (frame_config_clear() + esp_restart(), fires immediately
* without waiting for release) -- never returns. * without waiting for release) -- never returns.
+1 -1
View File
@@ -1 +1 @@
1.4.0 1.4.1