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.

ESP32-S3 Super Mini GPIO5 GND (internal pull-up) Push-button momentary, to GND
signal (GPIO5) ground

Reset push-button: GPIO5 → button → GND (active-low, internal pull-up)

Button terminalESP32-S3 Super MiniNotes
Terminal AGPIO5Sense pin; idles HIGH via internal pull-up, LOW when pressed.
Terminal BGNDPulls 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

FileRole
include/OXConfigManager.h · src/OXConfigManager.cppConfig store + reset routing (portable).
include/OXSwitchManager.h · src/OXSwitchManager.cppDebounce + long-press engine (portable).
include/gpio/EspGpioInput.h · src/gpio/EspGpioInput.cppArduino digitalRead() backend (device only).
src/gpio/OXSwitchManagerDevice.cppRegisters the default GPIO input + switch-manager factories (device only).
test/test_oxswitchmanager/ · test/test_oxconfigmanager/Host suites with a fake GPIO input.