Problemstellung
Die Victron Solaranlage mit 6× JK-BMS v15 Akkus kann keinen maximalen Lade-SOC zentral begrenzen. Ohne Steuerung würden die Akkus täglich auf 100% geladen — was die Lebensdauer von Lithium-Zellen drastisch verkürzt.
Mit der Victron-eigenen Spannungsbegrenzung auf 55V via DVCC wurden die Akkus trotzdem immer auf ~98% geladen — weit über dem optimalen Bereich für tägliche Zyklen.
Die Lösung: Jedes der 6 JK-BMS wird einzeln über ESP32-Mikrocontroller via Bluetooth angesteuert. Sobald ein Akku seinen Ziel-SOC erreicht, wird der Ladevorgang für genau diesen Akku deaktiviert — unabhängig von den anderen. Victron liefert weiterhin Strom für die restlichen Akkus.
Ladestrategie
| Zeitraum | Ziel-SOC | Hysterese | Verhalten |
|---|---|---|---|
| Mo–Sa | 90% | 5% | Laden stoppt bei 90%, startet erst wieder unter 85% |
| Sonntag | 100% | 2% | Vollladung für Zell-Balancing, startet erst wieder unter 98% |
| Carryover | 100% | 2% | Falls Sonntag nicht alle voll werden → 100%-Modus bleibt aktiv |
Die Hysterese ist das Kern-Feature: Ohne sie würde das System bei Erreichen des Ziels sofort abschalten, der SOC fällt auf 89,9%, das System schaltet wieder ein, erreicht 90%, schaltet ab — endloses Micro-Cycling. Mit 5% Puffer im 90%-Modus passiert das nicht.
Technische Architektur
| Steuerung | 2× ESP32 (esphome-jk-bms) |
| Kommunikation | Bluetooth Low Energy (BLE) |
| Plattform | Home Assistant |
| Komponenten | 1 Script + 11 Automations |
| Akkus | 6× JK-BMS v15 |
| Entwicklung | Full Vibecoded — 0 Zeilen manuell geschrieben |
Victron Ladestrom-Begrenzung via DVCC
Ein kritischer Nebeneffekt der Einzel-BMS-Steuerung: Sobald 5 von 6 Akkus ihr Ziel erreichen und abschalten, bekommt das letzte aktive BMS die vollen 210A der Victron-Anlage ab — über dem 200A-Limit des JK-BMS. Die Folge: Überlast-Fehler „Hoher Ladestrom".
Die Lösung: Ein Template-Sensor zählt in Echtzeit, wie viele BMS gerade laden. Via Modbus wird der Victron-Ladestrom dynamisch begrenzt:
| Aktive BMS | Victron-Strom | Pro BMS | Status |
|---|---|---|---|
| 6 | 200A | ~33A | ✅ |
| 5 | 180A | ~36A | ✅ |
| 4 | 160A | ~40A | ✅ |
| 3 | 130A | ~43A | ✅ |
| 2 | 100A | ~50A | ✅ |
| 1 | 80A | ~80A | 🔒 Sicher |
# Automation: Victron Ladestrom begrenzen trigger: - platform: state entity_id: sensor.bms_active_charging_count action: - service: modbus.write_register data: hub: victron slave: 100 address: 2705 value: {{ target_current }} # 80–200A je nach Count
BLE-Verify-Loop
Da Bluetooth-Befehle verloren gehen können, wird jeder Schaltbefehl verifiziert:
# Script: bms_set_charging sequence: - repeat: count: 3 # max. 3 Versuche sequence: - service: switch.turn_off # Befehl senden target: entity_id: switch.bms_X_charging - delay: seconds: 8 # BLE-Latenz abwarten - if: - condition: template value_template: states('switch…') == 'off' then: - stop: Erfolg ✅
Per-BMS Automation
Jeder der 6 Akkus hat eine identische Automation (hier BMS #3 als Beispiel):
# Automation: BMS3 Charge Control trigger: - platform: state entity_id: sensor.bms_3_bms_3_state_of_charge action: - if: # SOC ≥ Ziel → AUS - condition: template value_template: soc >= target_soc then: - service: script.bms_set_charging data: switch_entity: switch.bms_3_charging desired_state: "off" - if: # SOC < Ziel-Hysterese → EIN - condition: template value_template: soc < (target - hyst) then: - service: script.bms_set_charging data: switch_entity: switch.bms_3_charging desired_state: "on"
Wochenlogik
| Automation | Trigger | Aktion |
|---|---|---|
| Mo 00:01 | Zeit · Montag | Modus → 90% Limit |
| So 00:01 | Zeit · Sonntag | Modus → 100% Full |
| So 23:59 | Zeit · Sonntag | Wenn nicht alle 100% → Carryover starten |
| Carryover Reset | Alle BMS ≥ 99,5% | Carryover beenden, zurück zu 90% |
| 7-Tage-Warnung | Carryover > 7 Tage | Notification: Akkus prüfen! |