A lightweight Python script to monitor a physical power button via GPIO interrupts for use on the Orange Pi Zero 3 running Armbian.
- Zero CPU usage: Uses hardware edge events via
libgpiodPython bindings instead of constant polling. - Self-healing state tracking: Edge events are only used to wake the script up early — the button's real state is always re-confirmed with a fresh hardware read. This means a missed or dropped edge event (contact bounce, event queue overflow, etc.) can never leave the script stuck thinking the button is still pressed.
- Accurate startup state: Reads the actual pin value on startup instead of assuming the button is released, so it behaves correctly even if the script is (re)started while the button is already held down.
- Debouncing: Settles and re-checks the pin after every raw transition to ignore physical contact noise.
- Systemd Service: Can run as a
systemdservice for automatic startup.
- Button Wire 1: Connect to Physical Pin 12 (PC11 / GPIO 75).
- Button Wire 2: Connect to Physical Pin 9 (GND - Ground).
Install the Python 3 libgpiod bindings:
sudo apt update
sudo apt install python3-libgpiodClone the repository (or copy the script) and run it with root privileges:
sudo python3 power-button-gpio.pyPress and hold the button for HOLD_TIME seconds (3s by default) to see the trigger message. Short presses or noise are logged and ignored.
To make the script run automatically at boot:
- Copy the script to a permanent location (e.g.,
/usr/local/bin):
sudo cp power-button-gpio.py /usr/local/bin/
sudo chmod +x /usr/local/bin/power-button-gpio.py- Edit
power-button-gpio.serviceto ensure theExecStartpath points to the new Python script (/usr/bin/python3 /usr/local/bin/power-button-gpio.py). - Install the service:
sudo cp power-button-gpio.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now power-button-gpio.serviceAll tunable values live at the top of power-button-gpio.py:
| Constant | Default | Meaning |
|---|---|---|
GPIO_CHIP |
gpiochip1 |
GPIO chip device |
GPIO_PIN |
75 |
Pin number (PC11) |
HOLD_TIME |
3.0 |
Seconds the button must be held to trigger the action |
DEBOUNCE_TIME |
0.2 |
Settle time used to filter out contact bounce |
POLL_TIMEOUT |
1.0 |
Max seconds between hardware resyncs while idle/waiting |
By default, the poweroff command is commented out in power-button-gpio.py for safety during testing:
# os.system("poweroff") # uncomment to enable shutdownUncomment that line to enable an actual shutdown once a long press is detected.