veilleur-systemd.py
A heartbeat LED plus a per-second service check: the script becomes a systemd daemon with Restart=always, started at boot. The robustness pattern for a headless embedded board.
Hardware
An ODROID-C2 (Amlogic S905, 4 Cortex-A53, 2 GB) running Ubuntu Hardkernel or Armbian, with gigabit Ethernet and a Raspberry-Pi-compatible 40-pin header. Optional: LED on one of the kernel-controllable LEDs (sysfs leds) or a GPIO LED via gpiozero.
Wiring
No mandatory wiring; system LEDs live in /sys/class/leds and blink with a simple write.
How it works
The loop runs at 1 Hz: it toggles the sysfs brightness and restarts any service reported inactive. The systemd unit (simple, Restart=always) respawns it and starts it at boot.
Running it
On Ubuntu Hardkernel or Armbian: apt install gpiod python3-gpiod; locate the header chip with gpiodetect (usually gpiochip1 on Amlogic) then gpioinfo.
Variants
Add a hardware watchdog (systemd WatchdogSec + sd_notify), or report status to an MQTT broker (pip install paho-mqtt).
veilleur-systemd.py
#!/usr/bin/env python3
# Veilleur : fait clignoter une LED "battement de coeur" et relance
# les services declares dans VEILLE. A installer en service systemd.
import subprocess
import time
from pathlib import Path
# --- config ---
LED_GLOB = "/sys/class/leds/*"
VEILLE = ["ssh", "cron"] # services a maintenir en vie
def trouver_led():
for led in sorted(Path(LED_GLOB).glob("*")):
if (led / "brightness").exists():
return led / "brightness"
return None
def maintenir():
for service in VEILLE:
r = subprocess.run(["systemctl", "is-active", "--quiet", service])
if r.returncode != 0:
print(f"{service} inactif -> redemarrage")
subprocess.run(["systemctl", "restart", service])
led = trouver_led()
print("Veilleur demarre (LED:", led, ")")
while True:
if led:
led.write_text("1" if (int(time.time()) % 2) else "0")
maintenir()
time.sleep(1)
# Installation (en root) :
# cp veilleur-systemd.py /usr/local/bin/veilleur.py && chmod +x ...
# puis unite systemd de type simple avec Restart=always (voir doc).