MiroxMirox
  • Plataforma

    • Filosofia
    • Visão geral da plataforma
    • Recursos da plataforma
  • Mirox-Cloud

    • Visão geral da cloud
    • Microsserviços ligados
  • Mirox-Agent

    • Visão geral do agente
    • Opções de implementação
    • Data Scraper
    • Gémeo digital
  • Detalhes técnicos

    • Recolha de métricas
  • Informações

    • Centrais suportadas
  • Tipos de central

    • Centrais solares
    • Parques eólicos
    • Armazenamento por baterias
  • Monitorização e visualização

    • Monitorização em tempo real
    • Gémeo digital
    • Estados dos componentes
    • Deteção de perdas
    • Deteção de eficiência
    • Painel de KPI
  • Gestão de dados

    • Eventos
    • Tickets
    • Previsões
    • Relatórios
  • Integração e partilha

    • Cooperações
    • Tokens de API
    • VPN
    • Proxy
  • IA

    • Assistente de IA e assistentes
    • Acesso agêntico (MCP)
  • Faturação

    • Mercado e tarifas
    • Contabilidade e faturação
  • Colaboração

    • Convites
  • Segurança

    • Autenticação
    • Sistema de permissões
    • Restrições de cooperação
    • Registo de auditoria de acesso
  • Nós

    • mrxnode
  • Aplicação

    • Controlo de porta
    • Relé genérico
  • Cluster edge

    • Orquestração
  • Primeiros passos

    • Primeiros passos
  • Pessoal

    • Utilizar a VPN
    • Utilizar o proxy
    • Autenticação de dois fatores
    • Sessões
    • Tokens de API
  • Por central

    • Contactos
    • Dispositivos de rede
    • Registadores de dados
    • Componentes
    • VPN direta (por agente)
  • Organização

    • Permissões de membros
    • Cooperações
    • Armazenamento de ficheiros
  • Exportação de dados

    • API de exportação de métricas
    • MiroxQL — linguagem de consulta
    • Geração externa de relatórios
    • Grafana
    • Visão geral da API
  • Suporte

    • Pedir guia de integração
  • mrxnode

    • Visão geral
    • Guias
    • Implementação em contentor
    • Referência de comandos
    • Resolução de problemas
  • Relatórios

    • Gerador de relatórios externo
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Plataforma

    • Filosofia
    • Visão geral da plataforma
    • Recursos da plataforma
  • Mirox-Cloud

    • Visão geral da cloud
    • Microsserviços ligados
  • Mirox-Agent

    • Visão geral do agente
    • Opções de implementação
    • Data Scraper
    • Gémeo digital
  • Detalhes técnicos

    • Recolha de métricas
  • Informações

    • Centrais suportadas
  • Tipos de central

    • Centrais solares
    • Parques eólicos
    • Armazenamento por baterias
  • Monitorização e visualização

    • Monitorização em tempo real
    • Gémeo digital
    • Estados dos componentes
    • Deteção de perdas
    • Deteção de eficiência
    • Painel de KPI
  • Gestão de dados

    • Eventos
    • Tickets
    • Previsões
    • Relatórios
  • Integração e partilha

    • Cooperações
    • Tokens de API
    • VPN
    • Proxy
  • IA

    • Assistente de IA e assistentes
    • Acesso agêntico (MCP)
  • Faturação

    • Mercado e tarifas
    • Contabilidade e faturação
  • Colaboração

    • Convites
  • Segurança

    • Autenticação
    • Sistema de permissões
    • Restrições de cooperação
    • Registo de auditoria de acesso
  • Nós

    • mrxnode
  • Aplicação

    • Controlo de porta
    • Relé genérico
  • Cluster edge

    • Orquestração
  • Primeiros passos

    • Primeiros passos
  • Pessoal

    • Utilizar a VPN
    • Utilizar o proxy
    • Autenticação de dois fatores
    • Sessões
    • Tokens de API
  • Por central

    • Contactos
    • Dispositivos de rede
    • Registadores de dados
    • Componentes
    • VPN direta (por agente)
  • Organização

    • Permissões de membros
    • Cooperações
    • Armazenamento de ficheiros
  • Exportação de dados

    • API de exportação de métricas
    • MiroxQL — linguagem de consulta
    • Geração externa de relatórios
    • Grafana
    • Visão geral da API
  • Suporte

    • Pedir guia de integração
  • mrxnode

    • Visão geral
    • Guias
    • Implementação em contentor
    • Referência de comandos
    • Resolução de problemas
  • Relatórios

    • Gerador de relatórios externo
  • English
  • Deutsch
  • Español
  • Français
  • Português
  • Italiano
  • English
  • Relatórios

    • Geração Externa de Relatórios - Exemplos de API

Geração Externa de Relatórios - Exemplos de API

Obtenha dados de centrais diretamente a partir das APIs de exportação da Mirox e crie os seus próprios relatórios na ferramenta que preferir. Este exemplo percorre os endpoints relevantes com curl por uma questão de clareza, mas os mesmos princípios aplicam-se com Python, Power BI, Tableau ou qualquer cliente HTTP.

