How OXConfigManager Works
The reset feature, the GPIO5 wiring, and the config store
What this page is
The API reference tells you what each method does. This page explains how the reset feature is wired — both in hardware (the GPIO5 switch) and in software (how a long press becomes a reset callback) — and how the config store and switch detection compose. Read it before changing the reset behavior or adding new long-press actions.
Reset switch wiring (GPIO5)
The reset switch is a momentary push-button between GPIO5 and GND. No external resistor is needed: the firmware enables the ESP32-S3's internal pull-up, so the pin idles HIGH and reads LOW only while the button is held (active-low). Hold it 10 seconds to trigger the reset.
Reset push-button: GPIO5 → button → GND (active-low, internal pull-up)
| Button terminal | ESP32-S3 Super Mini | Notes |
|---|---|---|
| Terminal A | GPIO5 | Sense pin; idles HIGH via internal pull-up, LOW when pressed. |
| Terminal B | GND | Pulls GPIO5 low while the button is held. |
Prefer a button to 3V3 instead? Set resetActiveHigh = true and
resetUsePullup = false in ConfigOptions, and add an
external pull-down resistor so the pin idles LOW.
From a long press to a reset callback
The reset feature is layered on top of OXSwitchManager rather than re-implementing GPIO handling. The chain:
OXSwitchManager (debounce + long-press timer on GPIO5)
│ onLongPress(pin) — generic, pin-tagged
▼
OXConfigManager::onLongPressTrampoline(pin, this)
│ if (pin == resetSwitchPin) → triggerReset()
│ also notifies onSwitchLongPress() observers (any pin)
▼
OXConfigManager::triggerReset()
│
▼
your ConfigResetCallback(ctx)
During begin(), OXConfigManager registers a single
static trampoline as the switch manager's long-press handler and adds the
reset switch from ConfigOptions. When GPIO5's hold reaches
resetHoldMs, the trampoline sees pin == resetSwitchPin
and calls triggerReset(), which logs and invokes your
onReset callback. This is what "the reset function inherits
from switchLongPressDetected when the GPIO is GPIO5" means concretely: the
generic long-press event is filtered down to the reset pin.
Routing through triggerReset() gives one reset entry point, so
a software command (from the app or server) can call
triggerReset() directly and run the exact same handler.
Why a trampoline + pin filter
C-style callbacks can't capture this, so the handler is a
static function that receives the manager via the ctx
pointer registered alongside it. Inside, the pin argument is the router:
reset is just the first long-press action, and additional features call
onSwitchLongPress() + addSwitch() to handle other
pins — all flowing through the same trampoline. Adding a new GPIO action
touches no existing code.
The config store
Configuration is a fixed-capacity array of key/value string entries (32
entries, keys < 32 chars, values < 96 chars) — no heap, predictable
memory, fine for an MCU. Typed setters/getters
(setInt/getInt, setBool/getBool)
format to and parse from the stored string, so there is one storage path.
Setting an existing key overwrites in place; remove() compacts
the array so the used entries stay a dense prefix.
It is deliberately simple so it can grow: a persistence layer (write the
entries to internal flash via
OXFileManager, optionally
encrypted with OXSecurity) can be
added behind the same API, and clearAll() already provides the
data half of a factory reset for the reset callback to call.
Device vs. host build
The GPIO backend lives under src/gpio/, excluded from the
native test environment:
[env:native]
build_src_filter = +<*> -<main.cpp> -<backends/> -<crypto/> -<audio/> -<led/> -<gpio/>
OXSwitchManager and OXConfigManager themselves are
portable, so they compile into the host tests; only the
digitalRead() wrapper is device-only. Tests inject a
FakeGpioInput whose pin levels and the millis()
passed to poll() are scripted, so the full reset path — debounce,
5-second hold, callback — is verified with no button attached.
File map
| File | Role |
|---|---|
include/OXConfigManager.h · src/OXConfigManager.cpp | Config store + reset routing (portable). |
include/OXSwitchManager.h · src/OXSwitchManager.cpp | Debounce + long-press engine (portable). |
include/gpio/EspGpioInput.h · src/gpio/EspGpioInput.cpp | Arduino digitalRead() backend (device only). |
src/gpio/OXSwitchManagerDevice.cpp | Registers the default GPIO input + switch-manager factories (device only). |
test/test_oxswitchmanager/ · test/test_oxconfigmanager/ | Host suites with a fake GPIO input. |