- OptimizerStatus::Vivacite : optimizerAlive, échecs comptés PAR REQUÊTE (E17), deux consécutifs = mort, socket fermé = mort, retour au premier plan valide ; une abstention rompt la série sans ressusciter. strategieActive() : none sous L2, prioritaire sur tout ; rules dès qu'un optimiseur n'est plus vivant, sans attendre le cycle suivant. - SocketScheduler : branchement de la vivacité, cache abandonné à la mort, UpdateLearned journalisé une fois et ignoré. - NymeaEnergy.GetOptimizerStatus + OptimizerStatusChanged (une notification par transition, charge utile déclarée une fois) ; champs installateur absents s'ils sont inconnus ; jamais le token, tokenConfigured seulement. Pas de tier (Q5). - SetOptimizerEndpoint (persisté, appliqué à chaud) et SetOptimizerToken (écriture seule, fichier 0600, Q2), tous deux PermissionScopeAdmin ; token déclaré Variant pour qu'un mauvais type ne soit pas recopié au journal par le validateur nymea. - NymeaEnergy.GetPlan : plan en vigueur (appliqué au créneau courant, demandé ensuite), codes et paramètres filtrés seulement, inForce toujours présent, fallbackCode quand un optimiseur configuré n'a pas commandé. - Tests : tableau §7 ligne par ligne, transitions notifiées une fois, RPC, token absent de tout journal du moteur et de toute réponse. Sans endpoint : decisions IDENTIQUE (23 792 lignes), suites inchangées, journal >= info inchangé (8 739 lignes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
67 lines
3.2 KiB
C++
67 lines
3.2 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
|
#pragma once
|
|
|
|
#include <QDateTime>
|
|
#include <QHash>
|
|
#include <QString>
|
|
#include <QVariantMap>
|
|
#include "optimizerplan.h"
|
|
|
|
/*!
|
|
* \file publishedplan.h
|
|
* \brief Le plan EN VIGUEUR tel que l'app le lit (\c NymeaEnergy.GetPlan, brief 4 T4, exigence
|
|
* app 2).
|
|
*
|
|
* Fonctions PURES. L'arbitre appelle \c serialiser() en fin de cycle et garde le résultat : le
|
|
* \c Get rend ce qui a été publié, il ne recalcule rien (même règle que \c GetLoadTelemetry).
|
|
*
|
|
* \par Ce qui franchit la frontière — invariant 12
|
|
* Des codes, des nombres, des instants. Le \c reason libre d'un optimiseur n'y est jamais ;
|
|
* \c expected et \c diagnostics sont réduits à leurs clés documentées (§6), le reste est retiré ;
|
|
* ni \c planId, ni \c strategy, ni \c solver de l'optimiseur — des chaînes qu'il écrit librement.
|
|
*/
|
|
namespace PublishedPlan {
|
|
|
|
//! Valeur de \c strategy d'un plan du rule-based publié (celle de \c Plan::strategy).
|
|
constexpr const char *StrategieRegles = "rule-based";
|
|
|
|
/*!
|
|
* \brief Le plan du cycle, pour l'app.
|
|
*
|
|
* - **Sous un optimiseur** (\p plan.strategy == \c "optimizer", \p recu non nul) : le créneau
|
|
* courant, actions À LA PUISSANCE APPLIQUÉE (celles que l'adaptateur a rendues, après bornes,
|
|
* verrous, paliers et délestage L4), puis les créneaux suivants du plan reçu, actions à la
|
|
* puissance DEMANDÉE. \c computedAt et \c validUntil sont ceux de l'optimiseur, absents s'il ne
|
|
* les a pas donnés.
|
|
* - **Sous le rule-based** : un seul créneau, le courant, actions à la puissance appliquée ;
|
|
* \c computedAt = \p now, \c validUntil = fin du créneau. \c fallbackCode porte \p codeRepli
|
|
* s'il n'est pas vide (un optimiseur est configuré mais n'a pas commandé ce cycle).
|
|
*
|
|
* \param plan Plan du cycle (après \c finaliser()). \param slot Créneau dispatché, délestage L4
|
|
* fusionné. \param appliquees Retours d'\c applyAction() du cycle.
|
|
* \param recu Plan d'optimiseur appliqué ce cycle ; ignoré sous le rule-based.
|
|
* \param codeRepli Motif du repli rule-based d'une stratégie optimiseur ; vide sans optimiseur.
|
|
* \param now Instant du cycle.
|
|
* \return La charge utile de \c GetPlan, \c inForce à vrai.
|
|
*/
|
|
QVariantMap serialiser(const Plan &plan, const Slot &slot, const QHash<QString, LoadAction> &appliquees,
|
|
const OptimizerPlan::PlanRecu *recu, const QString &codeRepli, const QDateTime &now);
|
|
|
|
/*!
|
|
* \brief \c expected d'un créneau réduit aux clés documentées (§6).
|
|
* \param expected Tel que reçu. \return \c gridImportW, \c gridExportW s'ils sont des nombres finis.
|
|
*/
|
|
QVariantMap attenduPublie(const QVariantMap &expected);
|
|
|
|
/*!
|
|
* \brief \c diagnostics réduits à ce que l'app lit (§6, exigence app 4).
|
|
* \param diagnostics Tels que reçus.
|
|
* \return \c status s'il est l'une des quatre valeurs du §6, et \c inputsUsed.pv s'il vaut
|
|
* \c physics, \c hybrid (« plan calculé sur une prévision corrigée ») ou \c none ; rien
|
|
* d'autre — une valeur hors de cette liste fermée est un texte libre, elle est retirée.
|
|
*/
|
|
QVariantMap diagnosticsPublies(const QVariantMap &diagnostics);
|
|
|
|
}
|