MiroxMirox
  • Plateforme

    • Philosophie
    • Vue d'ensemble de la plateforme
    • Ressources de la plateforme
  • Mirox-Cloud

    • Vue d'ensemble du cloud
    • Microservices connectés
  • Mirox-Agent

    • Vue d'ensemble de l'agent
    • Options de déploiement
    • Data Scraper
    • Jumeau numérique
  • Détails techniques

    • Collecte de métriques
  • Informations

    • Centrales prises en charge
  • Types de centrale

    • Centrales solaires
    • Parcs éoliens
    • Stockage par batteries
  • Monitoring et visualisation

    • Monitoring en temps réel
    • Jumeau numérique
    • États des composants
    • Détection des pertes
    • Détection d'efficacité
    • Tableau de bord KPI
  • Gestion des données

    • Événements
    • Tickets
    • Prévisions
    • Rapports
  • Intégration et partage

    • Coopérations
    • Jetons API
    • VPN
    • Proxy
  • IA

    • Assistant IA et assistants
    • Accès agentique (MCP)
  • Facturation

    • Marché et tarifs
    • Comptabilité et facturation
  • Collaboration

    • Invitations
  • Sécurité

    • Authentification
    • Système de permissions
    • Restrictions de coopération
    • Journalisation d'audit d'accès
  • Nœuds

    • mrxnode
  • Application

    • Contrôle de porte
    • Relais générique
  • Cluster edge

    • Orchestration
  • Premiers pas

    • Premiers pas
  • Personnel

    • Utiliser le VPN
    • Utiliser le proxy
    • Authentification à deux facteurs
    • Sessions
    • Jetons API
  • Par centrale

    • Contacts
    • Périphériques réseau
    • Enregistreurs de données
    • Composants
    • VPN direct (par agent)
  • Organisation

    • Permissions des membres
    • Coopérations
    • Stockage de fichiers
  • Export de données

    • API d'export de métriques
    • MiroxQL — langage de requête
    • Génération externe de rapports
    • Grafana
    • Vue d'ensemble de l'API
  • Assistance

    • Demander un guide d'intégration
  • mrxnode

    • Vue d'ensemble
    • Guides
    • Déploiement de conteneur
    • Référence des commandes
    • Dépannage
  • Reporting

    • Générateur de rapports externe
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Plateforme

    • Philosophie
    • Vue d'ensemble de la plateforme
    • Ressources de la plateforme
  • Mirox-Cloud

    • Vue d'ensemble du cloud
    • Microservices connectés
  • Mirox-Agent

    • Vue d'ensemble de l'agent
    • Options de déploiement
    • Data Scraper
    • Jumeau numérique
  • Détails techniques

    • Collecte de métriques
  • Informations

    • Centrales prises en charge
  • Types de centrale

    • Centrales solaires
    • Parcs éoliens
    • Stockage par batteries
  • Monitoring et visualisation

    • Monitoring en temps réel
    • Jumeau numérique
    • États des composants
    • Détection des pertes
    • Détection d'efficacité
    • Tableau de bord KPI
  • Gestion des données

    • Événements
    • Tickets
    • Prévisions
    • Rapports
  • Intégration et partage

    • Coopérations
    • Jetons API
    • VPN
    • Proxy
  • IA

    • Assistant IA et assistants
    • Accès agentique (MCP)
  • Facturation

    • Marché et tarifs
    • Comptabilité et facturation
  • Collaboration

    • Invitations
  • Sécurité

    • Authentification
    • Système de permissions
    • Restrictions de coopération
    • Journalisation d'audit d'accès
  • Nœuds

    • mrxnode
  • Application

    • Contrôle de porte
    • Relais générique
  • Cluster edge

    • Orchestration
  • Premiers pas

    • Premiers pas
  • Personnel

    • Utiliser le VPN
    • Utiliser le proxy
    • Authentification à deux facteurs
    • Sessions
    • Jetons API
  • Par centrale

    • Contacts
    • Périphériques réseau
    • Enregistreurs de données
    • Composants
    • VPN direct (par agent)
  • Organisation

    • Permissions des membres
    • Coopérations
    • Stockage de fichiers
  • Export de données

    • API d'export de métriques
    • MiroxQL — langage de requête
    • Génération externe de rapports
    • Grafana
    • Vue d'ensemble de l'API
  • Assistance

    • Demander un guide d'intégration
  • mrxnode

    • Vue d'ensemble
    • Guides
    • Déploiement de conteneur
    • Référence des commandes
    • Dépannage
  • Reporting

    • Générateur de rapports externe
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Reporting

    • Génération de rapports externes - Exemples d'API

