# PV Peak-Shave Algorithmus für Home Assistant

Ein zeitraum-basierter Algorithmus zur Steuerung eines Huawei SUN2000 Wechselrichters mit LUNA2000 Akku. Ziel ist es, die tägliche PV-Einspeisespitze vollständig in den Akku zu laden und gleichzeitig Eigenverbrauch zu maximieren.

---

## Prioritäten

1. **PRIO 1** – Möglichst keinen Strom aus dem Netz beziehen
2. **PRIO 2** – Lokale Einspeisespitze in den Akku laden
3. **PRIO 3** – Die Anlage so netzdienlich wie möglich steuern

---

## Hardware

| Komponente | Details |
|---|---|
| Wechselrichter | Huawei SUN2000-4KTL-M1 |
| Akku | Huawei LUNA2000, 10 kWh nutzbare Kapazität |
| PV | Ost-West-Anlage, 3,6 kWp Ost + 2,0 kWp West |
| Steuerung | Home Assistant, Blueprint alle 5 Minuten (Tick) |

---

## Kernbegriffe

**SOC** – Aktueller Ladestand des Akkus in %  
**Min SOC** – 15 % (Hardware-End-of-Discharge-SOC im WR muss ebenfalls auf 15 % gesetzt sein)  
**SOC Puffer** – 30 %  
**WR-Limit** – Konfigurierbare maximale Lade-/Entladeleistung, default 5 kW

**Eigenverbrauch** – Huawei-Modus *Maximise Self Consumption*. PV versorgt zuerst das Haus, Überschuss lädt den Akku bis Max-Laden. Nachts entlädt der Akku für das Haus.

**Einspeisen** – Huawei-Modus *Fully Fed to Grid*. PV versorgt zuerst das Haus, der Akku entlädt zusätzlich ins Netz. Effektive Entladeleistung: `max(0, WR-Limit − Hausverbrauch − PV)`.

**Entladeleistung** – `max(0, WR-Limit kW − Hausverbrauch kW − PV kW)`, bei jedem Tick neu berechnet.

**Notwendige Zeit** – `max(0, (SOC − Min SOC) / 100 × Akku_kWh / Entladeleistung_kW × 60)` in Minuten. Wenn Entladeleistung = 0 (starke PV deckt WR-Limit), wird NotwendigeZeit auf 999 min gesetzt – Zone B startet per Frühstart, praktisch passiert nichts bis PV sinkt.

**PrognoseOK** – `Restprognose_kWh >= (100 − min_soc) / 100 × Akku_kWh`. Prüft ob genug PV kommt um den Akku von Min SOC auf 100 % zu laden. Die Formel ist fix auf Min SOC (nicht aktueller SOC), weil in Zone B der Akku bereits auf Min SOC entladen ist.  
Beispiel: min_soc=15 %, Akku=10 kWh → benötigt 8,5 kWh. 9,0 kWh → true. 7,0 kWh → false.

**Peak** – Prognostizierter Zeitpunkt der maximalen PV-Leistung (sensor.pv_peak_zeit_gewichtet). Fallback: sun.sun next_noon.

**Intervall** – Zeitfenster symmetrisch um den Peak, default 330 Minuten (lade_offset_min = 165 min).

**Restprognose** – Verbleibende PV-Energieprognose in kWh. Summe aus sensor.energy_production_today_remaining + sensor.energy_production_today_remaining_2, multipliziert mit kalibrierbarem Korrekturfaktor (default 1.0).

**Analyse-Modus** – input_boolean.peakshave_analyse_modus. Im Normalbetrieb wird nur bei Zustandsänderungen geloggt. Im Analyse-Modus zusätzlich bei jedem Tick.

---

## Zeiträume

| Zone | Von | Bis | Ziel |
|---|---|---|---|
| A | Sonnenaufgang − 60 Min | Peak − Intervall/2 − Notwendige Zeit | Akku auf Puffer SOC entladen, PV-Überschuss einspeisen |
| B | Ende Zone A | Peak − Intervall/2 | Akku auf Min SOC bringen |
| C | Peak − Intervall/2 | Peak + Intervall/2 | Akku im Peak laden |
| D | Peak + Intervall/2 | Sonnenuntergang | Zeit nach dem Peak mit PV |
| E | Sonnenuntergang | Sonnenaufgang − 60 Min | Zeit ohne PV, passiv |

---

## Regeln

Die Regeln werden bei jedem Tick in aufsteigender Rang-Reihenfolge geprüft. **Die erste zutreffende Regel gewinnt.** Trifft keine Regel zu, bleibt der letzte Zustand erhalten.

