Lot B côté app, partie NON bloquée par le lot plugin (voir §Limites).
§1 Locale (indépendant) — JSONRPC.Hello portait {} : l'app était en en_US de
fait alors que nymea gère la locale PAR CONNEXION (o:locale). Envoi de la
locale à chaque Hello, donc aussi après reconnexion subie (m_clientLocales
repart au défaut de la box à chaque socket). Locale demandée ET retenue
journalisées : un .qm introuvable rend exactement comme une absence de
traduction, sans cette trace un catalogue mal packagé passe inaperçu.
§2 i18n — flutter_localizations + intl + ARB (français seul). Aucune chaîne
en dur dans le nouvel écran. Les codes reçus de la box (domaine, mécanisme)
sont des clés ARB avec repli explicite sur code brut si l'app ne les connaît
pas : une box en avance sur l'app est un cas normal en parc déployé.
§3 Modèle — LoadConfigEntry est une VUE en lecture au-dessus de la map brute ;
l'écriture repart de la map d'origine (patched()). Pas de couche de filtrage
préventive : l'aller-retour neutre passe contre .75, donc l'écho verbatim est
sûr par construction (§7-1).
§4 Priorité à deux niveaux — groupByDomain / flattenToPayload. Le rang de
domaine se déduit de l'ordre d'apparition à plat ; la box ne sait rien des
groupes. Config non contiguë : signalée, ordre réel affiché, normalisation
seulement sur confirmation explicite. Miroir client de validateSet().
§5 Écritures asynchrones — LoadConfigProvider ne conclut jamais sur
l'acquittement du RPC : pending → LoadConfigChanged → confirmed|diverged.
NymeaEnergy.GetLoadConfig / SetLoadConfig deviennent RÉELS (ils étaient des
stubs journalisés). Conséquence traitée : EnergySetupProvider.persist()
n'émet plus setLoadConfig(buildLoadDescriptors()) — SetLoadConfig remplace
TOUT l'ensemble, et _commit() l'appelait à chaque changement d'UI : une
reconstruction depuis le modèle typé aurait écrasé la config réelle de la
box sans geste explicite.
Écran /energy/loads, gaté installateur (drawer + garde de routeur).
Limites — le lot plugin n'est PAS déployé sur .75 : GetLoadTelemetry,
LoadTelemetryChanged et o:domain sont absents (19 méthodes / 13 notifications
inchangées). Toute la moitié télémétrie du brief est donc hors d'atteinte, et
o:domain n'étant pas au schéma, la box rejetterait la clé (jsonvalidator.cpp:143).
Fixtures multi-domaines synthétiques : .75 n'a qu'une charge.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
141 lines
3.3 KiB
JSON
141 lines
3.3 KiB
JSON
{
|
|
"_source": "FIXTURE SYNTHÉTIQUE — PAS un dump machine.",
|
|
"_note": "Ordre volontairement ENTRELACÉ : ev(1), ecs(2), ev(3). Le domaine 'ev' n'est pas contigu. Sert le critère §7-3 : l'app doit le SIGNALER, afficher l'ordre réel, et n'écrire qu'après confirmation explicite.",
|
|
"loadConfigs": [
|
|
{
|
|
"adapter": "etmvariableload",
|
|
"enabled": true,
|
|
"id": "{11111111-1111-4111-8111-111111111111}",
|
|
"label": "Borne garage",
|
|
"domain": "ev",
|
|
"maxPowerW": 11000,
|
|
"minOffS": 0,
|
|
"minOnS": 0,
|
|
"mode": "dynamic",
|
|
"needs": {
|
|
"dailyDeadline": "07:00",
|
|
"minEnergyWhPerDay": 8000
|
|
},
|
|
"powerLevels": [],
|
|
"priority": 1,
|
|
"relays": [],
|
|
"sgReady": {}
|
|
},
|
|
{
|
|
"adapter": "etmvariableload",
|
|
"enabled": true,
|
|
"id": "{22222222-2222-4222-8222-222222222222}",
|
|
"label": "Borne extérieure",
|
|
"domain": "ev",
|
|
"maxPowerW": 7400,
|
|
"minOffS": 0,
|
|
"minOnS": 0,
|
|
"mode": "dynamic",
|
|
"needs": {
|
|
"dailyDeadline": "",
|
|
"minEnergyWhPerDay": 0
|
|
},
|
|
"powerLevels": [],
|
|
"priority": 3,
|
|
"relays": [],
|
|
"sgReady": {}
|
|
},
|
|
{
|
|
"adapter": "relay-router",
|
|
"enabled": true,
|
|
"id": "chauffe-eau",
|
|
"label": "chauffe-eau",
|
|
"domain": "ecs",
|
|
"maxPowerW": 0,
|
|
"minOffS": 60,
|
|
"minOnS": 60,
|
|
"mode": "fixed",
|
|
"needs": {
|
|
"dailyDeadline": "",
|
|
"minEnergyWhPerDay": 0
|
|
},
|
|
"powerLevels": [],
|
|
"priority": 2,
|
|
"relays": [
|
|
{
|
|
"powerW": 500,
|
|
"thingId": "{8538782f-2c8c-4a30-bfce-c8140f791c9b}"
|
|
},
|
|
{
|
|
"powerW": 1000,
|
|
"thingId": "{2ebe6bef-829b-4695-9d11-ddb4c16c5448}"
|
|
},
|
|
{
|
|
"powerW": 2000,
|
|
"thingId": "{b033b212-1adb-4df0-ba2b-8fa477de52a2}"
|
|
}
|
|
],
|
|
"sgReady": {}
|
|
},
|
|
{
|
|
"adapter": "sg-ready",
|
|
"enabled": true,
|
|
"id": "clim-salon",
|
|
"label": "Clim salon",
|
|
"domain": "hvac",
|
|
"maxPowerW": 0,
|
|
"minOffS": 0,
|
|
"minOnS": 0,
|
|
"mode": "fixed",
|
|
"needs": {
|
|
"dailyDeadline": "",
|
|
"minEnergyWhPerDay": 0
|
|
},
|
|
"powerLevels": [],
|
|
"priority": 4,
|
|
"relays": [],
|
|
"sgReady": {
|
|
"minStateHoldS": 900,
|
|
"states": [
|
|
{
|
|
"estimatedPowerW": 0.0,
|
|
"relays": [],
|
|
"state": 2
|
|
},
|
|
{
|
|
"estimatedPowerW": 1200.0,
|
|
"relays": [
|
|
"{aaaa1111-0000-4000-8000-000000000001}"
|
|
],
|
|
"state": 3
|
|
},
|
|
{
|
|
"estimatedPowerW": 2400.0,
|
|
"relays": [
|
|
"{aaaa1111-0000-4000-8000-000000000002}"
|
|
],
|
|
"state": 4
|
|
}
|
|
]
|
|
}
|
|
},
|
|
{
|
|
"adapter": "relay-router",
|
|
"enabled": true,
|
|
"id": "seche-serviettes",
|
|
"label": "Sèche-serviettes",
|
|
"maxPowerW": 0,
|
|
"minOffS": 30,
|
|
"minOnS": 30,
|
|
"mode": "fixed",
|
|
"needs": {
|
|
"dailyDeadline": "",
|
|
"minEnergyWhPerDay": 0
|
|
},
|
|
"powerLevels": [],
|
|
"priority": 5,
|
|
"relays": [
|
|
{
|
|
"powerW": 750,
|
|
"thingId": "{cccc3333-0000-4000-8000-000000000003}"
|
|
}
|
|
],
|
|
"sgReady": {}
|
|
}
|
|
]
|
|
} |