this post was submitted on 20 Apr 2026
11 points (100.0% liked)

Energie

390 readers
22 users here now

Community für Austausch zum Thema Energie.

Verwandte Communities:

Netiquette wird vorausgesetzt. Gepflegt wird ein respektvoller Umgang - ohne Hass, Hetze, Diskriminierung.

Bitte beachtet die Regeln von Feddit.org.

✅ Deutsch
✅ English

Attribution


founded 2 years ago
MODERATORS
 

Was ist das hier?

Eine Home Assistant Automation (Blueprint) die meinen Hausakku vor der solaren Mittagsspitze gezielt ins Netz entlädt - damit der Akku leer ist wenn die PV-Spitze kommt und diese vollständig aufgenommen werden kann, statt ins Netz zu drücken. Das Ziel ist Netzdienlichkeit, nicht Gewinnmaximierung.


Warum Peak-Shave?

Das Stromnetz hat täglich ein massives Problem: Zwischen 11 und 14 Uhr speisen Millionen PV-Anlagen gleichzeitig ins Netz ein. Die Netzfrequenz steigt, Regelenergie wird teuer, im Extremfall müssen Anlagen abgeregelt werden.

Ein Hausakku könnte helfen — aber nur wenn er zur richtigen Zeit leer ist. Im Normalbetrieb lädt der Akku am Morgen und ist zur Mittagsspitze bereits voll. Er kann dann die PV-Spitze nicht mehr aufnehmen und die überschüssige Energie geht trotzdem ins Netz.

Die Idee: Den Akku vor dem Peak aktiv entladen, damit er die Spitze aufnehmen kann. Der Akku verhält sich dann wie ein Grünspeicher — er verschiebt Energie zeitlich statt sie zu verschleiern.


Voraussetzungen

Hardware:

  • Huawei SUN2000 Wechselrichter (M1 oder MB0 Serie)
  • Huawei LUNA2000 Batteriespeicher
  • Huawei Smart Dongle (WLAN-FE oder 4G)

Software:

Benötigte Entitäten:

  • select.batterien_betriebsmodus — Betriebsmodus umschalten
  • sensor.batterien_batterieladung — aktueller SOC in %
  • sensor.netzbezug_live — aktueller Netzbezug in W
  • sensor.sun_next_noon — Zeitpunkt des nächsten Sonnenhöchststands
  • sensor.energy_production_today — Tagesprognose Ost-Dach (Forecast.Solar)
  • sensor.energy_production_today_2 — Tagesprognose West-Dach (Forecast.Solar)
  • sensor.energy_production_today_remaining — Restprognose ab jetzt
  • sensor.energy_production_today_remaining_2 — Restprognose ab jetzt (zweiter String)

Die Entity-IDs können bei eurer Installation abweichen — bitte anpassen.


Die Logik in einfacher Sprache

Wann startet die Automation?

Einmal täglich wird geprüft ob Peak-Shave heute sinnvoll ist:

  • Die Tagesprognose muss über einem einstellbaren Schwellwert liegen (Standard 15 kWh)
  • Der Akku muss genug Ladung haben (mehr als Ziel-SOC + 5%)
  • Die Sonne muss aufgegangen sein
  • Es muss noch genug Zeit bis zum Sonnenhöchststand sein

Wann genau startet sie?

Der Startzeitpunkt wird dynamisch berechnet:

Startzeit = Solar-Noon − Puffer (90 Min.) − Entladezeit − 10 Min. Sicherheit

Die Entladezeit hängt vom aktuellen SOC ab — je voller der Akku, desto früher startet die Automation. Bei SOC 80% und 5 kW Entladeleistung dauert es etwa 100 Minuten den Akku auf 20% zu entladen. Die Automation startet dann entsprechend früher.

Was passiert während des Entladens?

Der Wechselrichter wird auf fully_fed_to_grid gesetzt — PV-Strom und Akkustrom gehen ins Netz. Die Automation läuft still im Hintergrund und überwacht drei Stopp-Bedingungen.

