# 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`: ```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:** 1. **Plausibilitäts-Check**: SOC muss zwischen 99% und 105% liegen 2. **Debounce**: SOC muss für mindestens 30 Sekunden über 99% sein 3. **Spike-Protection**: 65535% wird ignoriert (liegt über 105%) ## Lösung 2: Nur Debounce (Einfacher) ```yaml 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: ```yaml 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: ```yaml 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:** 1. ✅ **30 Sekunden Debounce**: Warte 30s nachdem SOC > 99% 2. ✅ **Plausibilitäts-Check**: SOC muss < 105% sein 3. ✅ **Initial Delay**: Manual Control muss mindestens 60s aktiv sein 4. ✅ **Availability Check**: Sensor muss verfügbar sein ## Installation **Option A: Via Home Assistant UI** (Empfohlen für schnellen Test) 1. Gehe zu Einstellungen → Automationen & Szenen 2. Suche "Batterie Optimierung: Stopp bei Max-SOC" 3. Bearbeite die Automation 4. Ersetze den Inhalt mit einer der obigen Lösungen 5. Speichern **Option B: Via YAML** 1. Öffne deine `automations.yaml` oder die entsprechende Datei 2. Finde die Automation (ID oder Alias) 3. Ersetze sie mit der neuen Version 4. Home Assistant neu laden oder Automationen neu laden ## Testing ### Test 1: Manuelles Laden ohne Spike-Problem ```yaml # 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 ```yaml # 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: ```yaml # 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: ```yaml 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 1. **JETZT**: Implementiere Lösung 4 (kombinierter Ansatz) 2. **TESTE**: Aktiviere heute Abend manuelles Laden und beobachte 3. **MONITOR**: Installiere die Spike Detector Automation 4. **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: ```python # 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 ```