Add a dedicated error LED on GPIO 24
One LED cannot say two things at once, and in the default presence mode the status LED is already carrying "a card is here". The result was that a bad read - a checksum failure - was reported not at all: verified by driving the LED worker, which showed presence mode producing no light on invalid_card while error mode blinked. A second LED on its own pin (GPIO 24 = physical pin 18, matching the workstation app) now pulses for --error-pulse seconds on a bad read, leaving the status light to keep tracking the card. This also gives ERROR_BLINK_SECONDS, previously dead, a real use. --error-led-pin N / --error-led-active-low / --error-pulse S --no-error-led restores the single-LED blink install.sh rewrites the unit's ExecStart for all of it, verified for the default, active-low and no-error-led cases. Also extracts the repeated backend-opening code into _open_led(), which keeps the BadPinFactory-is-an-ImportError subtlety in one place instead of two, and treats the error pin colliding with the status pin as "no error LED" rather than opening one pin twice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -558,6 +558,9 @@ what `--list-ports` reports.
|
||||
| `--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 |
|
||||
| `--error-led-pin N` | `24` | BCM GPIO of a second LED, lit briefly on a bad read |
|
||||
| `--no-error-led` | off | No error LED; blink the status LED instead |
|
||||
| `--error-pulse S` | `1.0` | Seconds to hold the error LED on a bad read |
|
||||
| `--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 |
|
||||
@@ -666,30 +669,48 @@ Exit codes: `0` ok, `1` no port, `2` library missing, `3` port ambiguous.
|
||||
|
||||
## Status LED
|
||||
|
||||
An LED driven by card events, on **GPIO 23** (physical pin **16**) by default —
|
||||
the same pin the workstation app used. Optional: everything works without it.
|
||||
Two LEDs, each saying one thing. Both optional: everything works without
|
||||
either.
|
||||
|
||||
By default the light **tracks the card**: lit while a card is on the reader,
|
||||
dark otherwise.
|
||||
| LED | Default pin | Means |
|
||||
| --- | --- | --- |
|
||||
| **Status** | GPIO 23 (physical pin **16**) | Lit while a card is on the reader (`presence` mode) |
|
||||
| **Error** | GPIO 24 (physical pin **18**) | Lit briefly when a read fails (checksum mismatch) |
|
||||
|
||||
The status pin matches the workstation app. The error LED exists because one
|
||||
light cannot say two things at once: in the default `presence` mode the status
|
||||
LED is already carrying "a card is here", so **without a separate error LED a
|
||||
bad read is reported not at all**. A dedicated red LED on its own pin is the
|
||||
clearer arrangement.
|
||||
|
||||
```bash
|
||||
rdm-card-reader # lit only while a card is on the reader
|
||||
rdm-card-reader --led-mode error # lit whenever running, blinks on a bad read
|
||||
rdm-card-reader --led-pin 17 # a different pin
|
||||
rdm-card-reader --no-led # no LED at all
|
||||
rdm-card-reader # status LED tracks the card; error LED pulses on a bad read
|
||||
rdm-card-reader --led-mode error # status LED lit whenever running, blinks on a bad read
|
||||
rdm-card-reader --error-led-pin 25 # error LED on a different pin
|
||||
rdm-card-reader --no-error-led # no error LED; blink the status LED instead
|
||||
rdm-card-reader --no-led # no LEDs at all
|
||||
```
|
||||
|
||||
| Flag | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `--no-led` | off | Do not drive a LED |
|
||||
| `--led-pin` | `23` | **BCM** GPIO number — not the physical header pin |
|
||||
| `--no-led` | off | Do not drive any LED |
|
||||
| `--led-pin` | `23` | **BCM** GPIO number of the status LED — not the physical header pin |
|
||||
| `--led-mode` | `presence` | See the two readings below |
|
||||
| `--led-no-error-blink` | off | Do not blink on a bad read |
|
||||
| `--led-active-low` | off | Status LED wired active-low (cathode to the pin) |
|
||||
| `--error-led-pin` | `24` | BCM GPIO of the error LED |
|
||||
| `--error-led-active-low` | off | Error LED wired active-low |
|
||||
| `--error-pulse` | `1.0` | Seconds to hold the error LED on a bad read |
|
||||
| `--no-error-led` | off | No error LED; blink the status LED instead |
|
||||
| `--led-no-error-blink` | off | With `--no-error-led`, do not blink on a bad read |
|
||||
|
||||
`--led-pin` takes the **BCM GPIO number**. The two are easy to confuse, and it
|
||||
is the second most common reason a LED "does not work" — the default `23` is
|
||||
**physical pin 16**, not pin 23. The full mapping is under **Wiring** below.
|
||||
|
||||
Giving the error LED the same pin as the status LED is treated as "no error
|
||||
LED": two lights on one pin cannot be driven independently, so the app says so
|
||||
and falls back to the status blink rather than failing.
|
||||
|
||||
Two modes, because the light can mean two different things:
|
||||
|
||||
| Mode | Behaviour | Use when |
|
||||
@@ -704,8 +725,9 @@ Two modes, because the light can mean two different things:
|
||||
|
||||
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.
|
||||
transistor/MOSFET driver that inverts — pass **`--led-active-low`** (or
|
||||
`--error-led-active-low` for the error LED), or the light will do the opposite
|
||||
of what is wanted.
|
||||
|
||||
### It cannot break the reader
|
||||
|
||||
@@ -720,11 +742,12 @@ point:
|
||||
refusing to run.
|
||||
* **Never crashes on a dead pin.** A failed toggle is logged and ignored.
|
||||
|
||||
Startup reports which of the three states it is in (the mode shown is
|
||||
`presence` by default):
|
||||
Startup reports the state of each LED (the mode shown is `presence` by
|
||||
default):
|
||||
|
||||
```
|
||||
LED on GPIO 23 (presence mode, active-high, gpiozero) # working
|
||||
LED on GPIO 23 (presence mode, active-high, gpiozero) # status LED working
|
||||
Error LED on GPIO 24 (lit for 1.0s on a bad read, ...) # error LED working
|
||||
LED unavailable: gpiozero not installed # library missing
|
||||
LED unavailable: no usable GPIO on pin 23: ... # no pin factory / pin busy
|
||||
```
|
||||
@@ -747,6 +770,7 @@ 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, active-high, gpiozero)` | LED is initialised — suspect wiring, pin number, or simply no card read yet | See the wiring note below |
|
||||
| No error indication on a bad read | The error LED pin is wrong or the LED is unwired, and the status LED only blinks in `error` mode | Check `Error LED on GPIO …` in the journal; see 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
|
||||
@@ -867,9 +891,10 @@ so the Pi's TX line (pin 8) has nothing to send. Only pin 10 carries data.
|
||||
> on the reader-TX → pin-10 line. This is not a cause of "no cards read" if you
|
||||
> already see data, but it is worth fixing before relying on the device.
|
||||
|
||||
For the status LED: **anode** → GPIO pin through a ~330 Ω resistor,
|
||||
**cathode** → GND. See the pin numbering table below, and note the LED is
|
||||
optional — the reader works without it.
|
||||
For each LED: **anode** → GPIO pin through a ~330 Ω resistor,
|
||||
**cathode** → GND. Status LED on GPIO 23 (physical pin 16) and error LED on
|
||||
GPIO 24 (physical pin 18) by default. See the pin numbering table below, and
|
||||
note both LEDs are optional — the reader works without them.
|
||||
|
||||
On a Raspberry Pi you usually need to free up the primary UART first:
|
||||
|
||||
@@ -941,18 +966,20 @@ Look up the pin your wire is actually on, and pass the BCM number:
|
||||
| 12 | `18` | | 29 | `5` |
|
||||
| 13 | `27` | | 31 | `6` |
|
||||
| 15 | `22` | | 32 | `12` |
|
||||
| **16** | **`23`** (the default) | | 33 | `13` |
|
||||
| 18 | `24` | | 35 | `19` |
|
||||
| **16** | **`23`** (status LED default) | | 33 | `13` |
|
||||
| **18** | **`24`** (error LED default) | | 35 | `19` |
|
||||
| 19 | `10` | | 36 | `16` |
|
||||
| 21 | `9` | | 37 | `26` |
|
||||
| 22 | `25` | | 38 | `20` |
|
||||
| **23** | **`11`** | | 40 | `21` |
|
||||
|
||||
So an LED wired to **physical pin 23** needs `--led-pin 11`, and the default
|
||||
`--led-pin 23` requires the wire on **physical pin 16**.
|
||||
`--led-pin 23` requires the wire on **physical pin 16**. The error LED defaults
|
||||
to GPIO 24, which is **physical pin 18**.
|
||||
|
||||
```bash
|
||||
sudo ./deploy/install.sh --device /dev/serial0 --led-pin 11 # wire on physical pin 23
|
||||
sudo ./deploy/install.sh --device /dev/serial0 --led-pin 11 # status wire on physical pin 23
|
||||
sudo ./deploy/install.sh --device /dev/serial0 --error-led-pin 25 # error wire on physical pin 22
|
||||
```
|
||||
|
||||
Do **not** use physical pin 8 or 10 (GPIO 14 / 15 — the reader's own UART),
|
||||
|
||||
Reference in New Issue
Block a user