Files
ha-led-remote/README.md
T
bachirandClaude Opus 5.5 e4bd58afa7 Télécommande LED pour chambre d'enfant via Home Assistant
- Package HA : 8 scripts d'effets (calmes et « boum ») et une
  automatisation webhook local_only avec liste blanche stricte
- Page web autonome (HTML/CSS/JS ES5) tenant sur un écran de lecteur MP3
- Mini APK Android (WebView verrouillée) compilé sans Gradle
- Modèles + config.local.env non versionné : aucune valeur réelle
  (IP, ID du webhook, entité, prénom) dans le dépôt ; deploy.sh génère
  et déploie, android/build.sh injecte la configuration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 21:29:51 +02:00

11 KiB
Raw Blame History

Ma lumière — télécommande LED pour une chambre d'enfant

Une appli Android sur le lecteur MP3 d'un enfant pilote le ruban LED de sa chambre via Home Assistant. L'enfant n'a accès à rien d'autre dans HA.

[Lecteur MP3 Android]               [Home Assistant sur le LAN]
 appli « Ma lumière »
 (WebView plein écran)  --GET-->   /local/led/index.html   (page servie par HA)
                        --POST-->  /api/webhook/<id>       (local_only, POST)
                                        │
                                        ▼
                                   automatisation (liste blanche)
                                        │
                                        ▼
                          light.<ruban>  /  script.led_*  (8 effets)

Ce document décrit l'installation et récapitule les interventions réalisées le 10 octobre 2026.


1. Installation

Ce dépôt est public : il ne contient aucune valeur réelle. Les fichiers versionnés sont des modèles avec des marqueurs, remplacés au déploiement par les valeurs de config.local.env.

Marqueur Variable Exemple
__HA_IP__ / __HA_PORT__ adresse de HA sur le LAN 192.168.1.10 / 8123
__WEBHOOK_ID__ ID du webhook, long et aléatoire led-chambre-$(openssl rand -hex 16)
__ENTITE__ entité du ruban light.ruban_led
__PRENOM__ prénom affiché dans la page Camille
— SSH_HOST : alias SSH vers HA homeassistant
— APP_ID : identifiant Android de l'appli fr.exemple.lumiere

Étapes :

  1. Copier config.example.env en config.local.env et le remplir.
  2. Une seule fois, dans configuration.yaml de HA, ajouter packages: !include_dir_named packages sous homeassistant:, puis redémarrer HA.
  3. Lancer ./deploy.sh. Il génère dist/, copie le package et la page sur HA via SSH, lance ha core check, puis recharge les scripts et les automatisations. Le rechargement utilise un jeton HA placé dans .env (HA_TOKEN=…), optionnel.
  4. Compiler l'appli avec android/build.sh (il faut un SDK Android avec build-tools 30.0.2 et la plateforme 25), puis l'installer avec adb install -r android/build/ma-lumiere.apk.

Fichiers jamais versionnés (voir .gitignore) : config.local.env, .env, dist/, android/build/.


2. Contexte technique

Élément Valeur
Home Assistant HAOS 2026.6 sur Odroid N2, en HTTP sur le LAN, accès distant uniquement via VPN WireGuard
Ruban RGB non adressable, driver Zigbee Iderwel via Zigbee2MQTT, mode couleur xy
Lecteur MP3 Fanvace M36, Android 13, écran 640×1136 à 300 dpi (≈ 341 × 530 px utiles), WebView 108, navigateur bloqué par l'app lock

Constats faits pendant les tests sur le ruban :

  • Couleurs fixes, luminosité et transition (fondus) fonctionnent bien.
  • Les effets natifs du driver (colorloop, breathe…) ne sont pas fiables : ils ont été abandonnés au profit de scripts HA.
  • Le driver ne remonte pas l'effet en cours : l'attribut effect vaut toujours None dans HA.

3. Interventions sur Home Assistant

3.1 Fichiers modifiés ou créés

Fichier sur HA Action
/config/configuration.yaml 1 ligne ajoutée sous homeassistant: : packages: !include_dir_named packages
/config/packages/led_chambre.yaml créé : 8 scripts d'effets et l'automatisation webhook
/config/www/led/ créé : index.html, manifest.json, icon.svg, icon-180/192/512.png

