Files
espresso_frame/firmware/main/Kconfig.projbuild
T
tfaour c0fefc19f1
Firmware build check / build-check (push) Successful in 2m44s
Fix ee02 button-wakeup build: ext1 fallback for ESP32-S3
esp_sleep_enable_gpio_wakeup_on_hp_periph_powerdown() only exists on
ESP32-C6 (SOC_GPIO_SUPPORT_HP_PERIPH_PD_SLEEP_WAKEUP), so the ee02
(ESP32-S3) build failed with implicit-declaration errors in
{back,next,combo}_button.c once the epd13in3e driver's #error stopped
masking it.

Each button file now branches on that capability macro: the C6 path
(devkit/xiao) is untouched, and ESP32-S3 uses
esp_sleep_enable_ext1_wakeup_io() instead. The earlier ext1 attempt was
rejected on C6 hardware because its pull resistor didn't hold across
RTC_PERIPH power-down -- tracing the same path in ESP-IDF source shows
gpio_config()'s pull_up_en already delegates to rtc_gpio_pullup_en()
for RTC-capable pins on every non-original-ESP32 target, so the pull-up
should already survive the same power-down on S3. The _io() variant is
additive, so the three button files don't need cross-file mask
coordination. Also widens the button GPIO Kconfig range for
IDF_TARGET_ESP32S3 (0-21, matching its RTC-IO set) instead of the
C6-shaped 0-7.

Verified: ee02, devkit, and xiao all build clean end-to-end locally
(native ESP-IDF v6.0, no Docker in this sandbox). NOT verified: whether
this actually avoids the spurious-instant-wakeup bug on real EE02
hardware -- that failure mode was only ever confirmed empirically, not
root-caused in a way a compile can check. continue-on-error stays on
in CI's ee02 build step until that's confirmed.
2026-08-04 22:46:13 +00:00

269 lines
13 KiB
Plaintext

