MiroxMirox
  • Piattaforma

    • Filosofia
    • Panoramica della piattaforma
    • Risorse della piattaforma
  • Mirox-Cloud

    • Panoramica del cloud
    • Microservizi connessi
  • Mirox-Agent

    • Panoramica dell'agente
    • Opzioni di distribuzione
    • Data Scraper
    • Gemello digitale
  • Dettagli tecnici

    • Raccolta delle metriche
  • Informazioni

    • Impianti supportati
  • Tipi di impianto

    • Impianti solari
    • Parchi eolici
    • Accumulo a batteria
  • Monitoraggio e visualizzazione

    • Monitoraggio in tempo reale
    • Gemello digitale
    • Stati dei componenti
    • Rilevamento delle perdite
    • Rilevamento dell'efficienza
    • Dashboard KPI
  • Gestione dei dati

    • Eventi
    • Ticket
    • Previsioni
    • Report
  • Integrazione e condivisione

    • Cooperazioni
    • Token API
    • VPN
    • Proxy
  • IA

    • Assistente IA e wizard
    • Accesso agentico (MCP)
  • Fatturazione

    • Mercato e tariffe
    • Contabilità e fatturazione
  • Collaborazione

    • Inviti
  • Sicurezza

    • Autenticazione
    • Sistema di permessi
    • Restrizioni di cooperazione
    • Audit log degli accessi
  • Nodi

    • mrxnode
  • Applicazione

    • Controllo della porta
    • Relè generico
  • Cluster edge

    • Orchestrazione
  • Per iniziare

    • Per iniziare
  • Personale

    • Usare la VPN
    • Usare il proxy
    • Autenticazione a due fattori
    • Sessioni
    • Token API
  • Per impianto

    • Contatti
    • Dispositivi di rete
    • Datalogger
    • Componenti
    • VPN diretta (per agente)
  • Organizzazione

    • Permessi dei membri
    • Cooperazioni
    • Archiviazione file
  • Esportazione di dati

    • API di esportazione metriche
    • MiroxQL — linguaggio di query
    • Generazione esterna di report
    • Grafana
    • Panoramica dell'API
  • Assistenza

    • Richiedi una guida all'integrazione
  • mrxnode

    • Panoramica
    • Guide
    • Distribuzione su container
    • Riferimento comandi
    • Risoluzione dei problemi
  • Reportistica

    • Generatore di report esterno
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Piattaforma

    • Filosofia
    • Panoramica della piattaforma
    • Risorse della piattaforma
  • Mirox-Cloud

    • Panoramica del cloud
    • Microservizi connessi
  • Mirox-Agent

    • Panoramica dell'agente
    • Opzioni di distribuzione
    • Data Scraper
    • Gemello digitale
  • Dettagli tecnici

    • Raccolta delle metriche
  • Informazioni

    • Impianti supportati
  • Tipi di impianto

    • Impianti solari
    • Parchi eolici
    • Accumulo a batteria
  • Monitoraggio e visualizzazione

    • Monitoraggio in tempo reale
    • Gemello digitale
    • Stati dei componenti
    • Rilevamento delle perdite
    • Rilevamento dell'efficienza
    • Dashboard KPI
  • Gestione dei dati

    • Eventi
    • Ticket
    • Previsioni
    • Report
  • Integrazione e condivisione

    • Cooperazioni
    • Token API
    • VPN
    • Proxy
  • IA

    • Assistente IA e wizard
    • Accesso agentico (MCP)
  • Fatturazione

    • Mercato e tariffe
    • Contabilità e fatturazione
  • Collaborazione

    • Inviti
  • Sicurezza

    • Autenticazione
    • Sistema di permessi
    • Restrizioni di cooperazione
    • Audit log degli accessi
  • Nodi

    • mrxnode
  • Applicazione

    • Controllo della porta
    • Relè generico
  • Cluster edge

    • Orchestrazione
  • Per iniziare

    • Per iniziare
  • Personale

    • Usare la VPN
    • Usare il proxy
    • Autenticazione a due fattori
    • Sessioni
    • Token API
  • Per impianto

    • Contatti
    • Dispositivi di rete
    • Datalogger
    • Componenti
    • VPN diretta (per agente)
  • Organizzazione

    • Permessi dei membri
    • Cooperazioni
    • Archiviazione file
  • Esportazione di dati

    • API di esportazione metriche
    • MiroxQL — linguaggio di query
    • Generazione esterna di report
    • Grafana
    • Panoramica dell'API
  • Assistenza

    • Richiedi una guida all'integrazione
  • mrxnode

    • Panoramica
    • Guide
    • Distribuzione su container
    • Riferimento comandi
    • Risoluzione dei problemi
  • Reportistica

    • Generatore di report esterno
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Reportistica

    • Generazione di Report Esterni - Esempi di API

