Clément Saillant 0caffbbe8b feat(histoires): podcast manifest v2 parser
Pure C parser (cJSON) for /sdcard/podcasts/manifest.json v2
format (shows grouped with cover + episodes list). Skips shows
with zero episodes. SD loader guarded by #ifndef LISAEL_HOST_TEST.
Host test compiles and passes on Mac without IDF toolchain.
2026-06-14 17:10:44 +02:00
2026-06-14 00:40:46 +02:00

Lisael Box

Firmware ESP32-S3-BOX-3 pour une "boîte" à destination d'un jeune enfant : webradios FR enfants, boîte à sons (microSD), coin calme / respiration, horloge / veilleuse, et jeux adaptés. UI tactile LVGL, sans lecture obligatoire (gros boutons + icônes), volume bridé (plafond enfant).

⚠️ Statut : point de départ soigné, NON compilé / NON flashé. Ce dépôt a été écrit sans la carte ni ESP-IDF/ESP-ADF installés. Le code suit les APIs ESP-IDF 5.x, le BSP esp-box-3 (v3.2.x, LVGL 9) et ESP-ADF de façon idiomatique, mais rien n'a pu être bâti. Voir la section À vérifier sur le matériel — elle est honnête et exhaustive.

Matériel cible

  • ESP32-S3-BOX-3 : ESP32-S3 (8 Mo PSRAM octal, 16 Mo flash), LCD 320×240 tactile capacitif, codec audio ES8311 + HP, micro ES7210, microSD, IMU (ICM-42670). Pas de capteur température/humidité externe sur la carte de base (un add-on AHT30 existe ; non supposé présent ici).

Stack logicielle

  • ESP-IDF 5.4 / 5.5 (nouvelles APIs : driver/i2c_master.h, driver/temperature_sensor.h, esp_netif_sntp.h, …).
  • BSP espressif/esp-box-3 ^3.2.0 (managed component) — écran, tactile, LVGL port, codec ES8311 (esp_codec_dev), microSD (FATFS), boutons, IMU. Tire transitivement esp_lvgl_port ^2, LVGL 9.x, esp_codec_dev ~1.5.
  • LVGL 9 pour l'UI tactile.
  • ESP-ADF pour l'audio en streaming/décodage (webradio + lecture SD). ESP-ADF n'est pas un managed component : il s'installe à part (voir ci-dessous).
  • espressif/cjson pour le manifest.json SD et les réponses open-meteo.

Arborescence

lisael-box/
├── CMakeLists.txt            # projet ; injecte ESP-ADF via ADF_PATH
├── partitions.csv            # 16 MB : factory 4 MB + storage FAT
├── sdkconfig.defaults        # défauts communs
├── sdkconfig.defaults.esp32s3# PSRAM octal, 16 MB flash, 240 MHz, LVGL/PSRAM
├── main/
│   ├── CMakeLists.txt        # sources + REQUIRES (BSP, ADF guardé)
│   ├── idf_component.yml     # managed deps (esp-box-3, cjson)
│   ├── Kconfig.projbuild     # menuconfig : WiFi, lat/lon météo, volume
│   ├── lisael_config.h       # constantes partagées (TZ, NVS keys, volume)
│   ├── app_main.c            # séquence de boot + tâches
│   ├── net/
│   │   ├── wifi.{c,h}        # STA + reconnexion + creds NVS/menuconfig
│   │   ├── sntp_time.{c,h}   # SNTP + fuseau Europe/Paris
│   │   └── weather.{c,h}     # open-meteo.com (HTTPS, sans clé) périodique
│   ├── audio/
│   │   ├── audio_player.{c,h}# façade codec ES8311 + volume bridé (NVS)
│   │   ├── radio_pipeline.{c,h} # ESP-ADF http_stream→decoder→i2s
│   │   └── sd_player.{c,h}   # ESP-ADF fatfs→mp3→i2s + parse manifest.json
│   ├── ui/
│   │   ├── ui.{c,h}          # shell LVGL + routeur de modes + styles
│   │   ├── fr_date.{c,h}     # date FR en lettres (sans setlocale)
│   │   └── icons.{c,h}       # glyphes/emoji des tuiles et boutons
│   └── modes/
│       ├── home.c            # accueil : date FR, heure, météo, capteur, tuiles
│       ├── radio.c           # écran webradios + volume/stop
│       ├── radios.h          # liste de stations (URLs à vérifier)
│       ├── soundbox.c        # grille SD depuis manifest.json
│       ├── calm.c            # bulle de respiration (anim LVGL)
│       ├── clock.c           # horloge/veilleuse + histoire du soir
│       └── games.c           # Memory + Compter + Coloriage (stub)
└── sdcard/
    ├── README.md             # disposition attendue de la carte
    └── sounds/manifest.json  # exemple de manifeste

