etm-powersync-app/docs/DASHBOARD_SPEC.md
Patrick Schurig 0ebbde49da chore(docs): range specs/contrats/refs dans docs/, track l'autorité
- specs -> docs/ (DASHBOARD_SPEC compagnon du contrat)
- ref introspection nymea-jsonRPC -> docs/reference/
- mockups HTML -> docs/mockups/ ; briefs consommés -> docs/archive/
- track AGENTS.md + INTERFACE_etmvariableload.md (étaient untracked)
- INTERFACE_*: marqué miroir, canonique = repo plugin
2026-06-28 12:49:57 +02:00

13 KiB
Raw Permalink Blame History

Dashboard ETM-PowerSync — Brief d'implémentation Flutter

Spec pour Claude Code. Objectif : recréer l'écran Dashboard de l'app app.etm-powersync.fr (Flutter), tel que validé en maquette. Les fichiers HTML de référence (etm-powersync-dashboard-v4.html, etm-powersync-flux-drilldown.html) sont la source de vérité visuelle — ce document en est la transcription technique.


1. Contexte

ETM-PowerSync est un HEMS (Home Energy Management System). Le cœur intelligent s'appelle Héos (optimiseur prédictif MILP, horizon 2448 h). Le Dashboard doit faire deux choses : montrer l'état énergétique en direct, et rendre lisible et explicable ce que Héos décide — c'est le différenciateur produit. Public : clients résidentiels (langage clair, zéro jargon) + installateurs.


2. Principes directeurs (ne pas dévier)

  1. Chaque information à un seul endroit. Pas de doublon entre les blocs. L'autoconsommation est en KPI (haut) → elle n'apparaît nulle part ailleurs sur le Dashboard.
  2. Lisibilité avant densité. Lecture rapide en haut, détail optionnel en bas. Le client pressé s'arrête à la décision Héos ; le curieux scrolle.
  3. Expliquer = créer la confiance. Toute action automatique de Héos est accompagnée d'un pourquoi en langage courant.
  4. Cohérence des flux = physique réelle. Héos est au centre. Le solaire et le réseau alimentent (→ vers le centre) ; le centre répartit vers batterie et maison. Jamais « maison → batterie ».
  5. Passé plein, futur voilé. Sur tout graphe temporel : réalisé en couleur pleine, prévu en hachuré + fond grisé, ligne « maintenant » qui traverse.
  6. Fluide = rien ne saute. Chaque valeur live s'anime (interpolation), jamais de flash.
  7. Quality floor non négociable. Responsive, dark mode, focus clavier, prefers-reduced-motion respecté, contraste AA.

3. Design tokens (etm_tokens.dart)

Compléter le fichier existant avec ces valeurs. Typo : IBM Plex Sans (UI) + IBM Plex Mono (toutes les valeurs chiffrées / données).

Couleurs de marque (identiques light/dark sauf note)

Token Hex Usage
brand #31A3DD bleu ETM, accents, navigation active
solar #FEC113 (dark #FFCB33) production solaire
eco #28A06A (dark #33B87A) Héos, éco, autonomie, batterie
heat #EF8B2A chauffage / PAC
water #31A3DD eau chaude (ECS)
grid #8A98A3 réseau
import #E8806F import réseau

Thème clair

Token Valeur
bg #EEF2F5
bg2 #E4EAEE
surface #FFFFFF
ink #0D2B3B
muted #5D6F7B
faint #8B9AA4
line rgba(13,43,59,.10)
lineStrong rgba(13,43,59,.16)

Thème sombre

Token Valeur
bg #06141D
bg2 #0A1F2B
surface #0D2B3B (la couleur de marque devient la surface)
ink #EAF3F7
muted #9BB0BC
faint #6C8493
line rgba(255,255,255,.09)
lineStrong rgba(255,255,255,.16)

Couleurs des flux (graphe « plan de la journée »)

solToHouse #B8C34D · solToEcs #31A3DD · solToVe #28A06A · solToBatt #7FCF72 · solToGrid #FEC113 · battToHouse #2F6FB0 · gridToHouse #E8806F

Formes & profondeur

  • Rayons : cartes 20, contrôles internes 1314, pills/badges 30 (stadium).
  • Parti pris assumé : bordure hairline 1 px (line) + rayon large. Ombres quasi nulles en clair (0 1px 2px rgba(13,43,59,.04)), aucune en sombre. Ne pas revenir aux cartes blanches à ombre portée Material par défaut.
  • Espacement entre cartes : 14. Padding interne carte : 1416.

4. Architecture de l'écran

DashboardScreen = Scaffold + SingleChildScrollView (colonne), bottom nav fixe à 5 onglets. Ordre vertical des blocs :