Generazione di Report Esterni - Esempi di API

Estrai i dati degli impianti direttamente dalle API di esportazione di Mirox e crea i tuoi report con lo strumento che preferisci. Questo esempio illustra gli endpoint rilevanti con curl per maggiore chiarezza, ma gli stessi principi si applicano con Python, Power BI, Tableau o qualsiasi altro client HTTP.

Prerequisiti

Prima di poter esportare i dati per la generazione di report esterni, ti occorrono:

  1. Account Mirox - Un account utente Mirox valido
  2. Permessi - Il tuo account deve disporre del permesso per leggere il parco e generare report per quel parco
  3. UID del parco - L'identificatore univoco della risorsa parco su cui vuoi generare il report
  4. Token API - Un token API con almeno il gruppo di permessi Reporting (consulta Utilizzo dei token API per le istruzioni di creazione)

Endpoint di Esportazione Disponibili

La piattaforma Mirox fornisce diversi endpoint API per esportare i dati in formati adatti alla generazione di report esterni. Le informazioni sui parchi e le esportazioni degli eventi si trovano sotto il percorso API /v1/export/report/; le metriche di produzione utilizzano l'endpoint dedicato di esportazione tramite template /v1/export/metrics/template/{template_uid}.

Nota Importante

Gli endpoint API mostrati in questo documento sono esempi a scopo illustrativo. Gli endpoint esatti potrebbero cambiare. Consulta la documentazione API attuale su https://service.mirox.io/docs per le informazioni più recenti.

Informazioni sul Parco (JSON)

Le informazioni di base sul parco possono essere esportate in formato JSON con:

GET /v1/export/report/{park_uid}/info

Questo fornisce i metadati del parco, tra cui:

  • Nome, tipo e descrizione
  • Posizione geografica e fuso orario
  • Specifiche tecniche (produzione di picco, ecc.)
  • Informazioni su organizzazione e portafoglio
  • Indirizzo e dettagli di messa in servizio

Per i dettagli completi sullo schema della risposta, consulta la Documentazione API delle Informazioni sul Parco.

Eventi del Parco (CSV)

I dati degli eventi possono essere esportati in formato CSV con:

GET /v1/export/report/{park_uid}/events.csv

Questo endpoint supporta i seguenti parametri di query:

  • year: Filtra per anno (es. 2025)
  • quarter: Filtra per trimestre (1-4)
  • month: Filtra per mese (1-12)

Il CSV restituito contiene le seguenti colonne:

  • ID Evento
  • Data di Inizio
  • Data di Fine
  • Durata (ore)
  • Tipo
  • Creatore
  • Descrizione
  • Priorità

Filtraggio degli Eventi per Priorità

Il campo Priorità indica l'importanza dell'evento:

  • Valori >= 1000: Eventi importanti (arresti che impattano la produzione, allarmi)
  • Valori < 1000: Eventi informativi (connessioni, variazioni di stato minori)

Filtra per priorità nel tuo strumento di reporting per evidenziare gli eventi significativi.

Se non viene specificato alcun parametro temporale, l'endpoint restituisce gli eventi dell'ultimo trimestre completato.

Per i dettagli sui parametri della richiesta e sul formato della risposta, consulta la Documentazione API degli Eventi del Parco.

