Update: Battery Optimizer v3.4.0 mit allen Fixes und Features

This commit is contained in:
felix.zoesch
2025-12-12 08:20:19 +01:00
commit d2a41aad2d
78 changed files with 18053 additions and 0 deletions

255
DIAGNOSE_LADE_PROBLEM.md Normal file
View File

@@ -0,0 +1,255 @@
# Diagnose: Battery Charging nicht funktioniert
## Problem-Beschreibung
Heute Nacht wurde nicht geladen, obwohl:
- Der Speicher von INTERNAL auf REMOTE geschaltet wurde
- `goodwe_manual_control` aktiviert wurde
- Nach ein paar Sekunden wurde es wieder deaktiviert
## Wahrscheinliche Ursachen
### 1. Stündliche Ausführung stoppt das Laden
**Problem**: Die Automation "Batterie Optimierung: Stündliche Ausführung" läuft **jede Stunde** um xx:05 und prüft den Schedule für die aktuelle Stunde.
**Verhalten**:
- Stunde mit `action='charge'` → Laden wird aktiviert
- Stunde mit `action='auto'` → Laden wird deaktiviert
**Szenario**:
```
23:05 → Schedule sagt "charge" → Laden startet
00:05 → Schedule sagt "auto" → Laden stoppt
```
**Mögliche Ursachen**:
- Schedule enthält nur 1 Ladestunde statt mehrere
- Zeitzone-Problem: Falsche Stunde wird geprüft
- Tomorrow-Daten fehlen im Schedule
### 2. Schedule wurde nicht richtig erstellt
**Problem**: Die tägliche Berechnung um 14:05 hat keinen sinnvollen Ladeplan erstellt.
**Mögliche Ursachen**:
- Batterie war schon voll (kein Ladebedarf)
- Tomorrow-Preise waren noch nicht verfügbar
- Alle Nachtstunden waren nicht unter den N günstigsten
### 3. Zeitzone-Problem in execute_charging_schedule
**Problem**: Der Vergleich zwischen aktueller Zeit und Schedule-Einträgen schlägt fehl.
Code in Zeile 593-606:
```python
entry_dt = datetime.fromisoformat(entry['datetime'])
if entry_dt.tzinfo is None:
entry_dt = entry_dt.replace(tzinfo=TIMEZONE)
entry_date = entry_dt.date()
entry_hour = entry_dt.hour
if entry_date == current_date and entry_hour == current_hour:
current_entry = entry
```
**Mögliches Problem**: Die Datetimes im Schedule sind nicht korrekt timezone-aware.
## Debug-Schritte
### Schritt 1: Schedule prüfen
Gehe zu **Developer Tools → States** und suche nach:
```
pyscript.battery_charging_schedule
```
**Was zu prüfen**:
1. Wann wurde `last_update` zuletzt aktualisiert?
2. Wie viele `num_charges` sind geplant?
3. Wie viele `num_charges_tomorrow` für die Nacht?
4. Schau dir das `schedule` Array in den Attributen an
**Interpretation**:
- `num_charges = 0` → Keine Ladungen geplant (Batterie war voll?)
- `num_charges_tomorrow = 0` → Keine Nachtstunden geplant
- `has_tomorrow_data = false` → Morgen-Preise fehlen
### Schritt 2: Home Assistant Logs prüfen
Öffne die Home Assistant Logs und suche nach PyScript-Ausgaben:
**Für die tägliche Berechnung** (sollte um 14:05 laufen):
```
=== Batterie-Optimierung gestartet (v3.2 - FIXED Timezones) ===
Konfiguration geladen: SOC 20-100%, Max 5000W
Strompreise geladen: X Stunden (Tomorrow: true/false)
Benötigte Ladestunden: X (bei 5000W pro Stunde)
Top X günstigste Stunden ausgewählt
```
**Für die stündliche Ausführung** (läuft jede Stunde um xx:05):
```
Suche Ladeplan für YYYY-MM-DD HH:00 Uhr (lokal)
✓ Gefunden: YYYY-MM-DDTHH:00:00+01:00
⚡ Stunde HH:00 [heute/morgen]: action=charge/auto, power=XW, price=X.XXct
```
**Kritische Warnungen zu suchen**:
```
⚠ Keine Daten für YYYY-MM-DD HH:00
Keine zukünftigen Preise verfügbar
```
### Schritt 3: Zeitzone-Verifikation
Führe manuell den Schedule aus und beobachte die Logs:
**Developer Tools → Services**:
```yaml
service: pyscript.execute_charging_schedule
data: {}
```
**Was zu beobachten**:
1. Welche Zeit wird gesucht? "Suche Ladeplan für ..."
2. Wird ein Eintrag gefunden? "✓ Gefunden: ..."
3. Welche Aktion wird ausgeführt? "action=charge" oder "action=auto"
### Schritt 4: Manuellen Test durchführen
Um zu verifizieren, dass das Laden grundsätzlich funktioniert:
**Developer Tools → Services**:
```yaml
service: input_number.set_value
target:
entity_id: input_number.charge_power_battery
data:
value: -5000
```
Dann:
```yaml
service: input_boolean.turn_on
target:
entity_id: input_boolean.goodwe_manual_control
```
**Erwartetes Verhalten**:
1. ESS schaltet auf REMOTE
2. Keep-Alive Automation startet (alle 30s)
3. Batterie beginnt zu laden
**Wenn das funktioniert**: Problem liegt im Schedule/Optimizer
**Wenn das nicht funktioniert**: Problem liegt in den Automations/OpenEMS
### Schritt 5: Schedule-Berechnung triggern
Führe eine neue Berechnung aus:
**Developer Tools → Services**:
```yaml
service: pyscript.calculate_charging_schedule
data: {}
```
Dann prüfe:
1. Die Logs für die Berechnung
2. Den neuen Schedule in `pyscript.battery_charging_schedule`
3. Ob Ladestunden für heute Nacht geplant sind
## Typische Probleme und Lösungen
### Problem A: "Keine Ladung nötig (Batterie voll)"
**Symptom**: `num_charges = 0` im Schedule
**Ursache**: `current_soc >= max_soc - reserve`
**Lösung**: Normal, wenn Batterie voll ist. Warte bis SOC sinkt.
### Problem B: "Tomorrow-Daten fehlen"
**Symptom**: `has_tomorrow_data = false`, nur wenige Stunden im Schedule
**Ursache**: Berechnung lief vor 14:00, als Preise für morgen noch nicht verfügbar waren
**Lösung**: Warte bis nach 14:00, dann läuft automatische Neuberechnung
### Problem C: "Zeitzone-Mismatch"
**Symptom**: "⚠ Keine Daten für YYYY-MM-DD HH:00" obwohl Schedule existiert
**Ursache**: Zeitvergleich matcht nicht
**Lösung**: Siehe Code-Fix unten
### Problem D: "Keep-Alive Automation läuft nicht"
**Symptom**: ESS ist auf REMOTE, aber keine Modbus-Befehle werden gesendet
**Ursache**: Automation "Speicher manuell laden" ist deaktiviert oder fehlerhaft
**Lösung**: Prüfe ob Automation aktiviert ist und läuft
## Code-Verbesserungsvorschläge
### Fix 1: Logging verbessern in execute_charging_schedule
Füge mehr Debug-Output hinzu in Zeile 587:
```python
log.info(f"=== Stündliche Ausführung gestartet ===")
log.info(f"Lokale Zeit: {now.strftime('%Y-%m-%d %H:%M:%S %Z')}")
log.info(f"Suche Ladeplan für {current_date} {current_hour}:00 Uhr (lokal)")
log.info(f"Schedule hat {len(schedule)} Einträge")
# Zeige alle Schedule-Einträge für Debugging
for i, entry in enumerate(schedule):
entry_dt = datetime.fromisoformat(entry['datetime'])
if entry_dt.tzinfo is None:
entry_dt = entry_dt.replace(tzinfo=TIMEZONE)
log.debug(f" [{i}] {entry_dt}{entry['action']}")
```
### Fix 2: Robusteres Datetime-Matching
Ersetze den exakten Stunden-Match durch ein Zeitfenster (Zeile 603):
```python
# Statt exaktem Match:
if entry_date == current_date and entry_hour == current_hour:
# Verwende Zeitfenster (z.B. ±5 Minuten):
entry_start = entry_dt.replace(minute=0, second=0)
entry_end = entry_start + timedelta(hours=1)
if entry_start <= now < entry_end:
current_entry = entry
log.info(f"✓ Match gefunden für Zeitfenster {entry_start} - {entry_end}")
break
```
### Fix 3: Fallback für fehlende Matches
Nach der Schleife (Zeile 608):
```python
if not current_entry:
log.warning(f"⚠ Keine Daten für {current_date} {current_hour}:00")
# Debug: Zeige nächsten verfügbaren Eintrag
future_entries = []
for entry in schedule:
entry_dt = datetime.fromisoformat(entry['datetime'])
if entry_dt.tzinfo is None:
entry_dt = entry_dt.replace(tzinfo=TIMEZONE)
if entry_dt > now:
future_entries.append((entry_dt, entry['action']))
if future_entries:
next_entry = min(future_entries, key=lambda x: x[0])
log.info(f" Nächster Schedule-Eintrag: {next_entry[0]}{next_entry[1]}")
else:
log.warning("⚠ Keine zukünftigen Schedule-Einträge gefunden!")
return
```
## Nächste Schritte
1. **JETZT**: Führe Debug-Schritte 1-3 aus und notiere die Ergebnisse
2. **Prüfe**: Wie sieht der aktuelle Schedule aus?
3. **Teste**: Funktioniert manuelles Laden (Schritt 4)?
4. **Entscheide**: Basierend auf den Ergebnissen, welche Fix-Strategie anzuwenden ist
## Monitoring für die nächste Nacht
Um zu sehen, was heute Nacht passiert:
1. **Prüfe Schedule um 14:05**: Nach der täglichen Berechnung
2. **Setze Benachrichtigung**: Für 23:05 (erste mögliche Ladestunde)
3. **Überwache Logs**: Live während der Ladestunden
4. **Prüfe OpenEMS**: Logs auf dem BeagleBone für Controller-Aktivität
```bash
# Auf BeagleBone
tail -f /var/log/openems/openems.log | grep -i "active.*power"
```