Webradio was silent: the streams are stereo 44.1 kHz MP3, and opening the
ES8311 codec in stereo failed ("i2s_std_set_slot: dma descriptor") because the
stereo I2S DMA no longer fits the tight internal RAM — the podcast path works
only because its files are mono. Downmix the decoded stereo PCM to mono and
open the codec at one channel. Also switch the stream URLs to plain HTTP: the
HTTPS handshake intermittently failed to allocate AES memory, and these mounts
serve identical audio over http with no redirect. Add SuperLoustic (3 stations).
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 transitivementesp_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/cjsonpour lemanifest.jsonSD 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
-
ESP-IDF 5.4+ installé et exporté :
. $IDF_PATH/export.sh -
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.txtracine ajoute$ADF_PATH/componentsàEXTRA_COMPONENT_DIRS. SiADF_PATHest absent, le projet configure quand même (UI/horloge/respiration), mais les modules audio (webradio, lecture SD) ne sont pas liés et renvoientESP_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_boardpeut entrer en conflit avec le BSPesp-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éswifi_ssid/wifi_passdans le namespacelisael; 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 viaaudio_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 :
- 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_CONFIGvs…_AUDIO_DECODER_CONFIGvarie selon la révision ADF). cJSON = composant built-injsond'ESP-IDF. - Coexistence BSP ↔ ESP-ADF sur l'I2S/codec. C'est le point chaud. Le
BSP
esp-box-3initialise l'I2S et le codec ES8311 (bsp_audio_init/bsp_audio_codec_speaker_init), et ESP-ADFi2s_streamveut lui aussi posséder le port I2S. Deux approches connues, à arbitrer sur le matériel :- (A) ADF possède l'I2S : configurer
i2s_streamavec le port/pins du BOX-3 et ne pas appelerbsp_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 unraw_streamau lieu dei2s_stream. Les configsi2s_std(port, broches, horloge viai2s_stream_set_clk) dansradio_pipeline.c/sd_player.cportent desTODO(hardware)— elles doivent matcher les valeurs du BSP de votre version.
- (A) ADF possède l'I2S : configurer
- 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_boardd'ADF peut doublonner le BSP — c'est pourquoiboard.hn'est pas inclus. - URLs des webradios (
modes/radios.h) : ce sont des placeholders plausibles (Radio Pomme d'Api, Radio Doudou, etc.). Confirmez chaque flux (curl -I→audio/mpegouaudio/aac) et préférez du MP3 HTTP simple. - 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 monochromeLV_SYMBOL_*(déjà utilisé pour les flèches et contrôles). Les accents FR (é, à, û, î) demandent une police Latin-1 — à vérifier aussi. - Tailles de police montserrat (
lv_font_montserrat_28/48) : activez-les dansmenuconfig → Component config → LVGL → Font usagesi elles ne sont pas dans le set par défaut. - 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). - 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 exposebsp_sensor_init— à brancher si voulu). - 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. - Mémoire de jeu (
games.c). Les états Memory/Compter sont alloués vialv_mallocet 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. - 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.ymlne fige aujourd'hui que les versions sémantiques).
Licence
À définir (aligner sur la politique de l'org electron-rare).