Les tuiles disent la JOURNÉE, par différence de compteurs sur la fenêtre publiée. La nouvelle ligne dit ce que la BOX publie, qui part de la baseline — et elle ne s'affiche QUE lorsque cette origine diffère du début de journée. Le cas est arrivé de lui-même : `nymead` redémarré à 09:23, sonde à 09:26, et la box publiait 100 % d'autoconsommation. Vrai sur trois minutes ; absurde intitulé « aujourd'hui ». La ligne le rend lisible — « Instantané depuis 09:23 » — au lieu de le laisser passer pour la journée. Vérifié avec le MODÈLE de l'app et non à l'œil sur le JSON : `ratios_check.dart` importe `EnergyRatiosSnapshot` (idiome de `measurement_check.dart`) et rend `baselineRepriseEnJournee: true`, ratios couvrant 3 minutes. Le banc est passé en Europe/Paris entre-temps, et `periodStartedAt` suit sans que le code bouge — c'est l'intérêt d'une frontière publiée. Quand les deux coïncident, rien n'est ajouté : une phrase permanente cesse d'être lue, comme un avertissement permanent. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
50 lines
2.1 KiB
Dart
50 lines
2.1 KiB
Dart
// 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<void> main(List<String> 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 = <int, Completer<Map<String, dynamic>>>{};
|
|
ws.listen((raw) {
|
|
final m = jsonDecode(raw as String) as Map<String, dynamic>;
|
|
final rid = m['id'];
|
|
if (rid is int && pending.containsKey(rid)) pending.remove(rid)!.complete(m);
|
|
});
|
|
Future<Map<String, dynamic>> call(String m) {
|
|
final myId = ++id;
|
|
final c = Completer<Map<String, dynamic>>();
|
|
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<String, dynamic>.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();
|
|
}
|