diff --git a/docs/BRIEF_plugin_depuis_maquettes.md b/docs/BRIEF_plugin_depuis_maquettes.md index 4546b8d..797d436 100644 --- a/docs/BRIEF_plugin_depuis_maquettes.md +++ b/docs/BRIEF_plugin_depuis_maquettes.md @@ -129,9 +129,22 @@ combinatoire de `relayrouter.cpp` (toutes les combinaisons 2^N, doublons écart 16 relais). Deux implémentations d'une même règle divergeront : à la première correction côté moteur, l'app annoncera des paliers que la box n'atteint plus. -**Demande.** Exposer la liste — soit dans la télémétrie (`mechanism.stagesW: [...]`), soit en -retour d'un `GetLoadConfig` enrichi. À défaut, **le dire explicitement**, et l'app -documentera sa dérivation comme un miroir à resynchroniser. +**⚠️ Tranché par la rév. 3 du contrat, arrivée pendant la rédaction de ce brief.** +`INTERFACE_etmvariableload.md` §10 dit désormais : l'assistant calcule et **affiche** les +paliers atteignables côté app, et ces `powerLevels` ne sont **pas** envoyés — ils sont +« dérivés côté plugin ». La duplication est donc **voulue et contractuelle** : l'app dérive +pour montrer, le routeur dérive pour exécuter. + +**Ce qui reste, et qui devient la vraie demande :** un moyen de vérifier que les deux +dérivations n'ont pas divergé. Il existe déjà à moitié — la télémétrie publie +`mechanism.maxStageW`. L'app peut donc comparer **le maximum de sa propre liste** à celui que +la box annonce, et se taire si ça correspond, alerter sinon. Ça ne couvre pas les paliers +intermédiaires, mais ça attrape le cas qui compte : une règle de combinatoire changée d'un +côté seulement. + +**Demande minimale** : confirmer que `maxStageW` reste bien le maximum atteignable et non un +plafond de sécurité — sinon la comparaison ne vaut rien. **Demande confortable** : publier la +liste complète (`mechanism.stagesW: [...]`), et l'app cessera de dériver. --- diff --git a/docs/mockups/configurer_mecanismes_mockup.html b/docs/mockups/configurer_mecanismes_mockup.html index 5e61822..729de82 100644 --- a/docs/mockups/configurer_mecanismes_mockup.html +++ b/docs/mockups/configurer_mecanismes_mockup.html @@ -288,6 +288,9 @@ créent pas de palier supplémentaire — les doublons sont écartés. +
Le picker liste les things par NOM, filtrés sur + l'interface nymea power — taper un UUID au doigt est une erreur + garantie. Il résout nom → ThingId et n'ajoute aucun champ au contrat.
Un ECS simple, c'est un seul relais — deux paliers, 0 et P. Une résistance multipalier en déclare 2, 3 ou 4. La puissance saisie est celle de la résistance, pas le calibre du contacteur : rien dans nymea ne dit ce qu'un relais diff --git a/tools/devlog/vm_logs.dart b/tools/devlog/vm_logs.dart index 83078ab..566c0b5 100644 --- a/tools/devlog/vm_logs.dart +++ b/tools/devlog/vm_logs.dart @@ -2,14 +2,32 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -// Capte les traces `dart:developer log()` de l'app en cours d'exécution. +// Pont VM Service — rend visibles les traces `dart:developer log()` de l'app. // -// `flutter run` ne les imprime PAS sur stdout (elles partent au VM Service, pas à -// stdout ni à logcat). Sans ce pont, tout ce que `NymeaService._log()` journalise est -// invisible depuis le poste — donc les traces de locale, de télémétrie et d'écriture -// aussi. +// ## Pourquoi ce fichier existe // -// Usage : dart vm_logs.dart ws://127.0.0.1:PORT/TOKEN=/ws +// `flutter run` **n'imprime pas** ces traces sur stdout : elles partent au VM Service, ni sur +// la console, ni dans `logcat`. Tout ce que `NymeaService._log()` journalise — locale demandée +// et retenue, aller-retours RPC, séquence d'écriture, télémétrie poussée — est donc invisible +// depuis le poste tant qu'on n'est pas branché ici. +// +// Éprouvé le 2026-08-25, premier passage de l'app sur appareil (Redmi Note 9S) : sans ce pont, +// aucun constat du journal de vérification n'était atteignable. +// +// ## Usage +// +// flutter run -d --use-application-binary=build/app/outputs/flutter-apk/app-debug.apk +// # relever « A Dart VM Service on … is available at: http://127.0.0.1:PORT/TOKEN=/ » +// dart tools/devlog/vm_logs.dart 'ws://127.0.0.1:PORT/TOKEN=/ws' +// +// Le `/ws` final est obligatoire, et les guillemets aussi — le jeton contient un `=`. +// +// ## Le piège d'horodatage, déjà payé une fois +// +// Le VM Service livre **l'historique bufférisé d'un coup** au moment du `streamListen`. +// Horodater à la réception écrase donc toute la chronologie sous une seule seconde — c'est ce +// qui est arrivé au premier essai. On lit `event.timestamp`, jamais `DateTime.now()`. + Future main(List args) async { final uri = args.first; final ws = await WebSocket.connect(uri);