Files
ha-led-remote/CLAUDE.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

81 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Télécommande LED chambre — Home Assistant
## Objectif
Permettre à ma fille de piloter le ruban LED de sa chambre depuis son lecteur MP3 Android, via une page web ultra simple, **sans lui donner accès au reste de Home Assistant**.
## Matériel
- Ruban LED **RGB non adressable** : toute la longueur affiche la même couleur. Aucun effet de « vague » spatiale n'est possible, seulement des effets globaux (cycles, fondus, respiration).
- Driver **Zigbee Iderwel** (PWM), intégré à Home Assistant.
- **Dépôt public** : aucune valeur réelle (IP, ID du webhook, entité, prénom, identifiant Android) dans les fichiers versionnés. Elles sont dans `config.local.env` (non versionné, modèle : `config.example.env`). Les fichiers versionnés sont des modèles avec des marqueurs `__HA_IP__`, `__HA_PORT__`, `__WEBHOOK_ID__`, `__ENTITE__`, `__PRENOM__` ; `deploy.sh` génère `dist/` et déploie, `android/build.sh` génère `Config.java` et la config réseau. Ne jamais réintroduire de valeur réelle dans un fichier versionné.
- entity_id du ruban : `ENTITE` dans `config.local.env` (mode couleur `xy` ; `hs_color` accepté, converti par HA)
- intégration Zigbee : **Zigbee2MQTT**
- HA : HAOS sur Odroid N2, adresse `HA_IP:HA_PORT` ; accès SSH via l'alias `SSH_HOST` (**root** : lecture seule par défaut). Jeton HA de dev dans `.env` (non versionné).
- **Effets natifs du driver (`colorloop`, `breathe`…) peu fiables** : testés, ne pas les utiliser. Les effets passent par des scripts HA. Couleurs fixes, luminosité et `transition` fonctionnent bien.
- Le driver ne remonte pas l'attribut `effect` (toujours `None` dans HA).
- MP3 : **Fanvace M36, Android 13**, écran 640×1136 à 300 dpi (≈ 341 px CSS de large), WebView 108. Branché en ADB.
- **Pas de navigateur accessible** (app lock) : la page est affichée par un mini APK WebView (`android/`, code dans le paquet `app.lumiere`, identifiant installé = `APP_ID` appliqué via `--rename-manifest-package`), qui n'autorise que `http://HA_IP:HA_PORT/local/led/`. Recompiler avec `android/build.sh` (clé de debug `~/.android/debug.keystore` : garder la même pour les mises à jour), installer avec `adb install -r android/build/ma-lumiere.apk`. Si l'IP de HA change : modifier `config.local.env`, recompiler et réinstaller.
## Architecture
```
[Page HTML statique] --POST JSON--> [Webhook HA (local_only)] --> [Automatisation] --> light.* / scripts d'effets
/config/www/led/ /api/webhook/<id>
servie sur /local/led/
```
1. **Scripts d'effets** (`script.led_<nom>`) : boucles infinies (`repeat: while true`) de `light.turn_on` avec `transition`, en `mode: restart`.
2. **Automatisation webhook** : point d'entrée unique, qui ne peut agir que sur le ruban et sur une liste fermée de scripts.
3. **Page web** : gros boutons, aucune authentification, à ajouter sur l'écran d'accueil du MP3.
## Contrat du webhook (corps JSON)
| action | champs | effet |
|--------------|--------------------------|-----------------------------------------------------------------|
| `off` | — | arrête tous les effets et éteint le ruban (transition 1 s) |
| `couleur` | `teinte` (0–359) | arrête les effets, couleur fixe `hs_color: [teinte, 100]` |
| `luminosite` | `valeur` (5–100) | `brightness_pct`, valeur bornée côté HA |
| `effet` | `nom` (ex. `arc_en_ciel`) | arrête l'effet en cours et lance `script.led_<nom>` s'il figure dans la liste blanche |
## Contraintes et règles
- **Sécurité**
- Webhook en `local_only: true` et `allowed_methods: [POST]`, avec un ID aléatoire long.
- Liste blanche stricte des scripts dans l'automatisation ; ne jamais construire un entity_id arbitraire à partir du JSON.
- Toutes les valeurs numériques sont bornées et ont un `default` côté HA.
- Aucun jeton HA dans la page.
- **Zigbee** : ne pas inonder le réseau. Garder au moins 1 s entre deux commandes dans les scripts (idéalement 2–3 s avec `transition` égale au delay). Les fondus sont lissés par le driver.
- **Effets** : lancer un nouvel effet ou une couleur fixe arrête toujours l'effet en cours.
- **Pas de retour d'état** : le webhook ne renvoie rien. La page ne connaît pas l'état du ruban et l'UI ne doit pas faire semblant de le connaître (pas de toggle on/off avec un état affiché).
- **Page web**
- Un seul fichier HTML autonome (CSS et JS inline), sans dépendance externe ni CDN.
- JS compatible avec un vieux navigateur Android : ES5 de préférence, ou au minimum sans syntaxe récente (`?.`, `??`, etc.). Utiliser `fetch` s'il est disponible, sinon `XMLHttpRequest`.
- Pensée pour un petit écran tactile en portrait : grandes cibles tactiles, peu de texte, très visuelle (pastilles de couleur, icônes d'effets), retour visuel immédiat au tap.
- Balises `<meta name="viewport">` et `apple-mobile-web-app` / `manifest` minimal pour que le raccourci sur l'écran d'accueil ressemble à une appli.
- Interface en français, pour une enfant.
## Effets (en place dans `packages/led_chambre.yaml`)
- Calmes (≥ 2 s entre commandes) : `arc_en_ciel` (pas de 30°, 3 s), `respiration` (10 ↔ 100 %, 3 s), `coucher_de_soleil` (5 s), `ocean` (4 s), `veilleuse` (orange 5 %, extinction en fondu après 30 min).
- Boum (1 commande/s, le minimum) : `disco` (sauts de couleur), `boum` (flash 100 % puis fondu à 25 %), `tourbillon` (arc-en-ciel rapide). Pas de stroboscope.
- Le webhook remet 100 % quand on sort d'un effet qui baisse la luminosité (veilleuse, respiration, boum) ou quand le ruban est éteint.
- Piège : dans une palette en `variables`, une teinte `0` arrive vide dans `hs_color` et fait planter le script → utiliser `360` pour le rouge.
- Ajouter un effet = script `led_<nom>` + entrée dans `effets` et `tous_les_effets` de l'automatisation + tuile dans la page ; déployer avec `./deploy.sh` (copie, `ha core check`, `script.reload` / `automation.reload`, pas de redémarrage).
## Livrables attendus
1. `scripts.yaml` : les scripts d'effets
2. `automations.yaml` : l'automatisation webhook (ou un package `packages/led_chambre.yaml` regroupant les deux)
3. `www/led/index.html` : la page
4. Procédure de test :
- `curl -X POST -H "Content-Type: application/json" -d '{"action":"effet","nom":"arc_en_ciel"}' http://<ha>:8123/api/webhook/<id>`
- tester chaque action avec curl **avant** de toucher à la page
5. APK « Ma lumière » (`android/`) installé via ADB, à autoriser dans l'app lock
## Ordre de travail
1. Scripts d'effets, testés depuis Outils de développement → Actions
2. Automatisation webhook, testée avec curl
3. Page web, testée d'abord sur desktop en vue mobile, puis sur le MP3