Aucun autre fichier existant n'a été modifié. En particulier, scripts.yaml et automations.yaml n'ont pas été touchés.

3.2 Sauvegardes laissées sur HA

Sauvegarde Contenu
/config/configuration.yaml.bak-led-20261010 configuration.yaml d'origine, avant l'ajout de packages:
/config/led_chambre.yaml.bak-20261010-boum package avant l'ajout des effets disco/boum/tourbillon
/config/led_chambre.yaml.bak-20261010-disco package avant la correction du bug disco

Ces sauvegardes sont volontairement placées hors de packages/, pour que HA ne les charge pas.

3.3 Opérations effectuées

  1. Vérification de la configuration avec ha core check avant chaque mise en service.
  2. Un redémarrage de HA, pour activer packages:.
  3. Ensuite, uniquement des rechargements à chaud (script.reload, automation.reload), sans redémarrage.

3.4 Contenu du package led_chambre.yaml

Scripts d'effets, tous en mode: restart :

Script Comportement Rythme Zigbee
led_arc_en_ciel tour des teintes par pas de 30° 1 commande / 3 s
led_respiration garde la couleur, luminosité 10 % ↔ 100 % 1 / 3 s
led_coucher_de_soleil orange → rose → rouge → violet 1 / 5 s
led_ocean bleu → turquoise → cyan → bleu profond 1 / 4 s
led_veilleuse orange à 5 %, puis extinction en fondu au bout de 30 min —
led_disco saut de couleur vive chaque seconde 1 / s
led_boum flash d'une couleur à 100 %, puis fondu à 25 % 1 / s
led_tourbillon arc-en-ciel rapide, pas de 45° 1 / s

Il n'y a pas de stroboscope : le réseau Zigbee ne le permet pas, et il présente un risque photosensible.

Automatisation led_chambre_webhook :

  • Webhook avec local_only: true, allowed_methods: [POST] et un ID aléatoire long.

  • mode: restart : si plusieurs commandes arrivent très vite, seule la dernière compte.

  • Contrat du corps JSON :

    action champ effet
    off — arrête tous les effets et éteint le ruban (fondu 1 s)
    couleur teinte 0–359 arrête les effets et applique une couleur fixe
    luminosite valeur 5–100 change la luminosité sans couper l'effet en cours
    effet nom arrête l'effet en cours et lance script.led_<nom> s'il est dans la liste blanche
  • Liste blanche stricte : le JSON ne sert jamais à construire un entity_id. Les valeurs sont bornées et ont des valeurs par défaut, et toute autre requête est ignorée.

  • La luminosité revient automatiquement à 100 % quand le ruban était éteint, ou quand on sort de la veilleuse, de la respiration ou de Boum.


4. Interventions sur le lecteur MP3

  • Installation via ADB de l'appli « Ma lumière », aujourd'hui en version 1.1.
  • Aucun autre réglage n'a été modifié sur l'appareil.
  • Le débogage USB a été activé pour l'installation.

Ce que fait l'appli : c'est un wrapper WebView de 37 Ko qui affiche en plein écran la page servie par HA.

  • Elle n'autorise la navigation que vers http://<HA>/local/led/, et bloque toute requête vers une autre adresse.
  • Le HTTP non chiffré n'est autorisé que vers l'IP de HA.
  • Si HA ne répond pas, elle affiche « La lumière ne répond pas » avec un bouton Réessayer.
  • Le cache est désactivé, et la page est rechargée à chaque retour dans l'appli (ajouté en v1.1). Une modification de la page sur HA apparaît donc sans réinstaller l'appli.

5. Fichiers du dépôt

├── CLAUDE.md                     consignes du projet
├── README.md                     ce document
├── config.example.env            modèle de configuration (à copier en config.local.env)
├── deploy.sh                     génère dist/ depuis les modèles et déploie sur HA
├── packages/led_chambre.yaml     modèle → /config/packages/led_chambre.yaml
├── www/led/                      modèles → /config/www/led/
│   ├── index.html                la page (HTML/CSS/JS ES5 en un seul fichier)
│   ├── manifest.json
│   └── icon.svg, icon-*.png
└── android/                      sources de l'APK
    ├── build.sh                  compilation sans Gradle → build/ma-lumiere.apk
    ├── AndroidManifest.xml
    ├── res/                      icônes, thème, network_security_config (modèle)
    └── src/app/lumiere/MainActivity.java

