import 'package:flutter/foundation.dart'; import '../services/nymea_service.dart'; import '../models/nymea_models.dart'; /// Rôles de l'EMS (Energy Management System). enum EmsRole { evCharger, dhw, // Chauffe-eau heatPump, // Pompe à chaleur / SG-Ready battery, solarMeter, // Compteur solaire gridMeter, // Compteur réseau } extension EmsRoleExt on EmsRole { String get label => switch (this) { EmsRole.evCharger => 'EV Charger', EmsRole.dhw => 'Chauffe-eau', EmsRole.heatPump => 'Pompe à chaleur', EmsRole.battery => 'Batterie', EmsRole.solarMeter => 'Compteur solaire', EmsRole.gridMeter => 'Compteur réseau', }; String get icon => switch (this) { EmsRole.evCharger => '🚗', EmsRole.dhw => '🌡️', EmsRole.heatPump => '♨️', EmsRole.battery => '🔋', EmsRole.solarMeter => '☀️', EmsRole.gridMeter => '⚡', }; /// Interfaces nymea compatibles avec ce rôle. List get compatibleInterfaces => switch (this) { EmsRole.evCharger => ['evcharger'], EmsRole.dhw => ['simpleheatpump', 'relay', 'smartplug', 'powerswitch'], EmsRole.heatPump => ['sgready', 'sgrelay', 'heatpump'], EmsRole.battery => ['battery', 'energystorage', 'batterymonitor'], EmsRole.solarMeter => ['solarinverter', 'energymeter', 'meter', 'inverter', 'smartmeter'], EmsRole.gridMeter => ['energymeter', 'smartmeter', 'meter'], }; /// Label d'interface affiché dans la liste de sélection (Step 1). String interfaceLabelFor(String iface) => switch (iface.toLowerCase()) { 'sgready' => 'SG-Ready', 'sgrelay' => 'SG-Ready', 'heatpump' => 'Heat Pump', 'simpleheatpump' => 'SimpleHeatpump', 'solarinverter' => 'Inverter', 'energymeter' => 'Meter', 'meter' => 'Meter', 'inverter' => 'Inverter', 'smartmeter' => 'Smart Meter', 'evcharger' => 'EV Charger', 'battery' => 'Battery', 'energystorage' => 'Energy Storage', _ => iface, }; } /// Assignation d'un thing à un rôle EMS. class RoleAssignment { final EmsRole role; final NymeaThing thing; final bool enabled; final Map params; // puissance, priorité, etc. const RoleAssignment({ required this.role, required this.thing, this.enabled = true, this.params = const {}, }); RoleAssignment copyWith({ bool? enabled, Map? params, }) => RoleAssignment( role: role, thing: thing, enabled: enabled ?? this.enabled, params: params ?? this.params, ); } /// Résultat d'un test de connexion de rôle. enum ConnectionTestStatus { idle, testing, success, failure } class ConnectionTestResult { final ConnectionTestStatus status; final String? message; const ConnectionTestResult(this.status, [this.message]); } /// Gère les assignations de rôles EMS et les flux de configuration. class EnergySetupProvider extends ChangeNotifier { final Map _assignments = { for (final r in EmsRole.values) r: null, }; ConnectionTestResult _testResult = const ConnectionTestResult(ConnectionTestStatus.idle); Map get assignments => _assignments; ConnectionTestResult get testResult => _testResult; RoleAssignment? assignmentFor(EmsRole role) => _assignments[role]; bool isConfigured(EmsRole role) => _assignments[role] != null; // ── Assignation locale ─────────────────────────────────────────────────────── void assign(EmsRole role, NymeaThing thing, Map params) { _assignments[role] = RoleAssignment(role: role, thing: thing, params: params); notifyListeners(); } void unassign(EmsRole role) { _assignments[role] = null; notifyListeners(); } void setEnabled(EmsRole role, bool enabled) { final current = _assignments[role]; if (current != null) { _assignments[role] = current.copyWith(enabled: enabled); notifyListeners(); } } // ── Filtrage des things compatibles avec un rôle ───────────────────────────── List compatibleThings( EmsRole role, NymeaService service) { return service.things.where((thing) { try { final cls = service.thingClasses .firstWhere((c) => c.id == thing.thingClassId); return cls.interfaces.any( (i) => role.compatibleInterfaces .contains(i.toLowerCase())); } catch (_) { return false; } }).toList(); } // ── Test de connexion (simulé — à brancher sur RPC réel) ──────────────────── Future testConnection(EmsRole role, NymeaService service) async { _testResult = const ConnectionTestResult(ConnectionTestStatus.testing); notifyListeners(); await Future.delayed(const Duration(seconds: 2)); final assignment = _assignments[role]; if (assignment == null) { _testResult = const ConnectionTestResult( ConnectionTestStatus.failure, 'Aucun appareil configuré pour ce rôle.'); } else { // En mode simulation, retourne toujours succès _testResult = ConnectionTestResult( ConnectionTestStatus.success, '${assignment.thing.name} a répondu correctement.'); } notifyListeners(); } void resetTest() { _testResult = const ConnectionTestResult(ConnectionTestStatus.idle); notifyListeners(); } }