Prérequis

  1. ESP-IDF 5.4+ installé et exporté :

    . $IDF_PATH/export.sh
    
  2. ESP-ADF installé séparément (audio streaming/décodage). ESP-ADF n'est pas distribué via le registre de composants ; on le clone et on exporte ADF_PATH :

    git clone --recursive https://github.com/espressif/esp-adf.git ~/esp/esp-adf
    export ADF_PATH=~/esp/esp-adf
    # (esp-adf fournit aussi $ADF_PATH/export.sh qui définit ADF_PATH)
    

    Le CMakeLists.txt racine ajoute $ADF_PATH/components à EXTRA_COMPONENT_DIRS. Si ADF_PATH est absent, le projet configure quand même (UI/horloge/respiration), mais les modules audio (webradio, lecture SD) ne sont pas liés et renvoient ESP_ERR_NOT_SUPPORTED à l'exécution (gardes __has_include("audio_pipeline.h")).

    ⚠️ Compatibilité de versions à vérifier. ESP-ADF s'épingle historiquement à des versions précises d'ESP-IDF, et son abstraction audio_board peut entrer en conflit avec le BSP esp-box-3 (les deux veulent gérer l'I2S/le codec). Voir À vérifier sur le matériel.

Build & flash

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

# 2. configurer le WiFi 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

Deux voies :

  • menuconfig : Lisael Box configuration → Wi-Fi → SSID / password. Les valeurs partent dans le binaire (pratique en dev).
  • NVS à l'exécution : lisael_wifi_save_credentials() écrit les clés wifi_ssid / wifi_pass dans le namespace lisael ; elles priment sur les valeurs menuconfig au boot suivant. Brancher un petit portail captif ou une commande console reste à faire (les valeurs menuconfig suffisent pour démarrer).

Météo

api.open-meteo.com (gratuit, sans clé, HTTPS via le CA bundle mbedTLS). La latitude/longitude viennent de NVS (lat/lon) sinon des défauts menuconfig (Paris). Rafraîchissement toutes les CONFIG_LISAEL_WEATHER_REFRESH_MIN min. En cas d'échec réseau, l'accueil affiche .

Carte microSD

Voir sdcard/README.md. En bref : FAT32, dossier /sounds/ contenant des .mp3 + un manifest.json ([{file, title, emoji}]). Les clips seront générés plus tard par TTS FR.

Modes

Mode Fichier Implémenté Notes
Accueil modes/home.c date FR en lettres, heure (SNTP), météo (open-meteo), temp interne de la puce (fallback), 5 tuiles
📻 Webradios modes/radio.c + audio/radio_pipeline.c code / ⚠️ URLs pipeline ESP-ADF http_stream→decoder→i2s ; URLs de stations à confirmer (modes/radios.h)
🔊 Boîte à sons modes/soundbox.c + audio/sd_player.c grille depuis manifest.json ; pipeline fatfs→mp3→i2s
🫧 Coin calme modes/calm.c bulle qui gonfle (~4 s) / dégonfle (~6 s) en boucle, "Inspire…/Souffle…", ambiance SD optionnelle
🕐 Horloge/veilleuse modes/clock.c grande heure + date FR, fond sombre doux, backlight tamisé, bouton "Histoire du soir"
🎮 Jeux modes/games.c Memory + Compter / 🚧 Coloriage stub feedback positif uniquement, pas de défaite ; Coloriage est un stub documenté (canvas tactile = plus lourd sur 320×240)

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

Liste honnête de ce qui n'a pas pu être testé et doit être validé sur une vraie carte :

  1. Compilation. Le code n'a jamais été bâti (ni ESP-IDF ni ESP-ADF installés ici). Attendez-vous à des ajustements : noms exacts de composants managés ESP-ADF dans REQUIRES (audio_pipeline, audio_stream, esp-adf-libs, audio_sal) et includes/macros décodeur exacts (DEFAULT_ESP_MP3_DECODER_CONFIG vs …_AUDIO_DECODER_CONFIG varie selon la révision ADF). cJSON = composant built-in json d'ESP-IDF.
  2. Coexistence BSP ↔ ESP-ADF sur l'I2S/codec. C'est le point chaud. Le BSP esp-box-3 initialise l'I2S et le codec ES8311 (bsp_audio_init / bsp_audio_codec_speaker_init), et ESP-ADF i2s_stream veut lui aussi posséder le port I2S. Deux approches connues, à arbitrer sur le matériel :
    • (A) ADF possède l'I2S : configurer i2s_stream avec le port/pins du BOX-3 et ne pas appeler bsp_audio_init ; n'utiliser le handle codec du BSP que pour le volume/gain. (approche codée ici)
    • (B) Le BSP possède l'I2S : écrire le PCM décodé vers le codec via esp_codec_dev_write() depuis un raw_stream au lieu de i2s_stream. Les configs i2s_std (port, broches, horloge via i2s_stream_set_clk) dans radio_pipeline.c / sd_player.c portent des TODO(hardware) — elles doivent matcher les valeurs du BSP de votre version.
  3. Version ESP-ADF compatible avec votre ESP-IDF 5.4/5.5 (ADF s'épingle souvent à une révision IDF précise). L'abstraction audio_board d'ADF peut doublonner le BSP — c'est pourquoi board.h n'est pas inclus.
  4. URLs des webradios (modes/radios.h) : ce sont des placeholders plausibles (Radio Pomme d'Api, Radio Doudou, etc.). Confirmez chaque flux (curl -Iaudio/mpeg ou audio/aac) et préférez du MP3 HTTP simple.
  5. Polices / emoji LVGL. Les fonts Montserrat par défaut ne contiennent pas les emoji ; les glyphes 📻🔊🫧… risquent d'apparaître en "tofu". Pour les rendre, embarquez une police emoji (subset Noto via lv_font_conv) ou remplacez par le set monochrome LV_SYMBOL_* (déjà utilisé pour les flèches et contrôles). Les accents FR (é, à, û, î) demandent une police Latin-1 — à vérifier aussi.
  6. Tailles de police montserrat (lv_font_montserrat_28/48) : activez-les dans menuconfig → Component config → LVGL → Font usage si elles ne sont pas dans le set par défaut.
  7. Backlight / luminosité. bsp_display_brightness_set() / bsp_display_backlight_on() supposés présents dans le BSP — à confirmer sur votre version (sinon le mode veilleuse ne tamise pas).
  8. Capteurs. Seule la température interne de la puce (driver/temperature_sensor.h) est lue, en fallback : ce n'est PAS la température de la pièce. L'IMU ICM-42670 et l'éventuel AHT30 ne sont pas exploités (le BSP expose bsp_sensor_init — à brancher si voulu).
  9. Profondeur de pile des tâches. net/weather à 8192 o (TLS+HTTP+JSON), tick à 4096 o, tâche LVGL gérée par le BSP — à surveiller au monitor (uxTaskGetStackHighWaterMark) sous charge audio + UI.
  10. Mémoire de jeu (games.c). Les états Memory/Compter sont alloués via lv_malloc et vivent le temps de l'écran (non libérés à la destruction) — OK pour une app mono-écran longue durée, à durcir si les écrans sont recréés en boucle.
  11. Politique supply-chain. Conformément au dépôt parent, les deps doivent à terme être miroitées/épinglées par hash contre la baseline auditée (idf_component.yml ne fige aujourd'hui que les versions sémantiques).

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%