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

225 lines
11 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.
# 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`) :
```bash
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.