Docs
Příklady

Pokročilý monitoring spotřeby energie

VeřejnéTyp obsahu: Návod

Ukázky v Pythonu pro sledování spotřeby stanic přes MyBox API — analýza trendů, varování před přetížením a odhalení abnormální spotřeby.

Proč monitorovat spotřebu?

Detailní monitoring spotřeby energie vám umožní:

  • Optimalizovat náklady - identifikovat největší spotřebiče
  • Analyzovat trendy - pochopit vzorce spotřeby
  • Předcházet přetížení - včasné varování před překročením limitů
  • Snižovat CO2 - sledovat a redukovat uhlíkovou stopu
  • Detekovat problémy - odhalit abnormální spotřebu

Real-time monitoring s MyBox API

Základní monitoring systém

import requests
import json
from datetime import datetime, timedelta
import pandas as pd
import matplotlib.pyplot as plt
from collections import deque

class EnergyMonitor:
    """
    Komplexní systém pro monitoring spotřeby energie
    """

    def __init__(self, device_id, api_key, api_secret):
        self.device_id = device_id
        self.api_key = api_key
        self.api_secret = api_secret
        self.base_url = "https://cloud.mybox.pro/admin-panel/v1"
        self.auth = (api_key, api_secret)

        # Datové struktury pro ukládání měření
        self.power_buffer = deque(maxlen=3600)  # 1 hodina dat (vzorek/sekundu)
        self.energy_data = []
        self.alerts = []

    def get_current_power(self):
        """
        Získání aktuálního příkonu
        """

        response = requests.get(
            f"{self.base_url}/external/live/device/{self.device_id}",
            auth=self.auth
        )

        if response.status_code == 200:
            data = response.json()

            # Extrakce telemetrických dat
            for owner_data in data.get('data', []):
                device = owner_data.get('device', {})
                nodes = device.get('nodes', [])

                for node in nodes:
                    if node.get('id') == 'ac-module':
                        sensors = node.get('sensors', [])

                        power_data = {
                            'timestamp': datetime.now(),
                            'l1_voltage': None,
                            'l2_voltage': None,
                            'l3_voltage': None,
                            'l1_current': None,
                            'l2_current': None,
                            'l3_current': None,
                            'total_power': None,
                            'power_factor': None,
                            'frequency': None
                        }

                        for sensor in sensors:
                            sensor_id = sensor.get('id', '')
                            value = sensor.get('value', '')

                            if 'voltage-l1' in sensor_id:
                                power_data['l1_voltage'] = float(value) if value else 0
                            elif 'voltage-l2' in sensor_id:
                                power_data['l2_voltage'] = float(value) if value else 0
                            elif 'voltage-l3' in sensor_id:
                                power_data['l3_voltage'] = float(value) if value else 0
                            elif 'current-l1' in sensor_id:
                                power_data['l1_current'] = float(value) if value else 0
                            elif 'current-l2' in sensor_id:
                                power_data['l2_current'] = float(value) if value else 0
                            elif 'current-l3' in sensor_id:
                                power_data['l3_current'] = float(value) if value else 0
                            elif 'act-power' in sensor_id:
                                power_data['total_power'] = float(value) if value else 0
                            elif 'power-factor' in sensor_id:
                                power_data['power_factor'] = float(value) if value else 0
                            elif 'frequency' in sensor_id:
                                power_data['frequency'] = float(value) if value else 0

                        # Výpočet celkového výkonu pokud není přímo k dispozici
                        if power_data['total_power'] is None:
                            p1 = (power_data['l1_voltage'] or 0) * (power_data['l1_current'] or 0)
                            p2 = (power_data['l2_voltage'] or 0) * (power_data['l2_current'] or 0)
                            p3 = (power_data['l3_voltage'] or 0) * (power_data['l3_current'] or 0)
                            power_data['total_power'] = (p1 + p2 + p3) / 1000  # kW

                        return power_data

        return None

    def start_monitoring(self, interval_seconds=5, duration_minutes=60):
        """
        Spuštění kontinuálního monitoringu

        Args:
            interval_seconds: Interval mezi měřeními
            duration_minutes: Celková doba monitoringu
        """

        import time

        end_time = datetime.now() + timedelta(minutes=duration_minutes)
        measurements = []

        print(f"Spouštím monitoring na {duration_minutes} minut...")
        print("-" * 50)

        while datetime.now() < end_time:
            # Získat aktuální data
            power_data = self.get_current_power()

            if power_data:
                measurements.append(power_data)
                self.power_buffer.append(power_data['total_power'])

                # Kontrola anomálií
                self._check_anomalies(power_data)

                # Zobrazení aktuálních hodnot
                self._display_current_values(power_data)

                # Uložení do bufferu
                self.energy_data.append(power_data)

            time.sleep(interval_seconds)

        # Analýza po dokončení
        self._analyze_session(measurements)

        return measurements

    def _check_anomalies(self, power_data):
        """
        Detekce anomálií ve spotřebě
        """

        alerts = []

        # Kontrola překročení limitů
        if power_data['total_power'] > 11:  # 11 kW limit
            alerts.append({
                'type': 'POWER_LIMIT',
                'message': f"Překročen limit výkonu: {power_data['total_power']:.2f} kW",
                'severity': 'HIGH'
            })

        # Kontrola nevyváženosti fází
        currents = [
            power_data['l1_current'] or 0,
            power_data['l2_current'] or 0,
            power_data['l3_current'] or 0
        ]

        if max(currents) > 0:
            imbalance = (max(currents) - min(currents)) / max(currents) * 100
            if imbalance > 20:  # 20% nevyváženost
                alerts.append({
                    'type': 'PHASE_IMBALANCE',
                    'message': f"Nevyváženost fází: {imbalance:.1f}%",
                    'severity': 'MEDIUM'
                })

        # Kontrola power factoru
        if power_data['power_factor'] and power_data['power_factor'] < 0.9:
            alerts.append({
                'type': 'LOW_POWER_FACTOR',
                'message': f"Nízký účiník: {power_data['power_factor']:.2f}",
                'severity': 'LOW'
            })

        # Zpracování alertů
        for alert in alerts:
            self.alerts.append({
                'timestamp': power_data['timestamp'],
                **alert
            })
            print(f"ALERT: {alert['message']}")

    def _display_current_values(self, power_data):
        """
        Zobrazení aktuálních hodnot
        """

        print(f"\n[{power_data['timestamp'].strftime('%H:%M:%S')}]")
        print(f"Výkon: {power_data['total_power']:.2f} kW")
        print(f"L1: {power_data['l1_current']:.1f}A @ {power_data['l1_voltage']:.0f}V")
        print(f"L2: {power_data['l2_current']:.1f}A @ {power_data['l2_voltage']:.0f}V")
        print(f"L3: {power_data['l3_current']:.1f}A @ {power_data['l3_voltage']:.0f}V")

        if power_data['power_factor']:
            print(f"Účiník: {power_data['power_factor']:.2f}")

    def _analyze_session(self, measurements):
        """
        Analýza naměřených dat
        """

        if not measurements:
            return

        df = pd.DataFrame(measurements)

        print("\n" + "=" * 50)
        print("ANALÝZA SPOTŘEBY")
        print("=" * 50)

        # Základní statistiky
        avg_power = df['total_power'].mean()
        max_power = df['total_power'].max()
        min_power = df['total_power'].min()

        print(f"\nStatistiky výkonu:")
        print(f"  Průměr: {avg_power:.2f} kW")
        print(f"  Maximum: {max_power:.2f} kW")
        print(f"  Minimum: {min_power:.2f} kW")

        # Výpočet spotřeby
        duration_hours = (df['timestamp'].max() - df['timestamp'].min()).total_seconds() / 3600
        total_energy = avg_power * duration_hours

        print(f"\nCelková spotřeba: {total_energy:.2f} kWh")
        print(f"Odhadovaná cena: {total_energy * 4.5:.2f} Kč")  # 4.5 Kč/kWh

        # Alertů souhrn
        if self.alerts:
            print(f"\nDetekováno {len(self.alerts)} alertů")
            alert_types = {}
            for alert in self.alerts:
                alert_types[alert['type']] = alert_types.get(alert['type'], 0) + 1

            for alert_type, count in alert_types.items():
                print(f"  - {alert_type}: {count}x")