menu "ESPresso Frame Configuration"
config FRAME_BOARD_NAME
string "Board variant name, reported to the server"
default "devkit_esp32c6"
help
Sent as the X-Frame-Board request header on every
GET /frame/config poll, so the server can learn which board
this device is and automatically fetch the right OTA build
from a configured Gitea repo's releases, and (see
routers/device.py's BOARD_PANEL_MAP) which EPD panel it
drives -- no manual "which board/panel" picker in the web
UI. Must match one of the asset names
.gitea/workflows/firmware-release-build.yml publishes
(firmware-<name>.bin): "devkit_esp32c6" (this default, for
the plain ESP32-C6-DevKitC-1 build), "xiao_esp32c6" (set via
sdkconfig.xiao for the Seeed XIAO ESP32-C6 build), or "ee02"
(set via sdkconfig.ee02 for the Seeed EE02/XIAO ESP32-S3
Plus + 13.3" panel build) -- see build_for_board.sh.
Chip-qualified rather than plain "devkit"/"xiao": the EE02
board also sockets a XIAO module (an ESP32-S3 one), so
"xiao" alone stopped disambiguating hardware once EE02
existed. The server keeps accepting the old bare
"devkit"/"xiao" names indefinitely too, since already-
flashed devices report whatever name their current firmware
was built with and can't be retroactively renamed.
config FRAME_XIAO_ANTENNA_INIT
bool "Select onboard antenna on Seeed XIAO ESP32-C6 (RF switch init)"
default n
help
The XIAO ESP32-C6 routes its antenna through an FM8625H RF
switch (GPIO3 = switch power enable, GPIO14 = antenna
select) so it can optionally use an external u.FL antenna
instead of the onboard ceramic one. Seeed's own Arduino
board package powers the switch and selects the onboard
antenna automatically at boot; plain ESP-IDF (what this
firmware uses) does not -- without this, the switch's
GPIOs are left floating and the radio may not reliably
reach the onboard antenna at all. Symptom: a softAP (or
STA connection) that starts successfully in the log but
is never actually visible/reachable over the air. Enabled
by default in sdkconfig.xiao; leave off for the DevKitC-1
dev board, which has no such switch.
config FRAME_PANEL_EE02_13IN3
bool "Build for the EE02 board + 13.3in Spectra 6 panel (ESP32-S3), not the 7.3in panel"
default n
help
Selects the epd13in3e driver component (13.3", 1600x1200)
instead of epd7in3e (7.3", 800x480) as main/epd_board.h's
target -- see firmware/components/epd13in3e. Firmware only
ever links one EPD driver at a time, same as the
devkit/xiao split links exactly one board's pin config.
Enabled by default in sdkconfig.ee02; leave off for the
ESP32-C6 boards (devkit/xiao), which drive the 7.3" panel.
config ESP_AP_SSID
string "Provisioning softAP SSID prefix"
default "ESPRESSO"
help
SSID prefix of the softAP the device brings up when it needs
provisioning; the device appends "_XXXXXX" (last 3 bytes of its
WiFi MAC) so multiple frames never collide on the same SSID.
The password is generated randomly per device on first boot and
shown on the e-ink panel both as a WiFi-join QR code and as
plaintext underneath it, so it can be typed in by hand on a
desktop/laptop that can't scan the QR.
config ESP_MAX_STA_CONN
int "Maximal STA connections"
default 4
range 1 4 if IDF_TARGET_ESP32C2
range 1 15
help
Maximum number of STAs allowed to connect to the soft-AP (wifi_config_t.ap.max_connection).
Upper bound matches ESP_WIFI_MAX_CONN_NUM in esp_wifi_types_native.h:
1-4 on ESP32-C2, 1-15 on other Wi-Fi chips.
Soft-AP and ESP-NOW share encryption keys; see Wi-Fi driver documentation
if ESP-NOW is enabled.
config ESP_ENABLE_DHCP_CAPTIVEPORTAL
bool "DHCP Captive portal"
default y
help
Enables more modern DHCP-based Option 114 to provide clients with the captive portal URI
config FRAME_STA_CONNECT_MAX_RETRIES
int "Home WiFi connect max retries before falling back to provisioning"
default 3
help
Number of failed connection attempts to the stored home WiFi network
before the device gives up and re-enters provisioning (softAP) mode.
config FRAME_STA_CONNECT_TIMEOUT_MS
int "Home WiFi connect timeout per attempt (ms)"
default 15000
help
How long to wait for an IP address on each connection attempt to the
stored home WiFi network before counting it as a failed retry.
config FRAME_SERVER_CHECK_TIMEOUT_MS
int "Tools server /frame/config request timeout (ms)"
default 3000
help
How long to wait for a GET /frame/config response from the
tools server -- doubles as both the reachability check for the
post-connect status screen and the source of the
server-configured refresh interval below.
config FRAME_FETCH_TIMEOUT_MS
int "Image fetch HTTP timeout (ms)"
default 15000
help
How long to wait on the GET /frame/image request before giving
up. The server does real work per request (Immich download +
resize + dither), so this is longer than the reachability
check's timeout.
config FRAME_SLEEP_INTERVAL_S
int "Fallback deep sleep interval between refreshes (seconds)"
default 3600
help
The refresh interval is normally set server-side (the "Refresh
interval" field in the server's web UI, delivered via GET
/frame/config) so it can be changed without reflashing. This
value is only a fallback: used before the device has ever
successfully reached a configured server, or if the server's
response doesn't include a valid interval (e.g. an older
server version). Lower this for bench testing so you don't
have to wait an hour per iteration.
config FRAME_RETRY_INTERVAL_S
int "Deep sleep interval after a failed cycle (seconds)"
default 300
help
How long the device deep-sleeps before retrying after the
server was unreachable or the fetch/display failed, instead of
waiting the full FRAME_SLEEP_INTERVAL_S.
config FRAME_NEXT_BUTTON_GPIO
int "Next-photo button GPIO (-1 to disable)"
default 2
range -1 21 if IDF_TARGET_ESP32S3
range -1 7
help
Button wired between this GPIO and GND (active-low, internal
pull-up enabled in firmware -- no external resistor needed).
Pressing it wakes the device (if asleep), forces the server to
advance to the next photo immediately (POST /frame/advance)
regardless of the configured refresh interval, and displays
it. Must be a deep-sleep-wakeup-capable GPIO: 0-7 on the
ESP32-C6, 0-21 on the ESP32-S3 (RTC-IO pins reachable by
esp_sleep_enable_ext1_wakeup_io()) -- required so a press
wakes the device promptly instead of only being noticed
during its brief awake windows. Set to -1 to disable the
feature.
config FRAME_BACK_BUTTON_GPIO
int "Back-photo button GPIO (-1 to disable)"
default 0
range -1 21 if IDF_TARGET_ESP32S3
range -1 7
help
Button wired between this GPIO and GND (active-low, internal
pull-up enabled in firmware -- no external resistor needed).
Pressing it wakes the device (if asleep), forces the server
to return to the previously-current photo immediately
(POST /frame/back), and displays it. Pressing next
afterwards returns to where you were before pressing back.
Must be a deep-sleep-wakeup-capable GPIO, same range as
FRAME_NEXT_BUTTON_GPIO above; defaults to a different pin
than the other buttons. Set to -1 to disable the feature.
config FRAME_COMBO_BUTTON_GPIO
int "Menu/reset button GPIO (-1 to disable)"
default 1
range -1 21 if IDF_TARGET_ESP32S3
range -1 7
help
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 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 a deep-sleep-wakeup-capable GPIO,
same range 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
menu, both reset tiers, and factory-reset-via-button --
reconfiguring then only works by erasing NVS over USB, see
firmware/README.md).
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 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)"
default 15000
depends on FRAME_COMBO_BUTTON_GPIO >= 0
help
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_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)"
default 3000
range 3000 10000
help
How long the NEXT or BACK button must be held before it
triggers a frame-wide action (see server/app/global_actions.py
-- e.g. cycling saved layouts) instead of that button's normal
short-press behavior. Only a first-boot/never-connected
fallback: once the device has fetched GET /frame/config at
least once, the server's own Frame.hold_duration_ms (set on
the Configuration tab) overrides this on every later boot --
see wifi_provisioning.h's frame_config_get_hold_duration_ms.
Floor matches the server's own minimum, so a long-held button
never means something different depending on which value
happened to apply.
config FRAME_BATTERY_ADC_GPIO
int "Battery voltage-divider ADC GPIO (-1 to disable)"
default -1
range -1 6
help
GPIO wired to the midpoint of a 2x200k voltage divider from
BAT+ to GND (halving the battery voltage into ADC range --
the wiring Seeed documents for the XIAO ESP32-C6's A0).
Must be GPIO 0-6, the ESP32-C6's only ADC-capable pins. The
settled XIAO design shares this with the back button's pin
(0): a high-impedance divider coexists fine with the
button's pull-up and deep-sleep wake, and the firmware
time-shares the pin (brief ADC read once per wake, restored
to button duty right after). -1 (the default) disables
battery reporting entirely -- correct for boards with no
battery wired, like the DevKitC-1 dev board.
config FRAME_VBUS_SENSE_GPIO
int "USB-power (VBUS) sense GPIO (-1 to disable)"
default -1
range -1 23
depends on FRAME_BATTERY_ADC_GPIO >= 0
help
GPIO wired to the midpoint of a 2x100k divider from the 5V
pin (which only carries voltage when USB is plugged in --
it's dead on battery power) -- a plain digital high/low
"on mains" signal, no ADC needed. The divider is required:
raw 5V exceeds the 3.3V pin limit. When on mains, the
battery indicator is hidden and no battery report is sent
(the charging voltage would read misleadingly full). -1
disables mains detection -- the indicator then shows
whenever the battery reading is plausible.
endmenu