clement 51dcae8c6c chore: retire config ESP-ADF morte + MAJ README
Le firmware n'utilise plus ESP-ADF (audio via esp_codec_dev +
esp-audio-player/esp_audio_codec). Supprime le bloc ADF_PATH du
CMake racine et main, le commentaire idf_component.yml, et l'en-tete
ADF de main/CMakeLists. Retire modes/radios.h (orphelin, URLs dans
radio.c). Corrige le commentaire 'STUB' de games.c (Coloriage est
implemente: canvas + flood-fill). Reecrit le README (statut compile
vert, archi box+Merlin, modes a jour).
2026-06-26 11:55:30 +02:00
2026-06-21 10:53:17 +02:00

Lisael Box

Firmware ESP32-S3-BOX-3 pour une « boîte » à destination d'un jeune enfant : webradios FR enfants, podcasts (Radio France), boîte à sons (microSD), coin calme / respiration, horloge / veilleuse, apprendre à lire, routines du matin / soir et mini-jeux. UI tactile LVGL 9, sans lecture obligatoire (gros boutons

  • icônes/emoji), volume bridé (plafond enfant).

Le contenu (podcasts, vignettes, voix des routines, mots de lecture) est produit et poussé vers la box par Merlin, un petit studio web côté serveur (voir tower/), exposé sur merlin.saillant.cc.

Statut : compile vert (ESP-IDF 5.4.4 + BSP esp-box-3 3.2.x), pas encore validé sur la carte. idf.py set-target esp32s3 && idf.py build réussit (binaire ≈ 2,5 Mo, 39 % libre dans la partition app de 4 Mo). Les comportements matériels (audio réel, tactile, IMU, backlight, SD) restent à dérouler sur une vraie BOX-3 — voir À vérifier sur le matériel.

Matériel cible

  • ESP32-S3-BOX-3 : ESP32-S3 (8 Mo PSRAM octal, 16 Mo flash), LCD 320×240 tactile capacitif (GT911), codec audio ES8311 + HP, micro ES7210, microSD, IMU ICM-42670 (utilisée par le jeu de labyrinthe). L'add-on AHT30 (température/humidité) n'est pas supposé présent.

Stack logicielle

  • ESP-IDF 5.4 / 5.5 (APIs récentes : driver/i2c_master.h, driver/temperature_sensor.h, esp_netif_sntp.h, …).
  • BSP espressif/esp-box-3 ^3.2.0 (managed component) — écran, tactile, port LVGL, codec ES8311 (esp_codec_dev), microSD (FATFS), boutons, IMU. Tire transitivement esp_lvgl_port ^2, LVGL 9.x, esp_codec_dev.
  • LVGL 9 pour l'UI tactile.
  • Audio SANS ESP-ADF. Le BSP possède l'I2S/le codec ; le décodage passe par chmorgan/esp-audio-player (MP3) + espressif/esp_audio_codec (AAC/M4A des podcasts), et le PCM est remis au codec ES8311 via esp_codec_dev. Cela évite le conflit de versions ESP-ADF audio_boardesp_lcd_ili9341 avec le BSP.
  • cJSON : composant built-in json d'ESP-IDF (manifestes SD, réponses open-meteo).

Architecture

                 Radio France RSS / open-meteo / TTS FR
                              │
                     ┌────────▼─────────┐      HTTP POST /put
   merlin.saillant.cc│  Merlin (tower/) │  ────────────────────▶  Lisael Box
   (studio web)      │  serveur :9555   │     (push delta)        (ESP32-S3)
                     └────────▲─────────┘  ◀────────────────────   :8080/put
                              │              POST /register {have}  file_server
                       merlin_ui.html
  • Lisael Box (main/) — le firmware embarqué (UI + modes + audio + réseau).
  • Merlin (tower/) — le studio de contenu côté serveur : récupère podcasts et génère vignettes/voix, puis pousse le delta vers la box.

Arborescence

