fix(tableau de bord): charger la configuration quand la box répond, pas au montage

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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
This commit is contained in:
Patrick Schurig 2026-09-06 14:42:14 +02:00
parent 9edd9cc51f
commit b3da81d277

View File

@ -48,18 +48,7 @@ class _DashboardScreenState extends State<DashboardScreen> {
@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<NymeaService>();
context.read<LoadConfigProvider>()
..attach(svc)
..load();
});
WidgetsBinding.instance.addPostFrameCallback((_) => _lireBilan());
_tick = Timer.periodic(_periode, (_) => _lireBilan());
}
@ -72,6 +61,22 @@ class _DashboardScreenState extends State<DashboardScreen> {
Future<void> _lireBilan() async {
if (!mounted) return;
final svc = context.read<NymeaService>();
// ── 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<LoadConfigProvider>();
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<DashboardScreen> {
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<LoadConfigProvider>();
if (cfg.entries.isNotEmpty) return;
_configDemandee = true;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
cfg
..attach(service)
..load();
});
}
@override
Widget build(BuildContext context) {
return Consumer<NymeaService>(
builder: (context, service, _) {
_assurerConfig(service);
final data = service.energyData;
return Scaffold(
backgroundColor: EtmTokens.bgOf(context),