[ TopBar : wordmark + toggle thème clair/sombre ]
[ 1. EnergyFlowCard   ]  ← flux en croix, temps réel, drill-down
[ 2. KpiRow           ]  ← 4 tuiles : autoconso, autonomie, vers/depuis réseau
[ 3. HeosDecisionCard ]  ← décision en cours + pourquoi
[ 4. DayPlanCard      ]  ← météo + barres horaires (réalisé/prévu)
[ BottomNav : Dashboard·Énergie·Things·A/C·Favoris ]

Onglets : Dashboard actif (couleur brand), les autres en faint.


5. Composants

5.1 EnergyFlowCard — flux en croix + drill-down

Layout : carte carrée (aspect 1:1, max 320). Stack :

  • Couche basse : CustomPaint (lignes hairline entre hub↔nœuds + particules animées).
  • Couche haute : nœuds en Positioned (Stack), GestureDetector sur les nœuds tappables.

Vue d'ensemble (overview) — positions cardinales :

Position Nœud Valeur (ex.) Direction flux Tap
centre (hub) Héos (icône HEMS, anneau eco pulsant)
haut Solaire 3.8 kW entrant (nœud→hub) prod
droite Batterie 87 % sortant (hub→nœud)
gauche Réseau 0.2 kW entrant
bas Maison 2.4 kW sortant conso

Drill-down conso (depuis Maison) — hub = Maison, autour : PAC (haut, heat), Eau chaude (droite, water), Voiture (bas, eco), Autres (estimé) (gauche, bordure dashed, grid).

Le nœud « Autres (estimé) » est obligatoire : il absorbe le non-mesuré pour que le bilan boucle (conso totale = somme des postes). Sans lui, l'addition ne tombe pas juste et le client se méfie.

Drill-down prod (depuis Solaire) — hub = Solaire, autour : Onduleur 1 (haut), Onduleur 2 (bas), chacun avec point d'état (vert OK / orange défaut). Sens : onduleur → hub.

Particules : CustomPainter + AnimationController en boucle. N points par segment circulant de la source vers la destination. Vitesse et densité ∝ puissance (flux fort = plus de points, plus rapides ; flux faible = 1 point lent). Couleur = couleur de la source.

Transitions drill-down : sortie = fade + scale 0.8 (~170 ms) ; entrée = « éclatement radial », chaque nœud apparaît en scale .25→1 avec overshoot (Curves.easeOutBack) et stagger (~60 ms entre nœuds). Détail intégral du sens/positions dans etm-powersync-flux-drilldown.html.

Affordance tap : badge + discret sur les nœuds tappables (Héos n'est pas tappable ; Solaire et Maison le sont). Profondeur max 2 niveaux — au-delà, écran dédié.

Icône HEMS : utiliser HemsIcon (déjà livré, hems_icon.dart), couleur eco.

5.2 KpiRow

Grille 2×2.

  • Tuile autoconsommation : anneau de progression (CustomPaint, couleur solar) + % en mono. S'anime au chargement (anneau qui se remplit + count-up).
  • Tuile autonomie : idem, couleur eco.
  • Tuile « Vers réseau » : icône flèche ←, valeur kWh du jour, badge fond eco léger.
  • Tuile « Depuis réseau » : icône flèche →, valeur kWh, badge fond import léger.

Ces deux métriques (autoconso/autonomie) sont les seules occurrences sur le Dashboard. Ne pas les répéter ailleurs.

5.3 HeosDecisionCard

Carte bordée eco (liseré subtil). Contenu :

  • En-tête : icône étincelle (mark Héos) + titre « Héos pilote en ce moment » + sous-titre mono « optimise sur 24 h · maj HH:MM » + point eco pulsant.
  • Résumé : 1 phrase en langage client, segment clé surligné eco (ex. « Le surplus part dans l'eau chaude et la voiture plutôt que d'être revendu à bas prix »).
  • Liste d'actions (1 par asset piloté) : icône + titre court + le pourquoi (1 ligne, muted) + puissance (kW, mono, eco), séparées par hairline.
  • Pied : lien « Voir le plan de la journée » → ouvre l'écran plein Plan de la journée (séparé, voir etm-powersync-plan-journee.html ; c'est là que vivent les pistes appareils détaillées + la ligne gains €).

5.4 DayPlanCard — météo + barres horaires

CustomPaint unique (préférer à fl_chart : contrôle fin du voile futur + bande météo intégrée). Une seule colonne temporelle, axe horaire partagé, de haut en bas :

  1. Bande météo : icône (soleil / soleil-nuage / lune) + température, à intervalles (~toutes les 4 h), posée sur l'axe.
  2. Barres empilées horaires (kWh) : segments positifs vers le haut (solToHouse, solToEcs, solToVe, solToBatt, solToGrid), négatifs vers le bas (battToHouse, gridToHouse). Axe Y 0/2/4.
  3. Axe X : 0h 6h 12h 18h 24h.