Pokročilá analýza dat

import numpy as np
from scipy import signal
from sklearn.ensemble import IsolationForest

class AdvancedEnergyAnalytics:
    """
    Pokročilé analytické funkce pro energetická data
    """

    def __init__(self, energy_monitor):
        self.monitor = energy_monitor
        self.df = None

    def load_historical_data(self, device_id, days=30):
        """
        Načtení historických dat
        """

        response = requests.get(
            f"{self.monitor.base_url}/external/history/telemetry/{device_id}/act-power",
            auth=self.monitor.auth,
            params={
                'from': (datetime.now() - timedelta(days=days)).isoformat(),
                'to': datetime.now().isoformat(),
                'interval': '15m'  # 15 minutové intervaly
            }
        )

        if response.status_code == 200:
            data = response.json()
            # Převod na DataFrame
            self.df = pd.DataFrame(data['data'])
            self.df['timestamp'] = pd.to_datetime(self.df['timestamp'])
            self.df.set_index('timestamp', inplace=True)

            return self.df

        return None

    def detect_consumption_patterns(self):
        """
        Detekce vzorců ve spotřebě
        """

        if self.df is None:
            return None

        patterns = {
            'daily_profile': self._analyze_daily_pattern(),
            'weekly_profile': self._analyze_weekly_pattern(),
            'peak_hours': self._find_peak_hours(),
            'baseline_consumption': self._find_baseline()
        }

        return patterns

    def _analyze_daily_pattern(self):
        """
        Analýza denního profilu spotřeby
        """

        hourly_avg = self.df.groupby(self.df.index.hour)['value'].mean()

        return {
            'hourly_average': hourly_avg.to_dict(),
            'morning_peak': hourly_avg[6:9].max(),
            'evening_peak': hourly_avg[17:21].max(),
            'night_minimum': hourly_avg[[23, 0, 1, 2, 3, 4, 5]].min()
        }

    def _analyze_weekly_pattern(self):
        """
        Analýza týdenního profilu
        """

        daily_avg = self.df.groupby(self.df.index.dayofweek)['value'].mean()

        return {
            'daily_average': daily_avg.to_dict(),
            'weekday_avg': daily_avg[0:5].mean(),
            'weekend_avg': daily_avg[5:7].mean(),
            'busiest_day': daily_avg.idxmax()
        }

    def _find_peak_hours(self, percentile=90):
        """
        Identifikace špičkových hodin
        """

        threshold = self.df['value'].quantile(percentile / 100)
        peak_data = self.df[self.df['value'] > threshold]

        peak_hours = peak_data.index.hour.value_counts().head(3)

        return {
            'threshold_kw': threshold,
            'top_hours': peak_hours.to_dict(),
            'peak_percentage': len(peak_data) / len(self.df) * 100
        }

    def _find_baseline(self):
        """
        Určení základní spotřeby (standby)
        """

        # Použít 5. percentil jako baseline
        baseline = self.df['value'].quantile(0.05)

        return {
            'baseline_kw': baseline,
            'baseline_daily_kwh': baseline * 24,
            'baseline_monthly_kwh': baseline * 24 * 30,
            'baseline_yearly_cost': baseline * 24 * 365 * 4.5  # 4.5 Kč/kWh
        }

    def anomaly_detection(self, contamination=0.05):
        """
        Detekce anomálií pomocí Isolation Forest
        """

        if self.df is None or len(self.df) < 100:
            return None

        # Příprava features
        features = []
        for i in range(len(self.df)):
            features.append([
                self.df.iloc[i]['value'],
                self.df.index[i].hour,
                self.df.index[i].dayofweek,
                self.df.iloc[max(0, i-1)]['value'] if i > 0 else 0,  # Předchozí hodnota
                self.df.iloc[min(len(self.df)-1, i+1)]['value'] if i < len(self.df)-1 else 0  # Následující
            ])

        # Trénování modelu
        clf = IsolationForest(contamination=contamination, random_state=42)
        predictions = clf.fit_predict(features)

        # Identifikace anomálií
        anomalies = self.df[predictions == -1].copy()
        anomalies['severity'] = 'HIGH'

        return {
            'count': len(anomalies),
            'anomalies': anomalies.to_dict('records'),
            'percentage': len(anomalies) / len(self.df) * 100
        }

    def forecast_consumption(self, days_ahead=7):
        """
        Predikce budoucí spotřeby
        """

        if self.df is None or len(self.df) < 168:  # Minimálně týden dat
            return None

        # Jednoduchý ARIMA model nebo Prophet by byl lepší,
        # ale pro demonstraci použijeme průměrování

        # Vypočítat průměrný profil pro každou hodinu každého dne v týdnu
        weekly_profile = {}

        for day in range(7):
            for hour in range(24):
                mask = (self.df.index.dayofweek == day) & (self.df.index.hour == hour)
                weekly_profile[(day, hour)] = self.df[mask]['value'].mean()

        # Generovat predikci
        forecast = []
        current_time = datetime.now()

        for i in range(days_ahead * 24):
            future_time = current_time + timedelta(hours=i)
            day = future_time.weekday()
            hour = future_time.hour

            predicted_value = weekly_profile.get((day, hour), 0)

            # Přidat náhodnou variabilitu (±10%)
            predicted_value *= np.random.uniform(0.9, 1.1)

            forecast.append({
                'timestamp': future_time,
                'predicted_kw': predicted_value,
                'confidence_lower': predicted_value * 0.8,
                'confidence_upper': predicted_value * 1.2
            })

        return pd.DataFrame(forecast)