Metriche del Parco (CSV)

Le metriche di produzione e prestazione possono essere esportate in formato CSV con l'endpoint di esportazione tramite template:

GET /v1/export/metrics/template/{template_uid}

Questo endpoint supporta i seguenti parametri di query:

  • park: Uno o più UID di parco (separati da virgola) da includere nell'esportazione
  • portfolio: Uno o più UID di portafoglio (separati da virgola); ogni portafoglio viene risolto nei suoi parchi
  • resolution: Intervallo di aggregazione (daily, weekly, monthly, quarterly o yearly; il valore predefinito è monthly)
  • year: Filtra per anno (es. 2025)
  • quarter: Filtra per trimestre (1-4)
  • month: Filtra per mese (1-12)
  • week: Filtra per settimana ISO (risoluzione settimanale)
  • day: Filtra per giorno (richiede month)

Il parametro resolution determina come vengono aggregati i dati:

  • daily: Restituisce una riga per giorno con le misurazioni giornaliere
  • monthly: Restituisce una riga per mese con i totali mensili aggregati e una colonna aggiuntiva "Days in Month"

Il tuo strumento di business intelligence deve gestire correttamente questi diversi formati di risoluzione per la visualizzazione e l'analisi.

Esportazioni Multi-Impianto

Una singola chiamata può esportare più impianti o interi portafogli contemporaneamente, passando UID di park e portfolio separati da virgola. Questo è il percorso consigliato quando crei un report che comprende più di un impianto.

Le colonne sono definite dal template di esportazione a cui fai riferimento. L'esempio seguente utilizza il template ABCD12340001 ("Report Technical v1"), che include:

  • Energy Production (kWh)
  • Energy Report (kWh)
  • Energy Shutdown by grid (kWh)
  • Energy Shutdown by external (kWh)
  • Energy Target (kWh)
  • Irradiation (kWh)

Per i dettagli completi sui parametri della richiesta e sul formato della risposta, consulta la documentazione API attuale su https://service.mirox.io/docs.

Esempi di Utilizzo dell'API

Di seguito sono riportati esempi di come utilizzare direttamente gli endpoint di esportazione con curl. Questi esempi illustrano la struttura delle chiamate API e il formato delle risposte.

Esempio 1: Recupero delle Informazioni sul Parco (JSON)

Richiesta:

curl "https://service.mirox.io/api/v1/export/report/ABC123DEF456/info" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Risposta (parziale):

{
  "uid": "ABC123DEF456",
  "name": "Sunnyside Solar Park",
  "type": "solar",
  "description": "Sunnyside Solar Park is a 42 MW photovoltaic installation...",
  "latitude": 48.7511,
  "longitude": 9.1225,
  "timezone": "Europe/Berlin",
  "peak_production_w": 42000000,
  "active": true,
  "created_at": "2024-05-16T10:30:25.104830Z",
  "portfolio": {
    "uid": "GHI789JKL012",
    "name": "Renewable South"
  },
  "organization": {
    "uid": "MNO345PQR678",
    "name": "GreenPower Inc."
  },
  "address": {
    "address1": "123 Solar Way",
    "zip_code": "70123",
    "city": "Sunnyville",
    "country": "Germany"
  }
}

Esempio 2: Esportazione dei Dati degli Eventi (CSV)

Richiesta:

curl "https://service.mirox.io/api/v1/export/report/ABC123DEF456/events.csv" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Risposta (CSV):

Event ID,Start Date,End Date,Duration (hours),Type,Creator,Description,Priority
9876543210123456789,2025-01-15 08:45,Ongoing,720.25,Sensor Error,System,Irradiation sensor malfunction detected,1200
8765432101234567890,2025-02-10 14:30,2025-02-15 09:15,114.75,Data Availability,System,Connection issues with data acquisition system,1100

Nota il campo Priority con valori superiori a 1000, che indica eventi significativi con impatto sulla produzione.

Esempio 3: Esportazione delle Metriche Mensili (CSV)

Richiesta:

