Power LED (GPIO 4)

The power LED is lit whenever the network interface is up — a proxy for "the Pi is booted and on the network". A tiny userspace daemon polls the interface's operstate from /sys/class/net/<iface>/operstate every 5 seconds and switches the LED on or off. Resistor + wiring are the same as the Network Activity LED: 220 Ω from GPIO 4 to LED anode, cathode to GND (yellow LED on the PiNAS build).

One script, parameterised by interface and LED pin via CLI args:

#!/usr/bin/env python3
"""Turn on LED whenever <iface> is UP.

Usage: power_led.py <iface> [gpio]
  iface     - e.g. eth0, end0, wlan0
  gpio      - BCM pin number (default 4)
"""
import sys
from gpiozero import LED
from time import sleep

IFACE = sys.argv[1]
LED_PIN = int(sys.argv[2]) if len(sys.argv) > 2 else 4

led = LED(LED_PIN)

def iface_up(iface):
    try:
        with open(f"/sys/class/net/{iface}/operstate") as f:
            return f.read().strip() == "up"
    except FileNotFoundError:
        return False

while True:
    if iface_up(IFACE):
        led.on()
    else:
        led.off()

    sleep(5)

Install it:

sudo install -m 0755 power_led.py /usr/local/bin/power_led.py

This is deployed by the pinas_power_led ansible role (interface eth0, pin GPIO 4), which also installs python3-lgpio and runs the service as the ledctl user with GPIOZERO_PIN_FACTORY=lgpio.

Interface name on Pi 4/5 may be end0 rather than eth0 for wired — check with ip -br link.

/etc/systemd/system/power_led.service:

[Unit]
Description=Power On activity LED (eth0 GPIO 4)
Requires=sys-subsystem-net-devices-eth0.device
After=sys-subsystem-net-devices-eth0.device network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /usr/local/bin/power_led.py eth0 4
Restart=on-failure
RestartSec=2

WorkingDirectory=/home/ledctl
Environment=HOME=/home/ledctl
Environment=GPIOZERO_PIN_FACTORY=lgpio
User=ledctl
Group=gpio

PrivateTmp=yes

[Install]
WantedBy=multi-user.target

Requires=/After=sys-subsystem-net-devices-eth0.device — udev creates this unit automatically once the kernel publishes eth0, so the script doesn't start before the interface exists.

Enable it:

sudo systemctl daemon-reload
sudo systemctl enable --now power_led.service
systemctl status power_led.service
journalctl -u power_led.service -f