Skip to content

Commit 6e923c8

Browse files
grischeclaude
andcommitted
ffmuc-leds-off: add package
Add a package that lets node operators darken all LEDs during normal operation, intended for nodes deployed in dark environments or where visible LEDs would expose the device to onlookers. LEDs follow their normal patterns throughout the boot sequence (preinit, regular, set_state done at S95) and during sysupgrade and setup mode, so error and progress signals stay debuggable. Only after S99 are LEDs darkened by iterating /sys/class/leds/* and setting each trigger to "none" and brightness to 0. The package is disabled by default. To enable: uci set leds-off.settings.enabled='1' uci commit leds-off gluon-reconfigure /etc/init.d/leds-off restart # or reboot Setup mode is detected via gluon-setup-mode.@setup_mode[0].configured and skipped as defense-in-depth, even though it runs a separate init path that would not invoke this script anyway. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent a2b6afd commit 6e923c8

5 files changed

Lines changed: 137 additions & 0 deletions

File tree

ffmuc-leds-off/Makefile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# SPDX-License-Identifier: MIT
2+
include $(TOPDIR)/rules.mk
3+
4+
PKG_NAME:=ffmuc-leds-off
5+
PKG_VERSION:=1
6+
PKG_RELEASE:=1
7+
PKG_LICENSE:=MIT
8+
9+
include $(TOPDIR)/../package/gluon.mk
10+
11+
define Package/$(PKG_NAME)
12+
TITLE:=Disable all LEDs during normal operation
13+
DEPENDS:=+gluon-core
14+
endef
15+
16+
define Package/$(PKG_NAME)/conffiles
17+
/etc/config/leds-off
18+
endef
19+
20+
define Package/$(PKG_NAME)/description
21+
Darkens all LEDs after the boot sequence completes (S99, after
22+
set_state done at S95). Intended for nodes deployed in dark
23+
environments or where visible LEDs would expose the device to
24+
onlookers. LEDs follow their normal patterns during preinit, boot,
25+
sysupgrade, and setup mode so error and progress signals stay
26+
debuggable. Disabled by default; enable per-node with
27+
`uci set leds-off.settings.enabled='1' && gluon-reconfigure`.
28+
endef
29+
30+
$(eval $(call BuildPackageGluon,$(PKG_NAME)))

ffmuc-leds-off/README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# ffmuc-leds-off
2+
3+
This package lets node operators turn off **all LEDs** during normal operation,
4+
for nodes deployed in dark environments or where the LEDs would expose the
5+
device to onlookers.
6+
7+
Errors and warnings remain visible because their existing LED behaviour is
8+
untouched:
9+
10+
- **Setup / config mode** — the device still blinks its status LED so users
11+
can find a misconfigured node.
12+
- **Sysupgrade in progress** — the OpenWrt diagnostic LED pattern fires
13+
normally, so users see the upgrade is running and won't power-off the
14+
device mid-flash.
15+
- **Boot in progress (preinit)** — LEDs run their normal patterns until the
16+
device finishes booting. Only after `set_state done` (S95) does this package
17+
darken them (S99).
18+
19+
## Configuration
20+
21+
The package is **disabled by default** after install. To darken the LEDs on
22+
a node:
23+
24+
```sh
25+
uci set leds-off.settings.enabled='1'
26+
uci commit leds-off
27+
gluon-reconfigure # registers the S99 init.d service
28+
/etc/init.d/leds-off restart # apply immediately (or reboot)
29+
```
30+
31+
To restore default LED behaviour:
32+
33+
```sh
34+
uci set leds-off.settings.enabled='0'
35+
uci commit leds-off
36+
gluon-reconfigure # unregisters the S99 init.d service
37+
/etc/init.d/leds-off stop # best-effort restore now (or reboot)
38+
```
39+
40+
A reboot is the safest way to restore LEDs whose default triggers come from
41+
kernel device tree (DTS) and aren't tracked in `/etc/config/system`.
42+
43+
## How it works
44+
45+
When `enabled='1'`, an init script at `/etc/init.d/leds-off` (START=99,
46+
i.e. *after* OpenWrt's `set_state done` at S95) iterates every entry under
47+
`/sys/class/leds/` and sets:
48+
49+
- `trigger``none`
50+
- `brightness``0`
51+
52+
This affects only software-controllable LEDs. LEDs wired directly to PHY
53+
chips (some RJ45 link/activity indicators) cannot be turned off in software
54+
and are unaffected by this package.
55+
56+
If the device is in setup mode (`gluon-setup-mode.@setup_mode[0].configured`
57+
is not `1`), the darkening step is skipped so the setup-mode blink pattern
58+
remains visible. In practice, setup mode runs a different init path
59+
(`/lib/gluon/setup-mode/init.d/`) entirely, so the standard `/etc/init.d/leds-off`
60+
wouldn't fire there anyway — the check is defence-in-depth.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
config settings 'settings'
2+
option enabled '0'
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/sh /etc/rc.common
2+
# /etc/rc.common imports this script and uses variables defined here
3+
# shellcheck disable=SC2034
4+
# shellcheck shell="busybox sh"
5+
6+
# Must run after /etc/init.d/done (S95), which calls `set_state done`
7+
# and would otherwise re-light LEDs after we darken them.
8+
START=99
9+
STOP=10
10+
11+
start() {
12+
local enabled
13+
config_load 'leds-off'
14+
config_get_bool enabled settings enabled 0
15+
16+
[ "$enabled" = 1 ] || return 0
17+
18+
# Defense-in-depth: setup mode uses a different init path, so this
19+
# normally won't run there anyway.
20+
local configured
21+
configured="$(uci -q get 'gluon-setup-mode.@setup_mode[0].configured')"
22+
[ "$configured" = 1 ] || return 0
23+
24+
local led
25+
for led in /sys/class/leds/*; do
26+
[ -e "$led/trigger" ] || continue
27+
echo none > "$led/trigger" 2>/dev/null
28+
[ -e "$led/brightness" ] && echo 0 > "$led/brightness" 2>/dev/null
29+
done
30+
}
31+
32+
stop() {
33+
# Best-effort restore: re-apply OpenWrt's UCI LED config. LEDs whose
34+
# defaults come from kernel DTS triggers may need a reboot to fully restore.
35+
/etc/init.d/led restart >/dev/null 2>&1
36+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/usr/bin/lua
2+
3+
local uci = require('simple-uci').cursor()
4+
5+
if uci:get_bool('leds-off', 'settings', 'enabled') then
6+
os.execute('/etc/init.d/leds-off enable')
7+
else
8+
os.execute('/etc/init.d/leds-off disable')
9+
end

0 commit comments

Comments
 (0)