curl "https://service.mirox.io/api/v1/export/metrics/template/ABCD12340001?park=ABC123DEF456&resolution=monthly" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Risposta (CSV):

Date (YYYY-MM),Energy Production (kWh),Energy Report (kWh),Energy Shutdown by grid (kWh),Energy Shutdown by external (kWh),Energy Target (kWh),Irradiation (kWh),Days in Month (d)
2025-01,950000.45,980000.00,15000.50,25000.75,980000.00,18.350,31
2025-02,1250000.32,1300000.00,2000.25,18500.40,1300000.00,22.780,28
2025-03,1850000.75,1900000.00,45000.20,30000.65,1900000.00,35.420,31

Questo esempio illustra i dati aggregati mensilmente con la colonna "Days in Month (d)" specifica dell'opzione a intervallo mensile.

Utilizzo in Strumenti Diversi

Queste chiamate API possono essere applicate in vari ambienti:

  • Python/Requests: Usa la libreria requests per effettuare chiamate API negli script Python
  • Power BI: Usa origini dati "Web" per importare direttamente dati JSON/CSV
  • Tableau: Configura connettori web per dati per l'integrazione delle API
  • Excel: Usa Power Query per importare e trasformare i dati delle API
  • Script Personalizzati: Implementa in qualsiasi linguaggio con supporto per client HTTP

Buone Pratiche

Per un utilizzo efficace delle API:

  1. Usa i token API in modo sicuro - Non codificare mai i token negli script; usa le variabili d'ambiente
  2. Gestisci correttamente i dati a intervalli - Assicurati che la tua analisi gestisca correttamente i formati di dati giornalieri e mensili
  3. Filtra gli eventi in modo appropriato - Usa il campo della priorità per concentrarti sugli eventi significativi (>=1000)
  4. Considera il volume dei dati - Per parchi di grandi dimensioni o periodi temporali lunghi, esporta i dati in blocchi gestibili
  5. Implementa la gestione degli errori - Gestisci correttamente gli errori HTTP e i problemi di rete

Risoluzione dei Problemi

Errori di Autenticazione

Se ricevi un errore HTTP 401:

  1. Controlla il tuo token API: Assicurati di utilizzare un token API valido e non scaduto. I token possono essere generati nelle impostazioni utente di Mirox.

  2. Verifica l'UID del parco: Assicurati che l'UID del parco sia valido e che tu vi abbia accesso. Il valore di esempio ABC123DEF456 è un segnaposto.

  3. Permessi del token: Verifica che al tuo token siano stati concessi i permessi necessari per accedere agli endpoint di esportazione.

Problemi di Codifica del CSV

Le esportazioni CSV utilizzano la codifica UTF-8. In alcuni strumenti (ad es. Excel), potrebbe essere necessario specificare esplicitamente la codifica durante l'importazione.

Esempio di Implementazione in Python: Generatore di Report SolarViz

L'esempio seguente mostra un'implementazione Python completa che utilizza le API descritte sopra per creare un report personalizzato sulla produzione di energia.

Prerequisiti

Per eseguire questo esempio in Python, ti occorrono le seguenti librerie:

pip install requests pandas matplotlib seaborn tabulate
  • requests: Per effettuare chiamate API alla piattaforma Mirox
  • pandas: Per la manipolazione e l'analisi dei dati
  • matplotlib e seaborn: Per creare visualizzazioni
  • tabulate: Per formattare le tabelle nel report

Codice di Esempio Completo

Di seguito è riportato il codice completo del generatore di report SolarViz:

#!/usr/bin/env python3
"""
SolarViz - Mirox External Report Generator

This script demonstrates how to fetch data from the Mirox API and generate
a custom energy production report with visualizations as a PDF file.
"""

import os
import requests
import json
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from datetime import datetime, timezone
import io
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle
from reportlab.graphics.shapes import Drawing
from reportlab.lib.units import inch, cm

# Configuration - Replace with your values
API_URL = "https://service.mirox.io"
API_TOKEN = "YOUR_API_TOKEN"  # Your personal access token
PARK_UID = "ABC123DEF456"  # The UID of the park you want to work with
TEMPLATE_UID = "ABCD12340001"  # The export template ("Report Technical v1")

