Bug : exportW clampé à max(0,-p) AVANT recrédit → sur-crédit en import (ECS restait allumé sur le réseau, ne délestait jamais). Fix : surplus net SIGNÉ (exportW - importW). Régime export inchangé. Le délestage strict est borné par minOn/minOff (protection compresseur, pas confort) : l'adaptateur expose minStage/maxStage (fenêtre de verrou évaluée au temps de cycle), le scheduler clampe bestStage et décrémente au palier réel → budget correct pour les charges suivantes (puissance verrouillée = engagée non-coupable). Seam de temps unifié : now=ctx.timestamp partagé par toLoadContext()/applyAction() ; lockWindow() est l'unique calcul, lockActive() en dérive (décision==exécution). Interface ILoadAdapter étendue (now) + contrat "temps=paramètre, jamais l'horloge" documenté pour les futurs adaptateurs. EvAdapter aligné. Build 0 erreur / 0 warning. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76 lines
3.6 KiB
C++
76 lines
3.6 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
|
#pragma once
|
|
|
|
#include <QDateTime>
|
|
#include "../types/loadaction.h"
|
|
#include "../types/loaddescriptor.h"
|
|
#include "../types/surpluscontext.h"
|
|
|
|
/*!
|
|
* \brief Vue runtime minimale exposée par un adaptateur à l'arbitre.
|
|
*/
|
|
struct LoadTelemetry {
|
|
double currentPowerW = 0; //!< Puissance mesurée (W).
|
|
bool available = true; //!< Faux si l'appareil nymea est absent ou en erreur.
|
|
QDateTime lastActionAt; //!< Dernier instant où applyAction() a produit un effet.
|
|
};
|
|
|
|
/*!
|
|
* \brief Interface pure des adaptateurs de charge.
|
|
*
|
|
* Les implémentations concrètes héritent de QObject + ILoadAdapter et déclarent leurs
|
|
* propres signaux (telemetryChanged, descriptorChanged).
|
|
*
|
|
* \invariant Les adaptateurs EXÉCUTENT, ils ne décident pas (AGENTS règle 2).
|
|
* \invariant applyAction() écrête les valeurs selon les limites matérielles réelles
|
|
* (second filet après l'écrêtage de l'arbitre).
|
|
* \invariant applyAction() avec \c reason vide doit être rejetée silencieusement.
|
|
* \invariant Les méthodes non-applyAction() retournent immédiatement (pas de I/O bloquant).
|
|
* \invariant **Temps = paramètre, jamais l'horloge.** Toute logique temporelle d'un
|
|
* adaptateur (verrous minOn/minOff, fenêtres, fraîcheur…) utilise EXCLUSIVEMENT le
|
|
* \c now (= \c ctx.timestamp) reçu en paramètre de \c toLoadContext()/applyAction().
|
|
* JAMAIS \c QDateTime::currentDateTime(). C'est cette source unique, partagée avec le
|
|
* scheduler, qui rend impossible toute divergence décision/exécution et qui rend la
|
|
* logique injectable en simulation. Contrat pour tout futur adaptateur (SgReady, Battery).
|
|
*/
|
|
class ILoadAdapter {
|
|
public:
|
|
virtual ~ILoadAdapter() = default;
|
|
|
|
/*!
|
|
* \brief Description statique de la charge : capacités, limites, priorité, needs.
|
|
* \return LoadDescriptor construit depuis la configuration matérielle.
|
|
* \note Peut être rappelé à chaque cycle — l'implémentation doit être légère.
|
|
*/
|
|
virtual LoadDescriptor descriptor() const = 0;
|
|
|
|
/*!
|
|
* \brief Télémétrie runtime (puissance, disponibilité, dernière action).
|
|
* \return LoadTelemetry issue de l'état courant de l'appareil nymea.
|
|
*/
|
|
virtual LoadTelemetry telemetry() const = 0;
|
|
|
|
/*!
|
|
* \brief Construit l'entrée §5 loads[] pour le SurplusContext.
|
|
* \param now Temps de cycle (\c ctx.timestamp). Source unique pour l'évaluation des
|
|
* verrous (minStage/maxStage) — JAMAIS \c QDateTime::currentDateTime() côté adaptateur,
|
|
* afin que décision (scheduler) et exécution (applyAction) partagent le même temps.
|
|
* \return LoadContext incluant declared, limits, needs et télémétrie type-spécifique.
|
|
*/
|
|
virtual LoadContext toLoadContext(const QDateTime &now) const = 0;
|
|
|
|
/*!
|
|
* \brief Applique l'action et retourne ce qui a réellement été envoyé au matériel.
|
|
*
|
|
* L'arbitre a déjà écrêté selon les limites et le budget — ceci est le second filet.
|
|
*
|
|
* \param action Action à appliquer. Doit avoir \c reason non vide.
|
|
* \param now Temps de cycle (\c ctx.timestamp) — MÊME source que toLoadContext(),
|
|
* pour que l'évaluation des verrous coïncide avec celle vue par le scheduler.
|
|
* \return L'action après écrêtage matériel (peut différer de l'entrée).
|
|
* \note Retour silencieux sans effet si \c action.reason est vide.
|
|
*/
|
|
virtual LoadAction applyAction(const LoadAction &action, const QDateTime &now) = 0;
|
|
};
|