3 Commits

Author SHA1 Message Date
Patrick Schurig
053263bc38 feat(rpc): NymeaEnergy.GetOptimizerProtocol sert le contrat embarqué
Le contrat OpenRPC est une ressource Qt du plugin (jamais lu sur disque à
l'exécution) ; GetOptimizerProtocol rend { protocolVersion, schema }, lecture,
PermissionScopeControlThings, aucun secret, sans *Changed (statique pour un
binaire). Documenté dans INTERFACE.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-17 21:30:44 +02:00
Patrick Schurig
7044b4cd07 fix(optimiseur): pas de puissances de cycle sous declared pour une borne (brief 4 T1)
Pour une borne, LoadDeclared::minPowerW/maxPowerW sont recalculés à chaque cycle par
EvAdapter::toLoadContext (phases visées, limite de phase) : ce ne sont pas des valeurs de
plaque, et le §5.3 réserve `declared` à ce que l'installateur a saisi. Ils ne sont plus
émis ; l'exemple du protocole n'en porte pas non plus. `phases` (champ 1.0) reste émis,
mais il porte lui aussi les phases VISÉES : écart E26, proposition de correction du
protocole dans le rapport T1/T5.

Golden site-pv-ecs-borne-sgready : seules les deux clés disparaissent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 16:21:48 +02:00
Patrick Schurig
13114a2695 feat(optimiseur): sérialiseur GetPlan, protocole 1.1 §5.1-§5.3 (brief 4 T1)
OptimizerProtocol::getPlanParams(SurplusContext, ContexteFil) rend les params d'une requête
GetPlan. Fonction pure, compilée dans le plugin mais appelée par personne : sans endpoint,
rien ne change.

- La prévision voyage À CÔTÉ du contexte (§11) : ContexteFil::prevision porte la sortie de
  EnergyArbitrator::instantanePrevision(), l'assemblage partagé avec GetForecastSnapshot.
  forecastDepuisInstantane() la pose sur la grille §5.2 : Wh par pas → p50W moyens
  (Wh × 3600 / resolutionS), case sans point = null, pv null sans courbe, weather null.
- ContexteFil porte aussi trigger (sa source viendra en T3), meter.source, la PV
  instantanée, la limite de phase, la réserve, le domaine et la mesure par charge.
- Inconnu = null ou absent, jamais 0 : contractedPowerW, pv.currentW, capacité et
  puissances batterie, tarif → null ; learned, comfort, group, champs réservés, force,
  powerLevels → absents ; borne configurée sans appareil → ni déclaration ni verrous.
- meter.exportW brut (règle 8). Champs 1.0 conservés ; energyTargets dérivés par
  resolveDeadline (installer) et de la dérogation à cible (user-intent).

Tests (loadmodel, logique pure) : 4 goldens dans data/optimizer (site sans PV ; PV + ECS
relay-router + borne + SG-Ready ; prévision absente ; charge available=false figée),
régénérables sous ETM_REGENERER_GOLDEN=1, plus 3 tests d'assertion. Contre-épreuves :
contractedPowerW à 0, Wh non convertis, exportW net → chacune fait échouer au moins un test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 16:01:34 +02:00