# Time range parameters
YEAR = datetime.now(timezone.utc).year
QUARTER = (datetime.now(timezone.utc).month - 1) // 3 + 1

# Setup headers
headers = {
    "Authorization": f"Bearer {API_TOKEN}",
    "Content-Type": "application/json"
}


def fetch_park_info():
    """Fetch basic park information as JSON"""
    response = requests.get(
        f"{API_URL}/api/v1/export/report/{PARK_UID}/info",
        headers=headers
    )
    response.raise_for_status()
    return response.json()


def fetch_events(year=None, quarter=None):
    """Fetch park events as DataFrame"""
    params = {}
    if year:
        params["year"] = year
    if quarter:
        params["quarter"] = quarter

    response = requests.get(
        f"{API_URL}/api/v1/export/report/{PARK_UID}/events.csv",
        headers=headers,
        params=params
    )
    response.raise_for_status()

    # Convert CSV content to DataFrame
    events_df = pd.read_csv(io.StringIO(response.content.decode('utf-8')))

    # Filter for significant events (priority >= 1000)
    significant_events = events_df[events_df['Priority'] >= 1000]

    # Process events data - remove ID, Priority, and format duration
    if not significant_events.empty:
        # Remove any ID-related columns (there could be 'ID', 'Event ID', etc.)
        id_columns = [col for col in significant_events.columns if 'id' in col.lower()]
        significant_events = significant_events.drop(id_columns, axis=1, errors='ignore')

        # Remove Priority column as well
        if 'Priority' in significant_events.columns:
            significant_events = significant_events.drop('Priority', axis=1)

        # Convert duration from minutes to days/hours
        if 'DurationMin' in significant_events.columns:
            def format_duration(minutes):
                if minutes < 60:
                    return f"{minutes} min"
                elif minutes < 24*60:
                    hours = minutes / 60
                    return f"{hours:.1f} hours"
                else:
                    days = minutes / (24*60)
                    return f"{days:.1f} days"

            significant_events['Duration'] = significant_events['DurationMin'].apply(format_duration)
            significant_events = significant_events.drop('DurationMin', axis=1)

    return significant_events


def fetch_metrics(resolution="monthly", year=None, quarter=None):
    """Fetch park production metrics as DataFrame"""
    params = {"park": PARK_UID, "resolution": resolution}
    if year:
        params["year"] = year
    if quarter:
        params["quarter"] = quarter

    response = requests.get(
        f"{API_URL}/api/v1/export/metrics/template/{TEMPLATE_UID}",
        headers=headers,
        params=params
    )
    response.raise_for_status()

    # Convert CSV content to DataFrame
    metrics_df = pd.read_csv(io.StringIO(response.content.decode('utf-8')))

    return metrics_df


def create_production_chart(metrics_df):
    """Create a chart visualizing energy production and target with stacked losses"""
    plt.figure(figsize=(8, 4))

    # Set seaborn style
    sns.set_style("whitegrid")

    # Prepare data for stacked bar chart
    x_positions = range(len(metrics_df))
    months = metrics_df.iloc[:, 0]

    # Create stacked bar chart
    # Base layer: Actual production
    plt.bar(x_positions, metrics_df['Energy Production (kWh)'],
            color='#2986cc', label='Actual Production')

    # Stack grid shutdown losses on top
    grid_shutdown = metrics_df['Energy Shutdown by grid (kWh)']
    external_shutdown = metrics_df['Energy Shutdown by external (kWh)']

    # Second layer: Grid shutdown losses
    plt.bar(x_positions, grid_shutdown,
            bottom=metrics_df['Energy Production (kWh)'],
            color='#e06666', label='Grid Shutdown Losses')

    # Third layer: External shutdown losses
    plt.bar(x_positions, external_shutdown,
            bottom=metrics_df['Energy Production (kWh)'] + grid_shutdown,
            color='#f1c232', label='External Shutdown Losses')

    # Plot Target as a line
    plt.plot(x_positions, metrics_df['Energy Target (kWh)'],
             marker='o', color='#6aa84f', linewidth=2, label='Target')

    # Customize the chart
    plt.title('Monthly Energy Production vs Target with Losses')
    plt.xlabel('Month')
    plt.ylabel('Energy (kWh)')
    plt.xticks(x_positions, months, rotation=45)

    # Add legend
    plt.legend(loc='upper left')

    plt.tight_layout()

    # Save chart to a bytes buffer
    buffer = io.BytesIO()
    plt.savefig(buffer, format='png', dpi=300)
    buffer.seek(0)
    plt.close()

    return buffer


