led-anim
Modifié par john le 2026/09/19 18:45
Animation arc-en-ciel sur le bandeau de LED du boîtier : les couleurs défilent en continu le long des 44 LED.
Matériel
| Élément | Valeur |
|---|---|
| Bandeau | 44 LED adressables, pilotage de type WS281x (ordre des couleurs RGB) |
| Broche de données | GPIO 18 (PWM) |
| Canal DMA | 10 |
Installation
Script dans /opt/led-anim/led-anim.py. Il dépend de rpi_ws281x, installé dans un venv dédié, indépendant du Python du système :
sudo python3 -m venv /opt/led-anim/venv
sudo /opt/led-anim/venv/bin/pip install rpi_ws281x
sudo chmod +x /opt/led-anim/led-anim.py
sudo /opt/led-anim/venv/bin/pip install rpi_ws281x
sudo chmod +x /opt/led-anim/led-anim.py
Il doit tourner en root : rpi_ws281x accède directement au DMA et au PWM.
Script
#!/opt/led-anim/venv/bin/python3
import time, colorsys, signal
from rpi_ws281x import PixelStrip, Color
LED_COUNT = 44
LED_PIN = 18
LED_FREQ_HZ = 800000
LED_DMA = 10
LED_BRIGHTNESS = 50
LED_INVERT = False
LED_CHANNEL = 0
STRIP_TYPE = 0x00100800 # WS2811_STRIP_RGB
SPEED = 0.02 # délai entre frames (s)
CYCLE = 600 # nb de frames pour un tour complet de la roue
strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA,
LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, STRIP_TYPE)
strip.begin()
def arret(signum, frame):
raise KeyboardInterrupt
signal.signal(signal.SIGTERM, arret)
try:
pos = 0
while True:
for i in range(LED_COUNT):
hue = ((pos / CYCLE) + (i / LED_COUNT)) % 1.0
r, g, b = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
strip.setPixelColor(i, Color(int(r*255), int(g*255), int(b*255)))
strip.show()
pos = (pos + 1) % CYCLE
time.sleep(SPEED)
except KeyboardInterrupt:
pass
finally:
for i in range(LED_COUNT):
strip.setPixelColor(i, Color(0, 0, 0))
strip.show()
time.sleep(0.1)
import time, colorsys, signal
from rpi_ws281x import PixelStrip, Color
LED_COUNT = 44
LED_PIN = 18
LED_FREQ_HZ = 800000
LED_DMA = 10
LED_BRIGHTNESS = 50
LED_INVERT = False
LED_CHANNEL = 0
STRIP_TYPE = 0x00100800 # WS2811_STRIP_RGB
SPEED = 0.02 # délai entre frames (s)
CYCLE = 600 # nb de frames pour un tour complet de la roue
strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA,
LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, STRIP_TYPE)
strip.begin()
def arret(signum, frame):
raise KeyboardInterrupt
signal.signal(signal.SIGTERM, arret)
try:
pos = 0
while True:
for i in range(LED_COUNT):
hue = ((pos / CYCLE) + (i / LED_COUNT)) % 1.0
r, g, b = colorsys.hsv_to_rgb(hue, 1.0, 1.0)
strip.setPixelColor(i, Color(int(r*255), int(g*255), int(b*255)))
strip.show()
pos = (pos + 1) % CYCLE
time.sleep(SPEED)
except KeyboardInterrupt:
pass
finally:
for i in range(LED_COUNT):
strip.setPixelColor(i, Color(0, 0, 0))
strip.show()
time.sleep(0.1)
- LED_BRIGHTNESS (0 à 255) règle la luminosité, SPEED et CYCLE la vitesse de défilement.
- Extinction à l'arrêt : SIGTERM (envoyé par systemctl stop) est converti en arrêt normal, puis le bloc finally éteint toutes les LED. Le time.sleep(0.1) final laisse à l'envoi DMA le temps d'aboutir ; sans lui, le bandeau garde ses dernières couleurs.
Service
/etc/systemd/system/led-anim.service :
[Unit]
Description=Animation du bandeau LED
After=multi-user.target
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
ExecStart=/opt/led-anim/venv/bin/python3 /opt/led-anim/led-anim.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
Description=Animation du bandeau LED
After=multi-user.target
StartLimitIntervalSec=300
StartLimitBurst=5
[Service]
ExecStart=/opt/led-anim/venv/bin/python3 /opt/led-anim/led-anim.py
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
StartLimitBurst limite les relances à cinq en cinq minutes : en cas d'erreur répétée, systemd abandonne au lieu de boucler indéfiniment.
sudo systemctl start led-anim # allumer
sudo systemctl stop led-anim # éteindre les LED
systemctl status led-anim # état
sudo systemctl stop led-anim # éteindre les LED
systemctl status led-anim # état
Historique
Remplace pixel-server (application Flask de pilotage du bandeau), désactivé en juillet 2026 après des mois de boucle de redémarrage et supprimé en septembre 2026.