Énergie : - Écran Énergie reécrit : line chart (production/conso/autoconso/batterie) et bar chart (bilan Wh par période) avec onglets 15 min / 1 h / 1 j / 1 sem - Datepicker pour sélectionner une période historique (chip dismissible) - Timelines des deux graphiques alignées (même x=i → data[i].timestamp) - PowerBalanceEntry + fetchPowerBalanceLogs() + simulation sinusoïdale - Overflow fixes : energy_flow_widget (Expanded sur titre), production_card Things : - Navigation 3 niveaux : ThingsScreen → CategoryOverviewScreen → ThingDetailScreen - Catégorie Cars ajoutée, carrousel corrigé (clamp RangeError) - ThingDetailScreen : executeAction, setStateValue, activeThumbColor fix - NymeaTile widget, state_history_chart widget (générique Logging.GetLogEntries) Modèles / service : - HistoryEntry, PowerBalanceEntry ajoutés - fetchHistory(), fetchPowerBalanceLogs() dans NymeaService - interfaceToCategoryMap étendu (Cars, etc.) - AppTheme : nouvelles couleurs (accentTeal, boostRed, pvGreen, minPvBlue…) 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/app_theme.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: AppTheme.gridGray,
|
|
),
|
|
ThingCategory.solar: ThingCategoryInfo(
|
|
category: ThingCategory.solar,
|
|
label: 'Solaire',
|
|
icon: Icons.solar_power_rounded,
|
|
color: AppTheme.solarYellow,
|
|
),
|
|
ThingCategory.battery: ThingCategoryInfo(
|
|
category: ThingCategory.battery,
|
|
label: 'Stockage',
|
|
icon: Icons.battery_charging_full_rounded,
|
|
color: AppTheme.batteryGreen,
|
|
),
|
|
ThingCategory.evCharger: ThingCategoryInfo(
|
|
category: ThingCategory.evCharger,
|
|
label: 'Chargeurs EV',
|
|
icon: Icons.electric_car_rounded,
|
|
color: AppTheme.minPvBlue,
|
|
),
|
|
ThingCategory.cars: ThingCategoryInfo(
|
|
category: ThingCategory.cars,
|
|
label: 'Cars',
|
|
icon: Icons.directions_car_rounded,
|
|
color: AppTheme.accentTeal,
|
|
),
|
|
ThingCategory.hvac: ThingCategoryInfo(
|
|
category: ThingCategory.hvac,
|
|
label: 'Chauffage & Climatisation',
|
|
icon: Icons.thermostat_rounded,
|
|
color: Color(0xFFFF7043),
|
|
),
|
|
ThingCategory.lighting: ThingCategoryInfo(
|
|
category: ThingCategory.lighting,
|
|
label: 'Éclairage',
|
|
icon: Icons.lightbulb_rounded,
|
|
color: Color(0xFFFFCA28),
|
|
),
|
|
ThingCategory.sensors: ThingCategoryInfo(
|
|
category: ThingCategory.sensors,
|
|
label: 'Capteurs',
|
|
icon: Icons.sensors_rounded,
|
|
color: Color(0xFF26C6DA),
|
|
),
|
|
ThingCategory.network: ThingCategoryInfo(
|
|
category: ThingCategory.network,
|
|
label: 'Réseau & Passerelles',
|
|
icon: Icons.router_rounded,
|
|
color: Color(0xFF7C4DFF),
|
|
),
|
|
ThingCategory.notifications: ThingCategoryInfo(
|
|
category: ThingCategory.notifications,
|
|
label: 'Services de notification',
|
|
icon: Icons.notifications_rounded,
|
|
color: Color(0xFFEC407A),
|
|
),
|
|
ThingCategory.weather: ThingCategoryInfo(
|
|
category: ThingCategory.weather,
|
|
label: 'Météo',
|
|
icon: Icons.wb_cloudy_rounded,
|
|
color: Color(0xFF42A5F5),
|
|
),
|
|
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: Color(0xFF78909C),
|
|
),
|
|
};
|
|
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
// 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]!;
|
|
} |