Le miroir INTERFACE_etmvariableload.md est passé en rév. 3 pendant la session (corps
identique au canonique du dépôt plugin, vérifié). Son §10 s'adresse nommément à l'agent
app — et il RATIFIE les maquettes dessinées aujourd'hui : relays[] = {thingId, powerW}
pour l'ECS relais, maxPowerW seul pour le continu, powerLevels absents de la config et
dérivés par le routeur.
Trois recalages :
- Le picker de relais filtre sur l'interface nymea « power » et présente les things par
NOM — nommé dans la maquette, il ne l'était pas.
- Le point 4 du brief plugin est tranché par la rév. 3 : la duplication de la
combinatoire est voulue (l'app dérive pour montrer, le routeur pour exécuter). La
demande devient donc un moyen de détecter la divergence — la télémétrie publie déjà
maxStageW, l'app peut y confronter le maximum de sa propre liste.
- En-tête du pont VM Service, que le commit précédent avait laissé dans sa forme brute.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPUo3RMr8SzK6qbFtfBm8H
77 lines
3.1 KiB
Dart
77 lines
3.1 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
// Pont VM Service — rend visibles les traces `dart:developer log()` de l'app.
|
|
//
|
|
// ## Pourquoi ce fichier existe
|
|
//
|
|
// `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 <device> --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<void> main(List<String> args) async {
|
|
final uri = args.first;
|
|
final ws = await WebSocket.connect(uri);
|
|
var id = 0;
|
|
void call(String method, [Map<String, dynamic> params = const {}]) {
|
|
ws.add(jsonEncode({
|
|
'jsonrpc': '2.0',
|
|
'id': (++id).toString(),
|
|
'method': method,
|
|
'params': params,
|
|
}));
|
|
}
|
|
|
|
ws.listen((raw) {
|
|
final m = jsonDecode(raw as String) as Map<String, dynamic>;
|
|
if (m['method'] != 'streamNotify') return;
|
|
final ev = (m['params'] as Map)['event'] as Map;
|
|
final kind = ev['kind'];
|
|
// L'heure de l'ENREGISTREMENT, pas celle de la réception : le VM Service livre
|
|
// l'historique bufférisé d'un coup au moment du streamListen, et horodater à la
|
|
// réception écraserait toute la chronologie sous une seule seconde.
|
|
final micros = (ev['timestamp'] as num?)?.toInt();
|
|
final ts = micros == null
|
|
? '--:--:--'
|
|
: DateTime.fromMillisecondsSinceEpoch(micros)
|
|
.toIso8601String()
|
|
.substring(11, 23);
|
|
if (kind == 'Logging') {
|
|
final rec = ev['logRecord'] as Map;
|
|
final name = (rec['loggerName'] as Map?)?['valueAsString'] ?? '';
|
|
final msg = (rec['message'] as Map?)?['valueAsString'] ?? '';
|
|
print('$ts [$name] $msg');
|
|
} else if (kind == 'WriteEvent') {
|
|
final bytes = ev['bytes'] as String?;
|
|
if (bytes != null) {
|
|
stdout.write('$ts [stdout] ${utf8.decode(base64.decode(bytes))}');
|
|
}
|
|
}
|
|
});
|
|
|
|
call('streamListen', {'streamId': 'Logging'});
|
|
call('streamListen', {'streamId': 'Stdout'});
|
|
call('streamListen', {'streamId': 'Stderr'});
|
|
print('--- branché sur $uri ---');
|
|
await Future<void>.delayed(const Duration(hours: 2));
|
|
}
|