docs(etm): contrats Doxygen — 25 derniers éléments hors fichiers différés
Complète la couverture : 31 → 6 avertissements. Les 6 restants sont exactement les deux fichiers différés jusqu'à l'étape 3 (relayrouter.h 3, energyarbitrator.h 3, ce dernier étant la cible d'ECS-412). energyratioscalculator.h traité EN PREMIER, pour la raison qui le distingue : c'était le seul endroit où l'absence de documentation cachait une règle métier. La règle était en fait écrite — mais en commentaires « // », invisibles à doxygen, donc invérifiables. Conversion en blocs Doxygen SANS réécriture du fond : les trois cas de reseed de la baseline (premier appel, changement de jour local, compteur non monotone) et la garantie « dénominateur ≤ 0 → n/a, jamais de NaN » deviennent des invariants opposables. Précisé au passage que le paramètre `now` doit être en heure LOCALE — passer de l'UTC déplacerait la frontière de journée. Reste du lot : loadaction.h (quels champs sont significatifs selon le kind), plan.h ([from, to[ et l'interdiction de retourner un plan invalide), loaddescriptor.h, loadconfigstore.h (tolérance de chargement : un fichier absent n'est pas une erreur, une entrée invalide est ignorée seule). Build amd64 0 erreur. Simulation : 7/7, dont testEnergyRatiosAlignment. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e70a60c180
commit
41d3a329e4
@ -24,9 +24,17 @@ class LoadConfigStore : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/*!
|
||||
* \brief Construit le store et charge le fichier s'il existe.
|
||||
* \param parent Propriétaire Qt.
|
||||
* \note Un fichier absent, illisible ou au JSON invalide n'est pas une erreur :
|
||||
* le store démarre à vide. Une ENTRÉE invalide est ignorée individuellement
|
||||
* (tolérance ascendante) — on ne perd pas les autres pour une seule.
|
||||
*/
|
||||
explicit LoadConfigStore(QObject *parent = nullptr);
|
||||
|
||||
/*! \brief Configs actuellement en mémoire (chargées au démarrage ou via setConfigs). */
|
||||
/*! \brief Configs actuellement en mémoire (chargées au démarrage ou via setConfigs).
|
||||
* \return Copie de l'ensemble courant ; toutes ont passé \c LoadConfig::isValid(). */
|
||||
LoadConfigs configs() const { return m_configs; }
|
||||
|
||||
/*!
|
||||
|
||||
@ -27,36 +27,59 @@
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
// [Phase 2] Ratios énergétiques canoniques (autoconsommation / autonomie), en %.
|
||||
//
|
||||
// Source canonique côté energymanager : remplace le seam interim app-side
|
||||
// (EnergyRatiosInterim.compute). PUR MESURE (frontière GPL) : dérive par Δ de
|
||||
// cumuls sur la période affichée (journée depuis minuit local), pas par
|
||||
// intégration du signal live → déterministe, pas de drift de polling.
|
||||
//
|
||||
// autonomie = (Δ totalConsumption − Δ totalAcquisition) / Δ totalConsumption
|
||||
// autoconsommation = (Δ totalProduction − Δ totalReturn) / Δ totalProduction
|
||||
//
|
||||
// Reseed de la baseline : 1er appel, nouveau jour local, OU compteur non
|
||||
// monotone (Δ<0 : restart nymead / re-add thing / rollover). Dénominateur ≤ 0
|
||||
// → n/a (valid=false), jamais de NaN. Porté 1:1 de l'interim app.
|
||||
/*!
|
||||
* \brief [Phase 2] Ratios énergétiques canoniques (autoconsommation / autonomie), en %.
|
||||
*
|
||||
* Source canonique côté energymanager : remplace le seam interim app-side
|
||||
* (\c EnergyRatiosInterim.compute). **PUR MESURE** (frontière GPL) : dérive par Δ de
|
||||
* cumuls sur la période affichée (journée depuis minuit local), pas par intégration du
|
||||
* signal live → déterministe, pas de drift de polling.
|
||||
*
|
||||
* \par Formules
|
||||
* \code
|
||||
* autonomie = (Δ totalConsumption − Δ totalAcquisition) / Δ totalConsumption
|
||||
* autoconsommation = (Δ totalProduction − Δ totalReturn) / Δ totalProduction
|
||||
* \endcode
|
||||
*
|
||||
* \invariant Reseed de la baseline dans trois cas, et seulement ceux-là : premier appel,
|
||||
* changement de jour local, OU compteur non monotone (Δ < 0 — redémarrage de nymead,
|
||||
* thing ré-ajouté, rollover).
|
||||
* \invariant Dénominateur ≤ 0 → résultat marqué n/a (\c valid == false). **Jamais de NaN**,
|
||||
* jamais un 0 % qui se ferait passer pour une mesure.
|
||||
* \invariant Porté 1:1 de l'interim app — toute divergence de formule est un défaut.
|
||||
*/
|
||||
class EnergyRatiosCalculator
|
||||
{
|
||||
public:
|
||||
/*! \brief Résultat d'un calcul : deux ratios, chacun accompagné de sa validité. */
|
||||
struct Ratios {
|
||||
bool autoconsommationValid = false; // false = n/a (dénominateur nul)
|
||||
double autoconsommation = 0.0; // % dans [0, 100]
|
||||
bool autonomieValid = false; // false = n/a
|
||||
double autonomie = 0.0; // % dans [0, 100]
|
||||
bool autoconsommationValid = false; //!< Faux = n/a (dénominateur nul) — ne pas afficher \c autoconsommation.
|
||||
double autoconsommation = 0.0; //!< Part de la production consommée sur place, % dans [0, 100].
|
||||
bool autonomieValid = false; //!< Faux = n/a (dénominateur nul) — ne pas afficher \c autonomie.
|
||||
double autonomie = 0.0; //!< Part de la consommation couverte sans soutirage, % dans [0, 100].
|
||||
};
|
||||
|
||||
/*! \brief Construit sans baseline : le premier \c compute() la posera. */
|
||||
EnergyRatiosCalculator() = default;
|
||||
|
||||
// Réinitialise la baseline (ex. switch d'installation).
|
||||
/*!
|
||||
* \brief Réinitialise la baseline (ex. changement d'installation).
|
||||
* \note Le \c compute() suivant repose la baseline et retourne donc n/a sur les deux
|
||||
* ratios : sans écart de cumuls, il n'y a rien à mesurer.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
// Calcule depuis les cumuls courants (mêmes unités en entrée — elles
|
||||
// s'annulent dans le ratio). `now` (heure LOCALE) sert à détecter le jour.
|
||||
/*!
|
||||
* \brief Calcule les deux ratios depuis les cumuls courants.
|
||||
* \param totalProduction Cumul de production. Unité libre — elle s'annule dans le ratio.
|
||||
* \param totalReturn Cumul réinjecté au réseau, même unité.
|
||||
* \param totalConsumption Cumul de consommation, même unité.
|
||||
* \param totalAcquisition Cumul soutiré au réseau, même unité.
|
||||
* \param now Horodatage en heure **LOCALE** : sert à détecter le changement
|
||||
* de jour, donc le reseed. Passer de l'UTC fausserait la frontière
|
||||
* de journée.
|
||||
* \return Les deux ratios ; un ratio dont le dénominateur est ≤ 0 revient \c valid == false.
|
||||
*/
|
||||
Ratios compute(double totalProduction,
|
||||
double totalReturn,
|
||||
double totalConsumption,
|
||||
|
||||
@ -28,24 +28,24 @@ struct LoadAction {
|
||||
enum Permission { Allow, Forbid };
|
||||
|
||||
QString loadId; //!< ThingId de la charge cible (string).
|
||||
Kind kind = Setpoint;
|
||||
Funding funding = Surplus;
|
||||
Kind kind = Setpoint; //!< Détermine QUELS champs ci-dessous sont significatifs.
|
||||
Funding funding = Surplus; //!< Origine du budget engagé. Interne — jamais sérialisé.
|
||||
|
||||
// --- Setpoint evcharger ---
|
||||
bool chargingEnabled = false;
|
||||
bool chargingEnabled = false; //!< Autorise la charge ; faux = suspendue (pas 0 A).
|
||||
double currentA = 0; //!< Courant consigne (A), écrêté par l'adaptateur.
|
||||
uint phaseCount = 0; //!< Nombre de phases (1 ou 3, 0 = inchangé).
|
||||
|
||||
// --- Setpoint battery ---
|
||||
double powerW = 0;
|
||||
Source source = Solar;
|
||||
double powerW = 0; //!< Consigne en W. Pour une charge pilotée : l'ENVELOPPE allouée.
|
||||
Source source = Solar; //!< Énergie autorisée pour cette consigne batterie.
|
||||
|
||||
// --- State sg-ready ---
|
||||
int state = 0; //!< État SG-Ready (1-4).
|
||||
|
||||
// --- Constraint battery ---
|
||||
Permission charge = Allow;
|
||||
Permission discharge = Allow;
|
||||
Permission charge = Allow; //!< Autorisation de charger la batterie sur ce créneau.
|
||||
Permission discharge = Allow; //!< Autorisation de la décharger (arbitrage grid-funding).
|
||||
|
||||
/*!
|
||||
* \brief Motif de la décision, non vide, en français.
|
||||
|
||||
@ -84,9 +84,10 @@ struct LoadDescriptor {
|
||||
QString label; //!< Nom lisible (affiché dans les logs).
|
||||
//! Type d'adaptateur : "evcharger"|"etmvariableload"|"sg-ready"|"battery".
|
||||
QString adapter;
|
||||
//! Rang de service, ASCENDANT (1 = premier servi) — cf. la note de classe ci-dessus.
|
||||
int priority = 0;
|
||||
LoadDeclared declared;
|
||||
LoadLimits limits;
|
||||
LoadNeeds needs;
|
||||
LoadDeclared declared; //!< Capacités de plaque : paliers, plafond, états.
|
||||
LoadLimits limits; //!< Verrous temporels imposés par le matériel.
|
||||
LoadNeeds needs; //!< Besoins utilisateur, transmis tels quels à l'optimiseur.
|
||||
QList<LoadAction::Kind> supportedKinds; //!< Kinds acceptés par applyAction().
|
||||
};
|
||||
|
||||
@ -17,9 +17,9 @@
|
||||
* \invariant Un Slot vide (actions vide) est valide — signifie "aucune action ce créneau".
|
||||
*/
|
||||
struct Slot {
|
||||
QDateTime from;
|
||||
QDateTime to;
|
||||
QList<LoadAction> actions;
|
||||
QDateTime from; //!< Début du créneau, inclus.
|
||||
QDateTime to; //!< Fin du créneau, EXCLUE — l'intervalle est [from, to[.
|
||||
QList<LoadAction> actions; //!< Actions à appliquer, triées par priorité croissante.
|
||||
};
|
||||
|
||||
/*!
|
||||
@ -49,6 +49,10 @@ struct Plan {
|
||||
return {};
|
||||
}
|
||||
|
||||
/*! \brief Vrai si le plan contient au moins un Slot. */
|
||||
/*!
|
||||
* \brief Vrai si le plan contient au moins un Slot.
|
||||
* \return Faux uniquement si \c timeSlots est vide. Un scheduler ne DOIT jamais
|
||||
* retourner un plan invalide (invariant IScheduler) — pas d'abstain vers l'arbitre.
|
||||
*/
|
||||
bool isValid() const { return !timeSlots.isEmpty(); }
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user