| Zeitraum | Rang | Status | Bedingung | Modus | Max-Laden |
|---|---|---|---|---|---|
| Immer | 1 | Netzbezug > Schwelle | | Eigenverbrauch | 5000 W |
| A | 2 | SOC < Min SOC | | Eigenverbrauch | 5000 W |
| A | 3 | SOC < Puffer SOC | | Eigenverbrauch | 1000 W |
| A | 4 | SOC > Puffer SOC | PrognoseOK | Einspeisen | 0 W |
| A | 5 | | | Eigenverbrauch | 5000 W |
| B | 2 | SOC < Min SOC | | Eigenverbrauch | 1000 W |
| B | 3 | | NOT PrognoseOK | Eigenverbrauch | 5000 W |
| B | 4 | Notwendige Zeit > Dauer A | PrognoseOK | Einspeisen | 0 W |
| C | 2 | | | Eigenverbrauch | 5000 W |
| D | 2 | | | Eigenverbrauch | 5000 W |
| E | 2 | | | Eigenverbrauch | 0 W |

### Wichtige Hinweise zu den Regeln

- **Rang 1** greift global in allen Zeiträumen. Netzbezug gilt erst ab konfigurierbarer Schwelle (default 1000 W) – kurze Schaltspitzen werden ignoriert.
- **A3** (Max-Laden 1000 W): Der Akku pendelt um Puffer SOC. Das ist gewollt, kein Fehler.
- **A5** (Fallback): Greift wenn SOC ≥ Puffer SOC aber PrognoseOK=false. Verhindert dass Max-Laden=0 aus Zone E aktiv bleibt.
- **B2 vor B3**: SOC-Schutz hat Vorrang vor PrognoseOK-Abbruch. Akku wird auch bei schlechter Prognose geschützt.
- **B4** (Frühstart): Dauer A = verbleibende Zeit bis zum formalen B-Startzeitpunkt zum Tick-Zeitpunkt. Ist Dauer A ≤ 0, feuert B4 sofort. Das ist der gewollte Frühstart wenn Zone A zu kurz ist.
- **Zone E**: Kein Software-Min-SOC-Schutz. Der Hardware-End-of-Discharge-SOC im Wechselrichter muss auf 15 % konfiguriert sein.

---

## Designphilosophie

Dieser Algorithmus ist bewusst einfach gehalten. Folgende Punkte wurden diskutiert und absichtlich nicht umgesetzt:

**PrognoseOK auf aktuellen SOC beziehen** – abgelehnt. In Zone B ist der Akku bereits auf Min SOC entladen. Der aktuelle SOC würde die Bewertung je nach Tageszeit verfälschen.

**Zeitraum A kann kurz oder leer werden** – kein Fehler. Regel B4 (Frühstart) greift dann sofort und startet die Entladung rechtzeitig.

**Hausverbrauch dynamisch messen** – abgelehnt. Konstanter Schätzwert (default 400 W), kalibrierbar über Log-Daten. Vereinfachung ist bewusst.

**Rang 1 kann System kurz festnageln** – akzeptiertes Risiko. Nach maximal einem Tick (5 Min) normalisiert sich der Betrieb.

**Zone E ohne Software-Min-SOC-Schutz** – bewusst. Verlässt sich auf Hardware-Schutz im Wechselrichter (muss auf 15 % konfiguriert sein).

**Allgemeiner Grundsatz:** Einfachheit vor Vollständigkeit. Optimierungen werden erst auf Basis realer Log-Daten eingebaut.

---

## Logging

**Pfad:** `/config/peakshave_log.csv`

**Trigger:**
- Zustandsänderung (Modus oder Max-Laden geändert) – immer
- Tick – nur wenn Analyse-Modus aktiv
- Unavailable – immer

**CSV-Felder:**

| Feld | Typ | Beschreibung |
|---|---|---|
| datum | YYYY-MM-DD | Datum |
| zeit | HH:MM:SS | Uhrzeit |
| zeitraum | A/B/C/D/E | Aktiver Zeitraum |
| rang | 1–4 / – | Ausgelöster Rang |
| modus_neu | Text | Neuer Betriebsmodus |
| modus_alt | Text | Vorheriger Betriebsmodus |
| max_laden_neu | W | Neuer Max-Laden-Wert |
| max_laden_alt | W | Vorheriger Max-Laden-Wert |
| soc | % | Aktueller Akkustand |
| pv_w | W | PV-Eingangsleistung |
| netzbezug_live | kW | Aktueller Netzbezug |
| einspeisung_live | kW | Aktuelle Einspeisung |
| prognose_ok | true/false | PrognoseOK zum Tick-Zeitpunkt |
| restprognose_kwh | kWh | Verbleibende PV-Prognose |
| peak_zeit | HH:MM | Prognostizierter PV-Peak |
| notwendige_zeit_min | min | Berechnete Entladezeit (999 wenn Entladeleistung = 0) |
| grund | Text | zustandsaenderung / tick_analyse / unavailable |
