docs: spec ESP-NOW commandes/evenements v1

This commit is contained in:
Claude Worker claude2
2026-06-11 05:41:10 +02:00
parent ac2fa5c2b0
commit 7dc42b7965
@@ -0,0 +1,78 @@
# ESP-NOW commandes & événements — design v1 (2026-06-11)
## Problème
Les 4 blocs Blockly ESP-NOW compilent vers des actions IR
(`espnow_register_peer`, `espnow_send`, `espnow_broadcast`, `espnow_wait`)
que **personne n'exécute** : le gateway ne sait que relayer des IR complets
(`/game/scenario/relay`), et le firmware master ignore les actions des steps.
La pile radio existe pourtant (`ESP32_ZACUS/lib/scenario_mesh/`, partagée
master/annexes) mais ne transporte que des chunks d'IR.
## Décisions de cadrage (validées)
1. **Rôle** : commandes ET événements — le scénario commande les annexes et
attend leurs événements.
2. **Orchestration** : **master autonome** — le firmware Freenove
(`idf_zacus`) exécute lui-même les actions espnow des steps ; pas de
dépendance au gateway pendant la partie.
3. **Périmètre** : bout-en-bout avec la BOX-3 (`box3_voice`) comme annexe.
4. **Sémantique `espnow_wait`** : action **bloquante** (événement ou timeout,
puis le déroulé continue ; timeout → log, pas d'échec de step).
5. **Côté annexe** : handler **ouvert** — la commande est une chaîne opaque
passée à un callback enregistrable ; l'annexe répond l'événement de son
choix. Démo livrée : `ping``pong`, branchement optionnel `stim:*`.
## Architecture (approche A retenue)
### 1. Protocole — `lib/scenario_mesh` (composant partagé)
- Les frames gagnent un **type** : `IR_CHUNK` (existant), `CMD`, `EVT`.
- Payload CMD/EVT : chaîne UTF-8 opaque ≤ 200 octets.
- API additive :
- `esp_err_t scenario_mesh_send_text(const uint8_t mac[6], uint8_t kind, const char *text);`
- `void scenario_mesh_set_text_cb(scenario_mesh_text_cb_t cb);`
(callback : kind, MAC source, texte ; dispatché hors contexte WiFi via la
queue/tâche existante).
- Pas d'ack applicatif en v1 : statut d'envoi radio natif + confirmation
logique par `wait`.
### 2. Master — `idf_zacus`
- À l'application d'un step, exécution séquentielle des actions `espnow_*`
(les autres kinds restent ignorés) :
- `espnow_register_peer {alias, mac}``scenario_mesh_register_peer`.
- `espnow_send {peer, command}` → résolution alias → frame CMD.
- `espnow_broadcast {command}` → frame CMD vers FF:FF:FF:FF:FF:FF.
- `espnow_wait {command, timeout_ms}` → sémaphore + timeout, débloqué par
un EVT dont le texte égale `command` ; timeout → `ESP_LOGW` et on
continue.
- Endpoint debug : `POST /game/espnow/cmd {peer|broadcast, command}` pour
tester le tuyau sans scénario.
### 3. Annexe — `box3_voice`
- Enregistre le callback texte : sur CMD reçue, passe la chaîne au handler
ouvert du firmware.
- Handler de démo : `ping` → répond EVT `pong` au MAC source ; préfixe
`stim:` → déclenche le générateur de stimulus existant (`melody`, `qr`)
puis répond `done:<cmd>` (automatisera les tests physiques P1/P3).
### 4. Tests
- Export Blockly→IR : déjà couvert (`test_blocks_export_espnow.py`).
- Master seul : `POST /game/espnow/cmd` vers un peer absent → statut radio
loggé ; step avec `espnow_wait` sans annexe → timeout propre.
- Bout-en-bout 2 cartes : step `espnow_send box3 "ping"` +
`espnow_wait "pong" 10s` → logs série des deux côtés, wait débloqué.
## Hors scope v1
Retries/ack applicatif, chiffrement, événements→transitions IR, file
d'événements persistante, exécution des autres kinds d'actions par le master.
## Découpage
1. **Commit 1** : protocole CMD/EVT + exécuteur master + endpoint debug,
testé sur la Freenove seule (timeout, statuts radio).
2. **Commit 2** : handler BOX-3 (`ping`/`pong`, `stim:*`) + test 2 cartes.