diff --git a/docs/architecture_cariflex_v2.pdf b/docs/architecture_cariflex_v2.pdf new file mode 100644 index 0000000..9b1256e Binary files /dev/null and b/docs/architecture_cariflex_v2.pdf differ diff --git a/docs/architecture_cariflex_v2.png b/docs/architecture_cariflex_v2.png new file mode 100644 index 0000000..e511dd8 Binary files /dev/null and b/docs/architecture_cariflex_v2.png differ diff --git a/docs/architecture_diagrams_v2.md b/docs/architecture_diagrams_v2.md new file mode 100644 index 0000000..46883e5 --- /dev/null +++ b/docs/architecture_diagrams_v2.md @@ -0,0 +1,248 @@ +# Cariflex - Diagrammes d'Architecture v2 + +> Mise à jour avec OCPI et GIREVE + +## 1. Architecture Générale + +```mermaid +graph TB + subgraph EXTERNAL["External Layer"] + EPEX["EPEX SPOT
Day-ahead Prices"] + ENTSOE["ENTSO-E
CO2/Prices"] + WEATHER["Weather API
Solcast/Météo"] + DSO["DSO/TSO
OpenADR/S2"] + end + + subgraph INTEROP["Interoperability Layer"] + OCPI["OCPI Gateway
━━━━━━━━━━━━━━
• Tarifs • Sessions
• CDRs • Roaming
• Commands"] + GIREVE["GIREVE Connector
━━━━━━━━━━━━━━
• Session data
• Roaming hub
• Billing
• PNIRE"] + end + + subgraph INTEGRATION["Integration Layer"] + FM["FlexMeasures EMS
━━━━━━━━━━━━━━
• Ingestion
• Forecasting
• Scheduling
• Reporting"] + + CITRINEOS["CitrineOS
CSMS
━━━━━━━━━━━━━━
• OCPP 2.0.1
• Charge Points
• Transactions"] + + EVEREST["EVerest
Middleware
━━━━━━━━━━━━━━
• ISO 15118
• Smart Charging
• Power Mgmt"] + + OPENLEADR["OpenLEADR
VEN Client
━━━━━━━━━━━━━━
• OpenADR 2.0b
• DSO Signals
• Flexibility"] + end + + subgraph MARKET["Market Layer (R&D)"] + GSY["Grid Singularity
gsy-e
━━━━━━━━━━━━━━
• P2P Trading
• Market Clearing"] + + OPLEM["OPLEM
━━━━━━━━━━━━━━
• Local Market
• Prosumer Opt."] + + HAMLET["HAMLET
━━━━━━━━━━━━━━
• Multi-agent
• Simulation"] + end + + subgraph DEVICES["Device Layer"] + PV["10 PV Panels
5kWc"] + BAT["10 Batteries
100kWh"] + EV["10 EVs
75kWh V2G"] + CHG["10 EV Chargers
22kW"] + end + + subgraph VIZ["Visualization"] + GRAFANA["Grafana
Dashboards"] + METABASE["Metabase
Analytics"] + CARIFLEX_UI["Cariflex UI
FM Frontend"] + end + + %% External to Interop + DSO -->|"Flex Requests"| OPENLEADR + EPEX -->|"Prices"| FM + ENTSOE -->|"CO2/Prices"| FM + WEATHER -->|"Irradiance"| FM + + %% Interop layer + OCPI <-->|"OCPI 2.2"| OtherCPOs["Other CPOs
(Roaming)"] + GIREVE <-->|"eMSP API"| GIREVEPlatform["GIREVE Platform"] + OCPI -->|"Session data"| FM + GIREVE -->|"CDRs/Sessions"| FM + + %% Integration to FM + CITRINEOS -->|"OCPP/REST"| FM + EVEREST -->|"OCPP"| CITRINEOS + OPENLEADR -->|"REST API"| FM + + %% Market to FM + GSY <-.->|"gsy-e-sdk"| FM + OPLEM <-.->|"sensor data"| FM + HAMLET <-.->|"forecasts"| FM + + %% Devices + PV -->|"Modbus"| FM + BAT -->|"Modbus"| FM + EV -->|"ISO 15118"| EVEREST + CHG -->|"OCPP 2.0.1"| CITRINEOS + + %% FM to Viz + FM -->|"PostgreSQL"| GRAFANA + FM -->|"PostgreSQL"| METABASE + FM -->|"REST API"| CARIFLEX_UI + + style FM fill:#2196F3,stroke:#1565C0,color:#fff + style OCPI fill:#E91E63,stroke:#C2185B,color:#fff + style GIREVE fill:#795548,stroke:#5D4037,color:#fff + style CITRINEOS fill:#4CAF50,stroke:#388E3C,color:#fff + style EVEREST fill:#FF9800,stroke:#F57C00,color:#fff + style OPENLEADR fill:#9C27B0,stroke:#7B1FA2,color:#fff + style GSY fill:#00BCD4,stroke:#0097A7,color:#fff +``` + +## 2. Flux OCPI - Session de Recharge + +```mermaid +sequenceDiagram + participant EV as EV Driver + participant CP as Charge Point + participant CitrineOS as CitrineOS CSMS + participant FM as FlexMeasures + participant OCPI as OCPI Gateway + participant OtherCPO as Other CPO + + %% Session start + EV->>CP: Plug in (RFID/App) + CP->>CitrineOS: StartTransaction + CitrineOS->>FM: POST /sensors/{id}/data (power) + FM->>OCPI: Check roaming rights + OCPI->>OtherCPO: POST /cdrs (session start) + OtherCPO-->>OCPI: 200 OK + OCPI-->>FM: Authorized + + %% Charging loop + loop Every 30s + CitrineOS->>FM: Power readings + FM->>OCPI: Update session + OCPI->>OtherCPO: PATCH /sessions/{id} + end + + %% Session end + EV->>CP: Unplug + CP->>CitrineOS: StopTransaction + CitrineOS->>FM: Final readings + FM->>OCPI: Generate CDR + OCPI->>OtherCPO: POST /cdrs + OtherCPO-->>OCPI: CDR accepted +``` + +## 3. Flux GIREVE - Session de Recharge + +```mermaid +sequenceDiagram + participant EV as EV Driver + participant CP as Charge Point + participant CitrineOS as CitrineOS CSMS + participant FM as FlexMeasures + participant GIREVE as GIREVE Platform + + %% Session start + EV->>CP: Start charging + CP->>CitrineOS: StartTransaction + CitrineOS->>FM: POST /sensors/{id}/data + FM->>GIREVE: POST /session (session start) + GIREVE-->>FM: Session acknowledged + + %% Charging loop + loop Every 30s + CitrineOS->>FM: Power readings + FM->>GIREVE: PATCH /session/{id} (consumption) + end + + %% Session end + EV->>CP: Stop charging + CP->>CitrineOS: StopTransaction + CitrineOS->>FM: Final readings + FM->>GIREVE: POST /cdr (final CDR) + GIREVE-->>FM: CDR accepted +``` + +## 4. Intégration Complète - Tous les Composants + +```mermaid +sequenceDiagram + participant GIREVE as GIREVE + participant OCPI as OCPI Gateway + participant FM as FlexMeasures + participant OpenLEADR as OpenLEADR + participant CitrineOS as CitrineOS + participant EVEREST as EVerest + participant EV as EV + participant BAT as Battery + participant PV as Panel + + %% Data ingestion + PV->>FM: Power readings (30s) + BAT->>FM: SOC readings (30s) + EVEREST->>CitrineOS: OCPP + CitrineOS->>FM: EV power readings + + %% Interoperability + FM->>GIREVE: Sessions + CDRs + FM->>OCPI: Tariffs + Sessions + OCPI->>OtherCPOs: Roaming + + %% Forecasting + FM->>FM: TrainPredictPipeline (daily) + FM->>DB: Save forecasts + + %% Scheduling (triggered by OpenADR) + DSO->>OpenLEADR: Flexibility request + OpenLEADR->>FM: POST /schedules/trigger + FM->>FM: StorageScheduler optimize + FM->>DB: Save schedule + FM->>CitrineOS: Charging profile + CitrineOS->>EVEREST: OCPP commands + EVEREST->>EV: Start/stop charging +``` + +## 5. Architecture Réseau Docker + +```mermaid +graph LR + subgraph Docker["Docker Network: cariflex-internal"] + FM_SRV["flexmeasures-server:5000"] + FM_WRK["flexmeasures-worker:5000"] + FM_DB["flexmeasures-db:5432"] + FM_REDIS["flexmeasures-redis:6379"] + + CITRINEOS["citrineos-server:8080"] + EVEREST["everest:8080"] + OCPI_GW["ocpi-gateway:8081"] + GIREVE_CONN["gireve-connector:8082"] + GSY["gsy-e:8080"] + end + + subgraph Traefik["Traefik (websecure)"] + ROUTER_FM["Router: cariflex.digitribe.fr"] + ROUTER_OCPI["Router: ocpi.cariflex.digitribe.fr"] + end + + ROUTER_FM -->|"HTTPS"| FM_SRV + ROUTER_OCPI -->|"HTTPS"| OCPI_GW + FM_SRV -->|"REST"| FM_WRK + FM_WRK -->|"RQ"| FM_REDIS + FM_WRK -->|"SQL"| FM_DB + FM_SRV -->|"SQL"| FM_DB + + CITRINEOS -->|"REST"| FM_SRV + EVEREST -->|"OCPP"| CITRINEOS + OCPI_GW -->|"REST"| FM_SRV + GIREVE_CONN -->|"REST"| FM_SRV + GSY -->|"REST"| FM_SRV +``` + +## 6. TODO - Intégrations + +| Intégration | Priorité | Complexité | Statut | +|-------------|----------|------------|--------| +| **OCPI Gateway** | Haute | Élevée | 📋 À faire | +| **GIREVE Connector** | Haute | Moyenne | 📋 À faire | +| **CitrineOS ↔ FM** | Haute | Moyenne | ⏳ À faire | +| **EVerest ↔ CitrineOS** | Haute | Moyenne | ⏳ À faire | +| **OpenLEADR ↔ FM** | Haute | Faible | ⏳ À faire | +| **Grid Singularity ↔ FM** | Moyenne | Élevée | ⏳ À faire | +| **OPLEM ↔ FM** | Moyenne | Moyenne | ⏳ À faire | +| **HAMLET ↔ FM** | Basse | Élevée | ⏳ À faire | +| **MQTT Brokers Cariflex** | Haute | Moyenne | ⏳ À faire | diff --git a/docs/architecture_v2.md b/docs/architecture_v2.md new file mode 100644 index 0000000..a246916 --- /dev/null +++ b/docs/architecture_v2.md @@ -0,0 +1,420 @@ +# Cariflex - Architecture d'Intégration EMS v2 + +> Documentation de l'architecture Cariflex - Plateforme d'Energy Management System +> **Mise à jour :** Intégration OCPI et GIREVE + +--- + +## 1. Vue d'Ensemble + +Cariflex est une plateforme EMS (Energy Management System) pour la Martinique, intégrant : + +### Composants Principaux +| Composant | Rôle | Protocole | Statut | +|-----------|------|-----------|--------| +| **FlexMeasures** | Moteur central EMS | REST API | ✅ Installé | +| **CitrineOS** | CSMS (Charge Station Management) | OCPP 2.0.1 | ✅ Extrait | +| **EVerest** | Middleware EV charging | OCPP/ISO 15118 | ✅ Extrait | +| **OpenLEADR** | Communication DSO | OpenADR 2.0b | ✅ Installé | +| **Grid Singularity** | Marché P2P | gsy-e-sdk | ✅ Extrait | +| **OPLEM** | Marché local | Python | ✅ Installé | +| **HAMLET** | Simulation LEM | Agent-based | ✅ Extrait | +| **OCPI** | Interopérabilité EV | OCPI 2.2 | 📋 À intégrer | +| **GIREVE** | Plateforme interop GIREVE | eMSP API | 📋 À intégrer | + +### Glossaire +- **OCPI** : Open Charge Point Interface - Protocole d'échange entre opérateurs de bornes +- **GIREVE** : Plateforme d'interopérabilité pour la mobilité électrique +- **eMSP** : E-Mobility Service Provider +- **CPO** : Charge Point Operator +- **CSMS** : Charge Station Management System +- **OCPP** : Open Charge Point Protocol + +--- + +## 2. Architecture Fonctionnelle Complète + +``` +┌─────────────────────────────────────────────────────────────────────────────────────────────┐ +│ CARIFLEX EMS - ARCHITECTURE v2 │ +├─────────────────────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────────────────────────────────────┐ │ +│ │ EXTERNAL LAYER │ │ +│ │ │ │ +│ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ +│ │ │ EPEX SPOT │ │ ENTSO-E │ │ Weather API │ │ DSO/TSO │ │ │ +│ │ │ (Day-ahead) │ │ (Prices, │ │ (Solcast, │ │ (OpenADR/ │ │ │ +│ │ │ Localflex) │ │ CO2) │ │ Météo) │ │ S2) │ │ │ +│ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ +│ │ │ │ │ │ │ │ +│ │ └─────────────────┴─────────────────┴─────────────────┘ │ │ +│ │ │ │ │ +│ │ ┌──────────────────────────────────────────────────────┼───────────────────────────┐ │ │ +│ │ │ INTEROPERABILITY LAYER │ │ │ │ +│ │ │ ▼ │ │ │ +│ │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ +│ │ │ │ OCPI │ │ GIREVE │ │ OpenLEADR │ │ │ │ +│ │ │ │ (eMSP/CPO) │ │ (Platform) │ │ (VEN) │ │ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ +│ │ │ │ • Tarifs │ │ • Session │ │ • Flex │ │ │ │ +│ │ │ │ • Sessions │ │ data │ │ requests │ │ │ │ +│ │ │ │ • CDRs │ │ • Roaming │ │ • Events │ │ │ │ +│ │ │ │ • Roaming │ │ • Billing │ │ • Reports │ │ │ │ +│ │ │ │ • Commands │ │ • CDRs │ │ │ │ │ │ +│ │ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │ │ │ +│ │ │ │ │ │ │ │ │ +│ │ └─────────┼─────────────────┼─────────────────┼────────────────────────────────────┘ │ │ +│ │ │ │ │ │ │ +│ │ ▼ ▼ ▼ │ │ +│ │ ┌──────────────────────────────────────────────────────────────────────────────────┐ │ │ +│ │ │ FLEXMEASURES EMS │ │ │ +│ │ │ │ │ │ +│ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ +│ │ │ │ INGESTION │ │ FORECAST │ │ SCHEDULING │ │ REPORTING │ │ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ │ │ +│ │ │ │ • Sensors │ │ • PV │ │ • Batteries │ │ • Assets │ │ │ │ +│ │ │ │ • Assets │ │ • Load │ │ • EVs │ │ • Schedules │ │ │ │ +│ │ │ │ • Beliefs │ │ • Prices │ │ • Grid │ │ • Forecasts │ │ │ │ +│ │ │ │ • OCPI CDRs │ │ • CO2 │ │ services │ │ • OCPI CDRs │ │ │ │ +│ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │ │ +│ │ │ │ │ │ +│ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ +│ │ │ │ DATA MODEL │ │ │ │ +│ │ │ │ Accounts ──► Assets ──► Sensors ──► Beliefs (timed data) │ │ │ │ +│ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ │ │ +│ │ └──────────────────────────────────────────────────────────────────────────────────┘ │ │ +│ │ │ │ +│ │ ┌──────────────────────────────────────────────────────────────────────────────────┐ │ │ +│ │ │ DEVICE LAYER │ │ │ +│ │ │ │ │ │ +│ │ │ ┌────────────────────┐ ┌────────────────────┐ ┌────────────────────┐ │ │ │ +│ │ │ │ CITRINEOS │ │ EVEREST │ │ _grid SINGULARITY │ │ │ │ +│ │ │ │ (CSMS) │ │ (Middleware) │ │ (Market) │ │ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ +│ │ │ │ • OCPP 2.0.1 │ │ • ISO 15118-2 │ │ • P2P trading │ │ │ │ +│ │ │ │ • Charge Points │ │ • OCPP proxy │ │ • Market clearing │ │ │ │ +│ │ │ │ • Transactions │ │ • Smart Charging │ │ • Price discovery │ │ │ │ +│ │ │ │ • Remote control │ │ • V2G │ │ │ │ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ +│ │ │ │ ← OCPP │ │ ← ISO 15118 │ │ ← gsy-e-sdk │ │ │ │ +│ │ │ │ → FM API │ → CitrineOS OCPP │ │ → FM API │ │ │ │ +│ │ │ └────────────────────┘ └────────────────────┘ └────────────────────┘ │ │ │ +│ │ │ │ │ │ +│ │ │ ┌─────────────────────────────────────────────────────────────────────────┐ │ │ │ +│ │ │ │ DEVICES │ │ │ │ +│ │ │ │ │ │ │ │ +│ │ │ │ 10 PV Panels (5kWc) │ Modbus TCP │ │ │ │ +│ │ │ │ 10 Batteries (100kWh) │ Modbus TCP │ │ │ │ +│ │ │ │ 10 EV Chargers (22kW) │ OCPP 2.0.1 │ │ │ │ +│ │ │ │ 10 EVs (75kWh V2G) │ ISO 15118 │ │ │ │ +│ │ │ └─────────────────────────────────────────────────────────────────────────┘ │ │ │ +│ │ └──────────────────────────────────────────────────────────────────────────────────┘ │ │ +│ │ │ │ +│ │ ┌──────────────────────────────────────────────────────────────────────────────────┐ │ │ +│ │ │ MARKET LAYER (R&D) │ │ │ +│ │ │ │ │ │ +│ │ │ ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ +│ │ │ │ OPLEM │ │ HAMLET │ │ EPEX LOCALFLEX │ │ │ │ +│ │ │ │ (Local Market) │ │ (Agent-based LEM) │ │ (Flexibility) │ │ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ +│ │ │ │ • Prosumer optim. │ │ • Multi-agent sim │ │ • Local flex market │ │ │ │ +│ │ │ │ • Battery agents │ │ • Battery agents │ │ • Price signals │ │ │ │ +│ │ │ │ • EV agents │ │ • EV agents │ │ • Flex bidding │ │ │ │ +│ │ │ └──────────────────────┘ └──────────────────────┘ └──────────────────────┘ │ │ │ +│ │ └──────────────────────────────────────────────────────────────────────────────────┘ │ │ +│ │ │ │ +│ │ ┌──────────────────────────────────────────────────────────────────────────────────┐ │ │ +│ │ │ VISUALIZATION LAYER │ │ │ +│ │ │ │ │ │ +│ │ │ ┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────────┐ │ │ │ +│ │ │ │ GRAFANA │ │ METABASE │ │ CARIFLEX UI │ │ │ │ +│ │ │ │ (Port 3001) │ │ (Analytics) │ │ (Port 5000) │ │ │ │ +│ │ │ │ │ │ │ │ │ │ │ │ +│ │ │ │ • Timeseries │ │ • SQL queries │ │ • Asset map │ │ │ │ +│ │ │ │ • Asset table │ │ • Reporting │ │ • Schedules │ │ │ │ +│ │ │ │ • OCPI CDRs │ │ • Data exploration │ │ • Forecasts │ │ │ │ +│ │ │ │ • Flexibility KPIs │ │ • Billing │ │ • OCPI sessions │ │ │ │ +│ │ │ └──────────────────────┘ └──────────────────────┘ └──────────────────────┘ │ │ │ +│ │ └──────────────────────────────────────────────────────────────────────────────────┘ │ │ +│ └─────────────────────────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────────────────────┘ +``` + +--- + +## 3. Intégration OCPI + +### 3.1 Qu'est-ce qu'OCPI ? + +**OCPI (Open Charge Point Interface)** est un protocole standard pour l'interopérabilité entre opérateurs de bornes de recharge EV. Il permet : + +- **Tarification** : Échange des tarifs entre opérateurs +- **Sessions** : Suivi des sessions de recharge en temps réel +- **CDRs** (Call Detail Records) : Facturation inter-opérateurs +- **Roaming** : Accès aux bornes d'autres opérateurs +- **Commands** : Démarrage/arrêt à distance + +### 3.2 Architecture OCPI dans Cariflex + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ OCPI INTEGRATION │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ OTHER │◄───────►│ CARIFLEX │◄───────►│ CITRINEOS │ │ +│ │ CPOs │ OCPI │ OCPI │ OCPP │ (CSMS) │ │ +│ │ │ 2.2 │ GATEWAY │ 2.0.1 │ │ │ +│ └──────────────┘ └──────┬───────┘ └──────────────┘ │ +│ │ │ +│ ▼ │ +│ ┌──────────────┐ │ +│ │ FLEXMEASURES │ │ +│ │ EMS │ │ +│ │ │ │ +│ │ • CDRs │ │ +│ │ • Sessions │ │ +│ │ • Tariffs │ │ +│ │ • Roaming │ │ +│ └──────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 3.3 Flux de Données OCPI + +```mermaid +sequenceDiagram + participant EV as EV Driver + participant OtherCPO as Other CPO + participant OCPI as Cariflex OCPI Gateway + participant FM as FlexMeasures + participant CitrineOS as CitrineOS CSMS + participant CP as Cariflex Charge Point + + %% Roaming in (EV driver from other CPO) + EV->>CP: Plug in (RFID/App) + CP->>CitrineOS: StartTransaction + CitrineOS->>FM: POST /sensors/{id}/data (power) + + FM->>OCPI: Check roaming rights + OCPI->>OtherCPO: POST /cdrs (session start) + OtherCPO-->>OCPI: 200 OK + OCPI-->>FM: Authorized + + %% Charging loop + loop Every 30s + CitrineOS->>FM: Power readings + FM->>OCPI: Update session + OCPI->>OtherCPO: PATCH /sessions/{id} + end + + %% Session end + EV->>CP: Unplug + CP->>CitrineOS: StopTransaction + CitrineOS->>FM: Final readings + FM->>OCPI: Generate CDR + OCPI->>OtherCPO: POST /cdrs + OtherCPO-->>OCPI: CDR accepted +``` + +### 3.4 Modules OCPI à Développer + +| Module | Endpoint | Description | +|--------|----------|-------------| +| `ocpi_versions` | `GET /ocpi/2.2` | Version negotiation | +| `ocpi_credentials` | `POST /ocpi/2.2/credentials` | Auth tokens | +| `ocpi_locations` | `GET /ocpi/2.2/locations` | Bornes Cariflex | +| `ocpi_sessions` | `GET/POST /ocpi/2.2/sessions` | Sessions de recharge | +| `ocpi_cdrs` | `POST /ocpi/2.2/cdrs` | Facturation | +| `ocpi_tariffs` | `GET /ocpi/2.2/tariffs` | Tarifs Cariflex | +| `ocpi_commands` | `POST /ocpi/2.2/commands` | Remote control | + +--- + +## 4. Intégration GIREVE + +### 4.1 Qu'est-ce que GIREVE ? + +**GIREVE** (Gestion des Itinéraires de Recharge des Véhicules Electriques) est une plateforme d'interopérabilité française pour la mobilité électrique : + +- **Agrégation** : Centralise les données de multiples CPOs et eMSPs +- **Roaming** : Facilite l'itinérance de recharge +- **Données** : Session data, CDRs, tarifs, disponibilité +- **Billing** : Facturation inter-opérateurs +- **PNIRE** : Point d'Intersection au Réseau d'Information + +### 4.2 Architecture GIREVE dans Cariflex + +``` +┌─────────────────────────────────────────────────────────────────────────────┐ +│ GIREVE INTEGRATION │ +├─────────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ GIREVE │◄───────►│ CARIFLEX │◄───────►│ FLEXMEASURES│ │ +│ │ PLATFORM │ eMSP │ GIREVE │ REST │ EMS │ │ +│ │ │ API │ CONNECTOR │ API │ │ │ +│ │ │ │ │ │ • CDRs │ │ +│ │ • Sessions │ │ • Tarifs │ │ • Sessions │ │ +│ │ • CDRs │ │ • Sessions │ │ • Billing │ │ +│ │ • Tarifs │ │ • CDRs │ │ • Reporting │ │ +│ │ • Roaming │ │ • Billing │ │ │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────────────────────────┐ │ +│ │ GIREVE SERVICES │ │ +│ │ │ │ +│ │ • PNIRE (Point d'Intersection au Réseau d'Information) │ │ +│ │ • Roaming hub (inter-CPO) │ │ +│ │ • Data aggregation (sessions, CDRs) │ │ +│ │ • Billing reconciliation │ │ +│ │ • Availability dissemination │ │ +│ └──────────────────────────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────────────┘ +``` + +### 4.3 Flux de Données GIREVE + +```mermaid +sequenceDiagram + participant EV as EV Driver + participant CP as Charge Point + participant CitrineOS as CitrineOS CSMS + participant FM as FlexMeasures + participant GIREVE as GIREVE Platform + participant OtherCPO as Other CPO + + %% Session start + EV->>CP: Start charging + CP->>CitrineOS: StartTransaction + CitrineOS->>FM: POST /sensors/{id}/data + FM->>GIREVE: POST /session (session start) + GIREVE-->>FM: Session acknowledged + + %% Charging loop + loop Every 30s + CitrineOS->>FM: Power readings + FM->>GIREVE: PATCH /session/{id} (consumption) + end + + %% Session end + EV->>CP: Stop charging + CP->>CitrineOS: StopTransaction + CitrineOS->>FM: Final readings + FM->>GIREVE: POST /cdr (final CDR) + GIREVE-->>FM: CDR accepted + + %% Roaming + OtherCPO->>GIREVE: GET /tariffs (Cariflex tariffs) + GIREVE-->>OtherCPO: Tariff data + OtherCPO->>GIREVE: POST /session (roaming session) + GIREVE->>FM: Validate roaming + FM-->>GIREVE: Authorized +``` + +### 4.4 Services GIREVE à Développer + +| Service | Endpoint | Description | +|---------|----------|-------------| +| `gireve_tariffs` | `GET /tariffs` | Diffusion des tarifs Cariflex | +| `gireve_sessions` | `POST /sessions` | Envoi des sessions | +| `gireve_cdrs` | `POST /cdrs` | Envoi des CDRs | +| `gireve_locations` | `GET /locations` | Disponibilité des bornes | +| `gireve_roaming` | `POST /validate` | Validation roaming entrant | +| `gireve_billing` | `GET /reports` | Rapports de facturation | + +--- + +## 5. Intégrations à Développer (Mise à Jour) + +| Intégration | Priorité | Complexité | Statut | Description | +|-------------|----------|------------|--------|-------------| +| **OCPI Gateway** | Haute | Élevée | 📋 À faire | Protocole OCPI 2.2 pour roaming | +| **GIREVE Connector** | Haute | Moyenne | 📋 À faire | Connexion plateforme GIREVE | +| **CitrineOS ↔ FM** | Haute | Moyenne | ⏳ À faire | OCPP 2.0.1 → FM API | +| **EVerest ↔ CitrineOS** | Haute | Moyenne | ⏳ À faire | ISO 15118 → OCPP proxy | +| **OpenLEADR ↔ FM** | Haute | Faible | ⏳ À faire | OpenADR 2.0b → FM scheduling | +| **Grid Singularity ↔ FM** | Moyenne | Élevée | ⏳ À faire | P2P trading → FM schedules | +| **OPLEM ↔ FM** | Moyenne | Moyenne | ⏳ À faire | Local market optimization | +| **HAMLET ↔ FM** | Basse | Élevée | ⏳ À faire | Multi-agent simulation | +| **MQTT Brokers Cariflex** | Haute | Moyenne | ⏳ À faire | Format compatible FM | + +--- + +## 6. Configuration Requise + +### 6.1 FlexMeasures (mise à jour) +```yaml +# Environment variables +FLEXMEASURES_ENV=production +FLEXMEASURES_PLATFORM_NAME=Cariflex +FLEXMEASURES_MENU_LOGO_PATH=/ui/static/images/cariflex-logo.jpg +FLEXMEASURES_REDIS_URL=flexmeasures-redis +FLEXMEASURES_REDIS_PORT=6379 +FLEXMEASURES_REDIS_DB_NR=0 +FLEXMEASURES_REDIS_PASSWORD=*** +S...n + +# New: OCPI settings +OCPI_ENABLED=true +OCPI_VERSION=2.2 +OCPI_BASE_URL=https://cariflex.digitribe.fr/ocpi +OCPI_CPO_IDENTIFIER=FR*CAR + +# New: GIREVE settings +GIREVE_ENABLED=true +GIREVE_BASE_URL=https://platform.gireve.com +GIREVE_CPO_ID=FR_CARIFLEX +GIREVE_API_KEY=*** +``` + +### 6.2 Grafana Datasource +```json +{ + "name": "PostgreSQL-FlexMeasures", + "type": "postgres", + "url": "flexmeasures-db:5432", + "database": "flexmeasures", + "user": "flexmeasures" +} +``` + +### 6.3 Nouvaires Services Docker à Ajouter +```yaml +# OCPI Gateway +cariflex-ocpi: + image: cariflex/ocpi-gateway:latest + environment: + OCPI_VERSION: "2.2" + FM_API_URL: "http://flexmeasures-server:5000" + CPO_IDENTIFIER: "FR*CAR" + ports: + - "8081:8080" + networks: + - cariflex-internal + +# GIREVE Connector +cariflex-gireve: + image: cariflex/gireve-connector:latest + environment: + GIREVE_API_URL: "https://platform.gireve.com" + FM_API_URL: "http://flexmeasures-server:5000" + CPO_ID: "FR_CARIFLEX" + networks: + - cariflex-internal +``` + +--- + +## 7. Prochaines Étapes + +1. **Développer OCPI Gateway** : Implémenter les endpoints OCPI 2.2 +2. **Développer GIREVE Connector** : Connexion à la plateforme GIREVE +3. **Intégrer CitrineOS** : Connecter via OCPP 2.0.1 aux bornes EV +4. **Intégrer EVerest** : Configurer ISO 15118 pour V2G +5. **Intégrer OpenLEADR** : Connecter au DSO pour flexibilité +6. **Créer brokers MQTT Cariflex** : Format compatible FM +7. **Automatiser forecasting/scheduling** : Cron jobs ou scheduler +8. **Intégrer Grid Singularity** : P2P trading +9. **Documentation complète** : API, déploiement, fonctionnement diff --git a/scripts/generate_architecture_diagram.py b/scripts/generate_architecture_diagram.py new file mode 100644 index 0000000..ad025db --- /dev/null +++ b/scripts/generate_architecture_diagram.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +"""Generate Cariflex architecture diagrams as PDF.""" +import matplotlib.pyplot as plt +import matplotlib.patches as mpatches +from matplotlib.patches import FancyBboxPatch, FancyArrowPatch +import matplotlib.patches as patches + +fig, ax = plt.subplots(1, 1, figsize=(20, 14)) +ax.set_xlim(0, 20) +ax.set_ylim(0, 14) +ax.axis('off') +fig.patch.set_facecolor('#f5f5f5') + +def draw_box(ax, x, y, w, h, text, color='#2196F3', textcolor='white', fontsize=9, alpha=1.0): + box = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.1", + facecolor=color, edgecolor='white', linewidth=2, alpha=alpha) + ax.add_patch(box) + ax.text(x + w/2, y + h/2, text, ha='center', va='center', + fontsize=fontsize, color=textcolor, fontweight='bold', wrap=True) + +def draw_arrow(ax, x1, y1, x2, y2, color='#666', label=''): + ax.annotate('', xy=(x2, y2), xytext=(x1, y1), + arrowprops=dict(arrowstyle='->', color=color, lw=1.5)) + if label: + mx, my = (x1+x2)/2, (y1+y2)/2 + ax.text(mx+0.1, my+0.1, label, fontsize=7, color=color) + +# Title +ax.text(10, 13.5, 'CARIFLEX EMS - Architecture d\'Intégration', + ha='center', fontsize=16, fontweight='bold', color='#1565C0') + +# External Layer +ax.text(0.5, 12.5, 'EXTERNAL', fontsize=10, fontweight='bold', color='#666') +draw_box(ax, 0.5, 11.5, 4, 0.8, 'EPEX SPOT\nDay-ahead Prices', '#FF9800') +draw_box(ax, 5, 11.5, 4, 0.8, 'ENTSO-E\nCO2 / Prices', '#FF9800') +draw_box(ax, 9.5, 11.5, 4, 0.8, 'Weather API\nSolcast/Météo', '#FF9800') +draw_box(ax, 14, 11.5, 5, 0.8, 'DSO/TSO\nOpenADR / S2', '#FF9800') + +# Arrows to FM +draw_arrow(ax, 2.5, 11.5, 5, 10.5, '#666', 'Prices') +draw_arrow(ax, 7, 11.5, 7, 10.5, '#666', 'CO2') +draw_arrow(ax, 11.5, 11.5, 9, 10.5, '#666', 'Irradiance') +draw_arrow(ax, 16.5, 11.5, 15, 10.5, '#666', 'Flex Requests') + +# FlexMeasures EMS (central) +draw_box(ax, 3, 8.5, 14, 1.8, '', '#2196F3', alpha=0.2) +ax.text(10, 9.8, 'FLEXMEASURES EMS', ha='center', fontsize=12, fontweight='bold', color='#1565C0') +draw_box(ax, 3.5, 8.7, 3, 0.8, 'INGESTION\n• Sensors • Assets • Beliefs', '#2196F3', fontsize=7) +draw_box(ax, 7, 8.7, 3, 0.8, 'FORECASTING\n• PV • Load • Prices', '#2196F3', fontsize=7) +draw_box(ax, 10.5, 8.7, 3, 0.8, 'SCHEDULING\n• Batteries • EVs • Grid', '#2196F3', fontsize=7) +draw_box(ax, 14, 8.7, 2.5, 0.8, 'REPORTING\n• Assets • Schedules', '#2196F3', fontsize=7) + +# Device Layer +ax.text(0.5, 7.8, 'INTEGRATION', fontsize=10, fontweight='bold', color='#666') +draw_box(ax, 0.5, 6.5, 5, 1, 'CITRINEOS (CSMS)\n• OCPP 2.0.1 • Charge Points • Transactions', '#4CAF50', fontsize=8) +draw_box(ax, 6, 6.5, 5, 1, 'EVEREST (Middleware)\n• ISO 15118 • Smart Charging • Power Mgmt', '#FF9800', fontsize=8) +draw_box(ax, 11.5, 6.5, 5, 1, 'OPENLEADR (VEN)\n• OpenADR 2.0b • DSO Signals • Flexibility', '#9C27B0', fontsize=8) + +# Arrows to devices +draw_arrow(ax, 3, 6.5, 3, 5.5, '#4CAF50', 'OCPP') +draw_arrow(ax, 8.5, 6.5, 8.5, 5.5, '#FF9800', 'ISO 15118') +draw_arrow(ax, 14, 6.5, 14, 5.5, '#9C27B0', 'Commands') + +# Devices +ax.text(0.5, 5.8, 'DEVICES', fontsize=10, fontweight='bold', color='#666') +draw_box(ax, 0.5, 4.5, 3.5, 1, '10 PV Panels\n5kWc each\nModbus TCP', '#FFC107', fontsize=8, textcolor='#333') +draw_box(ax, 4.5, 4.5, 3.5, 1, '10 Batteries\n100kWh each\nModbus TCP', '#FFC107', fontsize=8, textcolor='#333') +draw_box(ax, 8.5, 4.5, 3.5, 1, '10 EV Chargers\n22kW each\nOCPP 2.0.1', '#FFC107', fontsize=8, textcolor='#333') +draw_box(ax, 12.5, 4.5, 4, 1, '10 EVs\n75kWh V2G\nISO 15118', '#FFC107', fontsize=8, textcolor='#333') + +# Market Layer +ax.text(0.5, 3.8, 'MARKET (R&D)', fontsize=10, fontweight='bold', color='#666') +draw_box(ax, 0.5, 2.5, 5.5, 1, 'GRID SINGULARITY\ngsy-e (88 stars)\n• P2P Trading • Market Clearing', '#00BCD4', fontsize=8) +draw_box(ax, 6.5, 2.5, 5.5, 1, 'OPLEM\npip install oplem\n• Local Market • Prosumer Opt.', '#00BCD4', fontsize=8) +draw_box(ax, 12.5, 2.5, 5.5, 1, 'HAMLET\nconda hamlet\n• Multi-agent • Simulation', '#00BCD4', fontsize=8) + +# Visualization Layer +ax.text(0.5, 1.8, 'VISUALIZATION', fontsize=10, fontweight='bold', color='#666') +draw_box(ax, 0.5, 0.5, 4, 1, 'GRAFANA\n• 4 Timeseries • 1 Table\nPostgreSQL DS', '#E91E63', fontsize=8) +draw_box(ax, 5, 0.5, 4, 1, 'METABASE\n• SQL Analytics\n• Reporting', '#E91E63', fontsize=8) +draw_box(ax, 9.5, 0.5, 5, 1, 'CARIFLEX UI\n(FM Frontend)\n• Asset Map • Schedules', '#E91E63', fontsize=8) + +# Legend +ax.text(15, 1, 'Cariflex - Caribbean Flexibility Platform', + ha='center', fontsize=8, fontweight='bold', color='#1565C0', + bbox=dict(boxstyle='round', facecolor='white', alpha=0.8)) + +plt.tight_layout() +plt.savefig('/home/eric/cariflex/docs/architecture_cariflex.pdf', dpi=150, bbox_inches='tight') +plt.savefig('/home/eric/cariflex/docs/architecture_cariflex.png', dpi=150, bbox_inches='tight') +print("✅ Architecture diagrams generated") +print(" - PDF: /home/eric/cariflex/docs/architecture_cariflex.pdf") +print(" - PNG: /home/eric/cariflex/docs/architecture_cariflex.png") diff --git a/scripts/generate_architecture_v2.py b/scripts/generate_architecture_v2.py new file mode 100644 index 0000000..b3d5487 --- /dev/null +++ b/scripts/generate_architecture_v2.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python3 +"""Generate Cariflex architecture diagrams v2 (with OCPI and GIREVE) as PDF.""" +import matplotlib.pyplot as plt +import matplotlib.patches as mpatches +from matplotlib.patches import FancyBboxPatch +import numpy as np + +fig, ax = plt.subplots(1, 1, figsize=(22, 16)) +ax.set_xlim(0, 22) +ax.set_ylim(0, 16) +ax.axis('off') +fig.patch.set_facecolor('#f8f9fa') + +def draw_box(ax, x, y, w, h, text, color='#2196F3', textcolor='white', fontsize=8, alpha=1.0, border='white'): + box = FancyBboxPatch((x, y), w, h, boxstyle="round,pad=0.15", + facecolor=color, edgecolor=border, linewidth=1.5, alpha=alpha) + ax.add_patch(box) + ax.text(x + w/2, y + h/2, text, ha='center', va='center', + fontsize=fontsize, color=textcolor, fontweight='bold', wrap=True, + multialignment='center') + +def draw_arrow(ax, x1, y1, x2, y2, color='#666', label='', lw=1.2): + ax.annotate('', xy=(x2, y2), xytext=(x1, y1), + arrowprops=dict(arrowstyle='->', color=color, lw=lw)) + if label: + mx, my = (x1+x2)/2, (y1+y2)/2 + ax.text(mx+0.1, my+0.1, label, fontsize=6, color=color, style='italic') + +# Title +ax.text(11, 15.5, 'CARIFLEX EMS - Architecture d\'Intégration v2', + ha='center', fontsize=18, fontweight='bold', color='#1565C0') +ax.text(11, 15.1, 'avec OCPI et GIREVE', + ha='center', fontsize=12, color='#666') + +# ═══════════════════════════════════════════════════════════════════ +# EXTERNAL LAYER +# ═══════════════════════════════════════════════════════════════════ +ax.text(0.3, 14.3, 'EXTERNAL', fontsize=9, fontweight='bold', color='#888', style='italic') + +draw_box(ax, 0.3, 13.3, 4.5, 0.8, 'EPEX SPOT\nDay-ahead / Localflex', '#FF9800', fontsize=8) +draw_box(ax, 5.3, 13.3, 4.5, 0.8, 'ENTSO-E\nPrices / CO2', '#FF9800', fontsize=8) +draw_box(ax, 10.3, 13.3, 4.5, 0.8, 'Weather API\nSolcast / Météo', '#FF9800', fontsize=8) +draw_box(ax, 15.3, 13.3, 6, 0.8, 'DSO / TSO\nOpenADR / S2', '#FF9800', fontsize=8) + +# Arrows to interop/integration +draw_arrow(ax, 2.5, 13.3, 3, 12.5, '#FF9800', 'prices') +draw_arrow(ax, 7.5, 13.3, 8, 12.5, '#FF9800', 'CO2') +draw_arrow(ax, 12.5, 13.3, 10, 12.5, '#FF9800', 'weather') +draw_arrow(ax, 18.3, 13.3, 17, 12.5, '#FF9800', 'flex') + +# ═══════════════════════════════════════════════════════════════════ +# INTEROPERABILITY LAYER (NEW) +# ═══════════════════════════════════════════════════════════════════ +ax.text(0.3, 12.7, 'INTEROPERABILITY', fontsize=9, fontweight='bold', color='#888', style='italic') + +draw_box(ax, 0.3, 11.5, 9, 1, 'OCPI Gateway (eMSP/CPO)\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n• Tarifs • Sessions • CDRs • Roaming (in/out) • Commands', '#E91E63', fontsize=7.5) +draw_box(ax, 10, 11.5, 9, 1, 'GIREVE Connector\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n• Session data • Roaming hub • Billing • PNIRE • CDRs', '#795548', fontsize=7.5) + +# Arrows from external +draw_arrow(ax, 5.3, 11.5, 5.3, 10.8, '#E91E63', 'roaming') +draw_arrow(ax, 14.5, 11.5, 12, 10.8, '#795548', 'sessions') + +# ═══════════════════════════════════════════════════════════════════ +# INTEGRATION LAYER +# ═══════════════════════════════════════════════════════════════════ +ax.text(0.3, 11.0, 'INTEGRATION', fontsize=9, fontweight='bold', color='#888', style='italic') + +# FlexMeasures EMS (central) +draw_box(ax, 2, 9.2, 16, 1.5, '', '#2196F3', alpha=0.15) +ax.text(10, 10.4, 'FLEXMEASURES EMS', ha='center', fontsize=11, fontweight='bold', color='#1565C0') + +draw_box(ax, 2.3, 9.4, 3.5, 0.9, 'INGESTION\nSensors / Assets\nBeliefs / OCPI CDRs', '#2196F3', fontsize=7) +draw_box(ax, 6.2, 9.4, 3.5, 0.9, 'FORECASTING\nPV / Load\nPrices / CO2', '#2196F3', fontsize=7) +draw_box(ax, 10.1, 9.4, 3.5, 0.9, 'SCHEDULING\nBatteries / EVs\nGrid services', '#2196F3', fontsize=7) +draw_box(ax, 14, 9.4, 3.7, 0.9, 'REPORTING\nAssets / Sched\nForecasts / CDRs', '#2196F3', fontsize=7) + +# Sub-components +draw_box(ax, 0.3, 8.2, 5, 0.8, 'CITRINEOS (CSMS)\nOCPP 2.0.1 • Charge Points • Transactions', '#4CAF50', fontsize=7.5) +draw_box(ax, 5.8, 8.2, 5, 0.8, 'EVEREST (Middleware)\nISO 15118 • Smart Charging • V2G', '#FF9800', fontsize=7.5) +draw_box(ax, 11.3, 8.2, 5, 0.8, 'OPENLEADR (VEN)\nOpenADR 2.0b • DSO • Flexibility', '#9C27B0', fontsize=7.5) + +# Arrows to FM +draw_arrow(ax, 2.8, 8.2, 4, 9.2, '#4CAF50', 'REST') +draw_arrow(ax, 8.3, 8.2, 8, 9.2, '#FF9800', 'OCPP') +draw_arrow(ax, 13.8, 8.2, 12, 9.2, '#9C27B0', 'REST') + +# ═══════════════════════════════════════════════════════════════════ +# DEVICES LAYER +# ═══════════════════════════════════════════════════════════════════ +ax.text(0.3, 7.5, 'DEVICES', fontsize=9, fontweight='bold', color='#888', style='italic') + +draw_box(ax, 0.3, 6.3, 4.5, 1, '10 PV Panels\n5kWc each\nModbus TCP → FM', '#FFC107', textcolor='#333', fontsize=8) +draw_box(ax, 5.3, 6.3, 4.5, 1, '10 Batteries\n100kWh / 50kW\nModbus TCP → FM', '#FFC107', textcolor='#333', fontsize=8) +draw_box(ax, 10.3, 6.3, 4.5, 1, '10 EV Chargers\n22kW OCPP 2.0.1\n→ CitrineOS', '#FFC107', textcolor='#333', fontsize=8) +draw_box(ax, 15.3, 6.3, 5.5, 1, '10 EVs\n75kWh V2G\nISO 15118 → EVerest', '#FFC107', textcolor='#333', fontsize=8) + +# ═══════════════════════════════════════════════════════════════════ +# MARKET LAYER (R&D) +# ═══════════════════════════════════════════════════════════════════ +ax.text(0.3, 5.6, 'MARKET (R&D)', fontsize=9, fontweight='bold', color='#888', style='italic') + +draw_box(ax, 0.3, 4.4, 6.5, 1, 'GRID SINGULARITY\ngsy-e • P2P Trading • Market Clearing\nPrice discovery → FM schedules', '#00BCD4', fontsize=7.5) +draw_box(ax, 7.3, 4.4, 6.5, 1, 'OPLEM\nLocal Market • Prosumer Opt.\nBattery/EV agents → FM', '#00BCD4', fontsize=7.5) +draw_box(ax, 14.3, 4.4, 6.5, 1, 'HAMLET\nMulti-agent Simulation\nStrategy validation → FM', '#00BCD4', fontsize=7.5) + +# ═══════════════════════════════════════════════════════════════════ +# VISUALIZATION LAYER +# ═══════════════════════════════════════════════════════════════════ +ax.text(0.3, 3.7, 'VISUALIZATION', fontsize=9, fontweight='bold', color='#888', style='italic') + +draw_box(ax, 0.3, 2.5, 6, 1, 'GRAFANA (Port 3001)\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n4 Timeseries + 1 Table\nPostgreSQL-FlexMeasures DS', '#E91E63', fontsize=7.5) +draw_box(ax, 6.8, 2.5, 6, 1, 'METABASE\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nSQL Analytics • Reporting\nBilling • Data exploration', '#E91E63', fontsize=7.5) +draw_box(ax, 13.3, 2.5, 7, 1, 'CARIFLEX UI (Port 5000)\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\nAsset Map • Schedules\nForecasts • OCPI Sessions', '#E91E63', fontsize=7.5) + +# ═══════════════════════════════════════════════════════════════════ +# NETWORK LEGEND +# ═══════════════════════════════════════════════════════════════════ +ax.text(0.3, 1.8, 'PROTOCOLS:', fontsize=8, fontweight='bold', color='#666') + +protocols = [ + ('OCPP 2.0.1', '#4CAF50'), + ('ISO 15118', '#FF9800'), + ('OCPI 2.2', '#E91E63'), + ('OpenADR', '#9C27B0'), + ('Modbus', '#FFC107'), + ('REST API', '#2196F3'), + ('GIREVE', '#795548'), +] + +for i, (name, color) in enumerate(protocols): + x = 0.3 + i * 2.8 + rect = plt.Rectangle((x, 1.1), 0.3, 0.4, facecolor=color, edgecolor='white') + ax.add_patch(rect) + ax.text(x + 0.5, 1.3, name, fontsize=7, color='#333') + +# Footer +ax.text(11, 0.5, 'Cariflex - Caribbean Flexibility Platform - 2026', + ha='center', fontsize=10, fontweight='bold', color='#1565C0', + bbox=dict(boxstyle='round', facecolor='white', alpha=0.8)) + +plt.tight_layout() +plt.savefig('/home/eric/cariflex/docs/architecture_cariflex_v2.pdf', dpi=150, bbox_inches='tight') +plt.savefig('/home/eric/cariflex/docs/architecture_cariflex_v2.png', dpi=150, bbox_inches='tight') +print("✅ Architecture v2 diagrams generated") +print(" - PDF: /home/eric/cariflex/docs/architecture_cariflex_v2.pdf") +print(" - PNG: /home/eric/cariflex/docs/architecture_cariflex_v2.png")