From b3da81d2773d801ea871c60a60f0273b4831ad18 Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Sun, 6 Sep 2026 14:42:14 +0200 Subject: [PATCH] =?UTF-8?q?fix(tableau=20de=20bord):=20charger=20la=20conf?= =?UTF-8?q?iguration=20quand=20la=20box=20r=C3=A9pond,=20pas=20au=20montag?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le correctif précédent — charger au montage — n'a rien changé, vérifié à l'écran : PAC et « Eau chaude » affichaient toujours « non publié » alors que la box publie `{powerW: 0, source: "meter"}` pour les deux. La raison est le moment : l'écran se construit avant que la connexion soit établie, l'appel échoue en silence, et RIEN ne réessaie. Le tick existait, mais à cinq minutes. Deux accroches donc, et la première suffit dans le cas normal : un chargement dès que la box devient joignable (une seule fois, gardé par un drapeau), et un rattrapage sur le tick si la configuration est encore vide. C'est la troisième fois aujourd'hui que le même motif se présente — une absence côté APP présentée comme une absence côté BOX — et la deuxième fois qu'un correctif à ce motif échoue parce qu'il était posé au mauvais instant. Le symptôme se corrige où la donnée manque ; la cause vit dans le moment où on va la chercher. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw --- lib/screens/dashboard_screen.dart | 49 +++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/lib/screens/dashboard_screen.dart b/lib/screens/dashboard_screen.dart index 574f953..ab3acb2 100644 --- a/lib/screens/dashboard_screen.dart +++ b/lib/screens/dashboard_screen.dart @@ -48,18 +48,7 @@ class _DashboardScreenState extends State { @override void initState() { super.initState(); - WidgetsBinding.instance.addPostFrameCallback((_) { - _lireBilan(); - // ⚠️ La configuration des charges n'était chargée QUE par l'écran des rôles. Le - // détail de consommation en a besoin — c'est elle qui porte le `domain` de chaque - // charge — et sans elle il affichait « non publié » sur des charges que la box - // publiait bel et bien. Une absence côté app présentée comme une absence côté box : - // le défaut qu'on vient de corriger, reproduit un cran plus loin. - final svc = context.read(); - context.read() - ..attach(svc) - ..load(); - }); + WidgetsBinding.instance.addPostFrameCallback((_) => _lireBilan()); _tick = Timer.periodic(_periode, (_) => _lireBilan()); } @@ -72,6 +61,22 @@ class _DashboardScreenState extends State { Future _lireBilan() async { if (!mounted) return; final svc = context.read(); + // ── La configuration des charges, et pourquoi ICI plutôt qu'au montage ────── + // + // Le détail de consommation a besoin du `domain` de chaque charge, porté par + // `GetLoadConfig` — sans lui, il affiche « non publié » sur des charges que la box + // publie : une absence côté APP présentée comme une absence côté BOX. + // + // Un chargement unique au montage ne suffit pas : l'écran se construit avant que la + // connexion soit établie, l'appel échoue en silence, et **rien ne réessaie**. Vérifié + // à l'écran le 2026-09-06 — le correctif « charger au montage » n'a rien changé. + // Accroché au tick, il se rattrape de lui-même dès que la box répond. + final cfg = context.read(); + if (cfg.entries.isEmpty) { + cfg + ..attach(svc) + ..load(); + } // Les ratios de la box sont lus à côté du bilan, pas à sa place : ils ne couvrent pas // la même fenêtre, et c'est justement ce que l'écran doit pouvoir dire. final r = await svc.fetchEnergyRatios(); @@ -114,10 +119,30 @@ class _DashboardScreenState extends State { return out; } + /// Vrai une fois la configuration demandée avec une box joignable — évite de relancer + /// l'appel à chaque trame pendant que la réponse arrive. + bool _configDemandee = false; + + /// Le tick est à cinq minutes : trop lent pour un premier chargement. On se raccroche + /// donc aussi au moment où la box devient joignable, une seule fois. + void _assurerConfig(NymeaService service) { + if (_configDemandee || !service.isConnected) return; + final cfg = context.read(); + if (cfg.entries.isNotEmpty) return; + _configDemandee = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + if (!mounted) return; + cfg + ..attach(service) + ..load(); + }); + } + @override Widget build(BuildContext context) { return Consumer( builder: (context, service, _) { + _assurerConfig(service); final data = service.energyData; return Scaffold( backgroundColor: EtmTokens.bgOf(context),