etm-powersync-docs/ARCHITECTURE.md

14 KiB
Raw Blame History

Architecture — écosystème ETM-PowerSync

Document de référence transverse. Source de vérité ; les README de dépôt en sont des vues locales. Statut : v0.1 (structuration initiale). Les contrats d'interface sont en draft.


1. Principe directeur : deux frontières alignées

Tout l'écosystème repose sur une seule ligne, qui sépare deux choses à la fois :

Côté plugin Côté service
Licence GPL-3.0-or-later Propriétaire (ou ouvrable)
Exécution dans le processus nymead processus séparé
Données scalaire, événementiel (valeur instantanée) série temporelle (horizon)
Rôle capteurs, données, transport, règles simples intelligence (prévision, MPC, arbitrage)

La frontière de licence et la frontière technique coïncident. Un plugin nymea est lié à libnymea (GPL) et chargé dans nymead : il doit être GPL et ne contient donc aucune logique propriétaire. L'intelligence vit dans des services séparés, joints uniquement par API HTTP (« arm's length »), ce qui préserve le propriétaire. Précédent de référence : EOS, optimiseur autonome consommé par HTTP.


2. Vue d'ensemble par couches

┌─ Couche plugins nymea (GPL-3, dans nymead) ───────────────────────────┐
│  etm-powersync-plugins (mono-repo)        energy-plugin-etm           │
│  ├─ openmeteo   (Integration)             (Energy)                    │
│  ├─ linky       (Integration)             rule-based + load-management│
│  └─ tarif-api   (Integration)             + OptimizerManager          │
│  + plugins matériel existants : Keba, Eastron, Waveshare              │
└───────────────────────────────────────────────────────────────────────┘
        │ HTTP        │ TIC local   │ HTTP            │ socket/REST
        ▼             ▼             ▼                 ▼
┌─ Couche services (hors nymea) ────────────────────────────────────────┐
│  Open-Meteo self-hosted     tarif-provider        optimizer           │
│  (meteo-service)            (propriétaire/         (PROPRIÉTAIRE)     │
│   déploiement)              ouvrable)             MPC, Perez,         │
│  météo + satellite          grille TRV + RTE Tempo ombrage, arbitrage │
│                             → rank / prix                             │
└───────────────────────────────────────────────────────────────────────┘
┌─ Couche infrastructure (existante) ───────────────────────────────────┐
│  Proxmox (LXC/VM) · reverse proxy · dépôt APT (reprepro/GPG, 3 canaux)│
└───────────────────────────────────────────────────────────────────────┘

Dans les schémas, energy-plugin-etm désigne le dépôt etm-powersync-energy-plugin-etm (cf. §10).

