Update: Battery Optimizer v3.5.0 - Volle Ladung bis 100% SOC
## 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>
This commit is contained in:
@@ -3,9 +3,12 @@ Battery Charging Optimizer für OpenEMS + GoodWe
|
||||
Nutzt das bestehende manuelle Steuerungssystem
|
||||
|
||||
Speicherort: /config/pyscript/battery_charging_optimizer.py
|
||||
Version: 3.3.1 - FIXED: SOC-Plausibilitäts-Check (filtert 65535% Spikes beim Modus-Wechsel)
|
||||
Setzt charge_power_battery als negativen Wert (Laden = negativ)
|
||||
Nutzt bestehende Automations für ESS-Modus und Keep-Alive
|
||||
Version: 3.5.0 - REMOVED: Sicherheitspuffer und Reservekapazität (Hardware hat eigene Puffer)
|
||||
Batterie lädt jetzt bis 100% SOC
|
||||
CHANGED: Standardwerte - Preisschwelle 25ct, Ladeleistung 8000W
|
||||
FIXED: SOC-Plausibilitäts-Check (filtert 65535% Spikes beim Modus-Wechsel)
|
||||
Setzt charge_power_battery als negativen Wert (Laden = negativ)
|
||||
Nutzt bestehende Automations für ESS-Modus und Keep-Alive
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -29,7 +32,7 @@ def calculate_charging_schedule():
|
||||
Nutzt Ranking-Methode: Wählt die N günstigsten Stunden aus
|
||||
"""
|
||||
|
||||
log.info("=== Batterie-Optimierung gestartet (v3.2 - FIXED Timezones) ===")
|
||||
log.info("=== Batterie-Optimierung gestartet (v3.5.0 - Volle Ladung bis 100%) ===")
|
||||
|
||||
# Prüfe ob Optimierung aktiviert ist
|
||||
if state.get('input_boolean.battery_optimizer_enabled') != 'on':
|
||||
@@ -103,9 +106,8 @@ def load_configuration():
|
||||
'battery_capacity': float(state.get('input_number.battery_capacity_kwh') or 10) * 1000, # in Wh
|
||||
'min_soc': float(state.get('input_number.battery_optimizer_min_soc') or 20),
|
||||
'max_soc': float(state.get('input_number.battery_optimizer_max_soc') or 100),
|
||||
'max_charge_power': float(state.get('input_number.battery_optimizer_max_charge_power') or 5000),
|
||||
'price_threshold': float(state.get('input_number.battery_optimizer_price_threshold') or 28),
|
||||
'reserve_capacity': float(state.get('input_number.battery_optimizer_reserve_capacity') or 2) * 1000, # in Wh
|
||||
'max_charge_power': float(state.get('input_number.battery_optimizer_max_charge_power') or 8000),
|
||||
'price_threshold': float(state.get('input_number.battery_optimizer_price_threshold') or 25),
|
||||
'pv_threshold': float(state.get('input_number.battery_optimizer_pv_threshold') or 500), # in Wh
|
||||
}
|
||||
|
||||
@@ -287,15 +289,14 @@ def optimize_charging(price_data, pv_forecast, current_soc, config):
|
||||
avg_price = sum(all_prices) / len(all_prices)
|
||||
log.info(f"Preise: Min={min_price:.2f}, Max={max_price:.2f}, Avg={avg_price:.2f} ct/kWh")
|
||||
|
||||
# Verfügbare Ladekapazität berechnen
|
||||
# Verfügbare Ladekapazität berechnen (OHNE Reserven - Hardware hat eigene Puffer)
|
||||
available_capacity_wh = (config['max_soc'] - current_soc) / 100 * config['battery_capacity']
|
||||
available_capacity_wh -= config['reserve_capacity']
|
||||
|
||||
if available_capacity_wh <= 0:
|
||||
log.info("Batterie ist voll oder Reserve erreicht - keine Ladung nötig")
|
||||
log.info("Batterie ist bereits voll - keine Ladung nötig")
|
||||
return create_auto_only_schedule(future_price_data)
|
||||
|
||||
log.info(f"Verfügbare Ladekapazität: {available_capacity_wh/1000:.2f} kWh")
|
||||
log.info(f"Verfügbare Ladekapazität: {available_capacity_wh/1000:.2f} kWh (bis {config['max_soc']}% SOC)")
|
||||
|
||||
# ==========================================
|
||||
# Berechne benötigte Ladestunden
|
||||
@@ -628,6 +629,13 @@ def execute_charging_schedule():
|
||||
log.info(f" Grund: {reason}")
|
||||
|
||||
if action == 'charge':
|
||||
# Prüfe aktuellen SOC beim Ladestart
|
||||
current_soc_now = float(state.get('sensor.esssoc') or 50)
|
||||
if current_soc_now > 100 or current_soc_now < 0:
|
||||
log.warning(f"⚠ Ungültiger SOC beim Ladestart: {current_soc_now}%. Verwende trotzdem geplante Leistung.")
|
||||
else:
|
||||
log.info(f"📊 SOC beim Ladestart: {current_soc_now}%")
|
||||
|
||||
log.info(f"🔋 AKTIVIERE LADEN mit {abs(power_w)}W")
|
||||
|
||||
# Setze Ziel-Leistung als NEGATIVEN Wert (Laden = negativ)
|
||||
|
||||
Reference in New Issue
Block a user