Pré-requisitos

Antes de poder exportar dados para a geração externa de relatórios, precisa de:

  1. Conta Mirox - Uma conta de utilizador Mirox válida
  2. Permissões - A sua conta tem de ter permissão para ler o parque e gerar relatórios para esse parque
  3. UID do parque - O identificador único do recurso do parque sobre o qual pretende relatar
  4. Token de API - Um token de API com, pelo menos, o grupo de permissões Reporting (consulte Utilização de Tokens de API para obter instruções de criação)

Endpoints de Exportação Disponíveis

A plataforma Mirox disponibiliza vários endpoints de API para exportar dados em formatos adequados à geração externa de relatórios. As informações do parque e as exportações de eventos encontram-se no caminho de API /v1/export/report/; as métricas de produção utilizam o endpoint dedicado de exportação por modelo /v1/export/metrics/template/{template_uid}.

Nota Importante

Os endpoints de API apresentados neste documento são exemplos para ilustração. Os endpoints exatos podem mudar. Consulte a documentação atual da API em https://service.mirox.io/docs para obter as informações mais recentes.

Informações do Parque (JSON)

As informações básicas do parque podem ser exportadas como JSON com:

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

Isto fornece metadados do parque, incluindo:

  • Nome, tipo e descrição
  • Localização geográfica e fuso horário
  • Especificações técnicas (produção de pico, etc.)
  • Informações da organização e da carteira
  • Endereço e detalhes de colocação em serviço

Para detalhes completos sobre o esquema da resposta, consulte a Documentação da API de Informações do Parque.

Eventos do Parque (CSV)

Os dados de eventos podem ser exportados como CSV com:

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

Este endpoint suporta os seguintes parâmetros de consulta:

  • year: Filtrar por ano (por exemplo, 2025)
  • quarter: Filtrar por trimestre (1-4)
  • month: Filtrar por mês (1-12)

O CSV devolvido contém as seguintes colunas:

  • ID do evento
  • Data de início
  • Data de fim
  • Duração (horas)
  • Tipo
  • Criador
  • Descrição
  • Prioridade

Filtragem de Eventos por Prioridade

O campo Prioridade indica a importância do evento:

  • Valores >= 1000: Eventos importantes (paragens com impacto na produção, alarmes)
  • Valores < 1000: Eventos informativos (ligações, alterações menores de estado)

Filtre por prioridade na sua ferramenta de relatórios para destacar eventos significativos.

Se não forem especificados parâmetros temporais, o endpoint devolve os eventos do trimestre concluído mais recentemente.

Para detalhes sobre os parâmetros do pedido e o formato da resposta, consulte a Documentação da API de Eventos do Parque.

Métricas do Parque (CSV)

As métricas de produção e desempenho podem ser exportadas como CSV através do endpoint de exportação por modelo:

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

Este endpoint suporta os seguintes parâmetros de consulta:

  • park: Um ou mais UIDs de parques (separados por vírgulas) a incluir na exportação
  • portfolio: Um ou mais UIDs de carteiras (separados por vírgulas); cada carteira resolve-se nos seus parques
  • resolution: Intervalo de agregação (daily, weekly, monthly, quarterly ou yearly; o valor predefinido é monthly)
  • year: Filtrar por ano (por exemplo, 2025)
  • quarter: Filtrar por trimestre (1-4)
  • month: Filtrar por mês (1-12)
  • week: Filtrar por semana ISO (resolução semanal)
  • day: Filtrar por dia (requer month)

O parâmetro resolution determina como os dados são agregados:

  • daily: Devolve uma linha por dia com medições diárias
  • monthly: Devolve uma linha por mês com totais mensais agregados e uma coluna adicional "Days in Month"

A sua ferramenta de business intelligence deve processar estes diferentes formatos de resolução de forma adequada para visualização e análise.

Exportações Multi-Central

Uma única chamada pode exportar várias centrais ou carteiras inteiras de uma só vez, passando UIDs park e portfolio separados por vírgulas. Este é o caminho recomendado quando cria um relatório que abrange mais do que uma central.

As colunas são definidas pelo modelo de exportação que referencia. O exemplo abaixo utiliza o modelo ABCD12340001 ("Report Technical v1"), que inclui:

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

Para detalhes completos sobre os parâmetros do pedido e o formato da resposta, consulte a documentação atual da API em https://service.mirox.io/docs.

Exemplos de Utilização da API

Abaixo encontram-se exemplos de como utilizar os endpoints de exportação diretamente com curl. Estes exemplos demonstram a estrutura das chamadas à API e o formato das respostas.

Exemplo 1: Obter Informações do Parque (JSON)

Pedido:

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

Resposta (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"
  }
}

Exemplo 2: Exportar Dados de Eventos (CSV)

Pedido:

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

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

Repare no campo Priority com valores superiores a 1000, indicando eventos significativos com impacto na produção.

Exemplo 3: Exportar Métricas Mensais (CSV)

Pedido:

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

