This document describes how digital inputs work in cm::IOManager.
IOManager digital inputs are settings-driven and provide:
- GPIO configuration via Settings (pin, polarity, pull mode)
- Optional non-blocking button-like events (press/release/click/double/long)
- Runtime UI indicator (bool-dot)
The input system is designed to be usable early in boot (e.g. startup actions) and in the main loop without blocking delays.
For analog channels (ADC), see docs/IO-AnalogInputs.md.
Example (active-high button wired to 3.3V, internal pulldown, idle LOW):
ioManager.addDigitalInput(cm::IOManager::DigitalInputBinding{
.id = "testbutton",
.name = "Test Button",
.defaultPin = 33,
.defaultActiveLow = false,
.defaultPullup = false,
.defaultPulldown = true,
.defaultEnabled = true,
});Each input has a small set of settings.
GPIO(P): Which GPIO pin to useLOW-Active(L): Logic inversionPull-up(U): UseINPUT_PULLUPPull-down(D): UseINPUT_PULLDOWN
To keep keys short (ESP32 Preferences limit), IOManager uses slot-based keys:
- Inputs:
II%02uX(e.g.II00P) - Outputs:
IO%02uX(see IO-DigitalOutputs.md)
Suffix meanings for inputs:
P= pinL= active-lowU= pull-upD= pull-down
Important: slot-based keys depend on the order of addDigitalInput(...) calls.
If you reorder inputs in code, previously stored pins may appear to "move" to another input.
Registering an input for the runtime UI:
ioManager.addDigitalInputToLive(
"testbutton",
10,
"Live",
"Inputs",
"inputs",
"Test Button",
false
);pageName/cardName/groupName: live layout placementlabelOverride: label shown in the UIalarmWhenActive:true: input active is treated as an alarm condition (red/orange styling)false: input behaves like a normal boolean dot (green/gray)
Place persisted inputs in the Settings UI:
ioManager.addDigitalInputToSettingsGroup(
"testbutton",
"Digital - I/O",
"Digital Inputs",
"Test Button",
10
);Events are optional and configured per input:
ioManager.configureDigitalInputEvents(
"testbutton",
cm::IOManager::DigitalInputEventCallbacks{
.onPress = [](){ /* ... */ },
.onRelease = [](){ /* ... */ },
.onClick = [](){ /* ... */ },
.onDoubleClick = [](){ /* ... */ },
.onMultiClick = [](uint8_t count){ /* ... */ },
.onLongClick = [](){ /* ... */ },
}
);If onMultiClick is set, IOManager will fire it after the double-click timeout with the number of clicks (1..n), and onClick/onDoubleClick are not emitted.
These defaults are defined in cm::IOManager::DigitalInputEventOptions:
debounceMs = 40doubleClickMs = 350longClickMs = 700
You can override them per input:
cm::IOManager::DigitalInputEventOptions opt;
opt.longClickMs = 1200;
opt.doubleClickMs = 400;
opt.debounceMs = 60;
ioManager.configureDigitalInputEvents("testbutton", callbacks, opt);For dangerous actions (e.g. factory reset / AP mode), IOManager supports a dedicated callback:
onLongPressOnStartup
This callback is only eligible during a short startup window.
- Startup window duration:
STARTUP_LONG_PRESS_WINDOW_MS = 10000(10 seconds)
- While the startup window is active:
- a long press triggers
onLongPressOnStartup(if set)
- a long press triggers
- After the window:
onLongPressOnStartupis disabled- normal events (
onPress,onRelease,onClick,onDoubleClick,onLongClick) continue working
Example:
cm::IOManager::DigitalInputEventOptions opt;
opt.longClickMs = 2500;
ioManager.configureDigitalInputEvents(
"reset",
cm::IOManager::DigitalInputEventCallbacks{
.onLongPressOnStartup = [](){
ConfigManager.clearAllFromPrefs();
ConfigManager.saveAll();
ESP.restart();
}
},
opt
);Typical sketch order:
addDigitalInput(...)/addDigitalInputToSettingsGroup(...)/addDigitalInputToLive(...)/configureDigitalInputEvents(...)ConfigManager.loadAll()(loads persisted pins/polarity)ioManager.begin()(appliespinMode(...)and initializes states)- In
loop():ioManager.update()continuously reads inputs and emits events
| Method | Overloads / Variants | Description | Notes |
|---|---|---|---|
cm::IOManager::addDigitalInput |
addDigitalInput(const DigitalInputBinding& binding)addDigitalInput(const char* id, int pin = -1, bool activeLow = true, bool usePullup = true, bool usePulldown = false, bool registerSettings = true, int order = 100) |
Registers digital input channels and metadata. | Supports struct-based and inline registration. |
cm::IOManager::addDigitalInputToSettingsGroup |
addDigitalInputToSettingsGroup(...) (2 overloads) |
Places digital input settings into Settings UI. | Overloads support page/card/group variants. |
cm::IOManager::addDigitalInputToLive |
addDigitalInputToLive(const char* id, int order, const char* pageName, const char* cardName, const char* groupName, const char* labelOverride = nullptr, bool alarmWhenActive = false) |
Adds digital input indicator to Live UI. | Returns LiveControlHandleBool for callback wiring. |
cm::IOManager::configureDigitalInputEvents |
configureDigitalInputEvents(const char* id, DigitalInputEventCallbacks callbacks)configureDigitalInputEvents(const char* id, DigitalInputEventCallbacks callbacks, const DigitalInputEventOptions& options) |
Configures debounce/click/long-press event handling. | Includes startup long-press support. |