Afficher les derniers auteurs
| author | version | line-number | content |
|---|---|---|---|
| 1 | Animation arc-en-ciel sur le bandeau de LED du boîtier : les couleurs défilent en continu le long des 44 LED. | ||
| 2 | |||
| 3 | == Matériel == | ||
| 4 | |||
| 5 | |=Élément|=Valeur | ||
| 6 | |Bandeau|44 LED adressables, pilotage de type WS281x (ordre des couleurs RGB) | ||
| 7 | |Broche de données|GPIO 18 (PWM) | ||
| 8 | |Canal DMA|10 | ||
| 9 | |||
| 10 | == Installation == | ||
| 11 | |||
| 12 | 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 : | ||
| 13 | |||
| 14 | {{code language="bash"}} | ||
| 15 | sudo python3 -m venv /opt/led-anim/venv | ||
| 16 | sudo /opt/led-anim/venv/bin/pip install rpi_ws281x | ||
| 17 | sudo chmod +x /opt/led-anim/led-anim.py | ||
| 18 | {{/code}} | ||
| 19 | |||
| 20 | Il doit tourner en root : ##rpi_ws281x## accède directement au DMA et au PWM. | ||
| 21 | |||
| 22 | == Script == | ||
| 23 | |||
| 24 | {{code language="python"}} | ||
| 25 | #!/opt/led-anim/venv/bin/python3 | ||
| 26 | import time, colorsys, signal | ||
| 27 | from rpi_ws281x import PixelStrip, Color | ||
| 28 | |||
| 29 | LED_COUNT = 44 | ||
| 30 | LED_PIN = 18 | ||
| 31 | LED_FREQ_HZ = 800000 | ||
| 32 | LED_DMA = 10 | ||
| 33 | LED_BRIGHTNESS = 50 | ||
| 34 | LED_INVERT = False | ||
| 35 | LED_CHANNEL = 0 | ||
| 36 | STRIP_TYPE = 0x00100800 # WS2811_STRIP_RGB | ||
| 37 | |||
| 38 | SPEED = 0.02 # délai entre frames (s) | ||
| 39 | CYCLE = 600 # nb de frames pour un tour complet de la roue | ||
| 40 | |||
| 41 | strip = PixelStrip(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, | ||
| 42 | LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL, STRIP_TYPE) | ||
| 43 | strip.begin() | ||
| 44 | |||
| 45 | def arret(signum, frame): | ||
| 46 | raise KeyboardInterrupt | ||
| 47 | |||
| 48 | signal.signal(signal.SIGTERM, arret) | ||
| 49 | |||
| 50 | try: | ||
| 51 | pos = 0 | ||
| 52 | while True: | ||
| 53 | for i in range(LED_COUNT): | ||
| 54 | hue = ((pos / CYCLE) + (i / LED_COUNT)) % 1.0 | ||
| 55 | r, g, b = colorsys.hsv_to_rgb(hue, 1.0, 1.0) | ||
| 56 | strip.setPixelColor(i, Color(int(r*255), int(g*255), int(b*255))) | ||
| 57 | strip.show() | ||
| 58 | pos = (pos + 1) % CYCLE | ||
| 59 | time.sleep(SPEED) | ||
| 60 | except KeyboardInterrupt: | ||
| 61 | pass | ||
| 62 | finally: | ||
| 63 | for i in range(LED_COUNT): | ||
| 64 | strip.setPixelColor(i, Color(0, 0, 0)) | ||
| 65 | strip.show() | ||
| 66 | time.sleep(0.1) | ||
| 67 | {{/code}} | ||
| 68 | |||
| 69 | * ##LED_BRIGHTNESS## (0 à 255) règle la luminosité, ##SPEED## et ##CYCLE## la vitesse de défilement. | ||
| 70 | * 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. | ||
| 71 | |||
| 72 | == Service == | ||
| 73 | |||
| 74 | ##/etc/systemd/system/led-anim.service## : | ||
| 75 | |||
| 76 | {{code language="ini"}} | ||
| 77 | [Unit] | ||
| 78 | Description=Animation du bandeau LED | ||
| 79 | After=multi-user.target | ||
| 80 | StartLimitIntervalSec=300 | ||
| 81 | StartLimitBurst=5 | ||
| 82 | |||
| 83 | [Service] | ||
| 84 | ExecStart=/opt/led-anim/venv/bin/python3 /opt/led-anim/led-anim.py | ||
| 85 | Restart=on-failure | ||
| 86 | RestartSec=10 | ||
| 87 | |||
| 88 | [Install] | ||
| 89 | WantedBy=multi-user.target | ||
| 90 | {{/code}} | ||
| 91 | |||
| 92 | ##StartLimitBurst## limite les relances à cinq en cinq minutes : en cas d'erreur répétée, systemd abandonne au lieu de boucler indéfiniment. | ||
| 93 | |||
| 94 | {{code language="bash"}} | ||
| 95 | sudo systemctl start led-anim # allumer | ||
| 96 | sudo systemctl stop led-anim # éteindre les LED | ||
| 97 | systemctl status led-anim # état | ||
| 98 | {{/code}} | ||
| 99 | |||
| 100 | == Historique == | ||
| 101 | |||
| 102 | 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. |