// SPDX-License-Identifier: GPL-3.0-or-later // Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync #pragma once #include #include #include #include #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, et la même //! que \c activeStrategy : \c OptimizerStatus::StrategieRegles). constexpr const char *StrategieRegles = "rules"; /*! * \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 &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); }