Génération de rapports externes - Exemples d'API

Récupérez les données de centrale directement depuis les API d'export Mirox et créez vos propres rapports avec l'outil de votre choix. Cet exemple parcourt les endpoints pertinents avec curl par souci de clarté, mais les mêmes principes s'appliquent avec Python, Power BI, Tableau ou tout autre client HTTP.

Prérequis

Avant de pouvoir exporter des données pour la génération de rapports externes, vous avez besoin de :

  1. Compte Mirox - Un compte utilisateur Mirox valide
  2. Permissions - Votre compte doit avoir la permission de lire le parc et de générer des rapports pour ce parc
  3. UID du parc - L'identifiant unique de la ressource parc sur laquelle vous souhaitez produire un rapport
  4. Jeton d'API - Un jeton d'API disposant au minimum du groupe de permissions Reporting (voir Utilisation des jetons d'API pour les instructions de création)

Endpoints d'export disponibles

La plateforme Mirox fournit plusieurs endpoints d'API pour exporter des données dans des formats adaptés à la génération de rapports externes. Les exports d'informations de parc et d'événements se trouvent sous le chemin d'API /v1/export/report/ ; les métriques de production utilisent l'endpoint dédié d'export par modèle /v1/export/metrics/template/{template_uid}.

Remarque importante

Les endpoints d'API présentés dans ce document sont des exemples à titre d'illustration. Les endpoints exacts peuvent changer. Veuillez consulter la documentation d'API actuelle sur https://service.mirox.io/docs pour les informations les plus récentes.

Informations de parc (JSON)

Les informations de base du parc peuvent être exportées en JSON avec :

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

Cela fournit les métadonnées du parc, notamment :

  • Nom, type et description
  • Localisation géographique et fuseau horaire
  • Spécifications techniques (production de crête, etc.)
  • Informations sur l'organisation et le portefeuille
  • Adresse et détails de mise en service

Pour tous les détails sur le schéma de réponse, voir la documentation de l'API d'informations de parc.

Événements de parc (CSV)

Les données d'événements peuvent être exportées en CSV avec :

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

Cet endpoint prend en charge les paramètres de requête suivants :

  • year : Filtrer par année (par ex. 2025)
  • quarter : Filtrer par trimestre (1-4)
  • month : Filtrer par mois (1-12)

Le CSV renvoyé contient les colonnes suivantes :

  • ID d'événement
  • Date de début
  • Date de fin
  • Durée (heures)
  • Type
  • Créateur
  • Description
  • Priorité

Filtrage des événements par priorité

Le champ Priorité indique l'importance de l'événement :

  • Valeurs >= 1000 : Événements importants (arrêts impactant la production, alarmes)
  • Valeurs < 1000 : Événements informatifs (connexions, changements d'état mineurs)

Filtrez par priorité dans votre outil de reporting pour mettre en évidence les événements significatifs.

Si aucun paramètre temporel n'est spécifié, l'endpoint renvoie les événements du dernier trimestre complet.

Pour les détails sur les paramètres de requête et le format de réponse, voir la documentation de l'API d'événements de parc.

Métriques de parc (CSV)

Les métriques de production et de performance peuvent être exportées en CSV avec l'endpoint d'export par modèle :

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

Cet endpoint prend en charge les paramètres de requête suivants :

  • park : Un ou plusieurs UID de parc (séparés par des virgules) à inclure dans l'export
  • portfolio : Un ou plusieurs UID de portefeuille (séparés par des virgules) ; chaque portefeuille est résolu en ses parcs
  • resolution : Intervalle d'agrégation (daily, weekly, monthly, quarterly ou yearly ; par défaut monthly)
  • year : Filtrer par année (par ex. 2025)
  • quarter : Filtrer par trimestre (1-4)
  • month : Filtrer par mois (1-12)
  • week : Filtrer par semaine ISO (résolution hebdomadaire)
  • day : Filtrer par jour (nécessite month)

Le paramètre resolution détermine la façon dont les données sont agrégées :

  • daily : Renvoie une ligne par jour avec les mesures journalières
  • monthly : Renvoie une ligne par mois avec les totaux mensuels agrégés et une colonne supplémentaire « Jours dans le mois »

Votre outil de business intelligence doit gérer ces différents formats de résolution de manière appropriée pour la visualisation et l'analyse.

Exports multi-centrales

Un seul appel peut exporter plusieurs centrales ou des portefeuilles entiers à la fois en passant des UID park et portfolio séparés par des virgules. C'est la voie recommandée lorsque vous construisez un rapport couvrant plus d'une centrale.

Les colonnes sont définies par le modèle d'export que vous référencez. L'exemple ci-dessous utilise le modèle ABCD12340001 (« Report Technical v1 »), qui inclut :

  • Énergie produite (kWh)
  • Énergie rapportée (kWh)
  • Énergie perdue par coupure réseau (kWh)
  • Énergie perdue par coupure externe (kWh)
  • Énergie cible (kWh)
  • Irradiation (kWh)

Pour tous les détails sur les paramètres de requête et le format de réponse, consultez la documentation d'API actuelle sur https://service.mirox.io/docs.

Exemples d'utilisation de l'API

Vous trouverez ci-dessous des exemples d'utilisation directe des endpoints d'export avec curl. Ces exemples illustrent la structure des appels d'API et le format des réponses.

Exemple 1 : Récupérer les informations de parc (JSON)

Requête :

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

Réponse (partielle) :

{
  "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"
  }
}

Exemple 2 : Exporter les données d'événements (CSV)

Requête :

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

Réponse (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

Notez le champ Priority avec des valeurs supérieures à 1000, indiquant des événements significatifs impactant la production.

Exemple 3 : Exporter les métriques mensuelles (CSV)

Requête :

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

Réponse (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

Cet exemple illustre des données agrégées mensuellement avec la colonne « Days in Month (d) » propre à l'option d'intervalle mensuel.

Utilisation dans différents outils

Ces appels d'API peuvent être appliqués dans divers environnements :

  • Python/Requests : Utilisez la bibliothèque requests pour effectuer des appels d'API dans des scripts Python
  • Power BI : Utilisez les sources de données « Web » pour importer directement des données JSON/CSV
  • Tableau : Configurez des connecteurs de données web pour l'intégration d'API
  • Excel : Utilisez Power Query pour importer et transformer les données d'API
  • Scripts personnalisés : Implémentez dans n'importe quel langage prenant en charge un client HTTP

Bonnes pratiques

Pour une utilisation efficace de l'API :

  1. Utilisez les jetons d'API de manière sécurisée - Ne codez jamais les jetons en dur dans les scripts ; utilisez des variables d'environnement
  2. Traitez correctement les données par intervalle - Assurez-vous que votre analyse gère correctement les formats de données journaliers et mensuels
  3. Filtrez les événements de manière appropriée - Utilisez le champ de priorité pour vous concentrer sur les événements significatifs (>=1000)
  4. Tenez compte du volume de données - Pour les grands parcs ou de longues périodes, exportez les données par lots gérables
  5. Mettez en place une gestion des erreurs - Gérez correctement les erreurs HTTP et les problèmes réseau

Dépannage

Erreurs d'authentification

Si vous recevez une erreur HTTP 401 :

  1. Vérifiez votre jeton d'API : Assurez-vous d'utiliser un jeton d'API valide et non expiré. Les jetons peuvent être générés dans vos paramètres utilisateur Mirox.

  2. Vérifiez l'UID du parc : Assurez-vous que l'UID du parc est valide et que vous y avez accès. La valeur d'exemple ABC123DEF456 est un espace réservé.

  3. Permissions du jeton : Vérifiez que votre jeton a reçu les permissions nécessaires pour accéder aux endpoints d'export.

Problèmes d'encodage CSV

Les exports CSV utilisent l'encodage UTF-8. Dans certains outils (par ex. Excel), vous devrez peut-être spécifier explicitement l'encodage lors de l'importation.

Exemple d'implémentation Python : générateur de rapports SolarViz

L'exemple suivant montre une implémentation Python complète qui utilise les API décrites ci-dessus pour créer un rapport personnalisé de production d'énergie.

Prérequis

Pour exécuter cet exemple Python, vous aurez besoin des bibliothèques suivantes :

pip install requests pandas matplotlib seaborn tabulate
  • requests : Pour effectuer des appels d'API vers la plateforme Mirox
  • pandas : Pour la manipulation et l'analyse des données
  • matplotlib et seaborn : Pour créer des visualisations
  • tabulate : Pour formater les tableaux dans le rapport

Code complet de l'exemple

Voici le code complet du générateur de rapports 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()

Comment ça fonctionne

  1. Configuration : Le script définit l'URL de l'API Mirox, le jeton d'API et l'UID du parc au début.

  2. Collecte de données : Le script récupère trois types de données depuis Mirox :

    • Informations de parc (JSON) incluant le nom, la localisation et la capacité
    • Événements significatifs (CSV) filtrés par priorité
    • Métriques mensuelles de production d'énergie (CSV)
  3. Traitement des données : Le script :

    • Convertit les données CSV en DataFrames Pandas pour une manipulation facile
    • Calcule des métriques de performance telles que le ratio de production et l'impact des coupures
    • Crée une visualisation en barres empilées de la production mensuelle et des pertes par coupure par rapport à la ligne cible
  4. Génération du rapport : Le script construit un rapport PDF (à l'aide de ReportLab) contenant :

    • Un résumé des informations de parc
    • Les métriques de performance
    • Le graphique de production d'énergie
    • Le tableau des événements significatifs
  5. Sortie : Le rapport est enregistré sous forme de fichier PDF qui peut être :

    • Ouvert dans n'importe quel lecteur PDF
    • Partagé directement avec les parties prenantes
    • Archivé ou intégré dans des flux de reporting

Options de personnalisation

Le générateur de rapports SolarViz peut être personnalisé de plusieurs façons :

  • Périodes : Modifiez les variables YEAR et QUARTER pour générer des rapports pour différentes périodes
  • Types de graphiques : Modifiez la fonction create_production_chart pour utiliser différents styles de visualisation
  • Métriques supplémentaires : Récupérez et incluez des métriques supplémentaires depuis Mirox ou d'autres sources de données
  • Format du rapport : Adaptez la mise en page ReportLab, ou remplacez-la par une sortie HTML ou un autre format selon vos besoins
  • Automatisation : Intégrez le script dans des flux de travail automatisés avec des tâches cron ou des planificateurs de tâches

Fonctionnalités associées

  • Guide de génération de rapports externes — vue d'ensemble conceptuelle et options d'intégration supplémentaires
  • API d'export de métriques — référence complète de l'endpoint d'export par modèle utilisé ci-dessus
  • Utilisation des jetons d'API — créez et gérez le jeton dont cet exemple a besoin
  • Rapports — générez des rapports PDF/CSV prêts à l'emploi directement dans la plateforme
MIT Licensed | Copyright 2026 Mirox Verwaltungs GmbH