MiroxMirox
  • Plataforma

    • Filosofía
    • Visión general de la plataforma
    • Recursos de la plataforma
  • Mirox-Cloud

    • Visión general de la nube
    • Microservicios conectados
  • Mirox-Agent

    • Visión general del agente
    • Opciones de despliegue
    • Data Scraper
    • Gemelo digital
  • Detalles técnicos

    • Recopilación de métricas
  • Información

    • Plantas compatibles
  • Tipos de planta

    • Plantas solares
    • Parques eólicos
    • Almacenamiento por baterías
  • Monitorización y visualización

    • Monitorización en tiempo real
    • Gemelo digital
    • Estados de componentes
    • Detección de pérdidas
    • Detección de eficiencia
    • Panel de KPI
  • Gestión de datos

    • Eventos
    • Tickets
    • Previsiones
    • Informes
  • Integración y colaboración

    • Cooperaciones
    • Tokens de API
    • VPN
    • Proxy
  • IA

    • Asistente de IA y asistentes
    • Acceso agéntico (MCP)
  • Facturación

    • Mercado y tarifas
    • Contabilidad y facturación
  • Colaboración

    • Invitaciones
  • Seguridad

    • Autenticación
    • Sistema de permisos
    • Restricciones de cooperación
    • Registro de auditoría de acceso
  • Nodos

    • mrxnode
  • Aplicación

    • Control de puerta
    • Relé genérico
  • Clúster en el borde

    • Orquestación
  • Primeros pasos

    • Primeros pasos
  • Personal

    • Usar la VPN
    • Usar el proxy
    • Autenticación de dos factores
    • Sesiones
    • Tokens de API
  • Por planta

    • Contactos
    • Dispositivos de red
    • Registradores de datos
    • Componentes
    • VPN directa (por agente)
  • Organización

    • Permisos de miembros
    • Cooperaciones
    • Almacenamiento de archivos
  • Exportación de datos

    • API de exportación de métricas
    • MiroxQL — lenguaje de consulta
    • Generación externa de informes
    • Grafana
    • Visión general de la API
  • Soporte

    • Solicitar guía de integración
  • mrxnode

    • Visión general
    • Guías
    • Despliegue de contenedor
    • Referencia de comandos
    • Solución de problemas
  • Generación de informes

    • Generador de informes externo
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Plataforma

    • Filosofía
    • Visión general de la plataforma
    • Recursos de la plataforma
  • Mirox-Cloud

    • Visión general de la nube
    • Microservicios conectados
  • Mirox-Agent

    • Visión general del agente
    • Opciones de despliegue
    • Data Scraper
    • Gemelo digital
  • Detalles técnicos

    • Recopilación de métricas
  • Información

    • Plantas compatibles
  • Tipos de planta

    • Plantas solares
    • Parques eólicos
    • Almacenamiento por baterías
  • Monitorización y visualización

    • Monitorización en tiempo real
    • Gemelo digital
    • Estados de componentes
    • Detección de pérdidas
    • Detección de eficiencia
    • Panel de KPI
  • Gestión de datos

    • Eventos
    • Tickets
    • Previsiones
    • Informes
  • Integración y colaboración

    • Cooperaciones
    • Tokens de API
    • VPN
    • Proxy
  • IA

    • Asistente de IA y asistentes
    • Acceso agéntico (MCP)
  • Facturación

    • Mercado y tarifas
    • Contabilidad y facturación
  • Colaboración

    • Invitaciones
  • Seguridad

    • Autenticación
    • Sistema de permisos
    • Restricciones de cooperación
    • Registro de auditoría de acceso
  • Nodos

    • mrxnode
  • Aplicación

    • Control de puerta
    • Relé genérico
  • Clúster en el borde

    • Orquestación
  • Primeros pasos

    • Primeros pasos
  • Personal

    • Usar la VPN
    • Usar el proxy
    • Autenticación de dos factores
    • Sesiones
    • Tokens de API
  • Por planta

    • Contactos
    • Dispositivos de red
    • Registradores de datos
    • Componentes
    • VPN directa (por agente)
  • Organización

    • Permisos de miembros
    • Cooperaciones
    • Almacenamiento de archivos
  • Exportación de datos

    • API de exportación de métricas
    • MiroxQL — lenguaje de consulta
    • Generación externa de informes
    • Grafana
    • Visión general de la API
  • Soporte

    • Solicitar guía de integración
  • mrxnode

    • Visión general
    • Guías
    • Despliegue de contenedor
    • Referencia de comandos
    • Solución de problemas
  • Generación de informes

    • Generador de informes externo
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Generación de informes

    • Generación de Informes Externos - Ejemplos de API

Generación de Informes Externos - Ejemplos de API

Extraiga los datos de la planta directamente desde las API de exportación de Mirox y cree sus propios informes con la herramienta que prefiera. Este ejemplo recorre los endpoints relevantes con curl para mayor claridad, pero los mismos principios se aplican con Python, Power BI, Tableau o cualquier cliente HTTP.

Requisitos previos