lisael-box/
├── CMakeLists.txt              # projet (pas d'ESP-ADF)
├── partitions.csv             # 16 MB : factory 4 MB + storage FAT
├── sdkconfig.defaults[.esp32s3]# PSRAM octal, 16 MB flash, LVGL/PSRAM
├── main/
│   ├── app_main.c             # séquence de boot + tâches
│   ├── lisael_config.h        # constantes partagées (TZ, NVS keys, volume)
│   ├── net/
│   │   ├── wifi.{c,h} · wifi_portal.{c,h}  # STA + SoftAP/portail captif
│   │   ├── sntp_time.{c,h}    # SNTP + fuseau Europe/Paris
│   │   ├── weather.{c,h}      # open-meteo.com (HTTPS, sans clé)
│   │   ├── file_server.{c,h}  # endpoint /put (réception du push Merlin)
│   │   ├── box_register.{c,h} # POST /register {have} vers Merlin :9555
│   │   ├── podcast.{c,h}      # téléchargement des épisodes
│   │   └── udp_log.{c,h}      # sink de log UDP (debug)
│   ├── audio/
│   │   ├── audio_player.{c,h} # façade codec ES8311 + volume bridé (NVS)
│   │   ├── radio_pipeline.{c,h} # webradio HTTP MP3 (sans ESP-ADF)
│   │   ├── sd_player.{c,h}    # lecture MP3 SD (esp-audio-player)
│   │   ├── aac_player.{c,h}   # AAC/M4A (podcasts) via esp_audio_codec
│   │   ├── calm_tone.{c,h}    # synthèse 432 Hz du coin calme
│   │   ├── podcast_manifest.{c,h} · routine_manifest.{c,h}  # parseurs JSON
│   ├── ui/
│   │   ├── ui.{c,h}           # shell LVGL + routeur de modes + styles
│   │   ├── fr_date.{c,h}      # date FR en lettres (sans setlocale)
│   │   ├── icons.{c,h}
│   │   ├── fonts/             # Fredoka custom (accents FR), 18/24/30 px
│   │   └── assets/            # icônes/emoji Twemoji -> descripteurs LVGL
│   └── modes/                 # home, radio, calm, clock, games, balloons,
│                              # maze, histoires, wifi_setup, lire, routine
├── tower/                     # Merlin : studio de contenu (Python, voir + bas)
├── tools/                     # gen_covers.py, gen_icons.py, gen_lire_content.py,
│                              # push_to_box.sh
├── test/host/                 # tests hôte des parseurs de manifeste
└── sdcard/                    # disposition attendue de la carte + manifeste ex.

Prérequis

ESP-IDF 5.4+ installé et exporté :

. $IDF_PATH/export.sh

C'est tout — plus aucune dépendance ESP-ADF à installer. Les managed components (esp-box-3, esp-audio-player, esp_audio_codec, …) sont téléchargés automatiquement dans managed_components/ au premier build.

Build & flash

# 1. cibler l'ESP32-S3
idf.py set-target esp32s3

# 2. configurer le Wi-Fi et la météo (lat/lon, ville)
idf.py menuconfig
#   -> "Lisael Box configuration" -> Wi-Fi / Weather / Audio

# 3. build (télécharge les managed components dans managed_components/)
idf.py build

# 4. flash + monitor (macOS : le port apparaît en /dev/cu.usbmodem*)
idf.py -p /dev/cu.usbmodem* flash monitor
#   (Linux : -p /dev/ttyUSB0 ou /dev/ttyACM0 ; Ctrl+] pour quitter le monitor)

Provisioning Wi-Fi

Trois voies, par ordre de priorité au boot :

  • NVS à l'exécution : lisael_wifi_save_credentials() écrit wifi_ssid / wifi_pass dans le namespace lisaelprime sur le reste.
  • Portail captif SoftAP : le mode wifi_setup (modes/wifi_setup.c + net/wifi_portal.c) ouvre un point d'accès et une page de saisie quand aucune crédential valide n'est connue.
  • menuconfig : Lisael Box configuration → Wi-Fi → SSID / password (pratique en dev ; les valeurs partent dans le binaire).

Météo

api.open-meteo.com (gratuit, sans clé, HTTPS via le CA bundle mbedTLS). Lat/lon depuis NVS (lat/lon) sinon défauts menuconfig (Paris). Rafraîchissement toutes les CONFIG_LISAEL_WEATHER_REFRESH_MIN min ; en cas d'échec réseau, l'accueil affiche .

Modes