Fünf Fälle — klare Prioritäten

Fall A — Kein Netzbezug (höchste Priorität) Wenn der Netzbezug über 500 W für 60 Sekunden steigt, wird Peak-Shave sofort abgebrochen. Eigenverbrauch hat immer Vorrang. Die 60-Sekunden-Verzögerung verhindert Abbrüche durch kurze Leistungsspitzen.

Fall B — SOC-Ziel erreicht Wenn der Akku den eingestellten Mindest-SOC (Standard 20%) erreicht, wird zurück auf Eigenverbrauch geschaltet. Der Akku behält einen Sicherheitspuffer.

Fall C — Noon-Stopp Spätestens 90 Minuten vor dem Sonnenhöchststand wird gestoppt — damit genug Zeit bleibt den Akku von der PV-Spitze wieder vollzuladen.

Fall D — Startzeit-Check Alle 5 Minuten wird geprüft ob die berechnete Startzeit erreicht ist. Das 6-Minuten-Startfenster stellt sicher dass die Automation nicht mehrfach startet.

Fall E — Restprognose-Wächter Während des Entladens wird alle 5 Minuten geprüft ob die verbleibende PV-Prognose noch ausreicht um den Akku wieder vollzuladen. Wenn nicht — sofortiger Stopp. Das verhindert dass der Akku abends zu leer ist weil Wolken die Prognose zunichte gemacht haben.

Stopp wenn: Restprognose < (10 kWh − Akku aktuell in kWh)

Wirtschaftlichkeit

Das Ergebnis ist wirtschaftlich knapp negativ — das ist beabsichtigt:

  • Einspeisevergütung: ~8,5 ct/kWh
  • Zusätzlicher Akkuverschleiß: ~1,08 € pro Vollzyklus (6.500 € Akku ÷ 6.000 Zyklen)
  • Ca. 100 Peak-Shave Tage pro Jahr × 0,58 Extra-Zyklen = ~63 € Verschleiß
  • Ca. 100 Tage × 10 kWh × 8,5 ct = ~85 € Einnahmen
  • Ergebnis: ~22 € Gewinn pro Jahr — kaum über Break-even

Wer Peak-Shave wirtschaftlich betreiben will braucht eine höhere Einspeisevergütung oder dynamische Tarife. Das hier ist bewusst ein Beitrag zur Netzdienlichkeit — kein Geschäftsmodell.


Einstellbare Parameter

Parameter Standard Beschreibung
Prognose-Schwelle 15 kWh Mindest-Tagesprognose für Start
Ziel-SOC 20% Mindest-SOC beim Entladen
Stopp vor Solar-Noon 90 Min. Sicherheitspuffer für Nachladen
Netzbezugs-Schwelle 500 W Ab wann wird abgebrochen
Netzbezugs-Dauer 60 Sek. Wie lange muss Netzbezug anliegen

Hinweis zur Prognose-Schwelle: Forecast.Solar liegt in meiner Erfahrung systematisch 20-30% zu niedrig. Ich habe die Schwelle deshalb von 15 auf 12 kWh gesenkt. Wer genaue Prognosedaten hat kann höher ansetzen.

Hinweis zum Ziel-SOC: Mit Fall E als Sicherheitsnetz kann der Ziel-SOC aggressiver eingestellt werden — z.B. 10%. Fall E stoppt die Entladung automatisch wenn danach nicht mehr genug PV kommt um den Akku wieder vollzuladen.


Das Blueprint YAML