Resposta (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 exemplo demonstra dados agregados mensalmente com a coluna "Days in Month (d)" específica da opção de intervalo mensal.

Utilização em Diferentes Ferramentas

Estas chamadas à API podem ser aplicadas em vários ambientes:

  • Python/Requests: Utilize a biblioteca requests para fazer chamadas à API em scripts Python
  • Power BI: Utilize fontes de dados "Web" para importar dados JSON/CSV diretamente
  • Tableau: Configure conectores de dados web para integração de API
  • Excel: Utilize o Power Query para importar e transformar dados da API
  • Scripts Personalizados: Implemente em qualquer linguagem com suporte para cliente HTTP

Boas Práticas

Para uma utilização eficaz da API:

  1. Utilize Tokens de API de Forma Segura - Nunca coloque tokens diretamente no código dos scripts; utilize variáveis de ambiente
  2. Processe os Dados de Intervalo Corretamente - Garanta que a sua análise processa adequadamente os formatos de dados diários e mensais
  3. Filtre os Eventos de Forma Adequada - Utilize o campo de prioridade para se concentrar em eventos significativos (>=1000)
  4. Considere o Volume de Dados - Para parques grandes ou longos períodos de tempo, exporte os dados em blocos geríveis
  5. Implemente o Tratamento de Erros - Trate adequadamente os erros HTTP e os problemas de rede

Resolução de Problemas

Erros de Autenticação

Se receber um erro HTTP 401:

  1. Verifique o seu token de API: Garanta que está a utilizar um token de API válido e não expirado. Os tokens podem ser gerados nas definições de utilizador da Mirox.

  2. Confirme o UID do parque: Garanta que o UID do parque é válido e que tem acesso ao mesmo. O valor de exemplo ABC123DEF456 é um marcador de posição.

  3. Permissões do token: Verifique se o seu token recebeu as permissões necessárias para aceder aos endpoints de exportação.

Problemas de Codificação de CSV

As exportações CSV utilizam codificação UTF-8. Em algumas ferramentas (por exemplo, o Excel), poderá ter de especificar explicitamente a codificação ao importar.

Exemplo de Implementação em Python: Gerador de Relatórios SolarViz

O exemplo seguinte mostra uma implementação completa em Python que utiliza as APIs descritas acima para criar um relatório personalizado de produção de energia.

Pré-requisitos

Para executar este exemplo em Python, vai precisar das seguintes bibliotecas:

pip install requests pandas matplotlib seaborn tabulate
  • requests: Para fazer chamadas à API da plataforma Mirox
  • pandas: Para manipulação e análise de dados
  • matplotlib e seaborn: Para criar visualizações
  • tabulate: Para formatar tabelas no relatório

Código Completo do Exemplo

Abaixo encontra-se o código completo do gerador de relatórios 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()

Como Funciona

  1. Configuração: O script define o URL da API da Mirox, o token de API e o UID do parque no início.

  2. Recolha de Dados: O script obtém três tipos de dados da Mirox:

    • Informações do parque (JSON), incluindo nome, localização e capacidade
    • Eventos significativos (CSV) filtrados por prioridade
    • Métricas mensais de produção de energia (CSV)
  3. Processamento de Dados: O script:

    • Converte os dados CSV em DataFrames do Pandas para facilitar a manipulação
    • Calcula métricas de desempenho como o rácio de produção e o impacto das paragens
    • Cria uma visualização em barras empilhadas da produção mensal e das perdas por paragem face à linha de objetivo
  4. Geração do Relatório: O script cria um relatório PDF (utilizando o ReportLab) que contém:

    • Resumo das informações do parque
    • Métricas de desempenho
    • Gráfico de produção de energia
    • Tabela de eventos significativos
  5. Saída: O relatório é guardado como um ficheiro PDF que pode ser:

    • Aberto em qualquer leitor de PDF
    • Partilhado diretamente com as partes interessadas
    • Arquivado ou integrado em fluxos de trabalho de relatórios

Opções de Personalização

O gerador de relatórios SolarViz pode ser personalizado de várias formas:

  • Períodos de Tempo: Altere as variáveis YEAR e QUARTER para gerar relatórios para diferentes períodos
  • Tipos de Gráfico: Modifique a função create_production_chart para utilizar diferentes estilos de visualização
  • Métricas Adicionais: Obtenha e inclua métricas adicionais da Mirox ou de outras fontes de dados
  • Formato do Relatório: Adapte a disposição do ReportLab ou substitua-a por HTML ou outro formato de saída, conforme necessário
  • Automatização: Integre o script em fluxos de trabalho automatizados com tarefas cron ou agendadores de tarefas

Funcionalidades Relacionadas

  • Guia de Geração Externa de Relatórios — visão geral conceptual e opções adicionais de integração
  • API de Exportação de Métricas — referência completa para o endpoint de exportação por modelo utilizado acima
  • Utilização de Tokens de API — crie e faça a gestão do token que este exemplo necessita
  • Relatórios — gere relatórios PDF/CSV prontos a usar diretamente na plataforma
MIT Licensed | Copyright 2026 Mirox Verwaltungs GmbH