Files
lisael-box/README.md
T
Clément Saillant 72fee10538 docs: add README and SD card layout
Context:
  The README is the primary usable deliverable: how to install
  ESP-IDF + ESP-ADF, build, flash, and prepare the microSD card, plus an
  honest list of what is unverified.

Changes:
  - README.md: prerequisites (ADF_PATH), build/flash, provisioning,
    module table, child-safety notes, and a thorough "A verifier sur le
    materiel" section (build, BSP<->ADF I2S, radio URLs, emoji fonts...)
  - sdcard/README.md + sdcard/sounds/manifest.json example

Impact:
  A reader can stand the project up and knows exactly what still needs
  validation on real hardware.
2026-06-14 00:40:46 +02:00

220 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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](#à-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é :
```bash
. $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` :
```bash
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](#à-vérifier-sur-le-matériel).
## Build & flash
```bash
# 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`](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 -I` → `audio/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`).