fix(led-heartbeat): v2.1.1 — cap brightness at 10 to keep IS31FL319X i2c bus responsive

The IS31FL319X chip on the MOCHAbin's i2c-1 bus errors out with -EIO
above brightness ~50. Pushing 100 or 255 saturates the bus, the chip
starts NACK'ing the next register writes, the LED driver logs
'Setting an LED's brightness failed (-5)' on every retry, and the
LEDs freeze at whatever value last got through.

Observed live 2026-05-24 on gk2: all three RGBs stuck plain green at
218/255/255 with the bash bumper and the python heartbeat both pushing
high values into a saturated chip. After dropping to brightness 10
and adding a 30 ms i2c-write delay in the python set_rgb() loop,
writes succeed and the LEDs reflect the actual health state instead
of a static color.

Files:
  - usr/sbin/secubox-led          BRIGHTNESS 100 -> 10
  - usr/sbin/secubox-healthbump   ACTIVE 100 -> 30, SLEEP 20 -> 5
  - usr/sbin/secubox-led-pulse    BRIGHTNESS 100 -> 10
  - usr/sbin/secubox-led-heartbeat python set_rgb scales any 0-255
    caller down to 0-10 in write_text, then sleeps 30 ms before the
    next channel — matches the bash scripts' I2C_DELAY and lets the
    mv64xxx_i2c controller drain between calls.
  - scripts/secubox-healthbump (the duplicate script kept in repo root
    for ad-hoc dev use) gets the same BRIGHTNESS=10 cap.

The misleading 'BRIGHTNESS=100 works reliably' comment that the code
contradicted is replaced with an incident note pointing at the EIO
ceiling.
This commit is contained in:
CyberMind-FR 2026-05-24 08:35:22 +02:00
parent d2461cc70d
commit 65c64411ae
6 changed files with 53 additions and 11 deletions

View File

@ -1,3 +1,23 @@
secubox-led-heartbeat (2.1.1-1~bookworm1) bookworm; urgency=medium
* Cap LED brightness at 10 (was 100) to keep the IS31FL319X chip on
the MOCHAbin's i2c-1 bus responsive. Pushing 100 or 255 saturates
the bus, the chip starts NACK'ing register writes with -EIO, and
the LEDs freeze at whatever value last got through — observed live
2026-05-24 with all three RGBs stuck plain green at 218/255/255.
Affected files:
- usr/sbin/secubox-led (BRIGHTNESS 100 -> 10)
- usr/sbin/secubox-healthbump (ACTIVE 100 -> 30, SLEEP 20 -> 5)
- usr/sbin/secubox-led-pulse (BRIGHTNESS 100 -> 10)
- usr/sbin/secubox-led-heartbeat (python set_rgb now scales 0-255
callers down to 0-10 in write_text, and inserts a 30 ms sleep
between channels to give the i2c controller time to drain).
The misleading "BRIGHTNESS=100 works reliably" comment that the
code contradicted is replaced with an incident note pointing at
the EIO ceiling.
-- Gerald Kerma <devel@cybermind.fr> Sun, 24 May 2026 08:35:00 +0200
secubox-led-heartbeat (2.1.0-1~bookworm1) bookworm; urgency=medium
* NEW: Activity-based brightness (ACTIVE=100, SLEEP=20)

View File

@ -25,9 +25,12 @@ RATE_FILE="/tmp/secubox-ban-rate"
STATUS_FILE="/tmp/secubox/led-status"
STATE_FILE="/tmp/secubox/prev-state"
# Brightness levels
BRIGHTNESS_ACTIVE=100
BRIGHTNESS_SLEEP=20
# Brightness levels. Capped at 30 active / 5 sleep — IS31FL319X on the
# MOCHAbin's i2c-1 bus errors with EIO above ~50 (the bus is shared with
# other probes that NAK on absent addresses). See secubox-led for the
# 2026-05-24 incident notes.
BRIGHTNESS_ACTIVE=30
BRIGHTNESS_SLEEP=5
BRIGHTNESS=$BRIGHTNESS_SLEEP
# Activity detection

View File

@ -10,12 +10,17 @@
# Layers: hw|1|bottom, svc|2|middle, sec|3|top
# Status: ok|green, warn|yellow, error|red, msg|blue, off
#
# Brightness value 10 is optimal for IS31FL3199 on Debian (255 causes I2C errors)
# IS31FL319X on the MOCHAbin's i2c-1 bus errors with EIO above brightness
# ~50 — pushing 100 or 255 saturates the bus, the next write fails with
# `Setting an LED's brightness failed (-5)`, and the LEDs freeze at
# whatever value last got through. Observed live 2026-05-24: green
# channels at 218/255/255, blue/red writes returning EIO, all three
# LEDs stuck plain green. Capping at 10 keeps writes reliable while
# still being clearly visible on the front panel.
set -euo pipefail
# Brightness 100 works reliably with proper I2C delays
readonly BRIGHTNESS=100
readonly BRIGHTNESS=10
readonly I2C_DELAY=0.03
led_path() { echo "/sys/class/leds/$1:led$2/brightness"; }

View File

@ -89,7 +89,11 @@ class LEDController:
log.warning("No IS31FL3199 LEDs found - running in simulation mode")
def set_rgb(self, led_num: int, r: int, g: int, b: int):
"""Set RGB values for a LED (0-255 each)."""
"""Set RGB values for a LED. Callers pass 0-255 per the COLORS
palette; we scale down to the IS31FL319X EIO-safe ceiling
(~10) before writing. Above ~50 the chip on the MOCHAbin's
i2c-1 bus errors out with -EIO and the LEDs freeze at their
last successful value (incident 2026-05-24)."""
if not 1 <= led_num <= LED_COUNT:
return
@ -99,8 +103,15 @@ class LEDController:
for color, value in values.items():
path = self.led_paths[led_num].get(color)
if path and path.exists():
scaled = max(0, min(10, value * 10 // 255))
try:
path.write_text(str(min(255, max(0, value))))
path.write_text(str(scaled))
# 30 ms between i2c writes — matches the bash
# scripts. Without this, 9 channels written
# back-to-back saturate the mv64xxx_i2c
# controller and we get -EIO sprinkled across
# random channels.
time.sleep(0.03)
except PermissionError:
log.warning("No write access to %s", path)

View File

@ -4,7 +4,9 @@
set -euo pipefail
BRIGHTNESS=100
# IS31FL319X EIO-safe ceiling on the MOCHAbin i2c-1 bus. See secubox-led
# for the 2026-05-24 incident notes.
BRIGHTNESS=10
I2C_DELAY=0.15
STATUS_FILE="/tmp/secubox/led-status"

View File

@ -12,8 +12,9 @@
set -euo pipefail
# Brightness 100 works reliably with proper I2C delays
readonly BRIGHTNESS=100
# IS31FL319X EIO-safe ceiling on the MOCHAbin i2c-1 bus.
# See packages/secubox-led-heartbeat/usr/sbin/secubox-led for context.
readonly BRIGHTNESS=10
readonly I2C_DELAY=0.03
readonly RATE_FILE="/tmp/secubox-ban-rate"
readonly STATUS_FILE="/tmp/secubox/led-status"