feat(rpc): droits de NymeaEnergy.* séparés — lire, commander, configurer, administrer
Chaque méthode déclare son droit au registerMethod ; plus aucune ne tombe en Admin par la valeur par défaut de libnymea. - None (tout compte authentifié) : tous les Get* sauf GetOptimizerTrace, dont GetBatteryLevelConsideration (Admin par oubli jusqu'ici). GetOptimizerStatus ne porte ni l'endpoint ni le token. - ControlThings : SetChargingInfo, SetLoadDerogation, ClearLoadDerogation, ClearLoadFault, SetLockOnUnplug. - ConfigureThings : SetLoadConfig, SetTariff, SetForecastSite, SetAcquisitionTolerance, SetSpotMarketConfiguration. - Admin, désormais écrit : SetPhasePowerLimit, SetBatteryLevelConsideration, SetOptimizerEndpoint, SetOptimizerToken, GetOptimizerTrace, SetOptimizerTrace. Un registerMethod privé SANS valeur par défaut masque celui de JsonHandler : oublier le droit ne compile plus. C'est la seule garde possible pour une méthode Admin, le défaut étant Admin. Changement de contrat RPC (JSONRPC.Introspect publie permissionScope). Les droits ne mordent que sur un transport avec authentification. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
61db6cfd66
commit
8a055eee9c
@ -68,43 +68,54 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
QVariantMap params, returns;
|
||||
QString description;
|
||||
|
||||
// [ETM] DROITS — chaque méthode écrit le sien (consigne droits lecture/écriture, 2026-10-19).
|
||||
// None lire : tous les Get*, sauf GetOptimizerTrace. « None » veut dire « tout
|
||||
// compte AUTHENTIFIÉ », pas « sans jeton ».
|
||||
// ControlThings commander : les gestes de l'usager (mode, dérogation, défaut, verrou).
|
||||
// ConfigureThings décrire l'installation : charges, tarif, site, tolérance, spot market.
|
||||
// Admin raccordement, secret ou chemin système.
|
||||
// Les droits ne mordent que sur un transport AVEC authentification : sans, nymea laisse tout
|
||||
// passer. Les notifications, elles, ne sont filtrées par aucun droit — d'où les lectures en
|
||||
// None : les garder plus haut ne cacherait rien de ce que les *Changed diffusent déjà.
|
||||
// Table figée par TestCharging::testNymeaEnergyPermissionScopes.
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the phase power consumption limit. 0 if unset. This needs to be set in order for the smart charging to do anything.";
|
||||
returns.insert("phasePowerLimit", enumValueName(Uint));
|
||||
registerMethod("GetPhasePowerLimit", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetPhasePowerLimit", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Set the phase power consumption limit. This is the maximum allowed Ampere per phase. A value of 0 means unset. All smart charging will be disabled.";
|
||||
params.insert("phasePowerLimit", enumValueName(Uint));
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
registerMethod("SetPhasePowerLimit", description, params, returns);
|
||||
registerMethod("SetPhasePowerLimit", description, params, returns, Types::PermissionScopeAdmin);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the acquisition tolerance. This value will control how much solar surplus is required to start the charging.";
|
||||
returns.insert("acquisitionTolerance", enumValueName(Double));
|
||||
registerMethod("GetAcquisitionTolerance", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetAcquisitionTolerance", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Set the acquisition tolerance for the charging.";
|
||||
params.insert("acquisitionTolerance", enumValueName(Double));
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
registerMethod("SetAcquisitionTolerance", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("SetAcquisitionTolerance", description, params, returns, Types::PermissionScopeConfigureThings);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the battery level consideration. This value will control how much the energy storage is taking in account";
|
||||
returns.insert("batteryLevelConsideration", enumValueName(Double));
|
||||
registerMethod("GetBatteryLevelConsideration", description, params, returns);
|
||||
registerMethod("GetBatteryLevelConsideration", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Set the battery level consideration for the charging.";
|
||||
params.insert("batteryLevelConsideration", enumValueName(Double));
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
registerMethod("SetBatteryLevelConsideration", description, params, returns);
|
||||
registerMethod("SetBatteryLevelConsideration", description, params, returns, Types::PermissionScopeAdmin);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the lock on unplug setting.";
|
||||
returns.insert("lockOnUnplug", enumValueName(Bool));
|
||||
registerMethod("GetLockOnUnplug", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetLockOnUnplug", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Set the lock on unplug setting.";
|
||||
@ -119,7 +130,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
"charger' and nothing else.";
|
||||
params.insert("o:evChargerId", enumValueName(Uuid));
|
||||
returns.insert("chargingInfos", QVariantList() << objectRef<ChargingInfo>());
|
||||
registerMethod("GetChargingInfos", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetChargingInfos", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Set the charging info for an EV charger. The given object REPLACES the stored "
|
||||
@ -136,7 +147,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the list of available spot market data providers.";
|
||||
returns.insert("providers", QVariantList() << objectRef<SpotMarketProviderInfo>());
|
||||
registerMethod("GetAvailableSpotMarketProviders", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetAvailableSpotMarketProviders", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Set the current spotmarket configuration. If enabled, the provideId must be valid. You can get the available providers using GetAvailableSpotMarketProviders. "
|
||||
@ -148,20 +159,20 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
params.insert("o:providerId", enumValueName(Uuid));
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
returns.insert("o:fault", enumValueName(String)); // [ETM] SPOT_MARKET_NOT_IN_BUILD
|
||||
registerMethod("SetSpotMarketConfiguration", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("SetSpotMarketConfiguration", description, params, returns, Types::PermissionScopeConfigureThings);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the current spotmarket configuration.";
|
||||
returns.insert("o:providerId", enumValueName(Uuid));
|
||||
returns.insert("enabled", enumValueName(Bool));
|
||||
returns.insert("available", enumValueName(Bool));
|
||||
registerMethod("GetSpotMarketConfiguration", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetSpotMarketConfiguration", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the current score entries from the current spot market. If spot market is not enabled or not available, the list will be empty. The weighting of the available score entries goes from 0 (worst) to 1.0 (best).";
|
||||
returns.insert("spotMarketScoreEntries", QVariantList() << objectRef<ScoreEntry>());
|
||||
registerMethod("GetSpotMarketScoreEntries", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetSpotMarketScoreEntries", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
|
||||
params.clear(); returns.clear();
|
||||
@ -173,14 +184,14 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
// C'est la famille ECS-411 — un silence ambigu. Tout élément runtime a un Get* ET un
|
||||
// *Changed ; jamais une notification seule.
|
||||
returns.insert("degradedMode", enumValueName(Bool));
|
||||
registerMethod("GetChargingSchedules", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetChargingSchedules", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
|
||||
// [ETM] Configuration des charges pilotées (interface etmvariableload, contrat §4).
|
||||
params.clear(); returns.clear();
|
||||
description = "Get the configured controllable loads (etmvariableload).";
|
||||
returns.insert("loadConfigs", QVariantList() << objectRef<LoadConfig>());
|
||||
registerMethod("GetLoadConfig", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetLoadConfig", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Replace the full set of controllable load configs. Rejected as a whole "
|
||||
@ -273,7 +284,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
loadItem.insert("o:minOffS", enumValueName(Uint));
|
||||
params.insert("loadConfigs", QVariantList() << loadItem);
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
registerMethod("SetLoadConfig", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("SetLoadConfig", description, params, returns, Types::PermissionScopeConfigureThings);
|
||||
|
||||
// [Phase 2] Ratios canoniques autoconsommation / autonomie (% [0,100]). Champ omis
|
||||
// (jamais null) quand n/a (dénominateur ≤ 0). Source canonique de l'energymanager —
|
||||
@ -283,7 +294,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
"derived from the energy manager's cumulative counters over the current local "
|
||||
"day. A rate field is omitted (never null) when not available (denominator <= 0).";
|
||||
returns = energyRatiosSchema();
|
||||
registerMethod("GetEnergyRatios", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetEnergyRatios", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
// [ETM] ECS-410 — levée du verrou de défaut d'une charge. Délibérée et journalisée : le
|
||||
// défaut est collant par conception (« cesser toute commande jusqu'à intervention »), sa
|
||||
@ -308,7 +319,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
"notification. 'timestamp' is the end of the last arbitration cycle and is "
|
||||
"omitted while no cycle has run yet.";
|
||||
returns = loadTelemetrySchema();
|
||||
registerMethod("GetLoadTelemetry", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetLoadTelemetry", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
// --- Prévision PV ------------------------------------------------------------------------
|
||||
//
|
||||
@ -358,7 +369,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
returns.insert("o:fault", enumValueName(String)); // FORECAST_DATE_UNREADABLE
|
||||
returns.insert("o:faultParams", enumValueName(Variant)); // {fields: [from|to|knownAt]}
|
||||
registerMethod("GetPvForecast", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetPvForecast", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
// Désignation GLOBALE, sur le modèle d'Energy.SetRootMeter — même nature : une source unique
|
||||
// pour toute l'installation, désignée une fois. La prévision est une propriété du SITE, pas
|
||||
@ -385,7 +396,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
// ABSENT quand aucun site n'existe : annoncer une désignation manquante à une installation
|
||||
// sans plugin météo serait un avertissement qu'on ne peut pas satisfaire.
|
||||
returns.insert("o:fault", enumValueName(String)); // MISSING_FORECAST_SITE
|
||||
registerMethod("GetForecastSite", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetForecastSite", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
// GetPvForecast sert la TABLE ; GetForecastSnapshot sert la DÉCISION. Un arbitre qui lit la
|
||||
// table lirait sa propre trace au lieu de son entrée : il ne mesure plus, il se relit.
|
||||
@ -452,7 +463,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
// Variant, PAS Object : sans tarif saisi la valeur est `null` (brief 3 T4), et un null n'est
|
||||
// pas un objet. La forme de l'objet est dans la description et dans INTERFACE.md.
|
||||
returns.insert("o:price", enumValueName(Variant));
|
||||
registerMethod("GetForecastSnapshot", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetForecastSnapshot", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
// --- Tarif saisi (brief 3 T4) --------------------------------------------------------------
|
||||
// Un RÉGLAGE de l'installateur, persisté dans les réglages du moteur. Aucune décision ne le
|
||||
@ -478,7 +489,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
returns.insert("currency", enumValueName(String));
|
||||
returns.insert("includes", QVariantList() << enumValueName(String));
|
||||
returns.insert("timeZone", enumValueName(String));
|
||||
registerMethod("GetTariff", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetTariff", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Replace the tariff, effective immediately and persisted. One zone covering "
|
||||
@ -495,7 +506,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
returns.insert("o:fault", enumValueName(String));
|
||||
returns.insert("o:faultParams", enumValueName(Variant));
|
||||
registerMethod("SetTariff", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("SetTariff", description, params, returns, Types::PermissionScopeConfigureThings);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Designate the site whose PV forecast is kept. ALL the PV planes under that "
|
||||
@ -519,7 +530,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
// de l'absence — inchangé. Le type est donc contrôlé dans le handler.
|
||||
params.insert("o:acLimitW", enumValueName(Variant));
|
||||
returns.insert("energyError", enumRef<EnergyManager::EnergyError>());
|
||||
registerMethod("SetForecastSite", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("SetForecastSite", description, params, returns, Types::PermissionScopeConfigureThings);
|
||||
|
||||
// --- Dérogations -------------------------------------------------------------------------
|
||||
//
|
||||
@ -561,7 +572,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
"unknown value is OMITTED, never 0. The token is never returned: tokenConfigured "
|
||||
"only says whether one is set. Same payload as OptimizerStatusChanged.";
|
||||
returns = optimizerStatusSchema();
|
||||
registerMethod("GetOptimizerStatus", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetOptimizerStatus", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
description = "Set the external-optimizer endpoint, persisted and applied immediately: "
|
||||
@ -574,8 +585,8 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
registerMethod("SetOptimizerEndpoint", description, params, returns, Types::PermissionScopeAdmin);
|
||||
|
||||
// WRITE-ONLY (décision Q2) : aucune méthode ne relit le token. Admin : c'est un secret, et il
|
||||
// ouvre l'optimiseur à qui le détient — même niveau que les réglages d'installation du
|
||||
// handler restés au défaut nymea (SetPhasePowerLimit, SetBatteryLevelConsideration).
|
||||
// ouvre l'optimiseur à qui le détient — même niveau que SetPhasePowerLimit et
|
||||
// SetBatteryLevelConsideration.
|
||||
// Le TYPE de `token` est vérifié ici, pas par nymea : sous Qt 6, le validateur ne contrôle
|
||||
// plus le type des paramètres de base (jsonvalidator.cpp, #if QT_VERSION >= 6), un nombre
|
||||
// arrive donc au handler. Une clé EN TROP, elle, est refusée par le validateur, qui recopie
|
||||
@ -650,11 +661,11 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
returns.insert("o:slots", QVariantList() << planSlot);
|
||||
returns.insert("o:diagnostics", enumValueName(Variant)); // status, inputsUsed.pv
|
||||
returns.insert("o:fallbackCode", enumValueName(String));
|
||||
registerMethod("GetPlan", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetPlan", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
// [ETM] Le contrat OpenRPC du protocole optimiseur, EMBARQUÉ (ressource Qt) : celui du moteur qui
|
||||
// tourne, jamais un fichier relu sur disque. Lecture, aucun secret — même permission que les
|
||||
// autres Get* de l'optimiseur. Statique pour un binaire donné : pas de *Changed (invariant 11
|
||||
// tourne, jamais un fichier relu sur disque. Lecture, aucun secret — même droit que
|
||||
// GetOptimizerStatus et GetPlan. Statique pour un binaire donné : pas de *Changed (invariant 11
|
||||
// vise un état runtime ; celui-ci ne change qu'avec le paquet).
|
||||
params.clear(); returns.clear();
|
||||
description = "The OpenRPC 1.3 document of the engine <-> optimizer protocol spoken by THIS "
|
||||
@ -665,7 +676,7 @@ NymeaEnergyJsonHandler::NymeaEnergyJsonHandler(SpotMarketManager *spotMarketMana
|
||||
"Static for a given binary: no notification.";
|
||||
returns.insert("protocolVersion", enumValueName(String));
|
||||
returns.insert("schema", enumValueName(Object));
|
||||
registerMethod("GetOptimizerProtocol", description, params, returns, Types::PermissionScopeControlThings);
|
||||
registerMethod("GetOptimizerProtocol", description, params, returns, Types::PermissionScopeNone);
|
||||
|
||||
|
||||
// Notifications
|
||||
@ -870,6 +881,12 @@ QString NymeaEnergyJsonHandler::name() const
|
||||
return "NymeaEnergy";
|
||||
}
|
||||
|
||||
void NymeaEnergyJsonHandler::registerMethod(const QString &name, const QString &description, const QVariantMap ¶ms,
|
||||
const QVariantMap &returns, Types::PermissionScope permissionScope)
|
||||
{
|
||||
JsonHandler::registerMethod(name, description, params, returns, permissionScope);
|
||||
}
|
||||
|
||||
JsonReply *NymeaEnergyJsonHandler::GetPhasePowerLimit(const QVariantMap ¶ms)
|
||||
{
|
||||
Q_UNUSED(params)
|
||||
|
||||
@ -188,6 +188,24 @@ private slots:
|
||||
void onPowerBalanceChanged();
|
||||
|
||||
private:
|
||||
/*!
|
||||
* \brief [ETM] Enregistre une méthode AVEC son droit — le seul \c registerMethod visible ici.
|
||||
* \param name Nom de la méthode, sans le namespace.
|
||||
* \param description Description publiée par \c JSONRPC.Introspect.
|
||||
* \param params Schéma des paramètres.
|
||||
* \param returns Schéma du retour.
|
||||
* \param permissionScope Droit exigé par nymea, SANS valeur par défaut.
|
||||
*
|
||||
* \par Pourquoi masquer celui de JsonHandler
|
||||
* Le \c registerMethod de libnymea prend \c PermissionScopeAdmin par défaut : une méthode
|
||||
* enregistrée sans droit tombait en Admin sans que personne l'ait décidé
|
||||
* (\c GetBatteryLevelConsideration, une lecture). Déclaré ici, ce nom masque celui de la
|
||||
* classe de base : oublier le droit ne compile plus. Le test
|
||||
* \c TestCharging::testNymeaEnergyPermissionScopes fige la table publiée.
|
||||
*/
|
||||
void registerMethod(const QString &name, const QString &description, const QVariantMap ¶ms,
|
||||
const QVariantMap &returns, Types::PermissionScope permissionScope);
|
||||
|
||||
SpotMarketManager *m_spotMarketManager;
|
||||
SmartChargingManager *m_smartChargingManager = nullptr;
|
||||
LoadConfigStore *m_loadConfigStore = nullptr;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user