def calculate_performance_metrics(metrics_df):
    """Calculate performance metrics based on the production data"""
    performance = {}

    # Total energy production
    performance['total_production'] = metrics_df['Energy Production (kWh)'].sum()

    # Total target
    performance['total_target'] = metrics_df['Energy Target (kWh)'].sum()

    # Performance ratio (actual vs target)
    performance['performance_ratio'] = (performance['total_production'] / performance['total_target']) * 100

    # Total shutdown energy
    performance['grid_shutdown'] = metrics_df['Energy Shutdown by grid (kWh)'].sum()
    performance['external_shutdown'] = metrics_df['Energy Shutdown by external (kWh)'].sum()
    performance['total_shutdown'] = performance['grid_shutdown'] + performance['external_shutdown']

    # Lost production percentage
    performance['lost_production_pct'] = (performance['total_shutdown'] /
                                          (performance['total_production'] + performance['total_shutdown'])) * 100

    return performance


def generate_pdf_report(park_info, events_df, metrics_df, performance, chart_data):
    """Generate a PDF report with the data"""
    # Define the output filename
    output_file = f"SolarViz_Report_{park_info['name'].replace(' ', '_')}_{YEAR}_Q{QUARTER}.pdf"

    # Create PDF document
    doc = SimpleDocTemplate(output_file, pagesize=A4)
    styles = getSampleStyleSheet()

    # Modify existing styles
    styles['Title'].fontName = 'Helvetica-Bold'
    styles['Title'].fontSize = 18
    styles['Title'].alignment = 1  # Center aligned
    styles['Title'].spaceAfter = 12

    # Modify Heading2 style
    styles['Heading2'].fontName = 'Helvetica-Bold'
    styles['Heading2'].fontSize = 14
    styles['Heading2'].spaceBefore = 12
    styles['Heading2'].spaceAfter = 6

    # Modify Normal style
    styles['Normal'].fontName = 'Helvetica'
    styles['Normal'].fontSize = 10
    styles['Normal'].spaceBefore = 6
    styles['Normal'].spaceAfter = 6

    # Add a custom style for tables
    styles.add(ParagraphStyle(name='TableHeader',
                              parent=styles['Normal'],
                              fontName='Helvetica-Bold',
                              fontSize=9,
                              alignment=1))

    # Create document elements
    elements = []

    # Title
    elements.append(Paragraph(f"Energy Production Report: {park_info['name']}", styles['Title']))
    elements.append(Spacer(1, 0.5*cm))

    # Park Information section
    elements.append(Paragraph("Park Information", styles['Heading2']))

    park_info_data = [
        ["Name:", park_info['name']],
        ["Type:", park_info['type']],
        ["Location:", f"{park_info['address']['city']}, {park_info['address']['country']}"],
        ["Peak Capacity:", f"{park_info['peak_production_w'] / 1000000:.2f} MW"],
        ["Portfolio:", park_info['portfolio']['name']],
        ["Organization:", park_info['organization']['name']]
    ]

    park_info_table = Table(park_info_data, colWidths=[3*cm, 10*cm])
    park_info_table.setStyle(TableStyle([
        ('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
        ('FONTNAME', (1, 0), (1, -1), 'Helvetica'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('LEFTPADDING', (0, 0), (-1, -1), 6),
        ('TOPPADDING', (0, 0), (-1, -1), 3),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 3),
    ]))

    elements.append(park_info_table)
    elements.append(Spacer(1, 0.5*cm))

    # Performance Summary section
    elements.append(Paragraph(f"Performance Summary ({YEAR} Q{QUARTER})", styles['Heading2']))

    performance_data = [
        ["Total Energy Production:", f"{performance['total_production']:,.2f} kWh"],
        ["Target Production:", f"{performance['total_target']:,.2f} kWh"],
        ["Performance Ratio:", f"{performance['performance_ratio']:.2f}%"],
        ["Total Energy Lost to Shutdowns:", f"{performance['total_shutdown']:,.2f} kWh"],
        ["  • Grid Shutdowns:", f"{performance['grid_shutdown']:,.2f} kWh"],
        ["  • External Shutdowns:", f"{performance['external_shutdown']:,.2f} kWh"],
        ["Lost Production Percentage:", f"{performance['lost_production_pct']:.2f}%"]
    ]

    performance_table = Table(performance_data, colWidths=[6*cm, 7*cm])
    performance_table.setStyle(TableStyle([
        ('FONTNAME', (0, 0), (0, -1), 'Helvetica-Bold'),
        ('FONTNAME', (1, 0), (1, -1), 'Helvetica'),
        ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
        ('LEFTPADDING', (0, 0), (-1, -1), 6),
        ('TOPPADDING', (0, 0), (-1, -1), 3),
        ('BOTTOMPADDING', (0, 0), (-1, -1), 3),
    ]))

    elements.append(performance_table)
    elements.append(Spacer(1, 0.5*cm))

    # Monthly Production Chart
    elements.append(Paragraph("Monthly Production Chart", styles['Heading2']))

    # Add the chart image
    img = Image(chart_data, width=16*cm, height=8*cm)
    elements.append(img)
    elements.append(Spacer(1, 0.5*cm))

    # Add metrics data table below the graph
    elements.append(Paragraph("Monthly Production Data", styles['Heading2']))

    # Prepare metrics data for table
    # Select relevant columns
    if not metrics_df.empty:
        # Create a copy of the dataframe with selected columns
        table_df = metrics_df.copy()

        # Use the first column as the month column
        month_col_name = table_df.columns[0]

        # Create table data with headers
        metrics_data = [['Month', 'Production (kWh)', 'Target (kWh)',
                        'Grid Shutdown (kWh)', 'External Shutdown (kWh)']]

        # Add data rows with formatted numbers
        for _, row in table_df.iterrows():
            metrics_data.append([
                row[month_col_name],
                f"{row['Energy Production (kWh)']:,.2f}",
                f"{row['Energy Target (kWh)']:,.2f}",
                f"{row['Energy Shutdown by grid (kWh)']:,.2f}",
                f"{row['Energy Shutdown by external (kWh)']:,.2f}"
            ])

        # Create table and set style
        metrics_table = Table(metrics_data, repeatRows=1)
        metrics_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('ALIGN', (0, 0), (-1, 0), 'CENTER'),
            ('ALIGN', (1, 1), (-1, -1), 'RIGHT'),  # Right-align numeric columns
            ('BOTTOMPADDING', (0, 0), (-1, 0), 6),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('FONTSIZE', (0, 0), (-1, -1), 9),
        ]))
        elements.append(metrics_table)
    else:
        elements.append(Paragraph("No production data available for the selected period.", styles['Normal']))

    elements.append(Spacer(1, 0.5*cm))

    # Significant Events section
    elements.append(Paragraph("Significant Events", styles['Heading2']))

    if not events_df.empty:
        # Double check to make sure all ID columns and Priority are removed
        id_columns = [col for col in events_df.columns if 'id' in col.lower()]
        events_df = events_df.drop(id_columns, axis=1, errors='ignore')

        # Also remove Priority column if it still exists
        if 'Priority' in events_df.columns:
            events_df = events_df.drop('Priority', axis=1)

        # Convert DataFrame to a list of lists
        events_data = [events_df.columns.tolist()] + events_df.values.tolist()

        # Create table and set style
        events_table = Table(events_data, repeatRows=1)
        events_table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.lightgrey),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('ALIGN', (0, 0), (-1, 0), 'CENTER'),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 6),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.grey),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
            ('FONTSIZE', (0, 0), (-1, -1), 8),
        ]))
        elements.append(events_table)
    else:
        elements.append(Paragraph("No significant events recorded during this period.", styles['Normal']))

    elements.append(Spacer(1, 1*cm))

    # Footer section
    elements.append(Paragraph("Data Source", styles['Heading2']))
    elements.append(Paragraph(
        f"This report was generated using data exported from the Mirox platform via its external reporting API.<br/>"
        f"Report creation date: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M')}<br/><br/>"
        f"<i>Generated by SolarViz - External Reporting Tool</i>",
        styles['Normal']))

    # Build the PDF document
    doc.build(elements)

    return output_file


