From f5ed7c5df62c283d1ca304aa4be9ba9c9561f495 Mon Sep 17 00:00:00 2001 From: retr0 <42kdesigners@gmail.com> Date: Tue, 25 Aug 2026 12:43:49 +0200 Subject: [PATCH] =?UTF-8?q?ShineBridge=20v1.8.31=20=E2=80=94=20EMS-Fixes:?= =?UTF-8?q?=20konfigurierbarer=20Max-Ladestrom,=20Zwangsladen-Retry,=20Fau?= =?UTF-8?q?lt-State-Handling?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ems_max_current_ma konfigurierbar statt hardcoded 32A (Zwangsladen darf jetzt nicht mehr mehr fordern als die tatsächliche Wallbox liefern kann, z.B. 16A bei einer 11kW-Wallbox) - Zwangsladen setzt den Ladestrom bei jedem Poll erneut (statt nur einmal beim Start) — ein einzelner fehlgeschlagener Modbus-Write hängt nicht mehr die ganze Nacht - Unbekannte/Fehler-Ladezustände (z.B. Fahrzeug-Störung) werden nicht mehr wie 'abgesteckt' behandelt — Strom wird pausiert, aber der Zwangslade-Timer bleibt erhalten - Neues Settings-Feld 'Max. Ladestrom (A)' im EMS-Dialog Co-Authored-By: Claude Sonnet 5 --- .gitignore | 4 ++++ haos-addon/config.yaml | 2 +- haos-addon/src/ems_controller.py | 32 ++++++++++++++++++++++++++------ haos-addon/src/main.py | 1 + haos-addon/src/web/index.html | 6 ++++++ 5 files changed, 38 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index ba32ed8..4a684c8 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,7 @@ shinelanx-modbus/ __pycache__/ *.pyc .env + +# versehentlich getrackte Alt-Dateien, gehoeren nicht ins Repo +Modbus-Server-Kathrein.pdf +ShineLAN-X/releases/*.bin diff --git a/haos-addon/config.yaml b/haos-addon/config.yaml index edadfa2..eae45b0 100644 --- a/haos-addon/config.yaml +++ b/haos-addon/config.yaml @@ -1,5 +1,5 @@ name: ShineBridge -version: "1.8.30" +version: "1.8.31" slug: shinebridge description: Growatt Wechselrichter lokal in Home Assistant — Modbus TCP via ShineLAN-X, MQTT Discovery, Web UI url: https://gitea.bitfire.work/retr0/shinebridge diff --git a/haos-addon/src/ems_controller.py b/haos-addon/src/ems_controller.py index 33c6b57..c00ec90 100644 --- a/haos-addon/src/ems_controller.py +++ b/haos-addon/src/ems_controller.py @@ -23,6 +23,11 @@ TARGET_HOUR = 6 # Zielstunde: Vollladung bis 06:00 POLL_INTERVAL_S = 30 # Sekunden zwischen EMS-Updates PHASES = 3 # Anzahl der Phasen VOLTAGE_V = 230 # Netzspannung +MAX_CHARGE_MA = 32000 # Absolutes Wallbox-Limit (Hardware-Grenze WallboxReader). + # ACHTUNG: die tatsächlich installierte Wallbox/Zuleitung kann + # niedriger dimensioniert sein (z.B. 11kW-Wallbox = 16A) — dann + # über max_charge_ma im Konstruktor auf den echten Wert begrenzen, + # sonst fordert das Zwangsladen mehr an als das Gerät liefern kann. # Charging-State Werte (Kathrein Modbus) STATE_IDLE = 0 @@ -39,11 +44,13 @@ class EmsController: pv_timeout_h: float = PV_TIMEOUT_H, target_hour: int = TARGET_HOUR, phases: int = PHASES, + max_charge_ma: int = MAX_CHARGE_MA, ): self.min_pv_power = min_pv_power self.pv_timeout_h = pv_timeout_h self.target_hour = target_hour self.phases = phases + self.max_charge_ma = max_charge_ma self._pv_ok_since: Optional[float] = None # Zeitpunkt letzter ausreichender PV self._no_pv_since: Optional[float] = None # Zeitpunkt seit kein PV @@ -66,7 +73,7 @@ class EmsController: total_w = surplus_w + wallbox_w current_a = total_w / (VOLTAGE_V * self.phases) ma = int(current_a * 1000) - return max(6000, min(32000, ma)) + return max(6000, min(self.max_charge_ma, ma)) def update(self, wallbox_reader, pv_surplus_w: float, charging_state: int, wallbox_power_w: float = 0.0) -> str: @@ -84,8 +91,8 @@ class EmsController: if wallbox_reader.enable_ems(): self._ems_enabled = True log.info("[EMS] EMS aktiviert") - else: - # Auto weg → alles zurücksetzen + elif charging_state == STATE_IDLE: + # Wirklich kein Fahrzeug angesteckt → alles zurücksetzen, Timer neu starten if self._ems_enabled: wallbox_reader.set_current(0) self._ems_enabled = False @@ -93,6 +100,16 @@ class EmsController: self._no_pv_since = None log.info("[EMS] Auto abgesteckt — EMS zurückgesetzt") return "kein Fahrzeug" + else: + # Unbekannter/nicht abgedeckter Ladezustand (z.B. Fehler/Störung am Fahrzeug). + # NICHT wie "abgesteckt" behandeln — sonst verliert der Zwangslade-Timer seinen + # Fortschritt und die Deadline (Zielzeit) wird nie mehr erreicht, obwohl das Auto + # die ganze Zeit angesteckt war. Strom sicherheitshalber pausieren, aber Zustand/ + # Timer erhalten, damit nach Rückkehr in einen bekannten Zustand nahtlos weitergeht. + wallbox_reader.set_current(0) + log.warning("[EMS] Unbekannter Ladezustand %d (evtl. Störung am Fahrzeug) — " + "Strom pausiert, Zwangslade-Timer bleibt erhalten", charging_state) + return f"unbekannter Zustand ({charging_state})" if charging_state == STATE_COMPLETED: wallbox_reader.set_current(0) @@ -116,13 +133,16 @@ class EmsController: no_pv_h = (now - self._no_pv_since) / 3600.0 if no_pv_h >= self.pv_timeout_h: - # Zwangsladen bis Zielzeit + # Zwangsladen bis Zielzeit — Strom bei JEDEM Update erneut setzen (nicht nur beim + # ersten Eintritt), sonst bleibt ein einzelner fehlgeschlagener/verworfener Write + # (Modbus-Hänger, Fahrzeug-Störung) unbemerkt für den Rest der Nacht stehen. target = self._next_target() mins_left = (target - datetime.now()).total_seconds() / 60 if not self._forced_charging: - wallbox_reader.set_current(32000, self.phases) self._forced_charging = True - log.info("[EMS] Zwangsladen gestartet — %dmin bis %02d:00", int(mins_left), self.target_hour) + log.info("[EMS] Zwangsladen gestartet — %dmin bis %02d:00, max %.0fA", + int(mins_left), self.target_hour, self.max_charge_ma / 1000) + wallbox_reader.set_current(self.max_charge_ma, self.phases) return f"Zwangsladen ({no_pv_h:.1f}h kein PV, {int(mins_left)}min bis {self.target_hour:02d}:00)" # Warten auf PV diff --git a/haos-addon/src/main.py b/haos-addon/src/main.py index 6d8581f..0138d18 100644 --- a/haos-addon/src/main.py +++ b/haos-addon/src/main.py @@ -286,6 +286,7 @@ def _poll_loop(inv_cfg: Dict[str, Any], stop: threading.Event): pv_timeout_h=inv_cfg.get("ems_timeout", 4.0), target_hour=inv_cfg.get("ems_target_hour", 6), phases=inv_cfg.get("ems_phases", 3), + max_charge_ma=inv_cfg.get("ems_max_current_ma", 32000), ) log.info("[%s] Poll-Loop: %s @ %s:%s (Kathrein EMS) alle %ds", inv_id, inverter.name, host, port, interval) diff --git a/haos-addon/src/web/index.html b/haos-addon/src/web/index.html index d67d01a..e7fa7fd 100644 --- a/haos-addon/src/web/index.html +++ b/haos-addon/src/web/index.html @@ -495,6 +495,9 @@ GND → GND +
+ +
Obergrenze für Zwangsladen — auf die tatsächliche Wallbox-/Zuleitungs-Absicherung setzen (z.B. 16A bei einer 11kW-Wallbox), nicht höher als die Hardware zulässt