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>
59 lines
2.3 KiB
C++
59 lines
2.3 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
|
#pragma once
|
|
|
|
#include <QObject>
|
|
#include <QString>
|
|
#include "../types/loadconfig.h"
|
|
|
|
/*!
|
|
* \brief Store persistant des configs de charge pilotée (contrat etmvariableload §4).
|
|
*
|
|
* Master store unique : \c setConfigs() valide, **persiste** (\c /var/lib/nymea/\c
|
|
* energy-load-configuration.json, à côté de \c energy-manager-configuration.json) et émet
|
|
* \c changed() — l'arbitre reconstruit ses adaptateurs sur ce signal, le handler notifie l'app.
|
|
*
|
|
* Format fichier : \c {"version":1,"loads":[ ... ]}, chaque entrée étant un \c LoadConfig §4.
|
|
* Le tableau \c loads[] est **mot pour mot** le \c LoadDescriptor §4 (jonction inter-repos
|
|
* avec l'app).
|
|
*
|
|
* \invariant Écriture atomique (fichier temporaire + \c rename) — jamais de fichier mi-écrit.
|
|
* \invariant \c setConfigs() rejette en bloc (rien persisté) si une seule entrée est invalide.
|
|
*/
|
|
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).
|
|
* \return Copie de l'ensemble courant ; toutes ont passé \c LoadConfig::isValid(). */
|
|
LoadConfigs configs() const { return m_configs; }
|
|
|
|
/*!
|
|
* \brief Remplace l'ensemble des configs : valide tout → persiste → \c emit changed().
|
|
* \param configs Nouvel ensemble (remplace l'existant — l'app envoie la liste complète).
|
|
* \param[out] error Message FR si rejet (aucune écriture dans ce cas).
|
|
* \return true si validé + persisté ; false si invalide ou échec d'écriture.
|
|
*/
|
|
bool setConfigs(const LoadConfigs &configs, QString *error = nullptr);
|
|
|
|
signals:
|
|
/*! \brief Émis après une persistance réussie de \c setConfigs(). */
|
|
void changed();
|
|
|
|
private:
|
|
QString filePath() const;
|
|
bool load();
|
|
bool save(QString *error) const;
|
|
|
|
LoadConfigs m_configs;
|
|
};
|