Add --led-active-low for inverted LED wiring

active_high was hardcoded to True, so an LED wired the other way
round - cathode to the pin, anode to 3.3 V, or an inverting
transistor driver - had no configuration at all. The symptom is easy
to misread as a dark LED: the light actually does the opposite, on
with no card and off with one.

Exposed as --led-active-low on the app and on install.sh, which
rewrites the unit's ExecStart like the other LED options. The
startup line now names the polarity, so the journal says which
configuration is actually running:

  LED on GPIO 23 (presence mode, active-high, gpiozero)

Default is unchanged, so existing installs behave identically.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-10-05 22:11:27 +03:00
parent 04f0ab9efa
commit b357b5755a
4 changed files with 64 additions and 16 deletions
+29 -4
View File
@@ -557,6 +557,7 @@ what `--list-ports` reports.
| `--device PATH` | `/dev/serial0` | Serial device the service opens (UART; use `/dev/rdm-reader` for USB) |
| `--led-pin N` | `23` | BCM GPIO number of the status LED (physical pin 16) |
| `--led-mode M` | `presence` | `presence`: lit while a card is on the reader; `error`: lit whenever running |
| `--led-active-low` | off | LED is wired active-low (cathode to the pin, anode to 3.3 V); inverts the signal |
| `--heartbeat S` | `2.0` | Seconds before a silent reader counts as card removed — also the presence/LED window |
| `--port PORT` | `8765` | HTTP port for the bridge |
| `--dir PATH` | `/opt/rdm-card-reader` | Install location |
@@ -702,6 +703,9 @@ Two modes, because the light can mean two different things:
> read lights it before concluding the LED is broken.
Wiring: LED anode to the GPIO pin through a ~330 Ω resistor, cathode to GND.
For the opposite arrangement — cathode to the pin, anode to 3.3 V, or a
transistor/MOSFET driver that inverts — pass **`--led-active-low`**, or the
light will do the opposite of what is wanted.
### It cannot break the reader
@@ -720,9 +724,9 @@ Startup reports which of the three states it is in (the mode shown is
`presence` by default):
```
LED on GPIO 23 (presence mode, gpiozero) # working
LED unavailable: gpiozero not installed # library missing
LED unavailable: no usable GPIO on pin 23: ... # no pin factory / pin busy
LED on GPIO 23 (presence mode, active-high, gpiozero) # working
LED unavailable: gpiozero not installed # library missing
LED unavailable: no usable GPIO on pin 23: ... # no pin factory / pin busy
```
That distinction matters: `BadPinFactory` subclasses `ImportError`, so a naive
@@ -742,7 +746,28 @@ journalctl -u rdm-card-reader -n 40 --no-pager | grep -i led
| --- | --- | --- |
| `LED unavailable: no usable GPIO on pin 23: ...` | gpiozero cannot reach a pin backend, or systemd/group permission is missing | See the three checks below |
| `LED unavailable: gpiozero not installed: ...` | LED extras missing from the venv | Install from the bundled wheels (below) |
| `LED on GPIO 23 (presence mode, gpiozero)` | LED is initialised — suspect wiring, or simply no card read yet | See the wiring note below |
| `LED on GPIO 23 (presence mode, active-high, gpiozero)` | LED is initialised — suspect wiring, pin number, or simply no card read yet | See the wiring note below |
**Check 0 — is the light doing the opposite?** A dark LED and an *inverted* LED
are different faults. If the light is **on with no card and goes dark when a
card is placed**, the pin number is right and the polarity is wrong: the LED is
wired active-low. Pass `--led-active-low` (installer, or the app directly), and
confirm with the journal, which now names the polarity:
```
LED on GPIO 23 (presence mode, active-low, gpiozero)
```
To isolate polarity from everything else, run the service in `error` mode,
where the light is lit the whole time the app runs:
```bash
sudo ./deploy/install.sh --device /dev/serial0 --led-mode error
```
Lit continuously means the hardware path is good. Dark means wiring, pin
number or backend. Lit-while-idle *and* dark-when-a-card-arrives in `presence`
mode means polarity.
**Check 1 — the venv must see the system pin backend.** `gpiozero` is pure
Python, but the library it uses to talk to the pins (`lgpio` on Bookworm,