Consigne app §F, vérifiée sur le banc le 2026-10-15. - Lecture GetTariff à l'ouverture : aucun tarif / fixe / HC-HP (deux zones, la moins chère sur UNE plage) / lecture seule pour tout le reste (HC en deux fenêtres, > 2 zones, prix égaux) — jamais réécrit. - Écriture SetTariff en c€/kWh (€ × 100, 4 décimales) ; HC/HP : la plage HP est le complément exact de la plage HC ; revente facultative. Relue après succès (aucune notification). - Refus TARIFF_REFUSED rendu en français depuis faultParams (cause, zone nommée par le libellé envoyé, minute en cause). - Heures affichées comme celles de la box (timeZone). - Retirés : prix par défaut codés en dur, stockage local, fournisseurs fictifs, prix « live » inventés. Menu « Tarifs & providers » → « Tarif ». - Test : ce que l'app enverrait est identique, champ pour champ, au tarif réel du banc (aucune écriture faite sur la box). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
81 lines
2.5 KiB
Dart
81 lines
2.5 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
|
|
import '../models/tarif.dart';
|
|
import '../services/nymea_service.dart';
|
|
|
|
/// **Le tarif de la box courante** — lu et écrit sur le moteur, rien en local.
|
|
///
|
|
/// Avant `+etm69` ce provider était un stub : prix par défaut codés en dur (0,096 / 0,146
|
|
/// €/kWh), fournisseurs fictifs (Linky, JSON…), prix « live » inventés, et rien n'allait à la
|
|
/// box. Tout cela est retiré : le moteur est désormais la source de vérité (consigne F).
|
|
class TariffProvider extends ChangeNotifier {
|
|
NymeaService? _service;
|
|
|
|
bool _loading = false;
|
|
bool _enregistrement = false;
|
|
TarifBox? _tarif;
|
|
String? _erreurLecture;
|
|
|
|
bool get loading => _loading;
|
|
bool get enregistrement => _enregistrement;
|
|
|
|
/// `null` tant que rien n'est lu, ou si la lecture a échoué ([erreurLecture]).
|
|
TarifBox? get tarif => _tarif;
|
|
|
|
/// Non nul = le tarif n'a pas été LU. Ce n'est pas « aucun tarif ».
|
|
String? get erreurLecture => _erreurLecture;
|
|
|
|
void attach(NymeaService s) {
|
|
if (identical(_service, s)) return;
|
|
_service = s;
|
|
}
|
|
|
|
Future<void> load() async {
|
|
final s = _service;
|
|
if (s == null) return;
|
|
_loading = true;
|
|
notifyListeners();
|
|
final r = await s.getTariff();
|
|
_tarif = r.tarif == null ? null : TarifBox.fromJson(r.tarif!);
|
|
_erreurLecture = r.erreur;
|
|
_loading = false;
|
|
notifyListeners();
|
|
}
|
|
|
|
/// Écrit le tarif, puis le RELIT (aucune notification n'existe). Rend `null` en cas de
|
|
/// succès, sinon un message en français.
|
|
Future<String?> enregistrer(Map<String, dynamic> payload) async {
|
|
final s = _service;
|
|
if (s == null) return 'Pas de box connectée.';
|
|
_enregistrement = true;
|
|
notifyListeners();
|
|
final r = await s.setTariff(payload);
|
|
_enregistrement = false;
|
|
String? message;
|
|
if (r.erreur == 'TARIFF_REFUSED') {
|
|
final libelles = [
|
|
for (final z in (payload['zones'] as List? ?? const []))
|
|
if (z is Map) z['label'] as String? ?? ''
|
|
];
|
|
message = messageRefus(r.faultParams, libelles);
|
|
} else if (r.erreur != null) {
|
|
message = 'La box n\'a pas enregistré le tarif (${r.erreur}).';
|
|
}
|
|
if (message == null) {
|
|
await load();
|
|
} else {
|
|
notifyListeners();
|
|
}
|
|
return message;
|
|
}
|
|
|
|
/// Remet à zéro au changement d'installation — le tarif appartient à la box quittée.
|
|
void clearForSwitch() {
|
|
_tarif = null;
|
|
_erreurLecture = null;
|
|
_loading = false;
|
|
_enregistrement = false;
|
|
notifyListeners();
|
|
}
|
|
}
|