Le lot plugin B-bis (1.15.2+etm15) est sur .75 et GetLoadConfig/GetLoadTelemetry concordent : les critères 4 à 8 du brief deviennent atteignables. - models/load_telemetry.dart : vue en lecture. timestamp/budget/mechanism/lock/ faultCode nullables — omis porte un sens que zéro ne porterait pas. - services/telemetry_text.dart : rendu français des CODES (19 motifs, 3 défauts, 3 verrous, 4 mécanismes). Repli lisible sur un code inconnu ET sur un code connu privé d'un paramètre : une phrase trouée a l'air d'une donnée, le code brut a l'air de ce qu'il est. - providers/load_telemetry_provider.dart : instantané + LoadTelemetryChanged, fraîcheur à trois signaux (âge du timestamp, silence des trames, timestamp qui cesse d'avancer), machine à états de ClearLoadFault qui ne conclut JAMAIS sur l'acquittement du RPC. - load_config_provider : assignDomain() en brouillon, énumération fermée. - load_order_screen : budget, fraîcheur, mode dégradé, bloc par charge, encart défaut, menu de domaine. - nymea_service : getLoadTelemetry(), clearLoadFault(), aiguillage de la notification. Une box sans la méthode s'annonce comme telle, pas comme en panne. Seuil de fraîcheur à 180 s : le battement de cœur du plugin est de 60 s et le timestamp avance d'un cycle par minute. Un seuil plus court crierait « données anciennes » sur une installation vivante. Fixtures v3 prises sur .75 après déploiement, dont un cycle porteur d'un verrou — « lock » étant optionnel, un dump pris au mauvais moment ne l'éprouverait pas. 57 tests (30 avant), flutter analyze inchangé à 25 issues. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XPUo3RMr8SzK6qbFtfBm8H
308 lines
13 KiB
Plaintext
308 lines
13 KiB
Plaintext
{
|
|
"@@locale": "fr",
|
|
|
|
"installerLoadsTitle": "Rôles & appareils",
|
|
"@installerLoadsTitle": {
|
|
"description": "Titre de l'écran installateur de configuration des charges pilotables"
|
|
},
|
|
"installerLoadsSubtitle": "Ordre de service des charges pilotables",
|
|
"loadsEmpty": "Aucune charge pilotable déclarée sur cette installation.",
|
|
"loadsLoadError": "Lecture de la configuration impossible : {error}",
|
|
"@loadsLoadError": {
|
|
"placeholders": { "error": { "type": "String" } }
|
|
},
|
|
|
|
"sectionUnclassified": "Non classé",
|
|
"@sectionUnclassified": {
|
|
"description": "Bucket des charges sans o:domain — jamais rangées d'office dans un domaine"
|
|
},
|
|
|
|
"domainEv": "Véhicule électrique",
|
|
"domainEcs": "Eau chaude sanitaire",
|
|
"domainHvac": "Climatisation",
|
|
"domainHeating": "Chauffage",
|
|
"domainUnknown": "Domaine « {code} »",
|
|
"@domainUnknown": {
|
|
"description": "Repli quand la box renvoie un domaine que cette version d'app ne connaît pas",
|
|
"placeholders": { "code": { "type": "String" } }
|
|
},
|
|
|
|
"adapterRelayRouter": "Routeur de relais",
|
|
"adapterEtmVariableLoad": "Charge modulable",
|
|
"adapterSgReady": "SG-Ready",
|
|
"adapterEvCharger": "Borne de recharge",
|
|
"adapterUnknown": "Mécanisme « {code} »",
|
|
"@adapterUnknown": {
|
|
"placeholders": { "code": { "type": "String" } }
|
|
},
|
|
|
|
"loadEnabled": "Active",
|
|
"loadDisabled": "Exclue de l'arbitrage",
|
|
"loadPriority": "Rang {rank}",
|
|
"@loadPriority": {
|
|
"placeholders": { "rank": { "type": "int" } }
|
|
},
|
|
"loadMinOn": "Maintien ON minimal : {seconds} s",
|
|
"@loadMinOn": {
|
|
"placeholders": { "seconds": { "type": "int" } }
|
|
},
|
|
"loadMinOff": "Maintien OFF minimal : {seconds} s",
|
|
"@loadMinOff": {
|
|
"placeholders": { "seconds": { "type": "int" } }
|
|
},
|
|
"loadRelayCount": "{count, plural, =1{1 relais} other{{count} relais}}",
|
|
"@loadRelayCount": {
|
|
"placeholders": { "count": { "type": "int" } }
|
|
},
|
|
"loadMeterSlot": "Compteur dédié : non rattachable",
|
|
"@loadMeterSlot": {
|
|
"description": "Emplacement visuel réservé — LoadConfig n'a aucun champ pour rattacher un compteur à une charge"
|
|
},
|
|
|
|
"orderNotGroupedTitle": "Ordre non groupé",
|
|
"orderNotGroupedBody": "L'ordre en place sur la box n'est pas groupé par domaine : les charges d'un même domaine ne se suivent pas. L'ordre réel est affiché ci-dessous, tel que la box l'applique.",
|
|
"orderNotGroupedAction": "Normaliser l'ordre",
|
|
"orderNotGroupedWarning": "Normaliser modifiera l'ordre d'arbitrage réel de l'installation. Aucune écriture ne part tant que vous n'avez pas confirmé.",
|
|
"orderNormalizeConfirm": "Normaliser et enregistrer",
|
|
"cancel": "Annuler",
|
|
|
|
"saveOrder": "Enregistrer l'ordre",
|
|
"savePending": "Envoi en cours…",
|
|
"saveWaitingBox": "En attente de confirmation de la box…",
|
|
"saveConfirmed": "Configuration confirmée par la box.",
|
|
"saveRejected": "La box a refusé : {reason}",
|
|
"@saveRejected": {
|
|
"placeholders": { "reason": { "type": "String" } }
|
|
},
|
|
"saveDiverged": "La box a enregistré un état différent de celui demandé. L'affichage montre ce que la box applique réellement.",
|
|
|
|
"validationDuplicateId": "L'identifiant de charge « {id} » apparaît deux fois.",
|
|
"@validationDuplicateId": {
|
|
"placeholders": { "id": { "type": "String" } }
|
|
},
|
|
"validationThingClaimedTwice": "L'appareil {thingId} est commandé par deux charges actives, « {first} » et « {second} » : deux commandes contradictoires et une puissance comptée deux fois.",
|
|
"@validationThingClaimedTwice": {
|
|
"placeholders": {
|
|
"thingId": { "type": "String" },
|
|
"first": { "type": "String" },
|
|
"second": { "type": "String" }
|
|
}
|
|
},
|
|
|
|
"telemetryUnavailableTitle": "Télémétrie indisponible",
|
|
"telemetryUnavailableBody": "Cette box n'expose pas GetLoadTelemetry. Puissance allouée, verrous, disponibilité et motifs de décision ne sont pas lisibles depuis l'app.",
|
|
"telemetryStale": "Données anciennes — dernier point il y a {seconds} s",
|
|
"@telemetryStale": {
|
|
"placeholders": { "seconds": { "type": "int" } }
|
|
},
|
|
"telemetryDegradedMode": "Mode dégradé L2 — compteur muet, planification suspendue",
|
|
|
|
"faultTitle": "En défaut",
|
|
"faultClearAction": "Lever le défaut",
|
|
"faultCleared": "Défaut levé — confirmé par la télémétrie relue.",
|
|
"faultClearNoop": "Aucun défaut à lever sur cette charge.",
|
|
"faultUnknown": "Défaut « {code} »",
|
|
"@faultUnknown": {
|
|
"placeholders": { "code": { "type": "String" } }
|
|
},
|
|
|
|
"decisionUnknown": "Décision « {code} »{params}",
|
|
"@decisionUnknown": {
|
|
"description": "Repli obligatoire quand la box renvoie un decision.code absent de cet ARB — box plus récente que l'app. Affiche le code brut et ses paramètres, jamais une phrase vide.",
|
|
"placeholders": {
|
|
"code": { "type": "String" },
|
|
"params": { "type": "String" }
|
|
}
|
|
},
|
|
|
|
"telemetryTitle": "Arbitrage en direct",
|
|
"telemetryNeverRan": "Aucun cycle d'arbitrage depuis le démarrage du service.",
|
|
"@telemetryNeverRan": {
|
|
"description": "timestamp absent — l'absence de cycle est une information, pas un zéro"
|
|
},
|
|
"telemetryLastCycle": "Dernier cycle il y a {seconds} s",
|
|
"@telemetryLastCycle": {
|
|
"placeholders": { "seconds": { "type": "int" } }
|
|
},
|
|
"telemetryBudgetTitle": "Budget de surplus du cycle",
|
|
"telemetryBudgetAbsent": "Aucun budget publié pour ce cycle : la planification est suspendue.",
|
|
"budgetSurplus": "Surplus entrant",
|
|
"budgetEvReserved": "Réservé au véhicule",
|
|
"budgetRecredited": "Recrédité",
|
|
"budgetAllocated": "Alloué",
|
|
"budgetRemaining": "Reliquat",
|
|
"watts": "{watts} W",
|
|
"@watts": {
|
|
"placeholders": { "watts": { "type": "int", "format": "decimalPattern" } }
|
|
},
|
|
"telemetryAllocated": "Alloué {watts} W",
|
|
"@telemetryAllocated": {
|
|
"placeholders": { "watts": { "type": "int", "format": "decimalPattern" } }
|
|
},
|
|
"telemetryNotArbitrated": "Non arbitrée — absente du dernier cycle publié",
|
|
"@telemetryNotArbitrated": {
|
|
"description": "Charge présente dans GetLoadConfig mais absente de loads[] : elle est désactivée, jamais perdue"
|
|
},
|
|
|
|
"lockMinOn": "Maintien ON — {seconds} s restantes",
|
|
"@lockMinOn": {
|
|
"placeholders": { "seconds": { "type": "int" } }
|
|
},
|
|
"lockMinOff": "Maintien OFF — {seconds} s restantes",
|
|
"@lockMinOff": {
|
|
"placeholders": { "seconds": { "type": "int" } }
|
|
},
|
|
"lockMinStateHold": "Maintien d'état — {seconds} s restantes",
|
|
"@lockMinStateHold": {
|
|
"placeholders": { "seconds": { "type": "int" } }
|
|
},
|
|
"lockUnknown": "Verrou « {kind} » — {seconds} s restantes",
|
|
"@lockUnknown": {
|
|
"placeholders": {
|
|
"kind": { "type": "String" },
|
|
"seconds": { "type": "int" }
|
|
}
|
|
},
|
|
"lockAsOfCycle": "au dernier cycle",
|
|
"@lockAsOfCycle": {
|
|
"description": "Les secondes restantes ne sont PAS décomptées côté app : elles datent du cycle publié"
|
|
},
|
|
|
|
"mechanismRelayStage": "Palier {stage} W sur {max} W",
|
|
"@mechanismRelayStage": {
|
|
"placeholders": {
|
|
"stage": { "type": "int", "format": "decimalPattern" },
|
|
"max": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"mechanismVariableSetpoint": "Consigne {setpoint} W ({percent} %)",
|
|
"@mechanismVariableSetpoint": {
|
|
"placeholders": {
|
|
"setpoint": { "type": "int", "format": "decimalPattern" },
|
|
"percent": { "type": "int" }
|
|
}
|
|
},
|
|
"mechanismSgReadyState": "État SG-Ready {state} — estimation {estimated} W",
|
|
"@mechanismSgReadyState": {
|
|
"placeholders": {
|
|
"state": { "type": "int" },
|
|
"estimated": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"mechanismEvCharger": "{current} A sur {phases} phase(s)",
|
|
"@mechanismEvCharger": {
|
|
"placeholders": {
|
|
"current": { "type": "double", "format": "decimalPattern" },
|
|
"phases": { "type": "int" }
|
|
}
|
|
},
|
|
"mechanismUnknown": "Mécanisme « {kind} »",
|
|
"@mechanismUnknown": {
|
|
"placeholders": { "kind": { "type": "String" } }
|
|
},
|
|
|
|
"decisionEvSurplus": "Véhicule rechargé sur le surplus photovoltaïque.",
|
|
"decisionEvSpotMarket": "Véhicule rechargé sur un créneau tarifaire favorable.",
|
|
"decisionEvDeadline": "Véhicule prioritaire : l'échéance approche.",
|
|
"decisionEvEcoMin": "Pas de surplus : le courant minimum est maintenu.",
|
|
"decisionEvIdle": "Pas de surplus : la recharge est suspendue.",
|
|
"decisionLoadUnavailable": "Charge en défaut : aucune commande n'est émise, et {frozen} W restent comptés au budget.",
|
|
"@decisionLoadUnavailable": {
|
|
"placeholders": { "frozen": { "type": "int", "format": "decimalPattern" } }
|
|
},
|
|
"decisionLockMinOn": "Le maintien ON a relevé la consigne à {applied} W ; le budget en payait {budget} W.",
|
|
"@decisionLockMinOn": {
|
|
"placeholders": {
|
|
"applied": { "type": "int", "format": "decimalPattern" },
|
|
"budget": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"decisionLockMinOff": "Le maintien OFF interdit l'enclenchement ; le budget payait pourtant {requested} W sur {budget} W disponibles.",
|
|
"@decisionLockMinOff": {
|
|
"placeholders": {
|
|
"requested": { "type": "int", "format": "decimalPattern" },
|
|
"budget": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"decisionLockMinOffCapped": "Le maintien OFF plafonne la consigne à {applied} W ; {requested} W étaient demandés sur {budget} W de budget.",
|
|
"@decisionLockMinOffCapped": {
|
|
"placeholders": {
|
|
"applied": { "type": "int", "format": "decimalPattern" },
|
|
"requested": { "type": "int", "format": "decimalPattern" },
|
|
"budget": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"decisionSurplusSetpoint": "Consigne de {setpoint} W servie par le surplus ({budget} W de budget).",
|
|
"@decisionSurplusSetpoint": {
|
|
"placeholders": {
|
|
"setpoint": { "type": "int", "format": "decimalPattern" },
|
|
"budget": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"decisionSurplusSetpointStepped": "Consigne de {setpoint} W servie par le surplus, arrondie sur un palier déclaré ({budget} W de budget).",
|
|
"@decisionSurplusSetpointStepped": {
|
|
"placeholders": {
|
|
"setpoint": { "type": "int", "format": "decimalPattern" },
|
|
"budget": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"decisionSurplusInsufficient": "Le budget de {budget} W ne payait aucun palier — aucun verrou n'a mordu.",
|
|
"@decisionSurplusInsufficient": {
|
|
"placeholders": { "budget": { "type": "int", "format": "decimalPattern" } }
|
|
},
|
|
"decisionLockMinStateHold": "État {state} maintenu par protection anti court-cycle.",
|
|
"@decisionLockMinStateHold": {
|
|
"placeholders": { "state": { "type": "int" } }
|
|
},
|
|
"decisionSgForced": "Pompe à chaleur en état 4 (forcé) — estimation {estimated} W sur {budget} W de budget.",
|
|
"@decisionSgForced": {
|
|
"placeholders": {
|
|
"estimated": { "type": "int", "format": "decimalPattern" },
|
|
"budget": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"decisionSgRecommended": "Pompe à chaleur en état 3 (recommandation) — estimation {estimated} W sur {budget} W de budget.",
|
|
"@decisionSgRecommended": {
|
|
"placeholders": {
|
|
"estimated": { "type": "int", "format": "decimalPattern" },
|
|
"budget": { "type": "int", "format": "decimalPattern" }
|
|
}
|
|
},
|
|
"decisionSgNormal": "Pompe à chaleur en état 2 (normal, sans consigne) — {budget} W de budget.",
|
|
"@decisionSgNormal": {
|
|
"placeholders": { "budget": { "type": "int", "format": "decimalPattern" } }
|
|
},
|
|
"decisionDegradedL2": "Consigne de repli : le compteur est muet et le watchdog a suspendu la planification.",
|
|
"decisionSafeStateRelay": "État sûr avant retrait : tous les relais sont ouverts.",
|
|
"decisionSafeStateSetpoint": "État sûr avant retrait : consigne ramenée à 0 W.",
|
|
"decisionSafeStateSgReady": "État sûr avant retrait : état 2 (normal), jamais le blocage.",
|
|
|
|
"faultWriteFailed": "Échec d'écriture : l'échelle de commande est épuisée, plus aucune commande n'est émise tant que le défaut n'est pas levé.",
|
|
"faultThingMissing": "L'appareil commandé est absent de la configuration nymea.",
|
|
"faultUnusableEncoding": "Encodage SG-Ready inexploitable : l'état 2 ne peut pas être exprimé, cette pompe à chaleur n'est pas pilotable.",
|
|
"faultClearPending": "Levée demandée — en attente de la télémétrie…",
|
|
"faultClearStillFaulty": "La charge est toujours en défaut après la levée.",
|
|
"faultClearRejected": "La box a refusé la levée : {reason}",
|
|
"@faultClearRejected": {
|
|
"placeholders": { "reason": { "type": "String" } }
|
|
},
|
|
"faultClearHint": "La levée est une action délibérée : le défaut ne se lève jamais tout seul.",
|
|
|
|
"domainBattery": "Batterie",
|
|
"domainAssignTitle": "Classer « {label} »",
|
|
"@domainAssignTitle": {
|
|
"placeholders": { "label": { "type": "String" } }
|
|
},
|
|
"domainAssignAction": "Changer de domaine",
|
|
"domainAssignNone": "Retirer du classement",
|
|
"domainAssignHint": "Le domaine est une intention déclarée par l'installateur. L'arbitre ne la lit pas : elle ne sert qu'à grouper l'ordre de service.",
|
|
|
|
"localeRequested": "Locale demandée : {requested} · retenue par la box : {effective}",
|
|
"@localeRequested": {
|
|
"placeholders": {
|
|
"requested": { "type": "String" },
|
|
"effective": { "type": "String" }
|
|
}
|
|
}
|
|
}
|