Vizualizace a dashboardy

import plotly.graph_objects as go
from plotly.subplots import make_subplots

class EnergyDashboard:
    """
    Interaktivní dashboard pro vizualizaci energetických dat
    """

    def __init__(self, analytics):
        self.analytics = analytics

    def create_realtime_dashboard(self):
        """
        Vytvoření real-time dashboardu
        """

        # Vytvoření subplotů
        fig = make_subplots(
            rows=3, cols=2,
            subplot_titles=(
                'Aktuální výkon', 'Rozdělení fází',
                'Historie 24h', 'Týdenní trend',
                'Denní profil', 'Nákladová analýza'
            ),
            specs=[
                [{'type': 'indicator'}, {'type': 'bar'}],
                [{'type': 'scatter'}, {'type': 'scatter'}],
                [{'type': 'bar'}, {'type': 'pie'}]
            ]
        )

        # 1. Aktuální výkon (gauge)
        current_power = self.analytics.monitor.power_buffer[-1] if self.analytics.monitor.power_buffer else 0

        fig.add_trace(
            go.Indicator(
                mode="gauge+number+delta",
                value=current_power,
                title={'text': "Výkon (kW)"},
                delta={'reference': 11},
                gauge={
                    'axis': {'range': [None, 15]},
                    'bar': {'color': "darkblue"},
                    'steps': [
                        {'range': [0, 6], 'color': "lightgray"},
                        {'range': [6, 11], 'color': "gray"}
                    ],
                    'threshold': {
                        'line': {'color': "red", 'width': 4},
                        'thickness': 0.75,
                        'value': 11
                    }
                }
            ),
            row=1, col=1
        )

        # 2. Rozdělení fází (bar chart)
        last_measurement = self.analytics.monitor.energy_data[-1] if self.analytics.monitor.energy_data else {}

        fig.add_trace(
            go.Bar(
                x=['L1', 'L2', 'L3'],
                y=[
                    last_measurement.get('l1_current', 0),
                    last_measurement.get('l2_current', 0),
                    last_measurement.get('l3_current', 0)
                ],
                name='Proud (A)',
                marker_color=['red', 'yellow', 'blue']
            ),
            row=1, col=2
        )

        # 3. Historie 24h
        if self.analytics.df is not None:
            last_24h = self.analytics.df.last('24H')

            fig.add_trace(
                go.Scatter(
                    x=last_24h.index,
                    y=last_24h['value'],
                    mode='lines',
                    name='Výkon',
                    line=dict(color='blue', width=2)
                ),
                row=2, col=1
            )

        # 4. Týdenní trend
        if self.analytics.df is not None:
            weekly = self.analytics.df.resample('D').mean().last('7D')

            fig.add_trace(
                go.Scatter(
                    x=weekly.index,
                    y=weekly['value'],
                    mode='lines+markers',
                    name='Denní průměr',
                    line=dict(color='green', width=2)
                ),
                row=2, col=2
            )

        # 5. Denní profil
        patterns = self.analytics.detect_consumption_patterns()
        if patterns:
            hourly = patterns['daily_profile']['hourly_average']

            fig.add_trace(
                go.Bar(
                    x=list(hourly.keys()),
                    y=list(hourly.values()),
                    name='Hodinový průměr',
                    marker_color='lightblue'
                ),
                row=3, col=1
            )

        # 6. Nákladová analýza
        costs = self._calculate_costs()

        fig.add_trace(
            go.Pie(
                labels=list(costs.keys()),
                values=list(costs.values()),
                hole=.3
            ),
            row=3, col=2
        )

        # Aktualizace layoutu
        fig.update_layout(
            height=900,
            showlegend=False,
            title_text="Energy Monitoring Dashboard",
            title_font_size=20
        )

        return fig

    def _calculate_costs(self):
        """
        Výpočet nákladů podle tarifů
        """

        if self.analytics.df is None:
            return {}

        # Simulace různých tarifů
        high_tariff_hours = [7, 8, 17, 18, 19, 20]
        low_tariff_hours = [23, 0, 1, 2, 3, 4, 5]

        costs = {
            'Vysoký tarif': 0,
            'Nízký tarif': 0,
            'Běžný tarif': 0
        }

        for hour in range(24):
            hourly_consumption = self.analytics.df[self.analytics.df.index.hour == hour]['value'].sum()

            if hour in high_tariff_hours:
                costs['Vysoký tarif'] += hourly_consumption * 6.0  # 6 Kč/kWh
            elif hour in low_tariff_hours:
                costs['Nízký tarif'] += hourly_consumption * 3.0  # 3 Kč/kWh
            else:
                costs['Běžný tarif'] += hourly_consumption * 4.5  # 4.5 Kč/kWh

        return costs

    def export_report(self, filename='energy_report.html'):
        """
        Export reportu do HTML
        """

        fig = self.create_realtime_dashboard()
        fig.write_html(filename)

        print(f"Report exportován do {filename}")

