#!/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")