Design system - lib/theme/etm_tokens.dart : source de vérité couleurs + typo (IBM Plex Sans/Mono) - lib/models/nymea_user.dart : modèle utilisateur nymea avec permissions EtmRole - app_theme.dart : ThemeData migré vers IBM Plex Sans + couleurs EtmTokens Navigation & drawer - DrawerMenuButton : logo vert gradient + ombre - Bottom nav : EtmTokens.green actif, EtmTokens.muted inactif - DrawerPanel 320 px, restyled navy + gradient header + badges rôle Dashboard (01_dashboard.html) - Hero système : status pill + 3 métriques mono + illustration maison CustomPainter - EnergyFlowWidget : 4 nœuds animés CustomPainter (flèches directionnelles) · gridPower > 0 = soutirage → flèche Grid→Home (amber) · gridPower < 0 = injection → flèche Home→Grid (bleu) - EVChargingCard restyled : badge En charge + puissance mono 38px + 3 modes + SOC bar - KPI 2×2 : spark bars, trend line, progress bar - Consommateurs principaux + Décisions d'Héos (chips motifs) - Prévisions placeholder explicite Énergie - KPI 2×2 avec icônes + fond soft + IBM Plex Mono - Sélecteur période vert pill - LineChart double axe : kW (gauche) / SOC % (droite, normalisé) - BarChart bilan énergétique Wh (amber/bleu) - Section Météo & prévision placeholder Things - Grille 2 col à hauteur intrinsèque (pas de childAspectRatio) - Bandeau statut global (simulation / connecté / hors-ligne) - _CategoryCard : header icon+label+count, séparateur coloré, liste tous items - thing_category.dart : couleurs migrées vers EtmTokens A/C — Climatisation / Chauffage - Thermostats pièces EN HAUT : actives expandées, éteintes compactes - Températures actuelle → cible ± avec EtmTokens.mono - Sélecteur mode 4 boutons (Chauf/Clim/Auto/Vent) - Chip "Chauffe au solaire en ce moment" (Héos) - Sources pilotées par Héos EN BAS : · PAC SG-Ready : 4 états (Bloqué grisé / Normal / Recommandé / Forcé) + toggle Auto · Chauffe-eau : Surplus/Éco/Boost + temp eau 52°→60°C · Climatiseur : pré-refroidissement anticipé + info solaire Packages ajoutés : google_fonts, flutter_staggered_grid_view, flutter_secure_storage Asset : assets/house.svg (illustration maison CustomPainter) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
203 lines
8.0 KiB
Dart
203 lines
8.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import '../theme/etm_tokens.dart';
|
|
import 'nymea_models.dart';
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Catégories affichées dans le Things screen
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
enum ThingCategory {
|
|
energy, // smartmeter, energymeter, powersocket
|
|
solar, // solarinverter, solarpanel
|
|
battery, // battery, energystorage
|
|
evCharger, // evcharger, wallbox
|
|
cars, // evvehicle, electricvehicle + class name "car"/"vehicle"
|
|
hvac, // thermostat, heatingzone, ac, pump
|
|
lighting, // light, dimmablelight, colorlight
|
|
sensors, // sensor, temperaturesensor, humiditysensor, motionsensor
|
|
network, // networkdevice, gateway
|
|
notifications, // pushnotification, email, sms
|
|
media, // mediadevice, mediaplayer
|
|
weather, // weather
|
|
other, // tout le reste
|
|
}
|
|
|
|
class ThingCategoryInfo {
|
|
final ThingCategory category;
|
|
final String label;
|
|
final IconData icon;
|
|
final Color color;
|
|
|
|
const ThingCategoryInfo({
|
|
required this.category,
|
|
required this.label,
|
|
required this.icon,
|
|
required this.color,
|
|
});
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Mapping interface nymea → catégorie
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
const Map<String, ThingCategory> interfaceToCategoryMap = {
|
|
'smartmeter': ThingCategory.energy,
|
|
'electricmeter': ThingCategory.energy,
|
|
'energymeter': ThingCategory.energy,
|
|
'smartenergymeter': ThingCategory.energy,
|
|
'extendedsmartmeter': ThingCategory.energy,
|
|
'powersocket': ThingCategory.energy,
|
|
'smartplug': ThingCategory.energy,
|
|
'solarinverter': ThingCategory.solar,
|
|
'solarpanel': ThingCategory.solar,
|
|
'inverter': ThingCategory.solar,
|
|
'battery': ThingCategory.battery,
|
|
'energystorage': ThingCategory.battery,
|
|
'batterymonitor': ThingCategory.battery,
|
|
'evcharger': ThingCategory.evCharger,
|
|
'wallbox': ThingCategory.evCharger,
|
|
'evvehicle': ThingCategory.cars,
|
|
'electricvehicle': ThingCategory.cars,
|
|
'electriccar': ThingCategory.cars,
|
|
'vehicle': ThingCategory.cars,
|
|
'thermostat': ThingCategory.hvac,
|
|
'heatingzone': ThingCategory.hvac,
|
|
'ac': ThingCategory.hvac,
|
|
'airconditioner': ThingCategory.hvac,
|
|
'pump': ThingCategory.hvac,
|
|
'heatpump': ThingCategory.hvac,
|
|
'ventilation': ThingCategory.hvac,
|
|
'boiler': ThingCategory.hvac,
|
|
'light': ThingCategory.lighting,
|
|
'dimmablelight': ThingCategory.lighting,
|
|
'colorlight': ThingCategory.lighting,
|
|
'colortemperaturelight': ThingCategory.lighting,
|
|
'sensor': ThingCategory.sensors,
|
|
'temperaturesensor': ThingCategory.sensors,
|
|
'humiditysensor': ThingCategory.sensors,
|
|
'pressuresensor': ThingCategory.sensors,
|
|
'motionsensor': ThingCategory.sensors,
|
|
'doorsensor': ThingCategory.sensors,
|
|
'windowsensor': ThingCategory.sensors,
|
|
'smokesensor': ThingCategory.sensors,
|
|
'co2sensor': ThingCategory.sensors,
|
|
'lightsensor': ThingCategory.sensors,
|
|
'networkdevice': ThingCategory.network,
|
|
'gateway': ThingCategory.network,
|
|
'router': ThingCategory.network,
|
|
'pushnotification': ThingCategory.notifications,
|
|
'notificationservice': ThingCategory.notifications,
|
|
'notification': ThingCategory.notifications,
|
|
'email': ThingCategory.notifications,
|
|
'sms': ThingCategory.notifications,
|
|
'weather': ThingCategory.weather,
|
|
'weatherstation': ThingCategory.weather,
|
|
'mediadevice': ThingCategory.media,
|
|
'mediaplayer': ThingCategory.media,
|
|
};
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Infos visuelles par catégorie
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
const Map<ThingCategory, ThingCategoryInfo> categoryInfoMap = {
|
|
ThingCategory.energy: ThingCategoryInfo(
|
|
category: ThingCategory.energy,
|
|
label: 'Compteurs & Prises',
|
|
icon: Icons.electrical_services_rounded,
|
|
color: EtmTokens.muted,
|
|
),
|
|
ThingCategory.solar: ThingCategoryInfo(
|
|
category: ThingCategory.solar,
|
|
label: 'Solaire',
|
|
icon: Icons.solar_power_rounded,
|
|
color: EtmTokens.amber,
|
|
),
|
|
ThingCategory.battery: ThingCategoryInfo(
|
|
category: ThingCategory.battery,
|
|
label: 'Stockage',
|
|
icon: Icons.battery_charging_full_rounded,
|
|
color: EtmTokens.green,
|
|
),
|
|
ThingCategory.evCharger: ThingCategoryInfo(
|
|
category: ThingCategory.evCharger,
|
|
label: 'Chargeurs EV',
|
|
icon: Icons.electric_car_rounded,
|
|
color: EtmTokens.blue,
|
|
),
|
|
ThingCategory.cars: ThingCategoryInfo(
|
|
category: ThingCategory.cars,
|
|
label: 'Véhicules',
|
|
icon: Icons.directions_car_rounded,
|
|
color: EtmTokens.blue,
|
|
),
|
|
ThingCategory.hvac: ThingCategoryInfo(
|
|
category: ThingCategory.hvac,
|
|
label: 'Chauffage & Clim',
|
|
icon: Icons.thermostat_rounded,
|
|
color: EtmTokens.orange,
|
|
),
|
|
ThingCategory.lighting: ThingCategoryInfo(
|
|
category: ThingCategory.lighting,
|
|
label: 'Éclairage',
|
|
icon: Icons.lightbulb_rounded,
|
|
color: EtmTokens.amber,
|
|
),
|
|
ThingCategory.sensors: ThingCategoryInfo(
|
|
category: ThingCategory.sensors,
|
|
label: 'Capteurs',
|
|
icon: Icons.sensors_rounded,
|
|
color: EtmTokens.blue,
|
|
),
|
|
ThingCategory.network: ThingCategoryInfo(
|
|
category: ThingCategory.network,
|
|
label: 'Réseau',
|
|
icon: Icons.router_rounded,
|
|
color: Color(0xFF7C4DFF),
|
|
),
|
|
ThingCategory.notifications: ThingCategoryInfo(
|
|
category: ThingCategory.notifications,
|
|
label: 'Notifications',
|
|
icon: Icons.notifications_rounded,
|
|
color: Color(0xFFEC407A),
|
|
),
|
|
ThingCategory.weather: ThingCategoryInfo(
|
|
category: ThingCategory.weather,
|
|
label: 'Météo',
|
|
icon: Icons.wb_cloudy_rounded,
|
|
color: EtmTokens.blue,
|
|
),
|
|
ThingCategory.media: ThingCategoryInfo(
|
|
category: ThingCategory.media,
|
|
label: 'Multimédia',
|
|
icon: Icons.speaker_rounded,
|
|
color: Color(0xFFAB47BC),
|
|
),
|
|
ThingCategory.other: ThingCategoryInfo(
|
|
category: ThingCategory.other,
|
|
label: 'Autres',
|
|
icon: Icons.device_hub_rounded,
|
|
color: EtmTokens.faint,
|
|
),
|
|
};
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// Extension utilitaire sur NymeaThingClass
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
extension ThingClassCategoryExt on NymeaThingClass {
|
|
ThingCategory get category {
|
|
for (final iface in interfaces) {
|
|
final cat = interfaceToCategoryMap[iface.toLowerCase()];
|
|
if (cat != null) return cat;
|
|
}
|
|
// Fallback : nom de classe contient "car" ou "vehicle" → catégorie Cars
|
|
final lower = name.toLowerCase();
|
|
if (lower.contains('car') || lower.contains('vehicle')) {
|
|
return ThingCategory.cars;
|
|
}
|
|
return ThingCategory.other;
|
|
}
|
|
|
|
ThingCategoryInfo get categoryDetails => categoryInfoMap[category]!;
|
|
} |