Mode Fichier(s) Notes
🏠 Accueil modes/home.c date FR en lettres, heure (SNTP), météo (open-meteo), temp interne de la puce, tuiles en carrousel
📻 Webradios modes/radio.c + audio/radio_pipeline.c flux HTTP MP3, stations RadioKing réelles
🔊 Boîte à sons audio/sd_player.c grille depuis manifest.json, MP3 SD
🎧 Histoires modes/histoires.c + audio/aac_player.c podcasts Radio France (covers SD + AAC/M4A)
📖 Lire modes/lire.c apprendre à lire (366 mots, words.json, icône + voix TTS)
🫧 Coin calme modes/calm.c + audio/calm_tone.c bulle de respiration + tonalité 432 Hz synthétisée
🕐 Horloge/veilleuse modes/clock.c grande heure + date FR, fond sombre, backlight tamisé, « histoire du soir »
🗓️ Routine modes/routine.c + audio/routine_manifest.c matin / soir : étapes picto + voix, « Bravo ! », contenu poussé par Merlin
🎮 Jeux modes/games.c Memory · Compter · Coloriage (canvas + flood-fill) · Labyrinthe (inclinaison via IMU)
🎈 Ballons modes/balloons.c pop sounds synthétisés
⚙️ Réglages Wi-Fi modes/wifi_setup.c portail captif SoftAP

Carte microSD

Voir sdcard/README.md. En bref : FAT32, dossiers /sounds/ (MP3 + manifest.json), /podcasts/, /routines/, /lire/ peuplés par le push Merlin. Les manifestes suivent [{file, title, emoji}] (et variantes par mode).

Merlin — studio de contenu (tower/)

Serveur HTTP stdlib (http.server, port 9555), déployé sur l'hôte tower. Deux faces :

  • Machine : POST /register {id, have} (réservé LAN/tailnet). Le serveur calcule le delta (staging \ have, manifest.json en dernier) et le pousse vers la box : POST http://<box_ip>:8080/put?name=<subdir>/<file>.
  • Humain : le studio merlin_ui.html (SPA, 5 onglets : Podcasts, Fichiers, Box, Routines, Transferts), derrière Basic Auth optionnelle (MERLIN_AUTH="user:pass").

Génération de contenu (lisael_content.py) : RSS Radio France → transcodage ffmpeg (mp3 mono 48 kbps), covers redimensionnées 160×160 RGB565 .bin via LVGLImage.py, voix des routines via gateway TTS FR. Rafraîchissement hebdo (lisael_refresh.py + systemd/lisael-refresh.timer, dimanche 04:00). Le serveur tourne en service systemd/lisael-content.service (Restart=always).

# tests (offline) — nécessite Pillow + ffmpeg
cd tower && python3 -m pytest -q        # 23 tests

Sécurité enfant

  • Volume bridé : plafond CONFIG_LISAEL_VOLUME_MAX_PERCENT (défaut 60 %), appliqué partout via audio_player.c (clamp_volume), persisté en NVS.
  • Pas de lecture requise : icônes/emoji + gros boutons (≥ 56 px).
  • Jeux sans échec : aucun score punitif, retour « Bravo ! ».

À vérifier sur le matériel

Le code compile ; ce qui suit n'a pas encore été validé sur une vraie carte :

  1. Audio réel : sortie ES8311 (webradio MP3, podcasts AAC, MP3 SD, tonalité calme, pops), niveaux et plafond de volume.
  2. Tactile / UI : réactivité des tuiles et carrousels (le wrap infini est par flèches seulement, pas au swipe — voir .superpowers/sdd/carousel-wrap-report.md).
  3. IMU (labyrinthe) : lecture ICM-42670 via bsp_i2c_get_handle(), sens des axes, fallback « Capteur indisponible ».
  4. Backlight / veilleuse : bsp_display_brightness_set() doit tamiser en mode horloge.
  5. microSD : montage FATFS, lecture des manifestes et des assets poussés.
  6. Réseau bout-en-bout : provisioning (NVS / SoftAP / menuconfig), SNTP, open-meteo HTTPS, register/push delta depuis Merlin.
  7. URLs des webradios (modes/radio.c) : confirmer chaque flux (curl -Iaudio/mpeg).
  8. Profondeur de pile des tâches net/weather (TLS+HTTP+JSON) sous charge audio + UI (uxTaskGetStackHighWaterMark).
  9. Politique supply-chain : idf_component.yml ne fige aujourd'hui que les versions sémantiques ; à miroiter/épingler par hash contre la baseline auditée avant toute prod (conformément au dépôt parent).

Licence

À définir (aligner sur la politique de l'org electron-rare).

S
Description
Lisael Box — firmware ESP32-S3-BOX-3 : webradios FR enfants + boite a sons SD + coin calme + horloge. ESP-IDF/ESP-ADF/LVGL.
Readme 908 KiB
Languages
C 93.8%
Python 4%
HTML 1.8%
CMake 0.3%