Le miroir GitHub n'est pas encore synchronisé : les liens pointent sur git.etm-powersync.fr. INTERFACE.md n'est plus dans le dépôt public : la forme des méthodes NymeaEnergy.* se lit sur la box (JSONRPC.Introspect) ; GetOptimizerStatus n'est pas réservée à l'administrateur. Orthographe anglaise unifiée : optimizer, optimization. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ry3vBrJT1tHdxAaXdCWi6L
powersync-docs
Documentation ETM PowerSync — docs.etm-powersync.fr
MkDocs Material, docs-as-code, trois langues : fr (défaut) · de · en.
Licence : CC-BY-4.0 pour la documentation, GPL-3.0 pour les exemples de code.
La règle qui explique tout le reste
95 % du volume est GÉNÉRÉ, pas rédigé. Mesure du 2026-10-12 : 74 013 mots générés contre 3 506 mots de prose, sur 107 pages. Tout ce qui est entre
<!-- BEGIN GENERATED: <clé> --> … <!-- END GENERATED -->
est produit par un script depuis une source de vérité, et écrasé à chaque passage. Éditer à l'intérieur de ces marqueurs, c'est écrire quelque chose qui disparaîtra.
| Générateur | Source de vérité | Produit |
|---|---|---|
scripts/gen_device_reference.py |
PORTING_STATUS.yaml + les integrationplugin*.json et meta.json des 5 dépôts de plugins |
fiches appareils, index de catégorie, matrice de compatibilité, appareils/SUMMARY.md |
scripts/gen_api_reference.py |
introspect.json (introspection nymea) |
référence JSON-RPC (23 pages), api/SUMMARY.md |
scripts/gen_optimizer_reference.py |
docs/etm-powersync-optimizer-protocol.openrpc.json du moteur (etm-powersync-energy-plugin-etm, branche par défaut) |
tableaux de messages, listes fermées, règles nommées et machine de repli de optimiseur/protocole*.md, fiche de optimiseur/contrat*.md, copie servie du contrat ; garde-fou de contenu (IP privées, « cloud », « Héos ») |
Multi-langue — où passe la frontière
Deux régimes, et ils ne se traitent pas pareil :
- Le bloc de référence est en ANGLAIS, une seule fois, servi identique dans les trois
langues. Décision du 2026-10-12. La raison est une mesure, pas un goût : nymea ne sert
aucune traduction sur notre parc — vérifié sur le banc
hems, oùIntegrations.GetThingClassesrend la même charge utile au sha256 près (243 340 octets) pourfr_FR,de_DEeten_US. Les noms de modèles, de registres et d'unités sont donc déjà en anglais ; traduire les seuls en-têtes de colonnes autour aurait fabriqué des pages bilingues sans rien gagner. Le vocabulaire vit dans le dictREFde chaque générateur. Cas particulier, la référence optimiseur (2026-10-18) : le cadre est en anglais comme partout, mais les descriptions viennent du contrat du moteur, écrit en français. Les traduire ici ferait une seconde vérité : elles sont reprises telles quelles, et l'en-tête de colonne le dit (« from the contract, French »). - La prose et la navigation se TRADUISENT. Fichiers suffixés (
page.md= fr,page.de.md,page.en.md), libellés de nav parnav_translationsdansmkdocs.yml, échafaudage des pages créées par le dictSCAFFOLDdu générateur appareils.
Pourquoi
SCAFFOLDexiste. Sans lui, chaque nouvel appareil ajouté créerait sa fiche dans la seule langue par défaut, etfallback_to_defaultla servirait en français sous/de/et/en/. Le générateur crée donc les trois variantes — et ne réécrit jamais une page existante, pour que la prose traduite à la main survive aux régénérations.
Localisation ≠ traduction
docs/tarifs.md est l'exemple à connaître : la version FR parle de Tempo et du signal RTE,
la DE de §14a EnWG et de SMARD, l'EN des deux. Ce ne sont pas des traductions l'une de
l'autre, et c'est volontaire — les signaux tarifaires sont nationaux. Même traitement pour la
ligne correspondante de docs/fonctionnalites/index.md.
Travailler dessus
python3 -m venv .venv && . .venv/bin/activate
pip install -r requirements.txt
# Prévisualiser (les trois langues sont construites ensemble)
mkdocs serve
# Régénérer la référence appareils — exige les JSON des 5 dépôts de plugins
# dans .plugins-src/ (la CI les clone ; en local, copiez-les depuis le workspace)
python3 scripts/gen_device_reference.py --src .plugins-src --docs docs \
--lang fr --locales fr,de,en
# Régénérer la référence API
python3 scripts/gen_api_reference.py --src introspect.json --docs docs
# Régénérer la référence du protocole optimiseur — exige le contrat OpenRPC du moteur
# (la CI clone le moteur dans .engine-src/ ; en local, --src accepte le clone,
# un dossier qui contient le fichier, ou le fichier lui-même)
python3 scripts/gen_optimizer_reference.py --src .engine-src/etm-powersync-energy-plugin-etm --docs docs
# Ce que vérifie la CI : rien ne doit changer après régénération
mkdocs build --strict
python3 scripts/gen_device_reference.py --src .plugins-src --docs docs \
--lang fr --locales fr,de,en --check
python3 scripts/gen_optimizer_reference.py --src .engine-src/etm-powersync-energy-plugin-etm \
--docs docs --check
Le sélecteur de langue
Material affiche son icône translate — l'idéogramme 文 collé à un A. Elle dit
« traduire », pas « vous êtes en français », et à la taille du bandeau on y voit un
symbole asiatique plutôt qu'une langue. Depuis le 2026-10-15, stylesheets/extra.css
la masque et affiche à la place le drapeau de la langue courante plus son code,
comme sur etm-powersync.fr. La langue courante est aussi mise en évidence dans la
liste déroulante, où les trois lignes étaient jusque-là identiques.
Le drapeau se choisit sur html[lang], que mkdocs-static-i18n pose déjà par locale.
Aucun gabarit du thème n'est surchargé — rien à reprendre à chaque mise à jour de
Material. Les drapeaux sont des SVG en data: (les emojis drapeaux ne se rendent pas
sous Windows) et le aria-label du bouton est inchangé : c'est lui qui porte le sens
pour les lecteurs d'écran, le code « FR » du ::after restant décoratif.
⚠️ mkdocs build --strict échoue sur un simple avertissement. C'est pour cela que
navigation.instant est retiré de theme.features : il est incompatible avec le lien
contextuel du sélecteur de langue de mkdocs-static-i18n. Le commentaire est dans
mkdocs.yml, à l'endroit du retrait.
Déploiement
CI Gitea (.gitea/workflows/docs.yml) sur push vers main, plus un passage nocturne à 3 h
(les meta.json des dépôts de plugins bougent sans que ce dépôt-ci bouge). Pipeline :
clone des 5 dépôts de plugins et du moteur → génération appareils → génération API →
génération optimiseur → mkdocs build --strict → contrôle d'idempotence → rsync vers
le serveur.
Le build produit site/ (fr), site/de/ et site/en/ en une passe ; le rsync --delete
pousse l'ensemble.