Antes de poder exportar datos para la generación de informes externos, necesita:

  1. Cuenta de Mirox - Una cuenta de usuario de Mirox válida
  2. Permisos - Su cuenta debe tener permiso para leer el parque y generar informes de ese parque
  3. UID del parque - El identificador único del recurso de parque sobre el que desea informar
  4. Token de API - Un token de API con al menos el grupo de permisos Reporting (consulte Uso de Tokens de API para obtener instrucciones de creación)

Endpoints de exportación disponibles

La plataforma Mirox proporciona varios endpoints de API para exportar datos en formatos adecuados para la generación de informes externos. La información del parque y las exportaciones de eventos se encuentran bajo la ruta de API /v1/export/report/; las métricas de producción utilizan el endpoint dedicado de exportación de plantillas /v1/export/metrics/template/{template_uid}.

Nota importante

Los endpoints de API mostrados en este documento son ejemplos ilustrativos. Los endpoints exactos pueden cambiar. Consulte la documentación actual de la API en https://service.mirox.io/docs para obtener la información más reciente.

Información del parque (JSON)

La información básica del parque puede exportarse como JSON con:

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

Esto proporciona los metadatos del parque, incluyendo:

  • Nombre, tipo y descripción
  • Ubicación geográfica y zona horaria
  • Especificaciones técnicas (producción máxima, etc.)
  • Información de la organización y la cartera
  • Dirección y detalles de puesta en marcha

Para obtener todos los detalles sobre el esquema de respuesta, consulte la Documentación de la API de Información del Parque.

Eventos del parque (CSV)

Los datos de eventos pueden exportarse como CSV con:

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

Este endpoint admite los siguientes parámetros de consulta:

  • year: Filtrar por año (p. ej., 2025)
  • quarter: Filtrar por trimestre (1-4)
  • month: Filtrar por mes (1-12)

El CSV devuelto contiene las siguientes columnas:

  • ID de evento
  • Fecha de inicio
  • Fecha de fin
  • Duración (horas)
  • Tipo
  • Creador
  • Descripción
  • Prioridad

Filtrado de eventos por prioridad

El campo Prioridad indica la importancia del evento:

  • Valores >= 1000: Eventos importantes (paradas que afectan a la producción, alarmas)
  • Valores < 1000: Eventos informativos (conexiones, cambios de estado menores)

Filtre por prioridad en su herramienta de informes para resaltar los eventos significativos.

Si no se especifican parámetros de tiempo, el endpoint devuelve los eventos del trimestre completado más recientemente.

Para obtener detalles sobre los parámetros de la solicitud y el formato de respuesta, consulte la Documentación de la API de Eventos del Parque.

Métricas del parque (CSV)

Las métricas de producción y rendimiento pueden exportarse como CSV con el endpoint de exportación de plantillas:

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

Este endpoint admite los siguientes parámetros de consulta:

  • park: Uno o varios UID de parque (separados por comas) a incluir en la exportación
  • portfolio: Uno o varios UID de cartera (separados por comas); cada cartera se resuelve en sus parques
  • resolution: Intervalo de agregación (daily, weekly, monthly, quarterly o yearly; el valor predeterminado es monthly)
  • year: Filtrar por año (p. ej., 2025)
  • quarter: Filtrar por trimestre (1-4)
  • month: Filtrar por mes (1-12)
  • week: Filtrar por semana ISO (resolución semanal)
  • day: Filtrar por día (requiere month)

El parámetro resolution determina cómo se agregan los datos:

  • daily: Devuelve una fila por día con mediciones diarias
  • monthly: Devuelve una fila por mes con totales mensuales agregados y una columna adicional "Días del mes"

Su herramienta de inteligencia de negocio debe gestionar adecuadamente estos diferentes formatos de resolución para la visualización y el análisis.

Exportaciones multiplanta

Una sola llamada puede exportar varias plantas o carteras completas a la vez pasando UID de park y portfolio separados por comas. Esta es la vía recomendada cuando crea un informe que abarca más de una planta.

Las columnas se definen mediante la plantilla de exportación a la que haga referencia. El ejemplo siguiente utiliza la plantilla ABCD12340001 ("Report Technical v1"), que incluye:

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

Para obtener todos los detalles sobre los parámetros de la solicitud y el formato de respuesta, consulte la documentación actual de la API en https://service.mirox.io/docs.

Ejemplos de uso de la API

A continuación se muestran ejemplos de cómo utilizar los endpoints de exportación directamente con curl. Estos ejemplos demuestran la estructura de las llamadas a la API y el formato de las respuestas.

Ejemplo 1: Obtención de la información del parque (JSON)

Solicitud:

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

Respuesta (parcial):

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

Ejemplo 2: Exportación de datos de eventos (CSV)

Solicitud:

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

