From fdf68bbbe62f1a575ac1730f75cac128bc088918 Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Sat, 9 Aug 2025 16:28:28 +0200 Subject: [PATCH 01/12] Delete firmware.py --- packages/modules/devices/sungrow/sungrow/firmware.py | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 packages/modules/devices/sungrow/sungrow/firmware.py diff --git a/packages/modules/devices/sungrow/sungrow/firmware.py b/packages/modules/devices/sungrow/sungrow/firmware.py deleted file mode 100644 index b96018bf8b..0000000000 --- a/packages/modules/devices/sungrow/sungrow/firmware.py +++ /dev/null @@ -1,6 +0,0 @@ -from enum import Enum - - -class Firmware(Enum): - v1 = "v1" # bis 11/2024 - v2 = "v2" # ab 11/2024 From d9757dcab3cbb50d5e83eb0173a7f3c34374980d Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Sat, 9 Aug 2025 16:33:04 +0200 Subject: [PATCH 02/12] Read all currents together --- .../modules/devices/sungrow/sungrow/inverter.py | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/modules/devices/sungrow/sungrow/inverter.py b/packages/modules/devices/sungrow/sungrow/inverter.py index 791dc51744..1f304a917a 100644 --- a/packages/modules/devices/sungrow/sungrow/inverter.py +++ b/packages/modules/devices/sungrow/sungrow/inverter.py @@ -38,20 +38,17 @@ def update(self) -> float: dc_power = self.__tcp_client.read_input_registers(5016, ModbusDataType.UINT_32, wordorder=Endian.Little, unit=unit) * -1 - current_L1 = self.__tcp_client.read_input_registers(13030, ModbusDataType.INT_16, unit=unit) * -0.1 - current_L2 = self.__tcp_client.read_input_registers(13031, ModbusDataType.INT_16, unit=unit) * -0.1 - current_L3 = self.__tcp_client.read_input_registers(13032, ModbusDataType.INT_16, unit=unit) * -0.1 - currents = [current_L1, current_L2, current_L3] - else: + currents = self.__tcp_client.read_input_registers(13030, [ModbusDataType.INT_16]*3, unit=unit) + currents = [value * -0.1 for value in currents] + + elif self.device_config.configuration.version in (Version.SG, Version.SG_winet_dongle): power = self.__tcp_client.read_input_registers(5030, ModbusDataType.INT_32, wordorder=Endian.Little, unit=unit) * -1 dc_power = self.__tcp_client.read_input_registers(5016, ModbusDataType.UINT_32, wordorder=Endian.Little, unit=unit) * -1 - current_L1 = self.__tcp_client.read_input_registers(5021, ModbusDataType.UINT_16, unit=unit) * -0.1 - current_L2 = self.__tcp_client.read_input_registers(5022, ModbusDataType.UINT_16, unit=unit) * -0.1 - current_L3 = self.__tcp_client.read_input_registers(5023, ModbusDataType.UINT_16, unit=unit) * -0.1 - currents = [current_L1, current_L2, current_L3] + currents = self.__tcp_client.read_input_registers(5021, [ModbusDataType.INT_16]*3, unit=unit) + currents = [value * -0.1 for value in currents] imported, exported = self.sim_counter.sim_count(power) From c745c5c549b1cb0964e6e3e9623ee4a206e70853 Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Sat, 9 Aug 2025 16:34:21 +0200 Subject: [PATCH 03/12] Delete Firmware --- packages/modules/devices/sungrow/sungrow/config.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/modules/devices/sungrow/sungrow/config.py b/packages/modules/devices/sungrow/sungrow/config.py index 9825fe3af4..f56d927f96 100644 --- a/packages/modules/devices/sungrow/sungrow/config.py +++ b/packages/modules/devices/sungrow/sungrow/config.py @@ -2,7 +2,6 @@ from modules.common.component_setup import ComponentSetup from modules.devices.sungrow.sungrow.version import Version -from modules.devices.sungrow.sungrow.firmware import Firmware from ..vendor import vendor_descriptor @@ -11,13 +10,11 @@ def __init__(self, ip_address: Optional[str] = None, port: int = 502, modbus_id: int = 1, - version: Version = Version.SG, - firmware: Firmware = Firmware.v1): + version: Version = Version.SG: self.ip_address = ip_address self.port = port self.modbus_id = modbus_id self.version = version - self.firmware = firmware class Sungrow: From e6126cddba36acd16395147aeba17665b285e57d Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Sat, 9 Aug 2025 16:46:25 +0200 Subject: [PATCH 04/12] Improve Register handling without Firmware --- .../modules/devices/sungrow/sungrow/bat.py | 86 +++++++++++-------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/packages/modules/devices/sungrow/sungrow/bat.py b/packages/modules/devices/sungrow/sungrow/bat.py index 86c145e6cd..e7bffec7c1 100644 --- a/packages/modules/devices/sungrow/sungrow/bat.py +++ b/packages/modules/devices/sungrow/sungrow/bat.py @@ -33,52 +33,70 @@ def initialize(self) -> None: self.store = get_bat_value_store(self.component_config.id) self.fault_state = FaultState(ComponentInfo.from_component_config(self.component_config)) self.last_mode = 'Undefined' - self.firmware_check = self.check_firmware_register() + self.register_check = self.detect_register_check() - def check_firmware_register(self) -> bool: - if Firmware(self.device_config.configuration.firmware) == Firmware.v1: - return False + def detect_register_check(self) -> str: + # Battery register availability test unit = self.device_config.configuration.modbus_id + try: self.__tcp_client.read_input_registers(5213, ModbusDataType.INT_32, wordorder=Endian.Little, unit=unit) - log.debug("Wechselrichter Firmware ist größer gleich 95.09") - return True + self.__tcp_client.read_input_registers(5630, ModbusDataType.INT_16, unit=unit) + log.debug("Battery register check: using new_registers (5213/5630).") + return 'new_registers' + except Exception: + pass + + try: + self.__tcp_client.read_input_registers(13000, ModbusDataType.UINT_16, unit=unit) + log.debug("Battery register check: using old_registers (13021 + 13000 bits for sign).") + return 'old_registers' except Exception: - log.debug("Wechselrichter Firmware ist kleiner als 95.09") - return False + pass + + log.debug("Battery register check: using fallback (13021 + total vs PV power).") + return 'fallback' def update(self) -> None: unit = self.device_config.configuration.modbus_id - soc = int(self.__tcp_client.read_input_registers(13022, ModbusDataType.UINT_16, unit=unit) / 10) - version = Version(self.device_config.configuration.version) - - if Firmware(self.device_config.configuration.firmware) == Firmware.v2: - if self.firmware_check: # Firmware >= 95.09 - bat_current = self.__tcp_client.read_input_registers(5630, ModbusDataType.INT_16, unit=unit) * -0.1 - bat_power = self.__tcp_client.read_input_registers(5213, ModbusDataType.INT_32, - wordorder=Endian.Little, unit=unit) * -1 - else: # Firmware between 95.03 and 95.09 - bat_current = self.__tcp_client.read_input_registers(13020, ModbusDataType.INT_16, unit=unit) * -0.1 - if version == Version.SH: - bat_power = self.__tcp_client.read_input_registers(13021, ModbusDataType.INT_16, unit=unit) - elif version == Version.SH_winet_dongle: - bat_power = self.__tcp_client.read_input_registers(13021, ModbusDataType.UINT_16, unit=unit) - total_power = self.__tcp_client.read_input_registers(13033, ModbusDataType.INT_32, - wordorder=Endian.Little, unit=unit) - pv_power = self.__tcp_client.read_input_registers(5016, ModbusDataType.UINT_32, - wordorder=Endian.Little, unit=unit) - if total_power > pv_power: - bat_power = bat_power * -1 - else: # Firmware.v1 (Firmware < 95.03) + + # === Mode 1: new_registers === + if self.register_check == 'new_registers': + bat_current = self.__tcp_client.read_input_registers(5630, ModbusDataType.INT_16, unit=unit) * -0.1 + bat_power = self.__tcp_client.read_input_registers(5213, ModbusDataType.INT_32, + wordorder=Endian.Little, unit=unit) * -1 + + # === Mode 2: old_registers === + elif self.register_check == 'old_registers': bat_current = self.__tcp_client.read_input_registers(13020, ModbusDataType.INT_16, unit=unit) * -0.1 bat_power = self.__tcp_client.read_input_registers(13021, ModbusDataType.UINT_16, unit=unit) - if version in (Version.SH, Version.SH_winet_dongle): - resp = self.__tcp_client._delegate.read_input_registers(13000, 1, unit=unit) - binary = bin(resp.registers[0])[2:].zfill(8) - if binary[5] == "1": - bat_power = bat_power * -1 + + resp = self.__tcp_client._delegate.read_input_registers(13000, 1, unit=unit) + running_state = resp.registers[0] + is_charging = (running_state & 0x02) != 0 + is_discharging = (running_state & 0x04) != 0 + + if is_discharging: + bat_power = -abs(bat_power) + elif is_charging: + bat_power = abs(bat_power) + + # === Mode 3: fallback === + else: + bat_current = self.__tcp_client.read_input_registers(13020, ModbusDataType.INT_16, unit=unit) * -0.1 + bat_power = self.__tcp_client.read_input_registers(13021, ModbusDataType.UINT_16, unit=unit) + + total_power = self.__tcp_client.read_input_registers(13033, ModbusDataType.INT_32, + wordorder=Endian.Little, unit=unit) + pv_power = self.__tcp_client.read_input_registers(5016, ModbusDataType.UINT_32, + wordorder=Endian.Little, unit=unit) + + if total_power > pv_power: + bat_power = -abs(bat_power) + else: + bat_power = abs(bat_power) currents = [bat_current / 3] * 3 From 12b9cbee16257e962357502900acff467cdc1f20 Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Thu, 28 Aug 2025 17:15:34 +0200 Subject: [PATCH 05/12] flake8 --- packages/modules/devices/sungrow/sungrow/bat.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/modules/devices/sungrow/sungrow/bat.py b/packages/modules/devices/sungrow/sungrow/bat.py index e7bffec7c1..8382fa649e 100644 --- a/packages/modules/devices/sungrow/sungrow/bat.py +++ b/packages/modules/devices/sungrow/sungrow/bat.py @@ -11,7 +11,6 @@ from modules.common.store import get_bat_value_store from modules.devices.sungrow.sungrow.config import SungrowBatSetup, Sungrow from modules.devices.sungrow.sungrow.version import Version -from modules.devices.sungrow.sungrow.firmware import Firmware log = logging.getLogger(__name__) From 2476b37087cfa089d6c7bb62f7ee483da7fe6e2e Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Thu, 28 Aug 2025 17:16:02 +0200 Subject: [PATCH 06/12] flake8 --- packages/modules/devices/sungrow/sungrow/inverter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/devices/sungrow/sungrow/inverter.py b/packages/modules/devices/sungrow/sungrow/inverter.py index 1f304a917a..a934e04315 100644 --- a/packages/modules/devices/sungrow/sungrow/inverter.py +++ b/packages/modules/devices/sungrow/sungrow/inverter.py @@ -40,7 +40,7 @@ def update(self) -> float: currents = self.__tcp_client.read_input_registers(13030, [ModbusDataType.INT_16]*3, unit=unit) currents = [value * -0.1 for value in currents] - + elif self.device_config.configuration.version in (Version.SG, Version.SG_winet_dongle): power = self.__tcp_client.read_input_registers(5030, ModbusDataType.INT_32, wordorder=Endian.Little, unit=unit) * -1 From dbc3f03b0a973e96d12cf3114c7e6964ddb5b372 Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Thu, 28 Aug 2025 17:16:57 +0200 Subject: [PATCH 07/12] flake8 --- packages/modules/devices/sungrow/sungrow/config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/devices/sungrow/sungrow/config.py b/packages/modules/devices/sungrow/sungrow/config.py index f56d927f96..bc112dd867 100644 --- a/packages/modules/devices/sungrow/sungrow/config.py +++ b/packages/modules/devices/sungrow/sungrow/config.py @@ -10,7 +10,7 @@ def __init__(self, ip_address: Optional[str] = None, port: int = 502, modbus_id: int = 1, - version: Version = Version.SG: + version: Version = Version.SG): self.ip_address = ip_address self.port = port self.modbus_id = modbus_id From d9d2402dc485b0a6d2f9cb151c8f6d83b3076ca2 Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Thu, 28 Aug 2025 17:18:38 +0200 Subject: [PATCH 08/12] flake8 --- packages/modules/devices/sungrow/sungrow/bat.py | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/modules/devices/sungrow/sungrow/bat.py b/packages/modules/devices/sungrow/sungrow/bat.py index 8382fa649e..5c98036f54 100644 --- a/packages/modules/devices/sungrow/sungrow/bat.py +++ b/packages/modules/devices/sungrow/sungrow/bat.py @@ -10,7 +10,6 @@ from modules.common.simcount import SimCounter from modules.common.store import get_bat_value_store from modules.devices.sungrow.sungrow.config import SungrowBatSetup, Sungrow -from modules.devices.sungrow.sungrow.version import Version log = logging.getLogger(__name__) From 7419f6cd4cc514ec2b71b391428e94d46a149819 Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Fri, 29 Aug 2025 08:37:09 +0200 Subject: [PATCH 09/12] Create registers.py --- packages/modules/devices/sungrow/sungrow/registers.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/modules/devices/sungrow/sungrow/registers.py diff --git a/packages/modules/devices/sungrow/sungrow/registers.py b/packages/modules/devices/sungrow/sungrow/registers.py new file mode 100644 index 0000000000..dedc0cd587 --- /dev/null +++ b/packages/modules/devices/sungrow/sungrow/registers.py @@ -0,0 +1,6 @@ +from enum import Enum + +class RegMode(Enum): + NEW_REGISTERS = "new_registers" + OLD_REGISTERS = "old_registers" + FALLBACK = "fallback" From 91e459e4b7e37b1a3e5c85a6f4fe36f0b345b01a Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Fri, 29 Aug 2025 08:37:42 +0200 Subject: [PATCH 10/12] Update registers.py --- packages/modules/devices/sungrow/sungrow/registers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/modules/devices/sungrow/sungrow/registers.py b/packages/modules/devices/sungrow/sungrow/registers.py index dedc0cd587..eae908eaa2 100644 --- a/packages/modules/devices/sungrow/sungrow/registers.py +++ b/packages/modules/devices/sungrow/sungrow/registers.py @@ -1,6 +1,6 @@ -from enum import Enum +from enum import IntEnum -class RegMode(Enum): +class RegMode(IntEnum): NEW_REGISTERS = "new_registers" OLD_REGISTERS = "old_registers" FALLBACK = "fallback" From 25b316a6d40b7604515b9858a49a33f7bd1b9e17 Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Fri, 29 Aug 2025 08:39:00 +0200 Subject: [PATCH 11/12] Update registers.py --- packages/modules/devices/sungrow/sungrow/registers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/modules/devices/sungrow/sungrow/registers.py b/packages/modules/devices/sungrow/sungrow/registers.py index eae908eaa2..7c903cd2b7 100644 --- a/packages/modules/devices/sungrow/sungrow/registers.py +++ b/packages/modules/devices/sungrow/sungrow/registers.py @@ -1,6 +1,7 @@ -from enum import IntEnum +from enum import Enum -class RegMode(IntEnum): + +class RegMode(Enum): NEW_REGISTERS = "new_registers" OLD_REGISTERS = "old_registers" FALLBACK = "fallback" From 201df7f3d0847054066a9dc9b82125599147027c Mon Sep 17 00:00:00 2001 From: SeaSpotter Date: Fri, 29 Aug 2025 08:46:22 +0200 Subject: [PATCH 12/12] Updated to ENUMs --- packages/modules/devices/sungrow/sungrow/bat.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/modules/devices/sungrow/sungrow/bat.py b/packages/modules/devices/sungrow/sungrow/bat.py index 5c98036f54..5267f21774 100644 --- a/packages/modules/devices/sungrow/sungrow/bat.py +++ b/packages/modules/devices/sungrow/sungrow/bat.py @@ -10,6 +10,7 @@ from modules.common.simcount import SimCounter from modules.common.store import get_bat_value_store from modules.devices.sungrow.sungrow.config import SungrowBatSetup, Sungrow +from modules.devices.sungrow.sungrow.registers import RegMode log = logging.getLogger(__name__) @@ -33,7 +34,7 @@ def initialize(self) -> None: self.last_mode = 'Undefined' self.register_check = self.detect_register_check() - def detect_register_check(self) -> str: + def detect_register_check(self) -> RegMode: # Battery register availability test unit = self.device_config.configuration.modbus_id @@ -42,32 +43,32 @@ def detect_register_check(self) -> str: wordorder=Endian.Little, unit=unit) self.__tcp_client.read_input_registers(5630, ModbusDataType.INT_16, unit=unit) log.debug("Battery register check: using new_registers (5213/5630).") - return 'new_registers' + return RegMode.NEW_REGISTERS except Exception: pass try: self.__tcp_client.read_input_registers(13000, ModbusDataType.UINT_16, unit=unit) log.debug("Battery register check: using old_registers (13021 + 13000 bits for sign).") - return 'old_registers' + return RegMode.OLD_REGISTERS except Exception: pass log.debug("Battery register check: using fallback (13021 + total vs PV power).") - return 'fallback' + return RegMode.FALLBACK def update(self) -> None: unit = self.device_config.configuration.modbus_id soc = int(self.__tcp_client.read_input_registers(13022, ModbusDataType.UINT_16, unit=unit) / 10) # === Mode 1: new_registers === - if self.register_check == 'new_registers': + if self.register_check == RegMode.NEW_REGISTERS: bat_current = self.__tcp_client.read_input_registers(5630, ModbusDataType.INT_16, unit=unit) * -0.1 bat_power = self.__tcp_client.read_input_registers(5213, ModbusDataType.INT_32, wordorder=Endian.Little, unit=unit) * -1 # === Mode 2: old_registers === - elif self.register_check == 'old_registers': + elif self.register_check == RegMode.OLD_REGISTERS: bat_current = self.__tcp_client.read_input_registers(13020, ModbusDataType.INT_16, unit=unit) * -0.1 bat_power = self.__tcp_client.read_input_registers(13021, ModbusDataType.UINT_16, unit=unit)