[3a] structs protocole + interfaces LoadAdapter/Scheduler (zéro comportement)
LoadAction (kind+funding+§6 fields), LoadDescriptor, SurplusContext (§5), Plan/Slot, ILoadAdapter, IScheduler — noms de champs = OPTIMIZER_PROTOCOL.md. energyplugin.pri inclut etm/etm.pri. Build Qt6 vert, aucun fichier upstream touché. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ddba0db3d6
commit
f8109433ab
@ -37,6 +37,8 @@ HEADERS += \
|
|||||||
$$PWD/types/smartchargingstate.h \
|
$$PWD/types/smartchargingstate.h \
|
||||||
$$PWD/types/timeframe.h \
|
$$PWD/types/timeframe.h \
|
||||||
|
|
||||||
|
include($$PWD/etm/etm.pri)
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
$$PWD/energymanagerconfiguration.cpp \
|
$$PWD/energymanagerconfiguration.cpp \
|
||||||
$$PWD/energysettings.cpp \
|
$$PWD/energysettings.cpp \
|
||||||
|
|||||||
37
energyplugin/etm/adapters/iloadadapter.h
Normal file
37
energyplugin/etm/adapters/iloadadapter.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
// Vue runtime minimale qu'un adaptateur expose à l'arbitre.
|
||||||
|
struct LoadTelemetry {
|
||||||
|
double currentPowerW = 0;
|
||||||
|
bool available = true; // faux si l'appareil nymea est absent/erreur
|
||||||
|
QDateTime lastActionAt;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Interface pure — les implémentations concrètes héritent de QObject + ILoadAdapter.
|
||||||
|
// Signaux (telemetryChanged, descriptorChanged) déclarés dans les classes concrètes.
|
||||||
|
class ILoadAdapter {
|
||||||
|
public:
|
||||||
|
virtual ~ILoadAdapter() = default;
|
||||||
|
|
||||||
|
// Déclaration statique : capacités, limites, priorité, needs.
|
||||||
|
virtual LoadDescriptor descriptor() const = 0;
|
||||||
|
|
||||||
|
// Télémétrie runtime (courant, disponibilité, dernière action).
|
||||||
|
virtual LoadTelemetry telemetry() const = 0;
|
||||||
|
|
||||||
|
// Construit l'entrée §5 loads[] pour SurplusContext.
|
||||||
|
// Inclut declared, telemetry type-spécifique, learned courant.
|
||||||
|
virtual LoadContext toLoadContext() const = 0;
|
||||||
|
|
||||||
|
// Applique l'action. Retourne ce qui a réellement été appliqué
|
||||||
|
// (après écrêtage matériel). L'arbitre a déjà écrêté selon les limites
|
||||||
|
// et le budget — c'est le second filet.
|
||||||
|
virtual LoadAction applyAction(const LoadAction &action) = 0;
|
||||||
|
};
|
||||||
7
energyplugin/etm/etm.pri
Normal file
7
energyplugin/etm/etm.pri
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
HEADERS += \
|
||||||
|
$$PWD/types/loadaction.h \
|
||||||
|
$$PWD/types/loaddescriptor.h \
|
||||||
|
$$PWD/types/surpluscontext.h \
|
||||||
|
$$PWD/types/plan.h \
|
||||||
|
$$PWD/adapters/iloadadapter.h \
|
||||||
|
$$PWD/scheduler/ischeduler.h \
|
||||||
19
energyplugin/etm/scheduler/ischeduler.h
Normal file
19
energyplugin/etm/scheduler/ischeduler.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../types/surpluscontext.h"
|
||||||
|
#include "../types/plan.h"
|
||||||
|
|
||||||
|
// Interface pure — implémentations concrètes héritent de QObject + IScheduler.
|
||||||
|
//
|
||||||
|
// Règle : getPlan() DOIT retourner immédiatement (modèle cache §AGENTS invariant 5).
|
||||||
|
// SocketScheduler renvoie son dernier plan en cache et recalcule en fond.
|
||||||
|
// SocketScheduler embarque un RuleBasedScheduler comme fallback et renvoie
|
||||||
|
// TOUJOURS un Plan exploitable — l'abstain du protocole n'atteint jamais l'arbitre.
|
||||||
|
class IScheduler {
|
||||||
|
public:
|
||||||
|
virtual ~IScheduler() = default;
|
||||||
|
|
||||||
|
virtual Plan getPlan(const SurplusContext &ctx) = 0;
|
||||||
|
};
|
||||||
36
energyplugin/etm/types/loadaction.h
Normal file
36
energyplugin/etm/types/loadaction.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
// Noms de champs : identiques à OPTIMIZER_PROTOCOL.md §6 (font autorité).
|
||||||
|
// `funding` est interne à l'arbitre — absent du JSON protocole.
|
||||||
|
struct LoadAction {
|
||||||
|
enum Kind { Setpoint, Stage, State, Constraint };
|
||||||
|
enum Funding { Surplus, Grid }; // interne, non sérialisé
|
||||||
|
enum Source { Solar, GridSource }; // "solar"|"grid" — Setpoint battery
|
||||||
|
enum Permission { Allow, Forbid }; // "allow"|"forbid" — Constraint
|
||||||
|
|
||||||
|
QString loadId;
|
||||||
|
Kind kind = Setpoint;
|
||||||
|
Funding funding = Surplus;
|
||||||
|
|
||||||
|
// Setpoint — evcharger
|
||||||
|
bool chargingEnabled = false;
|
||||||
|
double currentA = 0;
|
||||||
|
uint phaseCount = 0;
|
||||||
|
// Setpoint — battery
|
||||||
|
double powerW = 0;
|
||||||
|
Source source = Solar;
|
||||||
|
// Stage — relay-stages (ECS)
|
||||||
|
int stage = 0;
|
||||||
|
// State — sg-ready
|
||||||
|
int state = 0;
|
||||||
|
// Constraint — battery v1
|
||||||
|
Permission charge = Allow;
|
||||||
|
Permission discharge = Allow;
|
||||||
|
|
||||||
|
QString reason; // obligatoire, non vide, français (AGENTS invariant 7)
|
||||||
|
double estimatedPowerW = 0; // hint pour comptabilité arbitre (rempli par le scheduler)
|
||||||
|
};
|
||||||
54
energyplugin/etm/types/loaddescriptor.h
Normal file
54
energyplugin/etm/types/loaddescriptor.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
#include "loadaction.h"
|
||||||
|
|
||||||
|
// Capacités déclarées par l'installateur (plaque signalétique, câblage).
|
||||||
|
// Noms de champs : OPTIMIZER_PROTOCOL.md §5 loads[].declared
|
||||||
|
struct LoadDeclared {
|
||||||
|
// evcharger
|
||||||
|
double minA = 0;
|
||||||
|
double maxA = 0;
|
||||||
|
int phases = 0;
|
||||||
|
// relay-stages (ECS) — puissances en W : [0, 1200, 2400]
|
||||||
|
QList<int> stages;
|
||||||
|
// battery
|
||||||
|
double maxChargeW = 0;
|
||||||
|
double maxDischargeW = 0;
|
||||||
|
double capacityWh = 0;
|
||||||
|
int reserveSocPercent = 0;
|
||||||
|
// sg-ready : états toujours 1-4, pas de déclaration nécessaire
|
||||||
|
};
|
||||||
|
|
||||||
|
// OPTIMIZER_PROTOCOL.md §5 loads[].limits
|
||||||
|
struct LoadLimits {
|
||||||
|
int minOnS = 0;
|
||||||
|
int minOffS = 0;
|
||||||
|
int chargingEnabledLockS = 0; // evcharger
|
||||||
|
int currentChangeLockS = 0; // evcharger
|
||||||
|
int minStateHoldS = 0; // sg-ready
|
||||||
|
};
|
||||||
|
|
||||||
|
// OPTIMIZER_PROTOCOL.md §5 loads[].needs
|
||||||
|
struct LoadNeeds {
|
||||||
|
int targetSocPercent = 0;
|
||||||
|
QDateTime deadline;
|
||||||
|
QString dailyDeadline; // "18:00"
|
||||||
|
int minEnergyWhPerDay = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Déclaration statique qu'un ILoadAdapter expose à l'arbitre.
|
||||||
|
struct LoadDescriptor {
|
||||||
|
QString id;
|
||||||
|
QString label;
|
||||||
|
QString adapter; // "evcharger"|"relay-stages"|"sg-ready"|"battery"
|
||||||
|
int priority = 0;
|
||||||
|
LoadDeclared declared;
|
||||||
|
LoadLimits limits;
|
||||||
|
LoadNeeds needs;
|
||||||
|
QList<LoadAction::Kind> supportedKinds;
|
||||||
|
};
|
||||||
33
energyplugin/etm/types/plan.h
Normal file
33
energyplugin/etm/types/plan.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
#include "loadaction.h"
|
||||||
|
|
||||||
|
// OPTIMIZER_PROTOCOL.md §6 (noms de champs identiques).
|
||||||
|
|
||||||
|
struct Slot {
|
||||||
|
QDateTime from;
|
||||||
|
QDateTime to;
|
||||||
|
QList<LoadAction> actions; // ordonnées par priorité de LoadDescriptor
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Plan {
|
||||||
|
QString planId;
|
||||||
|
QString strategy;
|
||||||
|
QList<Slot> slots;
|
||||||
|
|
||||||
|
// Créneau couvrant dt — créneau vide (from==to==invalid) si aucun.
|
||||||
|
Slot slotCovering(const QDateTime &dt) const {
|
||||||
|
for (const Slot &s : slots) {
|
||||||
|
if (dt >= s.from && dt < s.to)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isValid() const { return !slots.isEmpty(); }
|
||||||
|
};
|
||||||
95
energyplugin/etm/types/surpluscontext.h
Normal file
95
energyplugin/etm/types/surpluscontext.h
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (C) 2025 - 2026, Patrick Schurig / ETM PowerSync
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <QList>
|
||||||
|
#include <QString>
|
||||||
|
#include "loaddescriptor.h"
|
||||||
|
|
||||||
|
// Structures miroirs de OPTIMIZER_PROTOCOL.md §5 (noms de champs identiques).
|
||||||
|
|
||||||
|
struct SurplusSite {
|
||||||
|
double contractedPowerW = 0;
|
||||||
|
QList<double> phaseLimitA; // [63.0, 63.0, 63.0]
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SurplusMeter {
|
||||||
|
double importW = 0;
|
||||||
|
double exportW = 0;
|
||||||
|
QList<double> perPhaseA;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SurplusPv {
|
||||||
|
double currentW = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SurplusBattery {
|
||||||
|
bool present = false;
|
||||||
|
double socPercent = 0;
|
||||||
|
double powerW = 0;
|
||||||
|
double capacityWh = 0;
|
||||||
|
int reserveSocPercent = 0;
|
||||||
|
double maxChargeW = 0;
|
||||||
|
double maxDischargeW = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TariffEntry {
|
||||||
|
QDateTime from;
|
||||||
|
QString label;
|
||||||
|
double priceCtkWh = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SurplusTariff {
|
||||||
|
QString provider;
|
||||||
|
TariffEntry current;
|
||||||
|
QList<TariffEntry> next;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Télémétrie d'une charge dans le contexte §5 loads[].telemetry
|
||||||
|
struct LoadContextTelemetry {
|
||||||
|
double currentPowerW = 0;
|
||||||
|
// evcharger
|
||||||
|
bool pluggedIn = false;
|
||||||
|
bool charging = false;
|
||||||
|
double sessionWh = 0;
|
||||||
|
// relay-stages
|
||||||
|
int stage = 0;
|
||||||
|
// sg-ready
|
||||||
|
int state = 0;
|
||||||
|
// battery / electricvehicle
|
||||||
|
double socPercent = 0;
|
||||||
|
QDateTime lastSwitch;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Données apprises par l'optimiseur §8 (renvoyées pour persistance)
|
||||||
|
struct LoadLearned {
|
||||||
|
double dailyEnergyWh = 0;
|
||||||
|
double confidence = 0.0; // 0–1 ; < 0.7 → "profil en apprentissage"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Entrée loads[] dans le SurplusContext envoyé au scheduler.
|
||||||
|
// Construit par l'arbitre depuis ILoadAdapter::descriptor() + telemetry().
|
||||||
|
struct LoadContext {
|
||||||
|
QString id;
|
||||||
|
QString adapter; // "evcharger"|"relay-stages"|"sg-ready"|"battery"
|
||||||
|
QString label;
|
||||||
|
int priority = 0;
|
||||||
|
LoadDeclared declared;
|
||||||
|
LoadLearned learned;
|
||||||
|
LoadContextTelemetry telemetry;
|
||||||
|
LoadNeeds needs;
|
||||||
|
LoadLimits limits;
|
||||||
|
};
|
||||||
|
|
||||||
|
// OPTIMIZER_PROTOCOL.md §5 — transmis au scheduler à chaque cycle.
|
||||||
|
struct SurplusContext {
|
||||||
|
QDateTime timestamp;
|
||||||
|
SurplusSite site;
|
||||||
|
SurplusMeter meter;
|
||||||
|
SurplusPv pv;
|
||||||
|
SurplusBattery battery;
|
||||||
|
QList<LoadContext> loads;
|
||||||
|
SurplusTariff tariff;
|
||||||
|
// forecast : opaque, transmis tel quel si présent — réservé V2
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user