blueprint:
  name: "PV Peak-Shave Einspeisung (Grünspeicher)"
  description: >
    Entlädt den Akku vor dem solaren Höchststand gezielt ins Netz (fully_fed_to_grid),
    damit der Akku zur PV-Spitze leer ist und wieder vollgeladen werden kann.
    Verhält sich wie ein Grünspeicher mit Peak-Shave.
    Höchste Priorität: kein Netzbezug.
  domain: automation
  input:

    prognose_schwelle:
      name: Prognose-Schwelle (kWh)
      description: >
        Mindest-Tagesprognose damit die Automation überhaupt startet.
        Unter diesem Wert passiert nichts.
      default: 15
      selector:
        number:
          min: 5
          max: 40
          step: 0.5
          unit_of_measurement: kWh

    ziel_soc:
      name: Ziel-SOC beim Entladen (%)
      description: >
        Bis auf diesen SOC wird der Akku vor dem PV-Peak entladen.
        20% = 2 kWh Sicherheitspuffer bei 10 kWh Akku.
      default: 20
      selector:
        number:
          min: 5
          max: 50
          step: 5
          unit_of_measurement: "%"

    minuten_vor_noon:
      name: Stopp vor Solar-Noon (Minuten)
      description: >
        Spätestens so viele Minuten vor dem solaren Höchststand wird
        auf Maximaler Eigenverbrauch zurückgeschaltet.
      default: 90
      selector:
        number:
          min: 30
          max: 180
          step: 15
          unit_of_measurement: min

    netzbezug_schwelle:
      name: Netzbezugs-Schwelle (W)
      description: >
        Wenn der Netzbezug diesen Wert überschreitet, wird sofort auf
        Maximaler Eigenverbrauch zurückgeschaltet.
      default: 500
      selector:
        number:
          min: 100
          max: 2000
          step: 50
          unit_of_measurement: W

    netzbezug_dauer:
      name: Netzbezugs-Dauer vor Abbruch (Sekunden)
      description: >
        Der Netzbezug muss diese Zeit lang über der Schwelle liegen,
        bevor abgebrochen wird (verhindert kurze Spitzen).
      default: 60
      selector:
        number:
          min: 10
          max: 300
          step: 10
          unit_of_measurement: s

mode: queued
max: 2
max_exceeded: silent

trigger:
  - platform: time_pattern
    minutes: "/5"
    id: "check_startzeit"

  - platform: numeric_state
    entity_id: sensor.batterien_batterieladung
    below: !input ziel_soc
    id: "soc_ziel_erreicht"

  - platform: numeric_state
    entity_id: sensor.netzbezug_live
    above: !input netzbezug_schwelle
    for:
      seconds: 60
    id: "netzbezug_alarm"

  - platform: time_pattern
    minutes: "/5"
    id: "check_noon_stopp"

variables:
  prognose_schwelle_var: !input prognose_schwelle
  ziel_soc_var: !input ziel_soc
  minuten_vor_noon_var: !input minuten_vor_noon
  netzbezug_schwelle_var: !input netzbezug_schwelle

