pakutz79 d76e7e61d5 fix: detect actual EV phase instead of hardcoding phase A
- evcharger.cpp: phases() now calls meteredPhases() instead of returning PhaseNone
- smartchargingmanager: add chargerPhaseKey() with 3-level fallback
  1. meteredPhases() when charger is active
  2. effectivePhases from last known state
  3. fallback 'A' + warning (previous behavior)
- Remove 4 FIXME comments on lines 394, 477, 517
2026-04-05 07:09:38 +02:00

6.0 KiB

Agent Plugin — powersync-energy-plugin-etm (GPL3)

Lire aussi le CLAUDE.md du dossier parent avant de commencer.


Mon rôle

Je suis le plugin nymea Community du HEMS ETM-PowerSync.
Je contiens toute la logique GPL3 : recharge EV sur surplus, tarif HP/HC, protection surcharge, et le pont vers powersync-optimizer pour les tiers payants.

Licence : GPL3 — tout mon code est open-source assumé.
Origine : fork de nymea-energy-plugin-nymea (source nymea/Chargebyte, GPL3).
Pas de remote upstream Git public — mises à jour via portage manuel depuis etm-nymea/nymea-energy-plugin-nymea.


Règle fondamentale

Ce repo = fonctionnalités Community UNIQUEMENT.
Zéro logique Auto / Predict AI dans ce repo.
Ces features passent exclusivement par PowerSyncClient → optimizer.

Ce que je FOURNIS

API JSON-RPC EnergyPlugin.*

Méthode Rôle Tier
GetChargingInfos(evChargerId) Config recharge EV Community
SetChargingInfo(chargingInfo) Mettre à jour config borne EV Community
GetChargingSchedules(evChargerId) Planning calculé Community
GetAvailableSpotMarketProviders() Liste providers tarifs Community
SetSpotMarketConfiguration(enabled, providerId) Activer provider Community
GetSpotMarketScoreEntries(date) Cotations horaires Community
SetPhasePowerLimit(Uint) Protection surcharge Community
SetAcquisitionTolerance(Double) Seuil surplus Community
SetBatteryLevelConsideration(Double) Facteur batterie Community

Notifications push

ChargingInfoAdded/Removed/Changed, ChargingSchedulesChanged, SpotMarketConfigurationChanged, SpotMarketScoreEntriesChanged, PhasePowerLimitChanged

.so produit

libnymea_energypluginnymea.so   ← nom identique à l'upstream (drop-in replacement)
install : /usr/lib/nymea/energy/

Ce que je CONSOMME

Interfaces nymea (par interface, jamais par ThingClassId)

Interface États lus Actions envoyées
evcharger chargingEnabled, maxChargingCurrent, pluggedIn, charging, phases setChargingEnabled, setMaxChargingCurrent
electricvehicle batteryLevel, maxChargingCurrent, capacity
rootmeter / energymeter currentPowerPhaseA/B/C, currentPhaseA/B/C
energystorage currentPower, batteryLevel

Signal déclencheur

PowerBalanceEntryAdded depuis nymea-experience-plugin-energy → cycle ~1 min.

Service propriétaire (optionnel)

PowerSyncClient → Unix socket /run/powersync/optimizer.sock
Si absent → mode Community local, aucune erreur.


Architecture interne

powersync-energy-plugin-etm/
│
├── [code upstream nymea/Chargebyte]     ← ne pas modifier directement
│   ├── SmartChargingManager.*           ← à corriger (bugs phase EV)
│   ├── SpotMarketManager.*              ← aWATTar AT/DE ✅
│   └── NymeaEnergyJsonHandler.*         ← API JSON-RPC
│
└── etm/                                 ← tout notre code ETM ici
    ├── PowerSyncClient.*                ← pont vers optimizer (Unix socket)
    ├── tariff/
    │   └── StaticHcHpProvider.*         ← HP/HC statique (Community)
    └── [futures extensions Community]

PowerSyncClient — le pont vers l'optimizer

class PowerSyncClient : public QObject {
    Q_OBJECT
public:
    // Vérifie si powersync-optimizer tourne
    bool isAvailable() const;

    // Demande une décision d'optimisation (Auto/Predict AI)
    OptimizationResult requestOptimization(const SurplusData &data);

    // Récupère la météo J+1 (Auto)
    WeatherForecast getWeatherForecast();

    // Récupère le tarif dynamique courant (Predict AI)
    TariffData getDynamicTariff();

signals:
    void availabilityChanged(bool available);
    void optimizationResultReceived(OptimizationResult result);
};

Comportement du cycle principal :

void SmartChargingManager::runCycle() {
    if (m_powerSyncClient->isAvailable()) {
        // Auto / Predict AI — délègue à l'optimizer
        auto result = m_powerSyncClient->requestOptimization(buildSurplusData());
        applyOptimizationResult(result);
    } else {
        // Community — logique GPL3 locale
        planSurplusCharging();      // EV sur surplus
        planSpotMarketCharging();   // EV sur aWATTar
    }
}

État actuel du code

Fonctionnel

  • SmartChargingManager : recharge EV surplus (mode Eco) + aWATTar AT/DE
  • Overload protection triphasée
  • API JSON-RPC EnergyPlugin.* complète
  • Détection appareils par interface (zéro UUID hardcodé)

À corriger en priorité

Fichier Problème Priorité
evcharger.cpp:171, smartchargingmanager.cpp:394,477,517 Assume toujours phase A — faux pour EV sur phase B/C 🔴
EnergyPluginNymea::init() Pas de guard si EnergyManager* null 🟠
smartchargingmanager.cpp:59 Récurrence hebdo non terminée 🟠
smartchargingmanager.cpp:884 Planification limitée à 24h 🟠
smartchargingmanager.cpp:1835 Actions EV non séquentielles, pas de retry 🟠

À créer (code ETM dans etm/)

  • PowerSyncClient (pont Unix socket vers optimizer)
  • StaticHcHpProvider (tarif HP/HC statique — Community)

Règles de modification

  • Tout code ETM va dans etm/ — jamais dans le code upstream
  • Modifier le code upstream uniquement pour corriger des bugs (FIXME existants)
  • Tout changement d'API EnergyPlugin.* → mettre à jour INTERFACE.md
  • Ne jamais ajouter de logique Auto/Predict AI dans ce repo
  • Build : qmake energyplugin.pro && make -j$(nproc)

Portage des mises à jour nymea/Chargebyte

Quand une nouvelle version est disponible dans etm-nymea/nymea-energy-plugin-nymea :

  1. diff -r etm-nymea/nymea-energy-plugin-nymea/ powersync-energy-plugin-etm/
  2. Porter manuellement les corrections hors dossier etm/
  3. Ne jamais écraser etm/