La page est pensée pour tenir sur un seul écran du lecteur :

  • en haut, Veilleuse et Éteindre ;
  • 9 pastilles de couleur ;
  • 4 niveaux de luminosité ;
  • 4 animations calmes ;
  • 3 animations « boum » au style néon.

Elle n'affiche aucun état du ruban, puisque le webhook ne renvoie rien. Un appui réussi fait apparaître un halo blanc ; une erreur fait trembler le bouton et affiche un message rouge.


6. Tests réalisés

  • Ruban, en direct : couleurs, fondus, luminosité, puis effets natifs, qui se sont révélés peu fiables.
  • Webhook avec curl :
    • toutes les actions et les 8 effets fonctionnent, et un seul script tourne à la fois ;
    • les entrées non valides sont ignorées sans erreur : nom hors liste blanche (../light.autre), action inconnue, corps non JSON ;
    • les valeurs sont bornées (teinte 999 → 359, luminosité 1 → 5 %) ;
    • une requête GET est refusée (405) ;
    • les logs HA sont propres.
  • De bout en bout sur le lecteur : des taps simulés via ADB (couleur, arc-en-ciel, veilleuse, éteindre) ont été vérifiés dans l'état HA.
  • Modèles : les fichiers générés par deploy.sh --render-only sont identiques aux fichiers en service, hors commentaires. L'APK généré contient la bonne adresse et le bon identifiant.

Bug corrigé : led_disco plantait au bout d'environ 10 s, parce qu'une teinte 0 tirée d'une palette en variables arrivait vide dans hs_color. Le rouge vaut maintenant 360 dans les palettes de Disco et de Boum.


7. Maintenance

Tester le webhook (avec les valeurs de config.local.env) :

curl -X POST -H "Content-Type: application/json" \
  -d '{"action":"effet","nom":"arc_en_ciel"}' \
  http://<HA_IP>:<HA_PORT>/api/webhook/<WEBHOOK_ID>

Modifier la page ou un effet :

  1. Modifier le modèle (www/led/index.html ou packages/led_chambre.yaml).
  2. Lancer ./deploy.sh.
  3. Rouvrir l'appli sur le lecteur. Pas de réinstallation.

Ajouter un effet :

  1. Ajouter le script led_<nom> dans le package.
  2. Ajouter <nom> dans effets et dans tous_les_effets de l'automatisation.
  3. Ajouter une tuile dans la page.
  4. Lancer ./deploy.sh.

Recompiler l'appli, par exemple si l'IP de HA change :

  1. Mettre à jour config.local.env.
  2. Lancer android/build.sh, puis adb install -r android/build/ma-lumiere.apk.

Il faut garder la même clé de signature, ~/.android/debug.keystore. Sinon Android refusera la mise à jour et il faudra désinstaller l'appli d'abord.

Tout retirer :

  1. Supprimer /config/packages/led_chambre.yaml et /config/www/led/.
  2. Retirer la ligne packages: de configuration.yaml, ou restaurer la sauvegarde.
  3. Lancer ha core check, puis redémarrer HA.
  4. Désinstaller l'appli : adb uninstall <APP_ID>.

8. Reste à faire

  • Autoriser « Ma lumière » dans l'app lock du lecteur.
  • Réserver l'IP de HA sur la box, puisqu'elle est compilée dans l'appli.
  • Supprimer le jeton HA de développement (profil HA → Sécurité) et le fichier .env quand ils ne sont plus utiles. L'appli n'en a pas besoin.
  • Éventuellement, désactiver le débogage USB sur le lecteur.
  • Éventuellement, supprimer les sauvegardes *.bak* dans /config une fois que tout est validé.

ℹ️ Le dossier /local/ de HA est accessible sans authentification depuis le LAN. C'est voulu : la page ne contient aucun secret, et le webhook n'accepte que des commandes en liste blanche, uniquement depuis le réseau local.