action:
  - choose:

    # ══════════════════════════════════════════════════════════════════
    # FALL A: Notfall-Abbruch – Netzbezug zu hoch (höchste Priorität)
    # ══════════════════════════════════════════════════════════════════
    - conditions:
        - condition: trigger
          id: "netzbezug_alarm"
        - condition: state
          entity_id: select.batterien_betriebsmodus
          state: "fully_fed_to_grid"
      sequence:
        - action: select.select_option
          target:
            entity_id: select.batterien_betriebsmodus
          data:
            option: maximise_self_consumption
        - action: system_log.write
          data:
            message: >
              PV Peak-Shave: ABBRUCH – Netzbezug
              {{ states('sensor.netzbezug_live') | round(0) }} W
              über Schwelle {{ netzbezug_schwelle_var }} W.
            level: warning

    # ══════════════════════════════════════════════════════════════════
    # FALL B: SOC-Ziel erreicht
    # ══════════════════════════════════════════════════════════════════
    - conditions:
        - condition: trigger
          id: "soc_ziel_erreicht"
        - condition: state
          entity_id: select.batterien_betriebsmodus
          state: "fully_fed_to_grid"
      sequence:
        - action: select.select_option
          target:
            entity_id: select.batterien_betriebsmodus
          data:
            option: maximise_self_consumption
        - action: system_log.write
          data:
            message: >
              PV Peak-Shave: SOC {{ states('sensor.batterien_batterieladung') | round(0) }} %
              <= Ziel {{ ziel_soc_var }} %. Zurück auf Eigenverbrauch.
            level: info

    # ══════════════════════════════════════════════════════════════════
    # FALL C: Solar-Noon naht – Noon-Stopp
    # ══════════════════════════════════════════════════════════════════
    - conditions:
        - condition: trigger
          id: "check_noon_stopp"
        - condition: state
          entity_id: select.batterien_betriebsmodus
          state: "fully_fed_to_grid"
        - condition: template
          value_template: >
            {% set noon_ts = states('sensor.sun_next_noon') | as_timestamp(0) %}
            {% set now_ts = now().timestamp() %}
            {% set minuten_bis_noon = (noon_ts - now_ts) / 60 %}
            {{ minuten_bis_noon <= minuten_vor_noon_var and minuten_bis_noon >= 0 }}
      sequence:
        - action: select.select_option
          target:
            entity_id: select.batterien_betriebsmodus
          data:
            option: maximise_self_consumption
        - action: system_log.write
          data:
            message: >
              PV Peak-Shave: Noon-Stopp –
              {{ ((states('sensor.sun_next_noon') | as_timestamp(0) - now().timestamp()) / 60) | round(0) }}
              Min. bis Solar-Noon.
            level: info

    # ══════════════════════════════════════════════════════════════════
    # FALL E: Restprognose reicht nicht mehr für vollen Akku
    # ══════════════════════════════════════════════════════════════════
    - conditions:
        - condition: trigger
          id: "check_noon_stopp"
        - condition: state
          entity_id: select.batterien_betriebsmodus
          state: "fully_fed_to_grid"
        - condition: template
          value_template: >
            {% set verbleibend = states('sensor.energy_production_today_remaining') | float(0)
                               + states('sensor.energy_production_today_remaining_2') | float(0) %}
            {% set akku_kwh = (states('sensor.batterien_batterieladung') | float(0) / 100) * 10 %}
            {{ verbleibend < (10 - akku_kwh) }}
      sequence:
        - action: select.select_option
          target:
            entity_id: select.batterien_betriebsmodus
          data:
            option: maximise_self_consumption
        - action: system_log.write
          data:
            message: >
              PV Peak-Shave: Stopp – Restprognose
              {{ (states('sensor.energy_production_today_remaining') | float(0) +
                  states('sensor.energy_production_today_remaining_2') | float(0)) | round(1) }} kWh
              reicht nicht für vollen Akku
              (aktuell {{ (states('sensor.batterien_batterieladung') | float(0) / 100 * 10) | round(1) }} kWh).
            level: info

    # ══════════════════════════════════════════════════════════════════
    # FALL D: Startzeit-Check – Peak-Shave starten
    # ══════════════════════════════════════════════════════════════════
    - conditions:
        - condition: trigger
          id: "check_startzeit"
        - condition: not
          conditions:
            - condition: state
              entity_id: select.batterien_betriebsmodus
              state: "fully_fed_to_grid"
        - condition: state
          entity_id: sun.sun
          state: "above_horizon"
        - condition: template
          value_template: >
            {% set noon_ts = states('sensor.sun_next_noon') | as_timestamp(0) %}
            {% set now_ts = now().timestamp() %}
            {% set minuten_bis_noon = (noon_ts - now_ts) / 60 %}
            {{ minuten_bis_noon > minuten_vor_noon_var }}
        - condition: template
          value_template: >
            {% set akku_kwh = (states('sensor.batterien_batterieladung') | float(0) / 100) * 10 %}
            {% set akku_min_kwh = (ziel_soc_var | float(20) / 100) * 10 %}
            {% set entladbar_kwh = [akku_kwh - akku_min_kwh, 0] | max %}
            {% set entladeleistung_kw = 3.5 %}
            {% set entladezeit_min = (entladbar_kwh / entladeleistung_kw * 60) | int %}
            {% set noon_ts = states('sensor.sun_next_noon') | as_timestamp(0) %}
            {% set start_ts = noon_ts - (minuten_vor_noon_var * 60) - (entladezeit_min * 60) - 600 %}
            {% set now_ts = now().timestamp() %}
            {{ now_ts >= start_ts and now_ts < (start_ts + 360) }}
        - condition: template
          value_template: >
            {% set prognose = states('sensor.energy_production_today') | float(0)
                            + states('sensor.energy_production_today_2') | float(0) %}
            {{ prognose >= prognose_schwelle_var }}
        - condition: template
          value_template: >
            {{ states('sensor.batterien_batterieladung') | float(0) > ziel_soc_var | float(20) + 5 }}
      sequence:
        - action: select.select_option
          target:
            entity_id: select.batterien_betriebsmodus
          data:
            option: fully_fed_to_grid
        - action: system_log.write
          data:
            message: >
              PV Peak-Shave: START –
              Prognose {{ (states('sensor.energy_production_today') | float(0) +
                           states('sensor.energy_production_today_2') | float(0)) | round(1) }} kWh,
              SOC {{ states('sensor.batterien_batterieladung') | round(0) }} %,
              Solar-Noon in {{ ((states('sensor.sun_next_noon') | as_timestamp(0) -
                                 now().timestamp()) / 60) | round(0) }} Min.
            level: info

