## Hauptänderungen ### Removed - Sicherheitspuffer (20%) entfernt - führte zu unvollständiger Ladung - Reservekapazität (2 kWh) entfernt - Hardware hat eigene Puffer - Problem: Mehr Ladestunden geplant als nötig, aber tatsächliche Ladung begrenzt - Folge: Batterie erreichte nie 100% SOC ### Changed - Standardwert max_charge_power: 5000W → 8000W (+60%) - Standardwert price_threshold: 28ct → 25ct/kWh - Ladelogik vereinfacht: Direkte Berechnung ohne Puffer ### Fixed - Batterie lädt jetzt vollständig bis 100% SOC - Genauere Ladestunden-Berechnung - Bessere Kapazitätsnutzung: Volle Leistung in allen Stunden ## Projekt-Aufräumarbeiten ### Archiviert - Bugfix-Dokumentationen → archive/ - BUGFIX_TIMEZONE_v3.2.md - DIAGNOSE_LADE_PROBLEM.md - FIX_API_TIMING.md - FIX_CHARGING_CAPACITY.md - FIX_SOC_SPIKE_PROBLEM.md - FIX_SOC_SPIKE_REMOTE_MODE.md - SOC_CALIBRATION_GUIDE.md ### Entfernt - docs/ (Duplikate) - debug_log.txt, debug_schedule.py ### Neu - UPGRADE_TO_v3.5.0.md - Detaillierter Upgrade-Guide - PROJECT_SUMMARY_v3.5.0.md - Technische Zusammenfassung - pyscripts/ aktualisiert auf v3.5.0 ## Migration 1. Backup erstellen 2. Neue Skripte nach /config/pyscript/ kopieren 3. PyScript neu laden 4. Input Helper anpassen (8000W, 25ct) 5. Test durchführen Details: siehe UPGRADE_TO_v3.5.0.md --- Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
8.9 KiB
Fix: SOC springt auf 65535% beim Modus-Wechsel
Problem
Wenn der ESS-Modus von INTERNAL auf REMOTE wechselt, zeigt sensor.esssoc kurzzeitig 65535% (0xFFFF = ungültiger Wert).
Die Automation "Batterie Optimierung: Stopp bei Max-SOC" triggert bei SOC > 99% und beendet das Laden sofort wieder.
Lösung 1: Debounce + Plausibilitäts-Check (EMPFOHLEN)
Ersetze die Automation in battery_optimizer_automations.yaml:
# Automatisierung 8: Laden stoppen wenn SOC erreicht (FIXED)
alias: "Batterie Optimierung: Stopp bei Max-SOC"
description: "Beendet manuelles Laden wenn maximaler SOC erreicht (mit Spike-Protection)"
trigger:
- platform: numeric_state
entity_id: sensor.esssoc
above: 99
condition:
# 1. Manual Control muss aktiv sein
- condition: state
entity_id: input_boolean.goodwe_manual_control
state: "on"
# 2. SOC muss plausibel sein (nicht über 105%)
- condition: numeric_state
entity_id: sensor.esssoc
below: 105
# 3. SOC muss für mindestens 30 Sekunden über 99% sein (Debounce)
- condition: template
value_template: >
{% set soc = states('sensor.esssoc') | float(0) %}
{% set last_changed = as_timestamp(states.sensor.esssoc.last_changed) %}
{% set now = as_timestamp(now()) %}
{% set duration = now - last_changed %}
{{ soc > 99 and soc < 105 and duration > 30 }}
action:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.goodwe_manual_control
# ESS-Modus wird durch manuelle_speicherbeladung_deaktivieren gesetzt
- service: notify.persistent_notification
data:
title: "Batterie-Optimierung"
message: "Manuelles Laden beendet - SOC {{ states('sensor.esssoc') }}% erreicht"
mode: single
Was das macht:
- Plausibilitäts-Check: SOC muss zwischen 99% und 105% liegen
- Debounce: SOC muss für mindestens 30 Sekunden über 99% sein
- Spike-Protection: 65535% wird ignoriert (liegt über 105%)
Lösung 2: Nur Debounce (Einfacher)
alias: "Batterie Optimierung: Stopp bei Max-SOC"
description: "Beendet manuelles Laden wenn maximaler SOC erreicht"
trigger:
- platform: numeric_state
entity_id: sensor.esssoc
above: 99
for:
seconds: 30 # Warte 30 Sekunden bevor getriggert wird
condition:
- condition: state
entity_id: input_boolean.goodwe_manual_control
state: "on"
# Plausibilitäts-Check
- condition: numeric_state
entity_id: sensor.esssoc
below: 105
action:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.goodwe_manual_control
- service: notify.persistent_notification
data:
title: "Batterie-Optimierung"
message: "Manuelles Laden beendet - SOC {{ states('sensor.esssoc') }}% erreicht"
mode: single
Vorteil: Einfacher, verwendet Home Assistant's eingebaute for: Funktion
Lösung 3: Initial Delay nach Manual Control Aktivierung
Ignoriere SOC-Änderungen in den ersten 60 Sekunden nach Aktivierung:
alias: "Batterie Optimierung: Stopp bei Max-SOC"
description: "Beendet manuelles Laden wenn maximaler SOC erreicht"
trigger:
- platform: numeric_state
entity_id: sensor.esssoc
above: 99
condition:
- condition: state
entity_id: input_boolean.goodwe_manual_control
state: "on"
# Plausibilitäts-Check
- condition: numeric_state
entity_id: sensor.esssoc
below: 105
# Manual Control muss mindestens 60 Sekunden aktiv sein
- condition: template
value_template: >
{% set last_changed = as_timestamp(states.input_boolean.goodwe_manual_control.last_changed) %}
{% set now = as_timestamp(now()) %}
{% set duration = now - last_changed %}
{{ duration > 60 }}
action:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.goodwe_manual_control
- service: notify.persistent_notification
data:
title: "Batterie-Optimierung"
message: "Manuelles Laden beendet - SOC {{ states('sensor.esssoc') }}% erreicht"
mode: single
Vorteil: Ignoriert alle Spikes in der ersten Minute nach Modus-Wechsel
Empfehlung: Kombination (Lösung 4)
Die robusteste Lösung kombiniert alle Ansätze:
alias: "Batterie Optimierung: Stopp bei Max-SOC"
description: "Beendet manuelles Laden wenn maximaler SOC erreicht (robust gegen Spikes)"
trigger:
- platform: numeric_state
entity_id: sensor.esssoc
above: 99
for:
seconds: 30 # Debounce: 30 Sekunden warten
condition:
# 1. Manual Control aktiv
- condition: state
entity_id: input_boolean.goodwe_manual_control
state: "on"
# 2. Plausibilitäts-Check: SOC zwischen 99% und 105%
- condition: numeric_state
entity_id: sensor.esssoc
above: 99
- condition: numeric_state
entity_id: sensor.esssoc
below: 105
# 3. Manual Control muss mindestens 60 Sekunden aktiv sein
- condition: template
value_template: >
{% set last_changed = as_timestamp(states.input_boolean.goodwe_manual_control.last_changed) %}
{% set now = as_timestamp(now()) %}
{% set duration = now - last_changed %}
{{ duration > 60 }}
# 4. Sensor muss verfügbar sein
- condition: template
value_template: >
{{ states('sensor.esssoc') not in ['unavailable', 'unknown', 'none'] }}
action:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.goodwe_manual_control
- service: notify.persistent_notification
data:
title: "Batterie-Optimierung"
message: "Manuelles Laden beendet - SOC {{ states('sensor.esssoc') }}% erreicht"
# Logging für Debugging
- service: system_log.write
data:
message: "Battery charging stopped at SOC {{ states('sensor.esssoc') }}%"
level: info
mode: single
Schutz-Mechanismen:
- ✅ 30 Sekunden Debounce: Warte 30s nachdem SOC > 99%
- ✅ Plausibilitäts-Check: SOC muss < 105% sein
- ✅ Initial Delay: Manual Control muss mindestens 60s aktiv sein
- ✅ Availability Check: Sensor muss verfügbar sein
Installation
Option A: Via Home Assistant UI (Empfohlen für schnellen Test)
- Gehe zu Einstellungen → Automationen & Szenen
- Suche "Batterie Optimierung: Stopp bei Max-SOC"
- Bearbeite die Automation
- Ersetze den Inhalt mit einer der obigen Lösungen
- Speichern
Option B: Via YAML
- Öffne deine
automations.yamloder die entsprechende Datei - Finde die Automation (ID oder Alias)
- Ersetze sie mit der neuen Version
- Home Assistant neu laden oder Automationen neu laden
Testing
Test 1: Manuelles Laden ohne Spike-Problem
# Developer Tools → Services
service: input_boolean.turn_on
target:
entity_id: input_boolean.goodwe_manual_control
Warte 2 Minuten und prüfe:
- Bleibt Manual Control aktiv?
- Gibt es SOC-Spikes in den Logs?
Test 2: Simulation eines Spikes
# Developer Tools → States
# Suche sensor.esssoc und ändere temporär den Wert auf 65535
# (nur möglich wenn Sensor-Typ es erlaubt)
Test 3: Echtes Stoppen bei 100%
Warte bis Batterie wirklich bei 100% ist und prüfe ob das Laden dann korrekt gestoppt wird.
Alternative: Sensor-Filter
Wenn das Problem häufiger auftritt, kannst du auch einen gefilterten Sensor erstellen:
# In configuration.yaml
sensor:
- platform: filter
name: "ESS SOC Filtered"
entity_id: sensor.esssoc
filters:
# Entferne ungültige Werte
- filter: outlier
window_size: 4
radius: 10.0
# Entferne extreme Spikes
- filter: range
lower_bound: 0
upper_bound: 100
# Glättung
- filter: lowpass
time_constant: 10
Dann verwende sensor.ess_soc_filtered in allen Automationen statt sensor.esssoc.
Monitoring
Füge eine Notification hinzu wenn ungültige Werte erkannt werden:
alias: "Debug: SOC Spike Detector"
description: "Warnt bei ungültigen SOC-Werten"
trigger:
- platform: numeric_state
entity_id: sensor.esssoc
above: 105
action:
- service: notify.persistent_notification
data:
title: "SOC Spike erkannt!"
message: "SOC zeigt {{ states('sensor.esssoc') }}% - wahrscheinlich ungültiger Wert"
- service: system_log.write
data:
message: "SOC spike detected: {{ states('sensor.esssoc') }}% at {{ now() }}"
level: warning
mode: queued
Nächste Schritte
- JETZT: Implementiere Lösung 4 (kombinierter Ansatz)
- TESTE: Aktiviere heute Abend manuelles Laden und beobachte
- MONITOR: Installiere die Spike Detector Automation
- LANGFRISTIG: Erwäge einen gefilterten Sensor für mehr Robustheit
Zusätzliche Absicherungen
Füge auch in der execute_charging_schedule Funktion einen Check ein:
# In battery_charging_optimizer.py, Zeile 67
current_soc = float(state.get('sensor.esssoc') or 50)
# Plausibilitäts-Check hinzufügen:
if current_soc > 105 or current_soc < 0:
log.warning(f"⚠ Ungültiger SOC-Wert erkannt: {current_soc}%. Verwende letzten gültigen Wert.")
# Verwende einen Fallback-Wert oder den letzten gültigen Wert
current_soc = 50 # Oder aus einem gespeicherten State laden