diff --git a/energyplugin/etm/config/loadconfigstore.h b/energyplugin/etm/config/loadconfigstore.h index 548fda8..d1ee7ba 100644 --- a/energyplugin/etm/config/loadconfigstore.h +++ b/energyplugin/etm/config/loadconfigstore.h @@ -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; } /*! diff --git a/energyplugin/etm/ratios/energyratioscalculator.h b/energyplugin/etm/ratios/energyratioscalculator.h index 49915fb..8faedf4 100644 --- a/energyplugin/etm/ratios/energyratioscalculator.h +++ b/energyplugin/etm/ratios/energyratioscalculator.h @@ -27,36 +27,59 @@ #include -// [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, diff --git a/energyplugin/etm/types/loadaction.h b/energyplugin/etm/types/loadaction.h index f2c00e9..e270935 100644 --- a/energyplugin/etm/types/loadaction.h +++ b/energyplugin/etm/types/loadaction.h @@ -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. diff --git a/energyplugin/etm/types/loaddescriptor.h b/energyplugin/etm/types/loaddescriptor.h index e1c91d8..c18fc73 100644 --- a/energyplugin/etm/types/loaddescriptor.h +++ b/energyplugin/etm/types/loaddescriptor.h @@ -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 supportedKinds; //!< Kinds acceptés par applyAction(). }; diff --git a/energyplugin/etm/types/plan.h b/energyplugin/etm/types/plan.h index 97a3273..f6985c0 100644 --- a/energyplugin/etm/types/plan.h +++ b/energyplugin/etm/types/plan.h @@ -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 actions; + QDateTime from; //!< Début du créneau, inclus. + QDateTime to; //!< Fin du créneau, EXCLUE — l'intervalle est [from, to[. + QList 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(); } };