Alerting a notifikace

class AlertingSystem:
    """
    Systém pro zasílání alertů a notifikací
    """

    def __init__(self, thresholds):
        self.thresholds = thresholds
        self.alert_history = []

    def check_thresholds(self, measurement):
        """
        Kontrola překročení prahových hodnot
        """

        alerts = []

        # Kontrola výkonu
        if measurement['total_power'] > self.thresholds.get('max_power', 11):
            alerts.append({
                'type': 'POWER_EXCEEDED',
                'severity': 'HIGH',
                'value': measurement['total_power'],
                'threshold': self.thresholds['max_power'],
                'message': f"Výkon {measurement['total_power']:.2f} kW překročil limit {self.thresholds['max_power']} kW"
            })

        # Kontrola proudu na fázích
        for phase in ['l1', 'l2', 'l3']:
            current = measurement.get(f'{phase}_current', 0)
            max_current = self.thresholds.get(f'max_current_{phase}', 16)

            if current > max_current:
                alerts.append({
                    'type': f'CURRENT_EXCEEDED_{phase.upper()}',
                    'severity': 'HIGH',
                    'value': current,
                    'threshold': max_current,
                    'message': f"Proud na {phase.upper()} ({current:.1f}A) překročil limit {max_current}A"
                })

        return alerts

    def send_alert(self, alert):
        """
        Odeslání alertu
        """

        # Email notifikace
        if alert['severity'] == 'HIGH':
            self._send_email_alert(alert)

        # SMS pro kritické alerté
        if alert['severity'] == 'CRITICAL':
            self._send_sms_alert(alert)

        # Webhook pro integraci
        self._send_webhook(alert)

        # Uložení do historie
        self.alert_history.append({
            'timestamp': datetime.now(),
            **alert
        })

    def _send_email_alert(self, alert):
        """
        Odeslání emailové notifikace
        """

        import smtplib
        from email.mime.text import MIMEText

        subject = f"MyBox Alert: {alert['type']}"
        body = f"""
        Detekován alert ve vašem MyBox systému:

        Typ: {alert['type']}
        Závažnost: {alert['severity']}
        Hodnota: {alert['value']}
        Limit: {alert['threshold']}

        Zpráva: {alert['message']}

        Čas: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
        """

        # Zde byste implementovali skutečné odeslání emailu
        print(f"Email alert odeslán: {alert['type']}")

    def _send_webhook(self, alert):
        """
        Odeslání webhooku pro externí systémy
        """

        webhook_url = "https://your-webhook-endpoint.com/alerts"

        payload = {
            'timestamp': datetime.now().isoformat(),
            'alert': alert
        }

        # requests.post(webhook_url, json=payload)
        print(f"Webhook odeslán: {alert['type']}")

    def generate_daily_summary(self):
        """
        Generování denního souhrnu
        """

        today_alerts = [
            a for a in self.alert_history
            if a['timestamp'].date() == datetime.now().date()
        ]

        summary = {
            'date': datetime.now().date().isoformat(),
            'total_alerts': len(today_alerts),
            'by_severity': {},
            'by_type': {}
        }

        for alert in today_alerts:
            # Podle závažnosti
            severity = alert['severity']
            summary['by_severity'][severity] = summary['by_severity'].get(severity, 0) + 1

            # Podle typu
            alert_type = alert['type']
            summary['by_type'][alert_type] = summary['by_type'].get(alert_type, 0) + 1

        return summary

