import 'dart:async'; import 'package:flutter/foundation.dart'; import '../services/nymea_service.dart'; enum SchedulerStrategy { rulesBased, manual, aiPro } extension SchedulerStrategyExt on SchedulerStrategy { String get label => switch (this) { SchedulerStrategy.rulesBased => 'Basée sur les règles', SchedulerStrategy.manual => 'Manuelle', SchedulerStrategy.aiPro => 'AI (Pro)', }; bool get isPro => this == SchedulerStrategy.aiPro; } class SchedulerConfig { final double priceThreshold; // €/kWh final double minSurplus; // W final int planningHorizon; // heures final int recalcInterval; // minutes final double selfSufficiencyGoal; // % const SchedulerConfig({ this.priceThreshold = 0.08, this.minSurplus = 200, this.planningHorizon = 24, this.recalcInterval = 15, this.selfSufficiencyGoal = 70, }); SchedulerConfig copyWith({ double? priceThreshold, double? minSurplus, int? planningHorizon, int? recalcInterval, double? selfSufficiencyGoal, }) => SchedulerConfig( priceThreshold: priceThreshold ?? this.priceThreshold, minSurplus: minSurplus ?? this.minSurplus, planningHorizon: planningHorizon ?? this.planningHorizon, recalcInterval: recalcInterval ?? this.recalcInterval, selfSufficiencyGoal: selfSufficiencyGoal ?? this.selfSufficiencyGoal, ); } enum SchedulerStatus { ok, degraded, error } class SchedulerState { final SchedulerStatus status; final String reason; final DateTime? lastPlanning; final DateTime? nextPlanning; const SchedulerState({ this.status = SchedulerStatus.ok, this.reason = '', this.lastPlanning, this.nextPlanning, }); } /// Gère la stratégie, la configuration et l'état du scheduler EMS. class SchedulerProvider extends ChangeNotifier { SchedulerStrategy _strategy = SchedulerStrategy.rulesBased; SchedulerConfig _config = const SchedulerConfig(); SchedulerState _state = const SchedulerState(); bool _loading = false; SchedulerStrategy get strategy => _strategy; SchedulerConfig get config => _config; SchedulerState get state => _state; bool get loading => _loading; // ── Chargement depuis nymea (stub — à brancher sur RPC réel) ──────────────── Future load(NymeaService service) async { _loading = true; notifyListeners(); await Future.delayed(const Duration(milliseconds: 300)); _state = SchedulerState( status: SchedulerStatus.ok, reason: 'TariffManager: aWATTar AT actif', lastPlanning: DateTime.now().subtract(const Duration(minutes: 8)), nextPlanning: DateTime.now().add(const Duration(minutes: 7)), ); _loading = false; notifyListeners(); } // ── Mutations ──────────────────────────────────────────────────────────────── void setStrategy(SchedulerStrategy s) { _strategy = s; notifyListeners(); // TODO: _sendRequest('Energy.SetSchedulerStrategy', ...) } void updateConfig(SchedulerConfig c) { _config = c; notifyListeners(); // TODO: _sendRequest('Energy.SetSchedulerConfig', ...) } Future forceRecalc(NymeaService service) async { _loading = true; notifyListeners(); await Future.delayed(const Duration(seconds: 1)); _state = _state; // Mettre à jour depuis la réponse RPC _loading = false; notifyListeners(); } }