Aligner le firmware sur le SDK Hermes Gadget : contrat device, OTA durci, rendu par régions #5

Merged
speedi57 merged 9 commits from feat/alignement-sdk-gadget into main 2026-10-18 15:54:08 +00:00
Owner

Summary

Reprend du SDK Hermes Gadget (MIT) ce qui est transposable ici : un contrat
d'API explicite, un OTA plus sûr, et les deux mécanismes de rendu qui font
tomber le trafic au panneau. Le reste du SDK est cadré comme feuille de route
dans docs/alignement-hermes-gadget-sdk.md.

+ docs/device-api.md                     # contrat firmware <-> /api/device (proto) + manifeste OTA
+ docs/alignement-hermes-gadget-sdk.md   # comparaison + feuille de route (Tier 1/2/3)
  .forgejo/workflows/build.yml          # manifeste OTA : + "board"
  src/ota_updater.cpp                   # refus d'une image destinee a une autre carte
  lib/config_local.example.h            # OTA_DISABLE_SHA_CHECK 1 -> 0
  server/src/model.rs                   # payload /api/device : + proto
~ src/app.cpp, src/app.h, src/screen_*.cpp
+ src/render_stats.h                    # rendu par regions, animation deterministe, mesure

Contrat et OTA

  • docs/device-api.md fige /api/device et le manifeste OTA ; le payload
    annonce proto (le firmware peut refuser une version qu'il ne parle pas).
  • Le manifeste OTA porte board, et le firmware refuse une image dont le champ
    est absent ou ne correspond pas à sa carte.
  • OTA_DISABLE_SHA_CHECK valait 1 dans la configuration d'exemple : toute copie
    de l'exemple installait un firmware sans vérifier son SHA-256. Remis à 0.

Rendu

  • Animations pilotées par un compteur d'images, en arithmétique entière : plus
    de millis(), sinf() ni cosf() dans un chemin de rendu.
  • Redraw par régions : le contenu et l'indicateur d'activité du profil ont
    chacun une clé de hachage de leurs entrées, et ne sont composés et envoyés que
    quand elle change. Un écran immobile n'envoie rien.
  • Le rendu ne tourne plus sous le verrou de données : la tâche réseau publie un
    instantané, la boucle le recopie, puis le SPI est poussé hors verrou.
  • src/render_stats.h imprime une ligne [perf] (ticks sans envoi, moyennes et
    p95 de composition et de pushSprite, débit).

Vérifications

Commande Résultat
pio run (cible ESP-LCD) SUCCESS, RAM 15,2 %, Flash 1 259 788 o, 0 avertissement
cargo fmt --check, clippy --locked --all-targets -- -D warnings, cargo test --locked 0 avertissement, 4 tests
serveur contre https://hermes.thidev.fr, GET /api/device payload réel, "proto": 1
build.yml : YAML + rendu du heredoc manifeste valide avec board
rendu sur carte (ordre de dessin, débit, scintillement) non exécuté : demande le matériel, la ligne [perf] est l'outil

À trancher

  • L'anneau d'état reste un plein écran périodique : son englobant est
    l'écran entier et aucune région ne l'approche. Le supprimer implique un
    changement visible (localiser l'animation d'état dans un petit indicateur, ou
    anneau statique par état). Documenté avec les débits avant/après.
  • tests/ui_sim compile l'ancienne UI LVGL : désaccordé depuis la migration
    LovyanGFX, à remettre à niveau ou à retirer.
  • .forgejo/workflows/validate_workflow.py échoue aussi sur main : il
    attend on.push.branches == ['main'] alors que build.yml ne se déclenche que
    sur les tags. Hors périmètre, non touché.
## Summary Reprend du SDK Hermes Gadget (MIT) ce qui est transposable ici : un contrat d'API explicite, un OTA plus sûr, et les deux mécanismes de rendu qui font tomber le trafic au panneau. Le reste du SDK est cadré comme feuille de route dans `docs/alignement-hermes-gadget-sdk.md`. ```diff + docs/device-api.md # contrat firmware <-> /api/device (proto) + manifeste OTA + docs/alignement-hermes-gadget-sdk.md # comparaison + feuille de route (Tier 1/2/3) .forgejo/workflows/build.yml # manifeste OTA : + "board" src/ota_updater.cpp # refus d'une image destinee a une autre carte lib/config_local.example.h # OTA_DISABLE_SHA_CHECK 1 -> 0 server/src/model.rs # payload /api/device : + proto ~ src/app.cpp, src/app.h, src/screen_*.cpp + src/render_stats.h # rendu par regions, animation deterministe, mesure ``` ### Contrat et OTA - `docs/device-api.md` fige `/api/device` et le manifeste OTA ; le payload annonce `proto` (le firmware peut refuser une version qu'il ne parle pas). - Le manifeste OTA porte `board`, et le firmware refuse une image dont le champ est absent ou ne correspond pas à sa carte. - `OTA_DISABLE_SHA_CHECK` valait 1 dans la configuration d'exemple : toute copie de l'exemple installait un firmware sans vérifier son SHA-256. Remis à 0. ### Rendu - Animations pilotées par un compteur d'images, en arithmétique entière : plus de `millis()`, `sinf()` ni `cosf()` dans un chemin de rendu. - Redraw par régions : le contenu et l'indicateur d'activité du profil ont chacun une clé de hachage de leurs entrées, et ne sont composés et envoyés que quand elle change. Un écran immobile n'envoie **rien**. - Le rendu ne tourne plus sous le verrou de données : la tâche réseau publie un instantané, la boucle le recopie, puis le SPI est poussé hors verrou. - `src/render_stats.h` imprime une ligne `[perf]` (ticks sans envoi, moyennes et p95 de composition et de `pushSprite`, débit). ### Vérifications | Commande | Résultat | |---|---| | `pio run` (cible `ESP-LCD`) | SUCCESS, RAM 15,2 %, Flash 1 259 788 o, 0 avertissement | | `cargo fmt --check`, `clippy --locked --all-targets -- -D warnings`, `cargo test --locked` | 0 avertissement, 4 tests | | serveur contre `https://hermes.thidev.fr`, `GET /api/device` | payload réel, `"proto": 1` | | `build.yml` : YAML + rendu du heredoc | manifeste valide avec `board` | | rendu sur carte (ordre de dessin, débit, scintillement) | **non exécuté** : demande le matériel, la ligne `[perf]` est l'outil | ### À trancher - **L'anneau d'état reste un plein écran périodique** : son englobant *est* l'écran entier et aucune région ne l'approche. Le supprimer implique un changement visible (localiser l'animation d'état dans un petit indicateur, ou anneau statique par état). Documenté avec les débits avant/après. - **`tests/ui_sim` compile l'ancienne UI LVGL** : désaccordé depuis la migration LovyanGFX, à remettre à niveau ou à retirer. - **`.forgejo/workflows/validate_workflow.py` échoue aussi sur `main`** : il attend `on.push.branches == ['main']` alors que `build.yml` ne se déclenche que sur les tags. Hors périmètre, non touché.
Compare ce firmware au SDK communautaire Hermes Gadget (MIT) : ce qui mérite
d'être repris, ce qui est déjà en place ici, et ce qu'il ne faut pas reprendre.
Sert de feuille de route (Tier 1/2/3) avec les prérequis et les pièges.
Écrit le contrat firmware <-> hermes-device-server (/api/device) et le schéma du
manifeste OTA, avec le rôle du champ proto. Équivalent local, pour ce projet, de
docs/protocol.md du SDK.
Ajoute PROTO et le champ proto en tête du document /api/device, un test qui le
fige, et met le README à jour. Le firmware peut refuser une version qu'il ne
parle pas plutôt que d'afficher une donnée fausse.
Le manifeste OTA porte désormais « board » (généré par build.yml), et le
firmware refuse une image dont le champ est absent ou différent de OTA_BOARD_ID :
une image compilée pour une autre carte ne doit jamais être installée.
lib/config_local.example.h activait OTA_DISABLE_SHA_CHECK : toute copie de
l'exemple installait un firmware sans vérifier son SHA-256. Remis à 0, avec le
commentaire qui explique pourquoi le laisser à 0.
Le README annonçait encore LVGL 8.4 alors que l'UI est passée à LovyanGFX, et
décrivait un blocage de validation obsolète. Corrige l'architecture, les
dépendances et l'état de validation, et signale que tests/ui_sim compile
l'ancienne UI LVGL (donc désaccordé).
Les animations avançaient sur millis() avec des sinf()/cosf(), et chaque image
poussait les 424 Kio de l'écran entier sur le bus QSPI même quand rien ne
changeait. Reprend du SDK Hermes Gadget :

- animations pilotées par un compteur d'images (anim_frame/anim_tri) en
  arithmétique entière : un même numéro d'image produit les mêmes pixels ;
- redraw par régions : le contenu (écran + points de navigation + anneau) et
  l'indicateur d'activité du profil ont chacun une clé de hachage de leurs
  entrées, et ne sont composés et envoyés que quand leur clé change ;
- l'indicateur d'activité vit dans son propre sprite de 140x140 poussé avec sa
  clé de transparence : animer une fiche de profil ne coûte plus un écran ;
- render_stats.h mesure composition, pushSprite, p95 et débit, et imprime une
  ligne [perf] sur la console série ;
- le rendu ne tourne plus sous le verrou de données : la tâche réseau publie un
  instantané que la boucle recopie, puis le SPI est poussé hors verrou ;
- supprime le fondu mort (fade_active() renvoyait toujours false).

L'anneau d'état garde son animation, mais son englobant est l'écran entier : la
région de contenu reste donc réenvoyée en entier tant qu'il anime. Limite
documentée dans docs/alignement-hermes-gadget-sdk.md.
Décrit ce qui est repris du SDK (animation déterministe, régions, indicateur,
mesure) et pourquoi un anneau sur tout le périmètre ne peut pas être une région
bon marché, avec les débits avant/après. Met le README à jour : rendu par
régions, et ligne [perf] à comparer sur la carte.
fix(ui): sprite d'activité auto-suffisant et ordre de dessin d'origine
All checks were successful
server / Check (fmt, clippy, tests) (pull_request) Successful in 1m44s
server / Build release binary (tags server-v* only) (pull_request) Has been skipped
0c8c17c981
Corrige trois points de la refonte précédente :

- l'indicateur était poussé après la région de contenu, donc son bas passait
  par-dessus le nom du profil alors qu'il était dessiné avant lui auparavant.
  Il est de nouveau dessiné dans la région de contenu à sa place d'origine, et
  le sprite d'activité recompose les mêmes pièces (fond, avatar, indicateur,
  partie du nom tombant dans la boîte) dans le même ordre : les deux régions ne
  peuvent plus diverger ;
- le sprite d'activité est désormais auto-suffisant et poussé opaque, ce qui
  supprime la clé de transparence et le risque qu'une couleur de la palette
  tombe dessus et perce l'indicateur ;
- plus de poussée d'activité forcée après chaque poussée de contenu, et l'état
  tactile n'entre dans la clé de contenu que sur l'écran Version : un doigt qui
  bouge sur une autre fiche ne repeint plus tout l'écran.
hermes changed title from Aligner le firmware sur le SDK Hermes Gadget : contrat device, OTA durci, rendu par regions to Aligner le firmware sur le SDK Hermes Gadget : contrat device, OTA durci, rendu par régions 2026-10-18 15:48:36 +00:00
speedi57 deleted branch feat/alignement-sdk-gadget 2026-10-18 15:54:15 +00:00
hermes referenced this pull request from a commit 2026-10-18 17:11:10 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
thidev/hermes-compagnon!5
No description provided.