# 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

```cpp
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 :**
```cpp
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/`
