# Phase 2: InfluxDB Integration - Roadmap ## Ziel Nutzung historischer Verbrauchsdaten aus InfluxDB2 für: - Bessere Verbrauchsprognosen - Optimierte Ladeplanung - Lernender Algorithmus ## Datenquellen in InfluxDB ### Zu analysierende Daten **Verbrauch** - `sensor.house_consumption` (Hausverbrauch in W) - `sensor.totay_load` (Tages-Gesamtverbrauch) - `sensor.bought_from_grid_today` (Netzbezug) **Erzeugung** - `sensor.pv_power` (PV-Leistung) - `sensor.today_s_pv_generation` (Tagesertrag) **Batterie** - `sensor.battery_power` (Ladung/Entladung) - `sensor.battery_state_of_charge` (SOC) - `sensor.today_battery_charge` (Geladen heute) - `sensor.today_battery_discharge` (Entladen heute) **Netz** - `sensor.gw_netzbezug` (Bezug) - `sensor.gw_netzeinspeisung` (Einspeisung) ## Implementierungsschritte ### Schritt 1: InfluxDB Verbindung in PyScript ```python """ InfluxDB Connector für historische Daten Speicherort: /config/pyscript/influxdb_connector.py """ from influxdb_client import InfluxDBClient from datetime import datetime, timedelta # Konfiguration (später in configuration.yaml) INFLUXDB_URL = "http://your-influxdb-server:8086" INFLUXDB_TOKEN = "your-token" INFLUXDB_ORG = "your-org" INFLUXDB_BUCKET = "home_assistant" @service def get_historical_consumption(days: int = 30): """ Holt historische Verbrauchsdaten aus InfluxDB Args: days: Anzahl vergangener Tage Returns: Dict mit stündlichen Durchschnittswerten """ client = InfluxDBClient( url=INFLUXDB_URL, token=INFLUXDB_TOKEN, org=INFLUXDB_ORG ) query_api = client.query_api() # Flux Query für stündliche Durchschnittswerte query = f''' from(bucket: "{INFLUXDB_BUCKET}") |> range(start: -{days}d) |> filter(fn: (r) => r["entity_id"] == "house_consumption") |> filter(fn: (r) => r["_field"] == "value") |> aggregateWindow(every: 1h, fn: mean, createEmpty: false) |> yield(name: "mean") ''' result = query_api.query(query) # Verarbeite Ergebnisse nach Wochentag und Stunde consumption_by_hour = {} for table in result: for record in table.records: timestamp = record.get_time() value = record.get_value() weekday = timestamp.weekday() # 0=Montag, 6=Sonntag hour = timestamp.hour key = f"{weekday}_{hour}" if key not in consumption_by_hour: consumption_by_hour[key] = [] consumption_by_hour[key].append(value) # Berechne Durchschnittswerte avg_consumption = {} for key, values in consumption_by_hour.items(): avg_consumption[key] = sum(values) / len(values) client.close() log.info(f"Historische Daten geladen: {len(avg_consumption)} Stunden-Profile") return avg_consumption ``` ### Schritt 2: Erweiterte Verbrauchsprognose ```python def predict_consumption(start_time, hours=24): """ Prognostiziert Verbrauch basierend auf historischen Daten Args: start_time: Startzeit der Prognose hours: Anzahl Stunden Returns: Dict mit stündlichen Verbrauchsprognosen """ # Lade historische Daten (gecacht) if not hasattr(predict_consumption, 'historical_data'): predict_consumption.historical_data = get_historical_consumption(30) historical = predict_consumption.historical_data forecast = {} for h in range(hours): dt = start_time + timedelta(hours=h) weekday = dt.weekday() hour = dt.hour key = f"{weekday}_{hour}" # Durchschnittlicher Verbrauch für diese Wochentag/Stunde avg_consumption = historical.get(key, 800) # Fallback 800W # Saisonale Anpassungen month = dt.month if month in [12, 1, 2]: # Winter avg_consumption *= 1.2 elif month in [6, 7, 8]: # Sommer avg_consumption *= 0.9 forecast[dt] = avg_consumption return forecast ``` ### Schritt 3: Optimierung mit Verbrauchsprognose ```python def optimize_charging_schedule_v2(price_data, pv_forecast, battery_state, config): """ Erweiterte Optimierung mit Verbrauchsprognose """ schedule = {} # NEU: Verbrauchsprognose holen consumption_forecast = predict_consumption(datetime.now(), hours=48) # Sortiere Preise sorted_prices = sorted(price_data.items(), key=lambda x: x[1]) threshold = calculate_price_threshold(price_data, config) # Batterie-Simulation current_energy_kwh = (battery_state['soc'] / 100.0) * config['battery_capacity'] for dt, price in sorted(price_data.items()): if dt <= datetime.now(): continue # PV und Verbrauch für diese Stunde pv_kwh = pv_forecast.get(dt, 0) consumption_w = consumption_forecast.get(dt, 800) consumption_kwh = consumption_w / 1000.0 # Berechne Energie-Bilanz net_energy = pv_kwh - consumption_kwh # Entscheidung: Laden oder nicht? action = 'auto' power_w = 0 reason = [] if price <= threshold: # Prüfe ob Batterie-Kapazität benötigt wird max_capacity_kwh = (config['max_soc'] / 100.0) * config['battery_capacity'] available_capacity = max_capacity_kwh - current_energy_kwh # Erwartetes Defizit in den nächsten 6 Stunden future_deficit = calculate_future_deficit( dt, consumption_forecast, pv_forecast, hours=6 ) # Lade wenn: # 1. Günstiger Preis # 2. Defizit erwartet # 3. Kapazität vorhanden if future_deficit > 0.5 and available_capacity > 0.5: action = 'charge' charge_kwh = min(available_capacity, future_deficit, config['max_charge_power'] / 1000.0) power_w = -int(charge_kwh * 1000) current_energy_kwh += charge_kwh reason.append(f"Defizit erwartet: {future_deficit:.1f} kWh") # Update Batterie-Stand für nächste Iteration current_energy_kwh += net_energy current_energy_kwh = max( (config['min_soc'] / 100.0) * config['battery_capacity'], min(current_energy_kwh, max_capacity_kwh) ) schedule[dt.isoformat()] = { 'action': action, 'power_w': power_w, 'price': price, 'pv_forecast': pv_kwh, 'consumption_forecast': consumption_kwh, 'net_energy': net_energy, 'battery_soc_forecast': (current_energy_kwh / config['battery_capacity']) * 100, 'reason': ', '.join(reason) } return schedule def calculate_future_deficit(start_dt, consumption_forecast, pv_forecast, hours=6): """ Berechnet erwartetes Energie-Defizit in den nächsten X Stunden """ total_deficit = 0 for h in range(hours): dt = start_dt + timedelta(hours=h) consumption_w = consumption_forecast.get(dt, 800) pv_kwh = pv_forecast.get(dt, 0) consumption_kwh = consumption_w / 1000.0 net = consumption_kwh - pv_kwh if net > 0: total_deficit += net return total_deficit ``` ### Schritt 4: Konfiguration erweitern ```yaml # Neue Input Helper für InfluxDB input_text: influxdb_url: name: "InfluxDB URL" initial: "http://192.168.xxx.xxx:8086" influxdb_token: name: "InfluxDB Token" initial: "your-token" influxdb_org: name: "InfluxDB Organization" initial: "homeassistant" influxdb_bucket: name: "InfluxDB Bucket" initial: "home_assistant" input_number: historical_data_days: name: "Historische Daten (Tage)" min: 7 max: 365 step: 1 initial: 30 icon: mdi:calendar-range ``` ### Schritt 5: Neue Automatisierung ```yaml automation: # Wöchentliches Update der historischen Daten - id: battery_optimizer_update_historical_data alias: "Batterie Optimierung: Historische Daten aktualisieren" description: "Lädt wöchentlich neue historische Daten aus InfluxDB" trigger: - platform: time at: "03:00:00" - platform: time_pattern # Jeden Sonntag days: /7 action: - service: pyscript.get_historical_consumption data: days: 30 - service: notify.persistent_notification data: title: "Batterie-Optimierung" message: "Historische Daten aktualisiert" ``` ## Metriken & KPIs ### Neue Dashboard-Elemente ```yaml template: - sensor: - name: "Verbrauchsprognose Genauigkeit" unique_id: consumption_forecast_accuracy state: > {% set actual = states('sensor.today_load') | float %} {% set forecast = state_attr('input_text.battery_charging_schedule', 'total_consumption_forecast') | float %} {% if forecast > 0 %} {{ ((1 - abs(actual - forecast) / forecast) * 100) | round(1) }} {% else %} unknown {% endif %} unit_of_measurement: "%" icon: mdi:target - name: "Optimierungs-Einsparung" unique_id: optimizer_savings state: > # Berechne tatsächliche Kosten vs. ohne Optimierung # TODO: Implementierung basierend auf InfluxDB Daten unit_of_measurement: "EUR" icon: mdi:piggy-bank ``` ## Erwartete Verbesserungen ### Genauigkeit - **Verbrauchsprognose**: +40% durch historische Daten - **Ladeplanung**: +25% durch bessere Vorhersage - **ROI**: Messbare Einsparungen ### Intelligenz - Wochenend-Muster erkennen - Saisonale Anpassungen - Feiertags-Berücksichtigung ### Adaptivität - System lernt aus Fehlprognosen - Automatische Parameter-Anpassung - Kontinuierliche Verbesserung ## Nächste Schritte 1. **InfluxDB Setup prüfen** - Sind alle Sensoren geloggt? - Retention Policy konfiguriert? - Genug historische Daten (min. 30 Tage)? 2. **Connector implementieren** - InfluxDB Client installieren: `pip install influxdb-client` - Token und Zugangsdaten konfigurieren - Erste Testabfrage durchführen 3. **Verbrauchsmuster analysieren** - Wochentag vs. Wochenende - Tagesverlauf typisch? - Saisonale Unterschiede? 4. **Integration testen** - Mit historischen Daten simulieren - Prognose-Genauigkeit messen - Schrittweise in Produktion nehmen 5. **Dashboard erweitern** - Prognose vs. Ist-Verbrauch - Einsparungen visualisieren - Lernkurve anzeigen ## Fragen für Phase 2 Bevor wir starten: 1. **InfluxDB**: Ist bereits konfiguriert? Zugangsdaten? 2. **Daten-Historie**: Wieviel Tage sind verfügbar? 3. **Sensoren**: Welche sind in InfluxDB geloggt? 4. **Retention**: Wie lange werden Daten behalten? 5. **Performance**: Wie groß ist die Datenbank? Lass uns das in einem nächsten Schritt gemeinsam analysieren! --- **Status**: Phase 1 abgeschlossen ✅ **Nächster Meilenstein**: InfluxDB Integration 🎯