Merlin Studio v2: in-progress + completed transfer journal (duration, throughput, retry failed) alongside the routines tab.
10 KiB
Lisael Box — Mode « Routines » illustrées (design)
- Date : 2026-06-21
- Repo :
electron-rare/lisael-box(firmware) + Towerlisael-content+ Merlin Studio (merlin.saillant.cc) - Statut : design validé, prêt pour le plan d'implémentation
- Livraison : 2 lots — Firmware Mode Routine + chantier Merlin Studio v2 (onglet Routines ici, et la visu des transferts livrée dans le même chantier web/Tower).
1. But
Donner à Lisael (6 ans) un mode Routine illustrée à étapes : une séquence de pictogrammes (s'habiller → petit-déj → dents → cartable…) qu'il avance une par une, avec une voix qui annonce chaque étape et un « Bravo ! » final. Deux routines au lancement : Matin et Soir. Le contenu (étapes, emojis, textes, ordre) est édité par un parent depuis Merlin Studio (web) et poussé sur la box en WiFi — aucun reflash pour changer une routine.
2. Non-objectifs (YAGNI)
- Pas de minuteur par étape ni d'avance automatique (décision : avance manuelle).
- Pas de routines libres au-delà de Matin/Soir (deux routines fixes).
- Pas de logique horaire (la box ne devine pas matin/soir : l'enfant choisit).
- Pas de photos perso (emojis Twemoji uniquement).
- Pas de persistance de progression entre sessions (chaque ouverture repart au début).
- Pas de généralisation du pipeline de contenu Merlin (on étend, on ne refactore pas
lisael_content.pyen système de types génériques).
3. Décisions de cadrage (verrouillées)
| Sujet | Décision |
|---|---|
| Concept | Routine illustrée à étapes (gros picto + nom plein écran) |
| Routines | Matin + Soir (2, fixes) |
| Source du contenu | Pilotée par Merlin Studio (web) → manifest SD + assets poussés en WiFi |
| Interaction | Gros bouton « C'est fait ✓ » + voix TTS par étape + son de validation + Bravo final |
| Déclenchement | Tuile « Routine » à l'accueil → choix Matin/Soir |
| Pictogrammes | Twemoji choisis dans Merlin → .bin RGB565A8 généré par Tower |
| Édition web | Éditer les étapes de Matin/Soir : texte + emoji, ajouter/supprimer/réordonner |
| Voix | fr (= « siwis » de la gateway, voix validée pour le jeu Lire) |
| Reset | Repart de l'étape 1 à chaque ouverture, pas de persistance |
| Cap | ~12 étapes / routine, structures en PSRAM |
| Livraison | Tout d'un bloc (firmware + Tower + web), test final global |
4. Architecture d'ensemble
Merlin Studio (web) Tower (lisael-content) Box (firmware)
merlin.saillant.cc clems@192.168.0.120 ESP32-S3-BOX-3
───────────────── ────────────────────── ─────────────────
Onglet "Routines" ──POST──▶ routines.json (vérité)
édite Matin/Soir + Twemoji→.bin (RGB565A8)
(texte+emoji, + TTS→.mp3 (voix "fr")
ordre, +/−) + manifest SD
───push WiFi (:8080/put)──▶ /sdcard/routines/*
(delta, comme podcasts) routines.json + .bin + .mp3
│
mode Routine lit le manifest
Réutilise trois briques déjà en prod : le jeu Lire (pictos Twemoji .bin +
TTS .mp3 + cache PSRAM), l'autopush Tower (box_register + compute_delta
push_batchvers:8080/put), et Merlin Studio (UI + API + Basic Auth).
5. Contenu sur la SD — /sdcard/routines/
Manifest unique + assets, tout poussé par Tower :
{ "routines": [
{ "id":"matin", "title":"Le matin", "icon":"matin.bin", "steps":[
{"text":"Habille-toi", "icon":"matin_01.bin", "audio":"matin_01.mp3"},
{"text":"Petit-déjeuner", "icon":"matin_02.bin", "audio":"matin_02.mp3"},
{"text":"Brosse tes dents", "icon":"matin_03.bin", "audio":"matin_03.mp3"},
{"text":"Prépare ton cartable", "icon":"matin_04.bin", "audio":"matin_04.mp3"} ]},
{ "id":"soir", "title":"Le soir", "icon":"soir.bin", "steps":[ ... ] }
]}
Règles :
- pictos
.binRGB565A8 (même format/pipeline que Lire), audio.mp3mono. - noms de fichiers ASCII (
matin_01) ; les libellés accentués vivent dans le JSON (UTF-8, rendu par Fredoka) — leçon LFN/codepage FAT du jeu Lire. iconde routine = vignette du choix Matin/Soir (Twemoji ☀️ / 🌙).
6. Firmware — mode LISAEL_MODE_ROUTINE
Câblage
main/ui/ui.h: ajouterLISAEL_MODE_ROUTINEà l'enum +lv_obj_t *lisael_screen_routine(void);.main/modes/routine.c: nouvel écran.main/ui/assets/lisael_ic_routine.c: icône de tuile (Twemoji bakée, ✅/🗓️, RGB565A8).main/modes/home.c: ajouter la tuile au carrousel d'accueil + route dansui.c.
Écrans
- Choix : deux grosses cartes Matin (☀️) / Soir (🌙), tap → ouvre la routine.
- Étape plein écran : gros picto (cache PSRAM + FS
S:, commelire.c) + nom (Fredoka) + indicateur de progression 3/6 (pastilles) + bouton géant « C'est fait ✓ » + bouton retour Accueil.- à l'arrivée sur une étape : annonce vocale (
aac_playerlit le.mp3, type MP3). - tap « C'est fait » : son de validation (court) → étape suivante.
- dernière étape validée : écran Bravo (animation étoiles
lisael_ic_star+ son) → retour Accueil.
- à l'arrivée sur une étape : annonce vocale (
Données & RAM
main/audio/routine_manifest.{c,h}: parse/sdcard/routines/routines.json→ structureslisael_routine_t/lisael_step_t, allouées en PSRAM (heap_caps_*(MALLOC_CAP_SPIRAM)), caps 2 routines × 12 étapes.- Cache picto PSRAM : lire chaque
.binune fois en PSRAM et le présenter commelv_image_dsc_tRAM (data = buf+12), pour éviter la relecture SD à chaque frame (piège perf corrigé danslire.c). - Reset :
lisael_screen_routine()repart toujours de l'étape 0.
7. Tower — génération + push
Dans tower/lisael_content.py (module partagé), ajouter le support « routines » :
- vérité :
routines.jsoncôté Tower (/home/clems/lisael-content/), édité par l'API web. - pictos : pour chaque étape, télécharger le Twemoji de l'emoji → resize →
.binRGB565A8 viaLVGLImage(pipeline du jeu Lire). - voix : annonce TTS via la gateway (
POST <gateway>/v1/audio/speech,model=tts-1,voice=fr) →.mp3mono. Gateway = origine tailnet Tower:9300(⚠️ Cloudflare bloque l'UAPython-urllibsur les domaines publics → appel direct tailnet, ouUser-Agent: Mozilla/5.0). - manifest SD : composer
routines.json(chemins.bin/.mp3relatifs). - push : étendre
box_registerpour annoncer aussiroutines/*danshave, et réutilisercompute_delta+push_batchvers:8080/put?name=routines/<f>. - cache : ne régénérer un
.bin/.mp3que si l'emoji/texte a changé (hash du couple emoji+texte dans le nom ou un index), comme le suffixe_a48des podcasts.
8. Merlin Studio — onglet « Routines »
tower/merlin_ui.html: nouvel onglet, 2 sections Matin / Soir. Par étape : champ texte + sélecteur d'emoji + bouton supprimer ; + ajouter une étape ; réordonner (flèches ↑↓) ; bouton Enregistrer & pousser.tower/lisael_server.py:GET /api/routines(litroutines.json),POST /api/routines(sauve + régénère pictos/TTS + met à jour le manifest staging),POST /api/routines/push(push delta à la box). Sous la Basic Auth existante.- Sélecteur d'emoji : palette d'emojis enfant courants (dents/habits/repas/bain/dodo/ cartable/jouets…) + saisie libre d'un emoji.
9. Gestion d'erreurs (dégradés gracieux)
- pas de
routines.jsonsur SD → écran « Demande à un parent de préparer tes routines ». - picto manquant → case colorée avec 1ʳᵉ lettre (fallback du jeu Lire).
- audio manquant pour une étape → étape affichée sans voix (non bloquant).
- TTS gateway indisponible → Tower garde texte+picto, audio absent (non bloquant).
- push échoué (WiFi faible) → réessai au prochain
register(pattern existant) ; fichier partiel supprimé côté box (unlink, durcissement file-server existant).
10. Tests
- Hôte :
test/host/test_routine_manifest.c(JSON valide / malformé / vide / caps dépassés) ; test Tower de génération + delta (calqué surtest_delta.py). - Sur carte (box branchée en USB) : boot-burst USB-JTAG + écoute UDP — manifest chargé, pictos affichés, voix jouée par étape, son de validation, Bravo final.
11. Pré-requis build (dette à régler avant de compiler)
Le sdkconfig (gitigné) a été perdu avec /tmp. sdkconfig.defaults* ne contient
PAS tous les réglages critiques. Avant le premier build neuf, reconfigurer (ou
remonter dans sdkconfig.defaults, recommandé) :
FATFS_LFN_HEAP + FATFS_MAX_LFN=255, LV_USE_FS_STDIO + lettre S (83),
MBEDTLS_EXTERNAL_MEM_ALLOC + MBEDTLS_DYNAMIC_BUFFER, ESP_WIFI_TX_BUFFER_TYPE=1,
SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY, + les creds WiFi (ou override NVS). Sans ces
réglages : manifest illisible, pictos invisibles, reset TLS. À traiter dans le plan
(ce sera la première tâche, sinon rien ne tourne).
12. Critères d'acceptation
- Une tuile « Routine » apparaît au carrousel d'accueil ; tap → choix Matin/Soir.
- Choisir Matin enchaîne les étapes : gros picto + nom, voix qui annonce, bouton « C'est fait ✓ », son de validation, jusqu'au Bravo final.
- Le contenu vient de
/sdcard/routines/routines.json(aucun contenu en dur figé). - Depuis Merlin, ajouter/supprimer/réordonner une étape + changer texte/emoji, puis « Enregistrer & pousser » → la box reflète le changement après push (au boot/register).
- Dégradés gracieux vérifiés : pas de manifest, picto/audio manquant, push partiel.
- Tests hôte verts (parser + delta Tower).