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

298
FIX_SOC_SPIKE_PROBLEM.md Normal file
View File

@@ -0,0 +1,298 @@
# 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
```