OptaButton is a small, focused Arduino library for handling physical pushbuttons predictably across:
- Classic Arduino boards (Uno, Mega, etc.)
- Arduino Opta controllers (AFX00001 / AFX00002 / AFX00003)
- Opta Digital Expansion modules (AFX00005 / AFX00006)
It provides a clean, event-based API for buttons that is intentionally simple and heavily commented.
I love that Opta exists, and the analog expansion is especially coming in handy. But if you're coming from a purely Arduino IDE/Uno/Mega type environment you're in for some surprises.
The Arduino Opta Blueprint library (Arduino_Opta_Blueprint) has been updated recently—looking forward to good things—but when I was getting started with Opta, some of the examples on the official Opta tutorial weren't even working. Some of that is likely on me, but regardless I had to spend a long time digging through the Opta_Blueprint folders for not-totally-clear-to-me comments and code in order to put this library together so someone in my shoes wouldn't have to next time.
Plus I found most button libraries weren't speaking my learning language when I first started out, so I'm hoping this one fills a hole.
So... why are there button libraries?
Because buttons:
- bounce
- get held down
- get tapped real fast
- need long-press behavior
- need hold-and-accelerated-repeat
- behave differently across hardware platforms
Learning how to handle those things in simple code is a great way to learn, but you don't want to have to do it every time. If you install the library, instead of writing debounce code in loop(), you ask questions like:
thisButton.isShortPressed();
thatButton.isLongPressed();
thisOtherButton.isRepeating();And those questions mean the same thing on both AVR and Opta, so you can just use this out of the box.
If you happen to be curious how those things might be implemented, this library has plain-english comments on every line.
- Edge-based button handling
- Debounce handled internally
- Short press detection
- Long press detection
- Long-press release detection
- Hold-repeat with optional acceleration
- Works with:
- GPIO (INPUT_PULLUP)
- Opta controller digital inputs
- Opta digital expansion inputs
- No blocking delays
- No interrupts required
- Clear, beginner-readable implementation
OptaButton supports multiple hardware input sources:
| Input mode | Description |
|---|---|
| GPIO | Classic Arduino digital pins (Uno, Mega, etc.) |
| OPTA_CTL | Opta controller onboard digital inputs |
| EXP_DIG | Opta digital expansion modules (AFX00005 / AFX00006) |
There used to be an EXP_ANA mode, but the Opta Analog Expansion (AFX00007) is not recommended for pushbutton input. It’s too slow and doesn’t behave like the other modes, so I removed it. The Analog Expansion is meant for other things—like outputting a 4-20mA current loop—which it does well.
- Configure pin as INPUT_PULLUP
- Wire button between the pin and GND
- LOW = pressed (default behavior)
- Wire button between the input and +24 V
- HIGH = pressed
- Wire button between the DI channel and +24 V
- HIGH = pressed
If your wiring causes the pressed state to be inverted relative to the default, set the invertedLogic constructor parameter to true.
When you create an OptaButton, you have to include the first three parameter arguments:
DefLab::ButtonInputMode mode, // which input hardware to use
uint8_t inputPin, // pin number or channel index
const char* label, // human-readable name for debuggingThe remaining six default to values I've found useful in my system, which uses a variety of momentary pushbuttons to both AVR and Opta. You must define these parameters in order up to the one you want to modify/override, but if you want to use the defaults after that you don't need to pass them.
For example, if you just wanted to modify the debounce time to 35ms, you'd create an OptaButton with four parameters (everything up to and including debounceMs) and the compiler would complete the button by taking the defaults after that.
However, if you were only interested in modifying the long press time, you'd still have to enter the first six parameter arguments—including debounceMs and inverted—even if you liked the defaults. You can't just skip to the one you want, because the compiler won't know which one you're talking about.
Here are the remaining parameters and their defaults:
uint16_t debounceMs = 20, // ms to ignore bounce after edge
bool inverted = false, // true if LOW=pressed instead of HIGH
uint16_t longPressMs = 800, // ms to hold before long press fires
uint16_t repeatStartMs = 100, // initial delay between repeats
uint16_t repeatMinMs = 8, // fastest delay when accelerating
uint8_t accelRate = 100 // how much to speed up per second#include <OptaButton.h>
using DefLab::ButtonInputMode;
OptaButton myButton(
ButtonInputMode::GPIO,
2,
"My Button"
);
void setup() {
OPTA_BEGIN(); // required on Opta, safe no-op on AVR
myButton.begin(); // configure the input hardware
}
void loop() {
OPTA_UPDATE(); // required on Opta, safe no-op on AVR
myButton.update(); // update button state machine
if (myButton.isShortPressed()) {
// handle short press
}
if (myButton.isRepeating()) {
// handle accelerated hold-repeat
}
}OptaButton provides two convenience macros:
OPTA_BEGIN();
OPTA_UPDATE();
On Opta boards, these expand to:
- OptaController.begin()
- OptaController.update()
On non-Opta boards, they compile out to no-ops.
This allows example sketches to remain portable without cluttering code with platform-specific preprocessor logic.
TL/DR: For Opta digital expansion modules, OptaButton includes internal safeguards to avoid over-polling inputs while remaining compatible with earlier Opta core behavior, which required updating input states every time you polled the pins. As the Opta core library evolves, this section will be updated if necessary.
This repository includes example sketches demonstrating common embedded UI patterns:
-
Three-button menu
(Program / Up / Down) -
Four-button menu
(Program / Cycle / Up / Down)
The examples are written as teaching tools:
- verbose comments
- no hidden magic
- designed to be read line-by-line
They intentionally favor clarity over brevity.
OptaButton depends on DefLab_Common for shared enums and utilities.
You do not need to understand DefLab_Common to use OptaButton, but it must be installed for the library to compile.
panchocoquito
Def Lab
MIT