/// Ce qu'une borne de recharge **publie réellement**, et rien d'autre. /// /// ## Pourquoi ce type existe /// /// L'app portait trois grandeurs de recharge qui n'étaient jamais lues sur la box : /// `EnergyData.chargingMode` (défaut `pv`), `chargingPower` (défaut 3,6 kW) et /// `solarSourcePercent` (défaut 82 %). Elles étaient affichées comme des mesures — « 3600 /// W », « 82 % solaire » — sur un écran de favoris que le client peut ouvrir. C'est la même /// famille de défaut que le SOC à 62 % en dur et les quatre pièces de climatisation /// fictives : une valeur par défaut présentée comme une lecture. /// /// Ce type ne porte donc **que des champs nullables**, et `null` veut dire *la box ne le /// publie pas* — jamais zéro. L'écran doit le dire, pas le combler. /// /// ## Ce qui est lisible aujourd'hui, mesuré sur `.75` le 2026-08-28 /// /// Les deux bornes du banc (Simulated wallbox, V2C Trydan) publient `pluggedIn`, /// `charging`, `currentPower` et `maxChargingCurrent`. Le mode, lui, ne vient pas du Thing /// mais de `NymeaEnergy.GetChargingInfos` — les deux bornes y étaient en /// `ChargingModeNormal`, `ChargingStateIdle`. /// /// **`sessionEnergy` existe** sur les deux (4,229 kWh sur la V2C), et le renommage /// `currentL1/L2/L3` **est déployé** — plus de `powerL1/L2/L3`. Ces deux champs ne sont pas /// portés ici pour autant : voir la note de `LoadMechanism` /// (`models/load_telemetry.dart`), l'égalité `sessionEnergy == chargeEnergy` relevée ce /// jour ne prouve pas encore que le premier survit à une interruption de charge, et c'est /// exactement ce que LM-1009 §C1 demande de savoir avant d'afficher un avancement. library; import 'energy_data.dart' show ChargingMode; class EvChargerLive { /// `thingId` de la borne — l'identifiant que `SetChargingInfo` attend. final String thingId; final String name; /// États du Thing. `null` = non publié par cette borne. final bool? pluggedIn; final bool? charging; final double? currentPowerW; /// Mode **tel que la box le porte** (`ChargingModeEco`, `ChargingModeNormal`, …), lu par /// `GetChargingInfos`. `null` = pas encore lu, ou aucune entrée pour cette borne — et /// dans ce cas l'écran n'a **aucun** mode à présenter comme courant. final String? apiMode; const EvChargerLive({ required this.thingId, required this.name, this.pluggedIn, this.charging, this.currentPowerW, this.apiMode, }); /// Traduction du mode de la box vers les trois boutons de l'IU. /// /// Les cinq valeurs de l'énumération se replient sur trois : les variantes « avec /// échéance » gardent le bouton de base, l'échéance étant une option à côté. `null` pour /// une valeur inconnue — une borne peut porter un mode qu'aucune version d'app ne /// connaît, et deviner serait pire que dire « mode non reconnu ». ChargingMode? get uiMode => switch (apiMode) { 'ChargingModeNormal' => ChargingMode.boost, 'ChargingModeEco' || 'ChargingModeEcoWithTargetTime' => ChargingMode.pv, 'ChargingModeEcoWithMinCurrent' || 'ChargingModeEcoMinWithTargetTime' => ChargingMode.minPv, _ => null, }; /// Vrai quand la borne porte une échéance dans son mode — l'information est dans le nom /// de l'énumération, pas dans un champ à part. bool get hasDeadlineMode => apiMode == 'ChargingModeEcoWithTargetTime' || apiMode == 'ChargingModeEcoMinWithTargetTime'; }