- 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
13 KiB
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 24–48 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)
- 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.
- 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.
- Expliquer = créer la confiance. Toute action automatique de Héos est accompagnée d'un pourquoi en langage courant.
- 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 ».
- Passé plein, futur voilé. Sur tout graphe temporel : réalisé en couleur pleine, prévu en hachuré + fond grisé, ligne « maintenant » qui traverse.
- Fluide = rien ne saute. Chaque valeur live s'anime (interpolation), jamais de flash.
- Quality floor non négociable. Responsive, dark mode, focus clavier,
prefers-reduced-motionrespecté, 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 13–14, 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 : 14–16.
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),GestureDetectorsur 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, couleursolar) +%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
kWhdu jour, badge fondecoléger. - Tuile « Depuis réseau » : icône flèche →, valeur
kWh, badge fondimportlé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 :
- Bande météo : icône (soleil / soleil-nuage / lune) + température, à intervalles (~toutes les 4 h), posée sur l'axe.
- Barres empilées horaires (kWh) : segments positifs vers le haut (
solToHouse,solToEcs,solToVe,solToBatt,solToGrid), négatifs vers le bas (battToHouse,gridToHouse). Axe Y0/2/4. - 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.dart—HemsIcon(size, color),CustomPainternatif sans dépendance. À utiliser pour le hub central.hems_icon.svg— équivalent SVG (currentColor) si passage parflutter_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é
- Compléter
etm_tokens.dart(couleurs light/dark, typo, radius). KpiRow+RingPainter(le plus simple, valide les tokens).HeosDecisionCard(statique, valide la typo/hairlines).EnergyFlowCardoverview +FlowPainter(lignes + particules), puis drill-down.DayPlanCard+DayPlanPainter(barres + voile futur + bande météo).- Assemblage
DashboardScreen+ bottom nav + toggle thème. - 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.