mise à jour docs
This commit is contained in:
parent
dc44f79d07
commit
c7fb20a7c8
144
ARCHITECTURE.md
144
ARCHITECTURE.md
@ -11,7 +11,7 @@ Tout l'écosystème repose sur une seule ligne, qui sépare **deux choses à la
|
|||||||
|
|
||||||
| | Côté plugin | Côté service |
|
| | Côté plugin | Côté service |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **Licence** | GPL-3.0-or-later | Propriétaire |
|
| **Licence** | GPL-3.0-or-later | Propriétaire (ou ouvrable) |
|
||||||
| **Exécution** | dans le processus `nymead` | processus séparé |
|
| **Exécution** | dans le processus `nymead` | processus séparé |
|
||||||
| **Données** | scalaire, événementiel (valeur instantanée) | série temporelle (horizon) |
|
| **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) |
|
| **Rôle** | capteurs, données, transport, règles simples | intelligence (prévision, MPC, arbitrage) |
|
||||||
@ -24,26 +24,29 @@ La frontière de licence et la frontière technique **coïncident**. Un plugin n
|
|||||||
|
|
||||||
```
|
```
|
||||||
┌─ Couche plugins nymea (GPL-3, dans nymead) ───────────────────────────┐
|
┌─ Couche plugins nymea (GPL-3, dans nymead) ───────────────────────────┐
|
||||||
│ openmeteo linky tarif energy-plugin-etm │
|
│ etm-powersync-plugins (mono-repo) energy-plugin-etm │
|
||||||
│ (Integration) (Integration) (Integration) (Energy) │
|
│ ├─ openmeteo (Integration) (Energy) │
|
||||||
│ météo/solaire compteur TIC prix/rank rule-based + LM + │
|
│ ├─ linky (Integration) rule-based + load-management│
|
||||||
│ OptimizerManager │
|
│ └─ tarif-api (Integration) + OptimizerManager │
|
||||||
│ + plugins matériel existants : Keba, Eastron, Waveshare │
|
│ + plugins matériel existants : Keba, Eastron, Waveshare │
|
||||||
└────────────┬──────────────┬──────────────┬───────────────┬───────────┘
|
└───────────────────────────────────────────────────────────────────────┘
|
||||||
│ (HTTP) │ (TIC local) │ (HTTP) │ (socket/REST)
|
│ HTTP │ TIC local │ HTTP │ socket/REST
|
||||||
┌────────────▼──────────────▼──────────────▼───────────────▼───────────┐
|
▼ ▼ ▼ ▼
|
||||||
│ Couche services (hors nymea) │
|
┌─ Couche services (hors nymea) ────────────────────────────────────────┐
|
||||||
│ Open-Meteo self-hosted tarif-provider powersync-optimizer │
|
│ Open-Meteo self-hosted tarif-provider optimizer │
|
||||||
│ (serveur, données) (propriétaire) (PROPRIÉTAIRE) │
|
│ (meteo-service) (propriétaire/ (PROPRIÉTAIRE) │
|
||||||
│ météo+satellite grille TRV + RTE Tempo MPC, Perez, │
|
│ déploiement) ouvrable) MPC, Perez, │
|
||||||
│ → rank/prix ombrage, arbitrage │
|
│ météo + satellite grille TRV + RTE Tempo ombrage, arbitrage │
|
||||||
|
│ → rank / prix │
|
||||||
└───────────────────────────────────────────────────────────────────────┘
|
└───────────────────────────────────────────────────────────────────────┘
|
||||||
┌─ Couche infrastructure (existante) ───────────────────────────────────┐
|
┌─ Couche infrastructure (existante) ───────────────────────────────────┐
|
||||||
│ Proxmox (LXC/VM) · reverse proxy · dépôt APT (reprepro/GPG, 3 canaux)│
|
│ Proxmox (LXC/VM) · reverse proxy · dépôt APT (reprepro/GPG, 3 canaux)│
|
||||||
└───────────────────────────────────────────────────────────────────────┘
|
└───────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
Symétrie à retenir : pour la **météo** comme pour le **tarif**, on a *un serveur* (produit la donnée, maintenu une fois) + *un plugin GPL* (l'expose dans nymea). Le plugin ne contient jamais la logique du serveur.
|
> 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -51,23 +54,32 @@ Symétrie à retenir : pour la **météo** comme pour le **tarif**, on a *un ser
|
|||||||
|
|
||||||
### Plugins nymea (GPL-3)
|
### Plugins nymea (GPL-3)
|
||||||
|
|
||||||
| Dépôt | Type (`IID`) | Rôle |
|
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 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `openmeteo` | `io.nymea.IntegrationPlugin` | Conditions météo/solaires actuelles (GHI/DNI/DHI, GTI par pan, satellite) |
|
| `etm-powersync-plugins/openmeteo` | `io.nymea.IntegrationPlugin` | Conditions météo/solaires actuelles (GHI/DNI/DHI, GTI par pan, satellite) |
|
||||||
| `linky` | `io.nymea.IntegrationPlugin` | Compteur principal (TIC) : option, période HC/HP, `ISOUSC`, couleur Tempo, puissances |
|
| `etm-powersync-plugins/linky` | `io.nymea.IntegrationPlugin` | Compteur principal (TIC) : option, période HC/HP, `ISOUSC`, couleur Tempo, puissances |
|
||||||
| `tarif` | `io.nymea.IntegrationPlugin` | Façade nymea du `tarif-provider` : expose `currentMarketPrice` + `rank` |
|
| `etm-powersync-plugins/tarif-api` | `io.nymea.IntegrationPlugin` | Client GPL d'une API tarifaire ; expose `currentMarketPrice` + `rank` |
|
||||||
| `energy-plugin-etm` | `io.nymea.EnergyPlugin` | Energy manager : rule-based surplus, load-management, `OptimizerManager` |
|
| `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 |
|
| *(existants)* Keba, Eastron, Waveshare | `io.nymea.IntegrationPlugin` | Charges et compteurs pilotés |
|
||||||
|
|
||||||
### Services (hors nymea)
|
### Services et déploiements (hors nymea)
|
||||||
|
|
||||||
| Composant | Licence | Nature | Rôle |
|
| Dépôt | Licence | Nature | Rôle |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| `powersync-optimizer` | **propriétaire** | FastAPI, service | MPC, transposition Perez, dérating NOCT, masque d'ombrage, arbitrage |
|
| `etm-powersync-optimizer` | **propriétaire** | code (FastAPI) | MPC, transposition Perez, dérating NOCT, masque d'ombrage, arbitrage |
|
||||||
| Open-Meteo self-hosted | AGPLv3 (amont) | serveur | Produit la donnée météo/satellite (prod commerciale) |
|
| `etm-powersync-tarif-provider` | propriétaire / **ouvrable** | code | Grille TRV (maj 2×/an) + poll RTE Tempo → prix/`rank` par client |
|
||||||
| `tarif-provider` | propriétaire | service | 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 |
|
||||||
|
|
||||||
> Le `powersync-optimizer` n'est **pas** un plugin : c'est le cœur de l'écosystème, composant à part entière.
|
> 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -88,10 +100,10 @@ Symétrie à retenir : pour la **météo** comme pour le **tarif**, on a *un ser
|
|||||||
- load-management (cf. §6) ;
|
- load-management (cf. §6) ;
|
||||||
- `OptimizerManager` = **transport pur** : sérialise l'état → HTTP → applique les consignes. Aucune mathématique d'optimisation.
|
- `OptimizerManager` = **transport pur** : sérialise l'état → HTTP → applique les consignes. Aucune mathématique d'optimisation.
|
||||||
|
|
||||||
**Communication arm's length** : l'optimiseur 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.
|
**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 :**
|
**Attributions à conserver :**
|
||||||
- code amont : copyright nymea GmbH + chargebyte (fork `energy-plugin-etm`), licence GPL-3 ;
|
- 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).
|
- 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.)*
|
*(Ceci décrit la mécanique technique, pas un avis juridique formel.)*
|
||||||
@ -104,18 +116,18 @@ Symétrie à retenir : pour la **météo** comme pour le **tarif**, on a *un ser
|
|||||||
nymea (energy experience)
|
nymea (energy experience)
|
||||||
│
|
│
|
||||||
┌──────────────┬─────────────────┼──────────────────┬──────────────┐
|
┌──────────────┬─────────────────┼──────────────────┬──────────────┐
|
||||||
openmeteo linky tarif energy-plugin-etm (Keba,
|
openmeteo linky tarif-api energy-plugin-etm
|
||||||
(weather) (TIC: période, (rank, prix) ├─ rule-based Eastron,
|
(weather) (TIC: période, (rank, prix) ├─ rule-based (Keba,
|
||||||
ISOUSC, Tempo) ├─ load-management Waveshare)
|
ISOUSC, Tempo) ├─ load-management Eastron,
|
||||||
│ │ │ └─ OptimizerManager
|
│ │ │ └─ OptimizerManager Waveshare)
|
||||||
│ │ │ │ (HTTP, transport)
|
│ │ │ │ (HTTP, transport)
|
||||||
▼ ▼ ▼ ▼
|
▼ ▼ ▼ ▼
|
||||||
Open-Meteo (local) tarif-provider ◄─── powersync-optimizer
|
Open-Meteo (local) tarif-provider ◄─── optimizer
|
||||||
self-hosted (RTE Tempo, (récupère lui-même
|
(meteo- (RTE Tempo, (récupère lui-même
|
||||||
grille TRV) météo + tarif en série)
|
service) grille TRV) météo + tarif en série)
|
||||||
```
|
```
|
||||||
|
|
||||||
L'optimiseur 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.
|
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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -140,51 +152,29 @@ nymea n'a **pas** d'interface `pricing` formelle ; le vocabulaire est convention
|
|||||||
| `validUntil` | `UnixTime` | fraîcheur |
|
| `validUntil` | `UnixTime` | fraîcheur |
|
||||||
| `averagePrice` / `lowestPrice` / `highestPrice` | `EuroCentPerKiloWattHour` | stats ±12 h |
|
| `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 optimiseur le consomment. Tout fournisseur (Awattar, Tibber, `tarif`) exposant ce vocabulaire est interchangeable du point de vue de l'energy manager.
|
**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
|
### 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'optimiseur, et a **priorité absolue** sur toute consigne — y compris celles de l'optimiseur. C'est une contrainte appliquée *après coup* par le plugin, pas une suggestion envoyée à l'optimiseur.
|
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
|
### Dégradation gracieuse
|
||||||
Si l'optimiseur 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.
|
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)
|
## 7. Contrats d'interface (draft v0.1, à versionner)
|
||||||
|
|
||||||
### `POST {optimizerUrl}/optimize`
|
Référence détaillée et versionnée dans [`interfaces/`](interfaces/README.md).
|
||||||
État temps réel + contraintes → planning. L'optimiseur a déjà ses séries météo/tarif.
|
|
||||||
```jsonc
|
|
||||||
// requête
|
|
||||||
{
|
|
||||||
"timestamp": 0,
|
|
||||||
"site": { "gridPower": 0, "pvPower": 0, "batterySoc": 0 },
|
|
||||||
"loads": [ { "id": "keba1", "type": "evcharger",
|
|
||||||
"controllable": true, "min": 6, "max": 16, "constraints": {} } ]
|
|
||||||
}
|
|
||||||
// réponse
|
|
||||||
{
|
|
||||||
"valid_until": 0, // garde de fraîcheur
|
|
||||||
"setpoints": [ { "id": "keba1", "current": 10, "from": 0, "to": 0 } ]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### `GET {tariffUrl}/tariff/{client}/now` et `/forecast`
|
- [`interfaces/optimize.md`](interfaces/optimize.md) — `POST {optimizerUrl}/optimize` : état temps réel + contraintes → planning.
|
||||||
```jsonc
|
- [`interfaces/tariff.md`](interfaces/tariff.md) — `GET {tariffUrl}/tariff/{client}/now` (scalaire) et `/forecast` (série).
|
||||||
// /now → scalaire (consommé par le plugin)
|
- Données Open-Meteo : voir le module `openmeteo` (`etm-powersync-plugins`) et `etm-powersync-meteo-service`.
|
||||||
{ "rank": 18, "price": 13.25, "validUntil": 0 } // price en c€/kWh
|
|
||||||
// /forecast → série (consommée par l'optimiseur)
|
|
||||||
{ "horizon": [ { "t": 0, "rank": 18, "buy": 13.25, "sell": 10.0 } ] }
|
|
||||||
```
|
|
||||||
|
|
||||||
### Données Open-Meteo
|
|
||||||
Voir le `README`/docs du dépôt `openmeteo` (variables, requêtes, conventions). Endpoint prévision (Météo-France) + endpoint satellite (MTG).
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. Configuration à l'installation
|
## 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'optimiseur.
|
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
|
### Tarif consommation
|
||||||
- **Manuel** : tarif unique *ou* HC/HP — saisie des prix et des plages horaires.
|
- **Manuel** : tarif unique *ou* HC/HP — saisie des prix et des plages horaires.
|
||||||
@ -206,14 +196,14 @@ c_batt (€/kWh) = prix_achat / (cycles_effectifs × capacité_utile)
|
|||||||
- La garantie en années plafonne la durée de vie quand le cyclage annuel est faible (d'où le `min`).
|
- La garantie en années plafonne la durée de vie quand le cyclage annuel est faible (d'où le `min`).
|
||||||
|
|
||||||
### Rendement
|
### Rendement
|
||||||
- `η` (aller-retour, défaut ~0,90, ajustable) — paramètre de l'optimiseur, par site.
|
- `η` (aller-retour, défaut ~0,90, ajustable) — paramètre de l'optimizer, par site.
|
||||||
|
|
||||||
| Saisie installateur | Stocké dans | Nature |
|
| Saisie installateur | Stocké dans | Nature |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Tarif conso (manuel/provider) | tarif-provider + config locale | tarif |
|
| Tarif conso (manuel/provider) | tarif-provider + config locale | tarif |
|
||||||
| Tarif revente (manuel/provider) | tarif-provider + config locale | tarif |
|
| Tarif revente (manuel/provider) | tarif-provider + config locale | tarif |
|
||||||
| Prix, garantie, cycles, DOD | config optimiseur (par install) | matériel |
|
| Prix, garantie, cycles, DOD | config optimizer (par install) | matériel |
|
||||||
| `η` | config optimiseur | matériel |
|
| `η` | config optimizer | matériel |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -222,14 +212,14 @@ c_batt (€/kWh) = prix_achat / (cycles_effectifs × capacité_utile)
|
|||||||
| Tier | Optimisation | Données nécessaires | Où |
|
| Tier | Optimisation | Données nécessaires | Où |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| **Community** | Surplus rule-based + load-management | `rank` (+ équilibre énergétique) | plugin GPL |
|
| **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` + `η` | optimiseur propriétaire |
|
| **Auto / Predict** | MPC, prévision, arbitrage | `rank` + `p_achat` + `p_revente` + `c_batt` + `η` | optimizer propriétaire |
|
||||||
|
|
||||||
**Règle d'arbitrage** (optimiseur) — stocker/revendre n'est rentable que si l'écart de prix dépasse le coût de cycle :
|
**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_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)
|
p_revente(t_vente) − p_achat(t_charge) > c_batt / η (revente depuis batterie)
|
||||||
```
|
```
|
||||||
Sans le terme `c_batt`, l'optimiseur sur-cycle la batterie pour des gains inexistants.
|
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.
|
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.
|
||||||
|
|
||||||
@ -240,12 +230,11 @@ La détermination du tier (clé de licence / config) est lue par `OptimizerManag
|
|||||||
| Dépôt | Contenu | Licence |
|
| Dépôt | Contenu | Licence |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `etm-powersync-docs` | ce document, source de vérité transverse | — |
|
| `etm-powersync-docs` | ce document, source de vérité transverse | — |
|
||||||
| `openmeteo` (nymea-plugin) | plugin météo/solaire | GPL-3 |
|
| `etm-powersync-plugins` | plugins GPL (modules : `openmeteo`, `linky`, `tarif-api`) | GPL-3 |
|
||||||
| `linky` (nymea-plugin) | plugin compteur TIC | GPL-3 |
|
| `etm-powersync-energy-plugin-etm` | energy manager (fork nymea-energy-plugin-nymea) | GPL-3 |
|
||||||
| `tarif-api` (nymea-plugin) | plugin façade tarif | GPL-3 |
|
| `etm-powersync-optimizer` | service d'optimisation | propriétaire |
|
||||||
| `powersync-energy-plugin-etm` | energy manager (fork nymea-energy-plugin-nymea) | GPL-3 |
|
| `etm-powersync-tarif-provider` | backend tarif (implémentation de référence) | propriétaire / ouvrable |
|
||||||
| `powersync-optimizer` | service d'optimisation | propriétaire |
|
| `etm-powersync-meteo-service` | déploiement Open-Meteo + how-to | — |
|
||||||
| `tarif-provider` | service tarif central | propriétaire |
|
|
||||||
|
|
||||||
Chaque dépôt porte son `README` (vue locale + renvoi ici), un `CLAUDE.md` (workflow multi-agent), et ses fichiers de licence/attribution.
|
Chaque dépôt porte son `README` (vue locale + renvoi ici), un `CLAUDE.md` (workflow multi-agent), et ses fichiers de licence/attribution.
|
||||||
|
|
||||||
@ -256,3 +245,4 @@ Chaque dépôt porte son `README` (vue locale + renvoi ici), un `CLAUDE.md` (wor
|
|||||||
- Schéma exact et versionnement formel des contrats `/optimize` et `/tariff` (passer de `draft` à `v1`).
|
- 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.
|
- 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.
|
- Cas revente en série (spot) — prévu par le mécanisme, non prioritaire.
|
||||||
|
- Éventuelle lib commune `optimizer` ↔ `tarif-provider` (client Open-Meteo, modèles de séries) — seulement si le code partagé grossit. YAGNI pour l'instant.
|
||||||
|
|||||||
22
interfaces/README.md
Normal file
22
interfaces/README.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Contrats d'interface
|
||||||
|
|
||||||
|
Référence unique et **versionnée** des interfaces entre composants. Tout dépôt (plugin ou service) qui implémente ou consomme une de ces interfaces cite la version exacte définie ici.
|
||||||
|
|
||||||
|
## Contrats
|
||||||
|
|
||||||
|
| Contrat | Producteur | Consommateur(s) | Version |
|
||||||
|
|---|---|---|---|
|
||||||
|
| [`optimize`](optimize.md) | `etm-powersync-optimizer` | `etm-powersync-plugin-etm` (`OptimizerManager`) | 0.1 (draft) |
|
||||||
|
| [`tariff`](tariff.md) | `etm-powersync-tarif-provider` | `tarif-api` (plugin), `etm-powersync-optimizer` | 0.1 (draft) |
|
||||||
|
| `openmeteo` | Open-Meteo (self-hosted, `etm-powersync-meteo-service`) | module `openmeteo`, `etm-powersync-optimizer` | voir module `openmeteo` |
|
||||||
|
|
||||||
|
## Politique de versionnement
|
||||||
|
|
||||||
|
- **`draft`** : en construction, peut changer sans préavis. Statut actuel de tous les contrats.
|
||||||
|
- **`vN`** (gelé) : une fois figé, un contrat `vN` ne change plus de façon incompatible. Toute rupture donne un `v(N+1)`.
|
||||||
|
- Le passage `draft → v1` se fait par décision actée dans `ARCHITECTURE.md` (annexe « points ouverts »).
|
||||||
|
- Conventions transverses (unités, azimut, vocabulaire `rank`) : définies dans `ARCHITECTURE.md`, non redéfinies ici.
|
||||||
|
|
||||||
|
## Règle
|
||||||
|
|
||||||
|
Un changement de contrat se décide **ici d'abord**, puis se répercute dans les dépôts producteur et consommateur. Jamais l'inverse.
|
||||||
68
interfaces/optimize.md
Normal file
68
interfaces/optimize.md
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
# Contrat `optimize` — v0.1 (draft)
|
||||||
|
|
||||||
|
- **Producteur** : `etm-powersync-optimizer` (propriétaire)
|
||||||
|
- **Consommateur** : `etm-powersync-plugin-etm` → `OptimizerManager` (GPL, transport pur)
|
||||||
|
- **Transport** : HTTP REST, `POST {optimizerUrl}/optimize`
|
||||||
|
|
||||||
|
## Principe
|
||||||
|
|
||||||
|
Le plugin envoie un **instantané** de l'état temps réel et des contraintes ; l'optimiseur renvoie un **planning** sur l'horizon. L'optimiseur possède déjà ses séries (météo Open-Meteo, prix/`rank` du `tarif-provider`) et la configuration matérielle du site (capacité batterie, `c_batt`, `η`). Ces dernières **ne sont pas** renvoyées à chaque appel.
|
||||||
|
|
||||||
|
## Requête
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"timestamp": 0, // epoch (s) de l'instantané
|
||||||
|
"site": {
|
||||||
|
"gridPower": 0, // W, signé (+ = soutirage, − = injection)
|
||||||
|
"pvPower": 0, // W produits
|
||||||
|
"batterySoc": 0, // %, état de charge courant
|
||||||
|
"batteryPower": 0 // W, signé (+ = charge, − = décharge) — TODO confirmer signe
|
||||||
|
},
|
||||||
|
"loads": [
|
||||||
|
{
|
||||||
|
"id": "keba1",
|
||||||
|
"type": "evcharger", // evcharger | heatpump | waterheater | relay | ...
|
||||||
|
"controllable": true,
|
||||||
|
"min": 6, // borne basse (A ou W selon type) — TODO unifier unité
|
||||||
|
"max": 16, // borne haute
|
||||||
|
"constraints": {} // TODO schéma (échéance VE, température cible PAC, etc.)
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Réponse
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"valid_until": 0, // epoch (s) — au-delà, le plugin retombe sur le rule-based
|
||||||
|
"mode": "optimized", // optimized | fallback — TODO utilité ?
|
||||||
|
"setpoints": [
|
||||||
|
{
|
||||||
|
"id": "keba1",
|
||||||
|
"current": 10, // consigne (A ou W selon type)
|
||||||
|
"from": 0, // epoch (s) début d'application
|
||||||
|
"to": 0 // epoch (s) fin
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"battery": { // optionnel — consigne batterie si arbitrage actif
|
||||||
|
"power": 0, // W, signé (+ = charge, − = décharge)
|
||||||
|
"from": 0,
|
||||||
|
"to": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Règles de consommation (côté plugin)
|
||||||
|
|
||||||
|
- Le plugin applique les `setpoints` **tels quels** (transport pur, aucune logique d'optimisation).
|
||||||
|
- **Le load-management reste prioritaire** : toute consigne qui ferait dépasser `ISOUSC` est écrêtée localement par le plugin, après réception. L'optimiseur propose, le plugin garantit la sécurité.
|
||||||
|
- Si `valid_until` est dépassé, si la réponse est invalide, ou si l'optimiseur est injoignable → repli immédiat sur la stratégie rule-based locale.
|
||||||
|
|
||||||
|
## Points ouverts (à figer pour v1)
|
||||||
|
|
||||||
|
- Représentation des bornes `min`/`max` : ampères vs watts selon le type de charge — unifier ou typer explicitement.
|
||||||
|
- Schéma des `constraints` par type de charge (échéance et SoC cible VE, consigne thermique PAC…).
|
||||||
|
- Signe et sémantique de `batteryPower` (requête) et `battery.power` (réponse).
|
||||||
|
- Utilité réelle du champ `mode`.
|
||||||
55
interfaces/tariff.md
Normal file
55
interfaces/tariff.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Contrat `tariff` — v0.1 (draft)
|
||||||
|
|
||||||
|
- **Producteur** : `etm-powersync-tarif-provider` (propriétaire, self-hosted)
|
||||||
|
- **Consommateurs** : plugin `tarif-api` (scalaire `/now`) et `etm-powersync-optimizer` (série `/forecast`)
|
||||||
|
- **Transport** : HTTP REST
|
||||||
|
|
||||||
|
## Principe
|
||||||
|
|
||||||
|
Le `etm-powersync-tarif-provider` central maintient la grille TRV (mise à jour 2×/an), interroge l'API RTE Tempo (un seul compte pour tout le parc) et résout le contrat de chaque client. Il expose :
|
||||||
|
|
||||||
|
- `/now` → un **scalaire** pour le plugin nymea (vocabulaire `rank` / `currentMarketPrice`) ;
|
||||||
|
- `/forecast` → une **série** pour l'optimiseur (pondération + prix achat/revente sur l'horizon).
|
||||||
|
|
||||||
|
Conventions (définies dans `ARCHITECTURE.md`) : `rank` ∈ [0,100], plus bas = meilleur ; prix en **c€/kWh** (`EuroCentPerKiloWattHour`).
|
||||||
|
|
||||||
|
## `GET {tariffUrl}/tariff/{client}/now`
|
||||||
|
|
||||||
|
Consommé par le plugin `tarif-api` → states nymea.
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"rank": 18, // 0–100, classement de l'heure courante
|
||||||
|
"buy": 13.25, // c€/kWh, prix d'achat courant
|
||||||
|
"sell": 10.00, // c€/kWh, prix de revente courant (constante OA le plus souvent)
|
||||||
|
"validUntil": 0 // epoch (s)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `GET {tariffUrl}/tariff/{client}/forecast`
|
||||||
|
|
||||||
|
Consommé par l'optimiseur → série sur l'horizon.
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
{
|
||||||
|
"horizon": [
|
||||||
|
{ "t": 0, "rank": 18, "buy": 13.25, "sell": 10.00 }
|
||||||
|
// un point par pas (horaire, ou 15-min selon disponibilité)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Résolution du tarif (côté serveur, non exposé)
|
||||||
|
|
||||||
|
Le client choisit à l'installation (cf. `ARCHITECTURE.md` §8) :
|
||||||
|
- **manuel** : tarif fixe ou HC/HP (prix + plages) → `rank` trivial (fixe = plat ; HC/HP = HC bas, HP haut) ;
|
||||||
|
- **provider** : EDF (Base/HC-HP/Tempo), Awattar, Tibber… → `rank` calculé sur le flux.
|
||||||
|
|
||||||
|
Dans tous les cas, la sortie est **unifiée** : l'optimiseur et le plugin ne voient que `rank` + `buy` + `sell`, jamais la logique de résolution.
|
||||||
|
|
||||||
|
## Points ouverts (à figer pour v1)
|
||||||
|
|
||||||
|
- Identification du client : segment d'URL `{client}`, en-tête, ou jeton ? Authentification du parc.
|
||||||
|
- `sell` : champ par point dans `forecast` (permet le cas revente spot) ou constante renvoyée à part quand OA ? Le mécanisme par point couvre les deux, au prix d'une légère redondance.
|
||||||
|
- Pas de temps de `forecast` (horaire vs 15-min) et profondeur d'horizon.
|
||||||
|
- Méthode de normalisation du `rank` (ratio autour de la moyenne vs rang/quantile) — décidée côté serveur, mais à documenter pour la reproductibilité.
|
||||||
Loading…
x
Reference in New Issue
Block a user