From 30f2667589a292b244d968a3932decd8de60e0f7 Mon Sep 17 00:00:00 2001 From: retr0 <42kdesigners@gmail.com> Date: Tue, 28 Apr 2026 12:17:52 +0200 Subject: [PATCH] =?UTF-8?q?Fix:=20Wallbox-Read=20resilient=20gegen=20Illeg?= =?UTF-8?q?alAddress,=20Relais-Matrix=20erg=C3=A4nzt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - wallbox_client: Bei Reg-Fehler Range überspringen statt komplett abbrechen → Meter-Daten kommen weiter wenn EVSE-Block (0x0060) nicht verfügbar - wallbox_client: set_current() schreibt jetzt auch EMS_RELAIS_REG (0x00A1) mit korrekter Phasen-Bitmaske (1→0x0001, 2→0x0003, 3→0x0007) - ems_controller: phases wird an set_current() und Zwangsladen übergeben Co-Authored-By: Claude Sonnet 4.6 --- haos-addon/src/ems_controller.py | 4 ++-- haos-addon/src/wallbox_client.py | 28 ++++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/haos-addon/src/ems_controller.py b/haos-addon/src/ems_controller.py index eccaa98..d692d53 100644 --- a/haos-addon/src/ems_controller.py +++ b/haos-addon/src/ems_controller.py @@ -99,7 +99,7 @@ class EmsController: self._no_pv_since = None self._forced_charging = False ma = self._surplus_to_ma(pv_surplus_w) - wallbox_reader.set_current(ma) + wallbox_reader.set_current(ma, self.phases) return f"PV-Laden {ma // 1000:.1f}A ({pv_surplus_w:.0f}W)" # Kein PV @@ -113,7 +113,7 @@ class EmsController: target = self._next_target() mins_left = (target - datetime.now()).total_seconds() / 60 if not self._forced_charging: - wallbox_reader.set_current(32000) + 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) return f"Zwangsladen ({no_pv_h:.1f}h kein PV, {int(mins_left)}min bis {self.target_hour:02d}:00)" diff --git a/haos-addon/src/wallbox_client.py b/haos-addon/src/wallbox_client.py index 8a30ca6..198bff2 100644 --- a/haos-addon/src/wallbox_client.py +++ b/haos-addon/src/wallbox_client.py @@ -11,11 +11,14 @@ from inverters import Inverter, Sensor log = logging.getLogger(__name__) SLAVE = 0 # Kathrein: Unit-ID 0 (Broadcast) -EMS_CTRL_REG = 0x00A0 +EMS_CTRL_REG = 0x00A0 +EMS_RELAIS_REG = 0x00A1 EMS_CURRENT_REG = 0x00A2 -EMS_ENABLE = 0x8000 -MIN_CURRENT_MA = 6000 -MAX_CURRENT_MA = 32000 +EMS_ENABLE = 0x8000 +MIN_CURRENT_MA = 6000 +MAX_CURRENT_MA = 32000 + +_PHASE_MASK = {1: 0x0001, 2: 0x0003, 3: 0x0007} class WallboxReader: @@ -45,21 +48,22 @@ class WallboxReader: return None reg_cache: Dict[int, int] = {} + any_ok = False for start, length in inverter.read_ranges: try: result = self._client.read_holding_registers(start, count=length, slave=SLAVE) if result.isError(): - log.error("[Wallbox] FC03 Fehler Reg 0x%04X: %s", start, result) - self._disconnect() - return None + log.warning("[Wallbox] FC03 Reg 0x%04X nicht verfügbar: %s", start, result) + continue for i, val in enumerate(result.registers): reg_cache[start + i] = val + any_ok = True except ModbusException as e: log.error("[Wallbox] Modbus Ausnahme: %s", e) self._disconnect() return None - return _extract(inverter.sensors, reg_cache) + return _extract(inverter.sensors, reg_cache) if any_ok else None def enable_ems(self) -> bool: if not self._connect(): @@ -71,16 +75,20 @@ class WallboxReader: log.error("[Wallbox] EMS enable Fehler: %s", e) return False - def set_current(self, ma: int) -> bool: + def set_current(self, ma: int, phases: int = 3) -> bool: """Ladestrom setzen. ma=0 → Pause, ma=0xFFFF → Abbruch.""" if not self._connect(): return False val = 0 if ma == 0 else max(MIN_CURRENT_MA, min(MAX_CURRENT_MA, ma)) + relais = _PHASE_MASK.get(phases, 0x0007) try: + r = self._client.write_register(EMS_RELAIS_REG, relais, slave=SLAVE) + if r.isError(): + log.warning("[Wallbox] Relais-Matrix Fehler: %s", r) r = self._client.write_register(EMS_CURRENT_REG, val, slave=SLAVE) ok = not r.isError() if ok: - log.info("[Wallbox] Strom gesetzt: %d mA", val) + log.info("[Wallbox] Strom gesetzt: %d mA (%d Phase(n))", val, phases) return ok except ModbusException as e: log.error("[Wallbox] set_current Fehler: %s", e)