1) « Vers réseau » — TROIS défauts, dont un seul était visible.
La valeur aberrante (9,10184409403335e+33 kWh) ne vient PAS de l'app : Energy.GetPowerBalance
la publie telle quelle sur .75. Trois des quatre compteurs cumulés sont corrompus
(totalReturn 9,1e+33, totalAcquisition 7,5e+33, totalConsumption -1,6e+33) alors que
totalProduction reste sain, et que les états du Thing compteur sont tous plausibles
(1429 kWh importés, 88 kWh exportés). C'est donc l'accumulation de l'experience-plugin
énergie qui déraille, côté box — signalé, pas corrigé ici.
Les deux autres défauts étaient bien dans l'app :
- « Depuis réseau » lisait l'OPPOSÉ du compteur d'export au lieu de totalAcquisition,
qui a son propre compteur. Dès que l'export était positif, la tuile affichait
0,0 kWh en permanence, quelle que soit l'électricité réellement achetée ;
- les deux tuiles étaient libellées « aujourd'hui » alors que ces compteurs sont
CUMULÉS depuis l'origine, jamais remis à zéro.
Corrigé : EnergyData porte gridExportKwh / gridImportKwh, transportés tels quels — l'app
ne maquille pas une donnée que la box publie fausse. Un plafond de plausibilité
(10 GWh, ~3000 ans de consommation) distingue « mesure » de « compteur cassé » : au-delà
la tuile affiche « — · compteur box invalide ». Imprimer le nombre le présenterait comme
une mesure ; l'effacer laisserait croire à zéro.
2) Thème : 126 sites basculés des constantes claires vers les variantes contextuelles
(EtmTokens.bg → bgOf(context), card → surfaceOf, ink → inkOf, muted → mutedOf,
faint → faintOf, line → lineOf) dans ac_screen, things_screen, energy_screen,
favorites_screen, main_drawer, ev_charging_card, energy_flow_widget. Ces écrans
restaient en palette claire quel que soit le sélecteur.
9 sites RESTENT en constante, et c'est délibéré : ce sont des tables statiques et des
helpers de haut niveau (categoryInfoMap, _options des favoris, _modeColor, peintres du
flux) où la couleur est une identité d'icône et où aucun BuildContext n'est en portée.
Les faire suivre le thème demande de threader le contexte jusqu'à ces tables — un
refactor à part entière, pas un correctif de fin de soirée.
Tests 80/80, analyze 0 erreur.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HajXLUczEyZd22JeewRfff
205 lines
8.1 KiB
Dart
205 lines
8.1 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,
|
|
'simpleheatpump': ThingCategory.hvac, // interfaces réelles (hems)
|
|
'smartgridheatpump': 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
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
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]!;
|
|
} |