def main():
    """Main function that orchestrates the report generation process"""
    try:
        print("Fetching park information...")
        park_info = fetch_park_info()

        print("Fetching events data...")
        events_df = fetch_events(year=YEAR, quarter=QUARTER)

        print("Fetching production metrics...")
        metrics_df = fetch_metrics(resolution="monthly", year=YEAR)

        print("Calculating performance metrics...")
        performance = calculate_performance_metrics(metrics_df)

        print("Creating visualization...")
        chart_data = create_production_chart(metrics_df)

        print("Generating PDF report...")
        output_file = generate_pdf_report(park_info, events_df, metrics_df, performance, chart_data)

        print(f"Report successfully generated: {output_file}")

    except Exception as e:
        print(f"Error generating report: {str(e)}")


if __name__ == "__main__":
    main()

Come Funziona

  1. Configurazione: Lo script imposta l'URL dell'API di Mirox, il token API e l'UID del parco all'inizio.

  2. Raccolta dei Dati: Lo script recupera tre tipi di dati da Mirox:

    • Informazioni sul parco (JSON) tra cui nome, posizione e capacità
    • Eventi significativi (CSV) filtrati per priorità
    • Metriche mensili di produzione di energia (CSV)
  3. Elaborazione dei Dati: Lo script:

    • Converte i dati CSV in DataFrame di Pandas per una facile manipolazione
    • Calcola metriche di prestazione come il rapporto di produzione e l'impatto degli arresti
    • Crea una visualizzazione a barre impilate della produzione mensile e delle perdite per arresto rispetto alla linea di target
  4. Generazione del Report: Lo script crea un report PDF (utilizzando ReportLab) contenente:

    • Riepilogo delle informazioni sul parco
    • Metriche di prestazione
    • Grafico della produzione di energia
    • Tabella degli eventi significativi
  5. Output: Il report viene salvato come file PDF che può essere:

    • Aperto in qualsiasi visualizzatore PDF
    • Condiviso direttamente con gli stakeholder
    • Archiviato o integrato nei flussi di lavoro di reporting

Opzioni di Personalizzazione

Il generatore di report SolarViz può essere personalizzato in diversi modi:

  • Periodi Temporali: Modifica le variabili YEAR e QUARTER per generare report per periodi diversi
  • Tipi di Grafico: Modifica la funzione create_production_chart per utilizzare stili di visualizzazione diversi
  • Metriche Aggiuntive: Recupera e includi metriche aggiuntive da Mirox o da altre fonti di dati
  • Formato del Report: Adatta il layout di ReportLab, oppure sostituiscilo con un formato di output HTML o di altro tipo secondo necessità
  • Automazione: Integra lo script nei flussi di lavoro automatizzati con cron job o schedulatori di attività

Funzionalità Correlate

  • Guida alla Generazione di Report Esterni — panoramica concettuale e opzioni di integrazione aggiuntive
  • API di Esportazione Metriche — riferimento completo per l'endpoint di esportazione tramite template utilizzato sopra
  • Utilizzo dei Token API — crea e gestisci il token necessario per questo esempio
  • Report — genera report PDF/CSV già pronti direttamente nella piattaforma
MIT Licensed | Copyright 2026 Mirox Verwaltungs GmbH