Traitement passé/futur : tout ce qui est à droite de la ligne « maintenant » = fond grisé + voile hachuré (lignes diagonales couleur surface, opacité ~.5) ; ligne « maintenant » verticale + tab HH:MM.

Légende sous le graphe : pastilles maison/eau/voiture/batterie/réseau/batt.→maison.

NE PAS mettre sur le Dashboard (retirés volontairement, ils vivent dans l'écran plein « Plan de la journée ») :

  • les pistes appareils (timelines ECS / batterie charge-décharge / VE) ;
  • la ligne gains (autoconso prévue / réseau ce soir / +€).

5.5 Toggle thème

Switch clair/sombre dans la TopBar, knob animé (overshoot). Persister le choix (provider de thème).


6. Animations & widgets

Effet Approche Flutter
Valeurs live (kW, %) TweenAnimationBuilder (count-up, easeOutCubic ~900 ms)
Particules de flux CustomPainter + AnimationController répété ; position = (t + offset) % 1 mappée sur le segment
Anneaux KPI CustomPaint, Tween sur l'angle balayé
Toggles / switch AnimatedAlign ou AnimatedPositioned, courbe overshoot (Curves.easeOutBack)
Segmented (pill qui glisse) Stack + AnimatedPositioned du « glider »
Cartes expandables (A/C) AnimatedSize
Drill-down croix AnimationController + Interval staggered (scale + opacity)
Anneau Héos (hub) pulsation lente en boucle (opacité 0.25↔0.6)

Reduced motion : si MediaQuery.of(context).disableAnimations, court-circuiter les animations (valeurs finales directes, pas de particules en boucle).


7. Modèles de données (esquisse)

class LiveFlow {                 // alimente EnergyFlowCard (overview)
  final double solarKw, gridKw, houseKw, batteryKw; // batteryKw signé
  final int batteryPct;
}

class FlowNode {                 // générique, réutilisé à chaque niveau
  final String label, valueText, iconKey;
  final FlowDirection direction; // inbound | outbound
  final bool tappable, estimated; // estimated → bordure dashed
  final NodeState? state;        // ok | warn (onduleurs)
  final String? drillTo;         // 'conso' | 'prod'
}

class HeosDecision {
  final String summary;          // langage client
  final List<HeosAction> actions;
  final DateTime updatedAt;
}
class HeosAction { final String assetIconKey, title, why; final double powerKw; }

class Kpi { final int autoconsumptionPct, autonomyPct; final double toGridKwh, fromGridKwh; }

class DayPlan {
  final List<HourlyFlow> hours;  // 0..23
  final List<WeatherPoint> weather;
  final double nowHour;          // ex. 14.5
}
class HourlyFlow {               // tous en kWh, signés selon sens
  final int hour;
  final double solToHouse, solToEcs, solToVe, solToBatt, solToGrid;
  final double battToHouse, gridToHouse;
}
class WeatherPoint { final int hour; final WeatherKind kind; final int tempC; }

Toutes les valeurs affichées proviennent de ces modèles (les chiffres des maquettes sont des exemples). Prévoir des états loading (skeleton) et vide (« en attente de données du compteur… », jamais d'écran blanc).


8. Assets fournis

  • hems_icon.dartHemsIcon(size, color), CustomPainter natif sans dépendance. À utiliser pour le hub central.
  • hems_icon.svg — équivalent SVG (currentColor) si passage par flutter_svg.

9. Arborescence suggérée

lib/features/dashboard/
  dashboard_screen.dart
  widgets/energy_flow_card.dart      + painters/flow_painter.dart
  widgets/kpi_row.dart               + painters/ring_painter.dart
  widgets/heos_decision_card.dart
  widgets/day_plan_card.dart         + painters/day_plan_painter.dart
  models/dashboard_models.dart
lib/shared/widgets/hems_icon.dart
lib/theme/etm_tokens.dart            (compléter)

10. Ordre de construction recommandé

  1. Compléter etm_tokens.dart (couleurs light/dark, typo, radius).
  2. KpiRow + RingPainter (le plus simple, valide les tokens).
  3. HeosDecisionCard (statique, valide la typo/hairlines).
  4. EnergyFlowCard overview + FlowPainter (lignes + particules), puis drill-down.
  5. DayPlanCard + DayPlanPainter (barres + voile futur + bande météo).
  6. Assemblage DashboardScreen + bottom nav + toggle thème.
  7. Passe quality floor : reduced motion, focus, contraste AA en clair et sombre.

Réfs visuelles : etm-powersync-dashboard-v4.html (écran complet) et etm-powersync-flux-drilldown.html (interaction croix). En cas de doute sur un espacement ou une couleur, ces fichiers font foi.