Symétrie à retenir : pour la météo comme pour le tarif, on a un backend (produit la donnée, maintenu une fois) + un plugin GPL (l'expose dans nymea). Le plugin ne contient jamais la logique du backend.


3. Composants

Plugins nymea (GPL-3)

Les plugins d'intégration sont des modules d'un seul dépôt etm-powersync-plugins (chacun dans son sous-dossier, build et packaging communs). L'energy manager est à part (fork avec amont distinct, type de plugin différent).

Module / dépôt Type (IID) Rôle
etm-powersync-plugins/openmeteo io.nymea.IntegrationPlugin Conditions météo/solaires actuelles (GHI/DNI/DHI, GTI par pan, satellite)
etm-powersync-plugins/linky io.nymea.IntegrationPlugin Compteur principal (TIC) : option, période HC/HP, ISOUSC, couleur Tempo, puissances
etm-powersync-plugins/tarif-api io.nymea.IntegrationPlugin Client GPL d'une API tarifaire ; expose currentMarketPrice + rank
etm-powersync-energy-plugin-etm io.nymea.EnergyPlugin Energy manager : rule-based surplus, load-management, OptimizerManager
(existants) Keba, Eastron, Waveshare io.nymea.IntegrationPlugin Charges et compteurs pilotés

Services et déploiements (hors nymea)

Dépôt Licence Nature Rôle
etm-powersync-optimizer propriétaire code (FastAPI) MPC, transposition Perez, dérating NOCT, masque d'ombrage, arbitrage
etm-powersync-tarif-provider propriétaire / ouvrable code Grille TRV (maj 2×/an) + poll RTE Tempo → prix/rank par client
etm-powersync-meteo-service déploiement + how-to Instance Open-Meteo auto-hébergée (docker-compose, config sync) — pas du code applicatif

L'optimizer n'est pas un plugin : c'est le cœur de l'écosystème, composant à part entière. meteo-service documente/déploie un logiciel amont (Open-Meteo, AGPLv3) ; on ne le développe pas.

tarif-api vs tarif-provider — à ne pas confondre

  • tarif-api : le plugin GPL (client), dans etm-powersync-plugins. Façade nymea, bête.
  • tarif-provider : le backend de référence (serveur), qui produit prix/rank.
  • interfaces/tariff.md : le contrat qui les relie. Comme tarif-api parle un protocole ouvert, un tiers peut substituer son propre provider sans toucher au plugin.

4. Frontière de licence

Ne doit JAMAIS entrer dans un plugin GPL :

  • transposition Perez, dérating thermique (NOCT) ;
  • modèle de prévision, MPC, scheduling sur horizon ;
  • masque d'ombrage appris (grille azimut × élévation) ;
  • stratégie de pondération tarifaire ;
  • arbitrage économique (revente, coût de stockage).

Peut/doit être dans un plugin GPL :

  • lecture des capteurs et de l'équilibre énergétique ;
  • rule-based surplus (hystérésis, priorités) ;
  • load-management (cf. §6) ;
  • OptimizerManager = transport pur : sérialise l'état → HTTP → applique les consignes. Aucune mathématique d'optimisation.

Communication arm's length : l'optimizer et le tarif-provider sont des processus séparés joints par REST/socket. Ils ne lient pas libnymea ni aucun en-tête GPL. Échange de données, jamais de code.

Attributions à conserver :

  • code amont : copyright nymea GmbH + chargebyte (fork etm-powersync-energy-plugin-etm), licence GPL-3 ;
  • données : Météo-France / EUMETSAT / Open-Meteo (CC-BY), RTE / CRE (Tempo, TRV).

(Ceci décrit la mécanique technique, pas un avis juridique formel.)


5. Flux

                         nymea (energy experience)
                                    │
   ┌──────────────┬─────────────────┼──────────────────┬──────────────┐
 openmeteo      linky            tarif-api       energy-plugin-etm
 (weather)    (TIC: période,    (rank, prix)     ├─ rule-based      (Keba,
              ISOUSC, Tempo)                      ├─ load-management  Eastron,
   │              │                  │            └─ OptimizerManager Waveshare)
   │              │                  │                    │ (HTTP, transport)
   ▼              ▼                  ▼                    ▼
 Open-Meteo    (local)         tarif-provider ◄─── optimizer
 (meteo-                       (RTE Tempo,           (récupère lui-même
  service)                      grille TRV)           météo + tarif en série)

L'optimizer récupère lui-même ses séries (météo Open-Meteo, prix/rank du tarif-provider). Les plugins ne lui poussent que l'état temps réel et les contraintes.


6. Conventions partagées

Scalaire vs série

Plugin = valeur instantanée (état nymea). Service = série temporelle (horizon). Aucune série ne transite par un état nymea.

Azimut

Stockage en convention géographique (0=N, 90=E, 180=S, 270=O), cohérent avec les diagrammes de course du soleil et le masque d'ombrage. Conversion vers Open-Meteo au moment de la requête :

azimuth_openmeteo = azimuth_geographique  180

Vocabulaire tarifaire (states nymea, adopté tel quel)

nymea n'a pas d'interface pricing formelle ; le vocabulaire est conventionnel (cf. plugin Awattar) :

État Unité Rôle
currentMarketPrice EuroCentPerKiloWattHour prix courant
rank 0100 (plus bas = meilleur) pondération (classement de l'heure)
validUntil UnixTime fraîcheur
averagePrice / lowestPrice / highestPrice EuroCentPerKiloWattHour stats ±12 h

Pondération = rank. Le signal relatif de scheduling se mappe sur le rank natif de nymea ; rule-based et optimizer le consomment. Tout fournisseur (Awattar, Tibber, tarif-api) exposant ce vocabulaire est interchangeable du point de vue de l'energy manager.

Load-management = contrainte dure, locale, prioritaire

La surveillance de la puissance souscrite (ISOUSC, protection fusible/disjoncteur) est une fonction de sécurité : elle agit en temps réel, sans dépendre du réseau ni de l'optimizer, et a priorité absolue sur toute consigne — y compris celles de l'optimizer. C'est une contrainte appliquée après coup par le plugin, pas une suggestion envoyée à l'optimizer.

Dégradation gracieuse

Si l'optimizer est injoignable ou renvoie un planning périmé (valid_until dépassé), OptimizerManager retombe sur le rule-based local. Le plugin fonctionne toujours seul. Résilience et hygiène de licence dans le même mécanisme.


7. Contrats d'interface (draft v0.1, à versionner)

Référence détaillée et versionnée dans interfaces/.

  • interfaces/optimize.mdPOST {optimizerUrl}/optimize : état temps réel + contraintes → planning.
  • interfaces/tariff.mdGET {tariffUrl}/tariff/{client}/now (scalaire) et /forecast (série).
  • Données Open-Meteo : voir le module openmeteo (etm-powersync-plugins) et etm-powersync-meteo-service.

8. Configuration à l'installation

Un écran unique pour l'installateur (paramètres généraux de l'installation), mais deux destinations de données selon la frontière : le tarif va au tarif-provider/config locale, le matériel d'arbitrage va à l'optimizer.

Tarif consommation

  • Manuel : tarif unique ou HC/HP — saisie des prix et des plages horaires.
  • Provider : choix du fournisseur et de l'option (EDF + Base/HC-HP/Tempo, Awattar, Tibber…).
  • Sortie unifiée : rank + prix absolu (même en tarif fixe, via un rank trivial).

Tarif revente

  • Même mécanisme (manuel ou provider).
  • Cas dominant : OA surplus → constante par client. Le mécanisme identique permet de basculer en série (revente spot) sans changer le modèle.

Coût de stockage

Saisie : prix d'achat batterie, garantie (années), cycles garantis fabricant, DOD.

capacité_utile   = capacité_nominale × DOD
cycles_effectifs = min(cycles_garantis, années × cycles_par_an_estimés)
c_batt (€/kWh)   = prix_achat / (cycles_effectifs × capacité_utile)
  • Attention : les cycles fabricant sont donnés à un DOD ; le DOD qualifie la capacité utile, il ne se multiplie pas une seconde fois.
  • La garantie en années plafonne la durée de vie quand le cyclage annuel est faible (d'où le min).

Rendement

  • η (aller-retour, défaut ~0,90, ajustable) — paramètre de l'optimizer, par site.
Saisie installateur Stocké dans Nature
Tarif conso (manuel/provider) tarif-provider + config locale tarif
Tarif revente (manuel/provider) tarif-provider + config locale tarif
Prix, garantie, cycles, DOD config optimizer (par install) matériel
η config optimizer matériel

9. Niveaux d'optimisation (tiers)

Tier Optimisation Données nécessaires
Community Surplus rule-based + load-management rank (+ équilibre énergétique) plugin GPL
Auto / Predict MPC, prévision, arbitrage rank + p_achat + p_revente + c_batt + η optimizer propriétaire

Règle d'arbitrage (optimizer) — stocker/revendre n'est rentable que si l'écart de prix dépasse le coût de cycle :

p_utilisation_évitée  p_achat(t_charge) > c_batt / η      (stockage pour autoconso différée)
p_revente(t_vente)    p_achat(t_charge) > c_batt / η      (revente depuis batterie)

Sans le terme c_batt, l'optimizer sur-cycle la batterie pour des gains inexistants.

La détermination du tier (clé de licence / config) est lue par OptimizerManager, qui active ou non la stratégie distante — avec repli rule-based dans tous les cas.


10. Dépôts

Dépôt Contenu Licence
etm-powersync-docs ce document, source de vérité transverse
etm-powersync-plugins plugins GPL (modules : openmeteo, linky, tarif-api) GPL-3
etm-powersync-energy-plugin-etm energy manager (fork nymea-energy-plugin-nymea) GPL-3
etm-powersync-optimizer service d'optimisation propriétaire
etm-powersync-tarif-provider backend tarif (implémentation de référence) propriétaire / ouvrable
etm-powersync-meteo-service déploiement Open-Meteo + how-to

Chaque dépôt porte son README (vue locale + renvoi ici), un CLAUDE.md (workflow multi-agent), et ses fichiers de licence/attribution.


Annexe — points encore ouverts

  • Schéma exact et versionnement formel des contrats /optimize et /tariff (passer de draft à v1).
  • Modèle fin de c_batt (dépendance DOD/vieillissement) — plus tard ; coût plat suffisant pour démarrer.
  • Cas revente en série (spot) — prévu par le mécanisme, non prioritaire.
  • Éventuelle lib commune optimizertarif-provider (client Open-Meteo, modèles de séries) — seulement si le code partagé grossit. YAGNI pour l'instant.