Installation

  1. YAML-Datei als pv_peak_shave_einspeisung.yaml in den Ordner config/blueprints/automation/ kopieren
  2. Home Assistant neu laden oder Entwicklerwerkzeuge → YAML → Blueprints neu laden
  3. Einstellungen → Automationen → Automation erstellen → Blueprint auswählen
  4. Entity-IDs anpassen falls sie bei eurer Installation abweichen
  5. Parameter nach eurer Anlage einstellen
  6. Automation speichern und aktivieren

Hinweise und Einschränkungen

Akkugröße: Das Blueprint ist auf 10 kWh ausgelegt (Huawei LUNA2000-10kWh). Wer eine andere Akkugröße hat muss in Fall E den Wert 10 durch die eigene Kapazität in kWh ersetzen.

Entladeleistung: Im Blueprint ist 3,5 kW Entladeleistung hardcodiert (Zeile entladeleistung_kw = 3.5). Bitte an die eigene Anlage anpassen.

Forecast.Solar: Die Prognosegenauigkeit variiert stark je nach Standort und Dachausrichtung. Die Prognose-Schwelle sollte nach ein paar Wochen Beobachtung kalibriert werden.

Manueller Eingriff: Wenn Peak-Shave manuell abgebrochen wird, startet die Automation an diesem Tag nicht mehr automatisch neu — das Startfenster ist dann verpasst. Ein manueller Neustart ist möglich.


Was diese Automation nicht ist

Das ist kein wirtschaftliches Optimierungssystem. Es gibt elegantere Ansätze um den Akkuverschleiß zu minimieren — z.B. Ladestart verzögern statt aktiv entladen. Aber diese Ansätze erreichen kein echtes Peak-Shave weil der Akku beim solaren Höchststand nicht leer genug ist.

Wer primär den Akku schonen will und Netzdienlichkeit als Nebenziel hat sollte einen anderen Ansatz wählen.


Getestet mit: Huawei SUN2000-4KTL-M1, SUN2000-5KTL-M1, LUNA2000-10kWh, huawei_solar v1.6.0, Home Assistant 2026.4

you are viewing a single comment's thread
view the rest of the comments
[–] kaida@feddit.org 1 points 2 months ago (1 children)

Woah, cool! Ich bin gespannt, ob das auch mit unserem Setup funktioniert (Fronius). Der Akkudoktor hatte mal eine selbstgeschriebene Applikation rausgebracht, aber bei mir lief die nicht, und ich fänd es auch viel cooler das mit dem vorhandenen HA umzusetzen

[–] favstarmafia@feddit.org 2 points 1 month ago

Ich habe ein GIT dazu angelegt, falls jemand mit daran arbeiten will: https://codeberg.org/favstarmafia/PeakShave