Příklad použití

# Konfigurace
API_KEY = "YOUR_API_KEY"
API_SECRET = "YOUR_API_SECRET"
DEVICE_ID = "qfeb-od13-ul2c-sgrl"

# Inicializace monitoru
monitor = EnergyMonitor(DEVICE_ID, API_KEY, API_SECRET)

# Spuštění monitoringu
measurements = monitor.start_monitoring(
    interval_seconds=5,
    duration_minutes=60
)

# Pokročilá analýza
analytics = AdvancedEnergyAnalytics(monitor)
analytics.load_historical_data(DEVICE_ID, days=30)

# Detekce vzorců
patterns = analytics.detect_consumption_patterns()
print(f"Denní špička: {patterns['daily_profile']['evening_peak']:.2f} kW")
print(f"Noční minimum: {patterns['daily_profile']['night_minimum']:.2f} kW")
print(f"Základní spotřeba: {patterns['baseline_consumption']['baseline_kw']:.2f} kW")

# Detekce anomálií
anomalies = analytics.anomaly_detection()
if anomalies:
    print(f"Detekováno {anomalies['count']} anomálií ({anomalies['percentage']:.1f}%)")

# Vytvoření dashboardu
dashboard = EnergyDashboard(analytics)
dashboard.export_report('energy_monitoring_report.html')

# Nastavení alertingu
alerting = AlertingSystem({
    'max_power': 11,
    'max_current_l1': 16,
    'max_current_l2': 16,
    'max_current_l3': 16
})

# Kontrola aktuálního stavu
current = monitor.get_current_power()
alerts = alerting.check_thresholds(current)
for alert in alerts:
    alerting.send_alert(alert)

print("Monitoring dokončen!")

Související návody

On this page

Stáhnout