// Ce que l'APP conclut des deux bornes de `GetEnergyRatios` — pas ce que le JSON montre. // // ⚠️ `dart run` : cette sonde **importe le modèle de l'app** (`EnergyRatiosSnapshot`) plutôt // que de relire la charge utile à sa façon. Une lecture parallèle ne prouverait rien sur ce // que l'écran dira — c'est la leçon de `measurement_check.dart`. import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:etm_powersync_app/models/energy_ratios_snapshot.dart'; Future main(List args) async { final host = args.isNotEmpty ? args[0] : '192.168.1.75'; final ws = await WebSocket.connect('ws://$host:4444') .timeout(const Duration(seconds: 8)); var id = 0; final pending = >>{}; ws.listen((raw) { final m = jsonDecode(raw as String) as Map; final rid = m['id']; if (rid is int && pending.containsKey(rid)) pending.remove(rid)!.complete(m); }); Future> call(String m) { final myId = ++id; final c = Completer>(); pending[myId] = c; ws.add(jsonEncode({'id': myId, 'method': m, 'params': const {}})); return c.future.timeout(const Duration(seconds: 15)); } await call('JSONRPC.Hello'); final r = await call('NymeaEnergy.GetEnergyRatios'); final p = Map.from(r['params'] as Map); print('brut : ${jsonEncode(p)}'); final s = EnergyRatiosSnapshot.fromJson(p); String q(DateTime? d) => d == null ? '—' : d.toLocal().toString(); print('périodeDébut : ${q(s.periodStartedAt)} (frontière de journée → BILAN)'); print('mesuréDepuis : ${q(s.measuredSince)} (baseline → RATIOS)'); print('fuseau : ${s.timeZone}'); print('datePeriode : ${s.datePeriode}'); print('baselineRepriseEnJournee : ${s.baselineRepriseEnJournee}'); if (s.baselineRepriseEnJournee) { final couvert = DateTime.now().difference(s.measuredSince!); print(' -> les ratios ne couvrent que ${couvert.inMinutes} min, ' 'pas la journée. C\'est CE que le drapeau rend lisible.'); } await ws.close(); }