Update: Battery Optimizer v3.4.0 mit allen Fixes und Features
This commit is contained in:
298
FIX_SOC_SPIKE_PROBLEM.md
Normal file
298
FIX_SOC_SPIKE_PROBLEM.md
Normal 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
|
||||
```
|
||||
Reference in New Issue
Block a user