Respuesta (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

Observe el campo Priority con valores superiores a 1000, que indican eventos significativos que afectan a la producción.

Ejemplo 3: Exportación de métricas mensuales (CSV)

Solicitud:

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

Respuesta (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

Este ejemplo demuestra datos agregados mensualmente con la columna "Days in Month (d)" específica de la opción de intervalo mensual.

Uso en diferentes herramientas

Estas llamadas a la API pueden aplicarse en diversos entornos:

  • Python/Requests: Utilice la biblioteca requests para realizar llamadas a la API en scripts de Python
  • Power BI: Utilice fuentes de datos "Web" para importar datos JSON/CSV directamente
  • Tableau: Configure conectores de datos web para la integración con la API
  • Excel: Utilice Power Query para importar y transformar datos de la API
  • Scripts personalizados: Implemente en cualquier lenguaje con soporte de cliente HTTP

Buenas prácticas

Para un uso eficaz de la API:

  1. Utilice los tokens de API de forma segura - Nunca codifique los tokens directamente en los scripts; use variables de entorno
  2. Gestione correctamente los datos por intervalo - Asegúrese de que su análisis maneje adecuadamente los formatos de datos diarios y mensuales
  3. Filtre los eventos adecuadamente - Utilice el campo de prioridad para centrarse en los eventos significativos (>=1000)
  4. Tenga en cuenta el volumen de datos - Para parques grandes o periodos de tiempo largos, exporte los datos en fragmentos manejables
  5. Implemente la gestión de errores - Maneje adecuadamente los errores HTTP y los problemas de red

Resolución de problemas

Errores de autenticación

Si recibe un error HTTP 401:

  1. Compruebe su token de API: Asegúrese de utilizar un token de API válido y no caducado. Los tokens pueden generarse en la configuración de usuario de Mirox.

  2. Verifique el UID del parque: Asegúrese de que el UID del parque sea válido y de que tenga acceso a él. El valor de ejemplo ABC123DEF456 es un marcador de posición.

  3. Permisos del token: Verifique que su token tenga concedidos los permisos necesarios para acceder a los endpoints de exportación.

Problemas de codificación CSV

Las exportaciones CSV utilizan la codificación UTF-8. En algunas herramientas (p. ej., Excel), puede que necesite especificar explícitamente la codificación al importar.

Ejemplo de implementación en Python: Generador de informes SolarViz

El siguiente ejemplo muestra una implementación completa en Python que utiliza las API descritas anteriormente para crear un informe personalizado de producción de energía.

Requisitos previos

Para ejecutar este ejemplo de Python, necesitará las siguientes bibliotecas:

pip install requests pandas matplotlib seaborn tabulate
  • requests: Para realizar llamadas a la API de la plataforma Mirox
  • pandas: Para la manipulación y el análisis de datos
  • matplotlib y seaborn: Para crear visualizaciones
  • tabulate: Para dar formato a las tablas del informe

Código de ejemplo completo

A continuación se muestra el código completo del generador de informes 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()

Cómo funciona

  1. Configuración: El script establece la URL de la API de Mirox, el token de API y el UID del parque al principio.

  2. Recopilación de datos: El script obtiene tres tipos de datos de Mirox:

    • Información del parque (JSON), incluyendo nombre, ubicación y capacidad
    • Eventos significativos (CSV) filtrados por prioridad
    • Métricas mensuales de producción de energía (CSV)
  3. Procesamiento de datos: El script:

    • Convierte los datos CSV en DataFrames de Pandas para facilitar su manipulación
    • Calcula métricas de rendimiento como la ratio de producción y el impacto de las paradas
    • Crea una visualización de barras apiladas de la producción mensual y las pérdidas por parada frente a la línea objetivo
  4. Generación del informe: El script crea un informe PDF (usando ReportLab) que contiene:

    • Resumen de la información del parque
    • Métricas de rendimiento
    • Gráfico de producción de energía
    • Tabla de eventos significativos
  5. Salida: El informe se guarda como un archivo PDF que puede:

    • Abrirse en cualquier visor de PDF
    • Compartirse directamente con las partes interesadas
    • Archivarse o integrarse en flujos de trabajo de generación de informes

Opciones de personalización

El generador de informes SolarViz puede personalizarse de varias maneras:

  • Periodos de tiempo: Cambie las variables YEAR y QUARTER para generar informes de diferentes periodos
  • Tipos de gráfico: Modifique la función create_production_chart para usar diferentes estilos de visualización
  • Métricas adicionales: Obtenga e incluya métricas adicionales de Mirox o de otras fuentes de datos
  • Formato del informe: Adapte el diseño de ReportLab o sustitúyalo por un formato de salida HTML u otro según sus necesidades
  • Automatización: Integre el script en flujos de trabajo automatizados con tareas cron o programadores de tareas

Funciones relacionadas

  • Guía de Generación de Informes Externos — descripción conceptual y opciones de integración adicionales
  • API de Exportación de Métricas — referencia completa del endpoint de exportación de plantillas utilizado anteriormente
  • Uso de Tokens de API — cree y gestione el token que necesita este ejemplo
  • Informes — genere informes PDF/CSV listos para usar directamente en la plataforma
MIT Licensed | Copyright 2026 Mirox Verwaltungs GmbH