From cdfad53549941d1a1dbd8bc6133ad025d7b039d7 Mon Sep 17 00:00:00 2001 From: cr0i Date: Sun, 18 Jan 2026 00:58:58 +0100 Subject: [PATCH 1/8] Update bat.py --- .../devices/solaredge/solaredge/bat.py | 90 +++++++++++++------ 1 file changed, 64 insertions(+), 26 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index cb81757c2a..1ef1ed7c97 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -24,12 +24,13 @@ log = logging.getLogger(__name__) FLOAT32_UNSUPPORTED = -0xffffff00000000000000000000000000 -MAX_DISCHARGE_LIMIT = 5000 -DEFAULT_CONTROL_MODE = 1 # Control Mode Max Eigenverbrauch -REMOTE_CONTROL_MODE = 4 # Control Mode Remotesteuerung -DEFAULT_COMMAND_MODE = 0 # Command Mode ohne Steuerung -ACTIVE_COMMAND_MODE = 7 # Command Mode Max Eigenverbrauch bei Steuerung - +MAX_CHARGEDISCHARGE_LIMIT = 5000 +CONTROL_MODE_DEFAULT = 1 # Control Mode Max Eigenverbrauch +CONTROL_MODE_REMOTE = 4 # Control Mode Remotesteuerung +COMMAND_MODE_DEFAULT = 0 # Command Mode ohne Steuerung +COMMAND_MODE_CHARGE = 3 # Command Mode Charge from PV+AC +COMMAND_MODE_DISCHARGE = 5 # Command Mode Discharge (Discharge to Grid not allowed) +COMMAND_MODE_MSC = 7 # Command Mode Max Eigenverbrauch bei Steuerung class KwargsDict(TypedDict): device_id: int @@ -47,6 +48,7 @@ class SolaredgeBat(AbstractBat): "StorageBackupReserved": (0xe008, ModbusDataType.FLOAT_32,), "StorageChargeDischargeDefaultMode": (0xe00a, ModbusDataType.UINT_16,), "RemoteControlCommandMode": (0xe00d, ModbusDataType.UINT_16,), + "RemoteControlCommandChargeLimit": (0xe00e, ModbusDataType.FLOAT_32,), "RemoteControlCommandDischargeLimit": (0xe010, ModbusDataType.FLOAT_32,), } @@ -61,7 +63,7 @@ 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.min_soc = 13 - self.StorageControlMode_Read = DEFAULT_CONTROL_MODE + self.StorageControlMode_Read = CONTROL_MODE_DEFAULT self.last_mode = 'undefined' def update(self) -> None: @@ -130,7 +132,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: log.warning("power_limit_mode not found, assuming 'no_limit'") power_limit_mode = 'no_limit' - if power_limit_mode == 'no_limit' and self.last_mode != 'limited': + if power_limit_mode == 'no_limit' and self.last_mode in ('undefined', None): """ Keine Speichersteuerung, andere Steuerungen zulassen (SolarEdge One, ioBroker, Node-Red etc.). Falls andere Steuerungen vorhanden sind, sollten diese nicht beeinflusst werden, @@ -139,14 +141,15 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: return if power_limit is None: - # Keine Ladung mit Speichersteuerung. - if self.last_mode == 'limited': + # Keine Speichersteuerung. + if self.last_mode in ('discharge-mode', 'charge-mode'): # Steuerung deaktivieren. log.debug(f"Speicher{battery_index}:Keine Steuerung gefordert, Steuerung deaktivieren.") values_to_write = { - "RemoteControlCommandDischargeLimit": MAX_DISCHARGE_LIMIT, - "StorageChargeDischargeDefaultMode": DEFAULT_COMMAND_MODE, - "RemoteControlCommandMode": DEFAULT_COMMAND_MODE, + "RemoteControlCommandChargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "RemoteControlCommandDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "StorageChargeDischargeDefaultMode": COMMAND_MODE_DEFAULT, + "RemoteControlCommandMode": COMMAND_MODE_DEFAULT, "StorageControlMode": self.StorageControlMode_Read, } self._write_registers(values_to_write, unit) @@ -154,9 +157,9 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: else: return - elif abs(power_limit) >= 0: + elif power_limit <= 0: """ - Ladung mit Speichersteuerung. + Autoladung mit Speichersteuerung. SolarEdge entlaedt den Speicher immer nur bis zur SoC-Reserve. Steuerung beenden, wenn der SoC vom Speicher die SoC-Reserve unterschreitet. """ @@ -179,15 +182,15 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: log.debug(f"SoC-Reserve Speicher{battery_index}: {int(soc_reserve)}%.") discharge_limit = int(values["RemoteControlCommandDischargeLimit"]) - if values["StorageControlMode"] == REMOTE_CONTROL_MODE: # Speichersteuerung ist aktiv. + if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Speichersteuerung ist aktiv. if soc_reserve > soc: # Speichersteuerung erst deaktivieren, wenn SoC-Reserve unterschritten wird. # Darf wegen 2 Speichern nicht bereits bei SoC-Reserve deaktiviert werden! log.debug(f"Speicher{battery_index}: Steuerung deaktivieren. SoC-Reserve unterschritten") values_to_write = { - "RemoteControlCommandDischargeLimit": MAX_DISCHARGE_LIMIT, - "StorageChargeDischargeDefaultMode": DEFAULT_COMMAND_MODE, - "RemoteControlCommandMode": DEFAULT_COMMAND_MODE, + "RemoteControlCommandDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "StorageChargeDischargeDefaultMode": COMMAND_MODE_DEFAULT, + "RemoteControlCommandMode": COMMAND_MODE_DEFAULT, "StorageControlMode": self.StorageControlMode_Read, } self._write_registers(values_to_write, unit) @@ -197,10 +200,10 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: # Limit nur bei Abweichung von mehr als 10W, um Konflikte bei 2 Speichern zu verhindern. log.debug(f"Discharge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") values_to_write = { - "RemoteControlCommandDischargeLimit": int(min(abs(power_limit), MAX_DISCHARGE_LIMIT)) + "RemoteControlCommandDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) - self.last_mode = 'limited' + self.last_mode = 'discharge-mode' else: # Speichersteuerung ist inaktiv. if soc_reserve < soc: @@ -208,13 +211,48 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: log.debug(f"Discharge-Limit aktivieren, Speicher{battery_index}: {int(abs(power_limit))}W.") self.StorageControlMode_Read = values["StorageControlMode"] values_to_write = { - "StorageControlMode": REMOTE_CONTROL_MODE, - "StorageChargeDischargeDefaultMode": ACTIVE_COMMAND_MODE, - "RemoteControlCommandMode": ACTIVE_COMMAND_MODE, - "RemoteControlCommandDischargeLimit": int(min(abs(power_limit), MAX_DISCHARGE_LIMIT)) + "StorageControlMode": CONTROL_MODE_REMOTE, + "StorageChargeDischargeDefaultMode": COMMAND_MODE_DISCHARGE, + "RemoteControlCommandMode": COMMAND_MODE_DISCHARGE, + "RemoteControlCommandDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) - self.last_mode = 'limited' + self.last_mode = 'discharge-mode' + + elif power_limit > 0: + """ + Aktive Speicherladung. + """ + registers_to_read = [ + "StorageControlMode", + "RemoteControlCommandChargeLimit", + ] + try: + values = self._read_registers(registers_to_read, unit) + except pymodbus.exceptions.ModbusException as e: + log.error(f"Failed to read registers: {e}") + self.fault_state.error(f"Modbus read error: {e}") + return + + if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Speichersteuerung ist aktiv. + log.debug(f"Charge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") + values_to_write = { + "RemoteControlCommandChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + } + self._write_registers(values_to_write, unit) + self.last_mode = 'charge-mode' + + else: # Speichersteuerung ist inaktiv. + log.debug(f"Charge-Limit aktivieren, Speicher{battery_index}: {int(abs(power_limit))}W.") + self.StorageControlMode_Read = values["StorageControlMode"] + values_to_write = { + "StorageControlMode": CONTROL_MODE_REMOTE, + "StorageChargeDischargeDefaultMode": COMMAND_MODE_CHARGE, + "RemoteControlCommandMode": COMMAND_MODE_CHARGE, + "RemoteControlCommandChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + } + self._write_registers(values_to_write, unit) + self.last_mode = 'charge-mode' def _read_registers(self, register_names: list, unit: int) -> Dict[str, Union[int, float]]: values = {} From a3f7ebc6b346703fd721062dd7c85c611914ea3c Mon Sep 17 00:00:00 2001 From: cr0i Date: Sun, 25 Jan 2026 22:07:29 +0100 Subject: [PATCH 2/8] Update bat.py --- .../devices/solaredge/solaredge/bat.py | 107 +++++++----------- 1 file changed, 42 insertions(+), 65 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index 1ef1ed7c97..fea5e0934b 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -8,9 +8,6 @@ import pymodbus -from control import data - - from modules.common import modbus from modules.common.abstract_device import AbstractBat from modules.common.component_state import BatState @@ -25,12 +22,11 @@ FLOAT32_UNSUPPORTED = -0xffffff00000000000000000000000000 MAX_CHARGEDISCHARGE_LIMIT = 5000 -CONTROL_MODE_DEFAULT = 1 # Control Mode Max Eigenverbrauch +CONTROL_MODE_MSC = 1 # Storage Control Mode Maximize Self Consumption CONTROL_MODE_REMOTE = 4 # Control Mode Remotesteuerung -COMMAND_MODE_DEFAULT = 0 # Command Mode ohne Steuerung -COMMAND_MODE_CHARGE = 3 # Command Mode Charge from PV+AC -COMMAND_MODE_DISCHARGE = 5 # Command Mode Discharge (Discharge to Grid not allowed) -COMMAND_MODE_MSC = 7 # Command Mode Max Eigenverbrauch bei Steuerung +REMOTE_CONTROL_COMMAND_MODE_DEFAULT = 0 # Default RC Command Mode ohne Steuerung +REMOTE_CONTROL_COMMAND_MODE_CHARGE = 3 # RC Command Mode Charge from PV+AC +REMOTE_CONTROL_COMMAND_MODE_DISCHARGE = 5 # RC Command Mode Discharge (Discharge to Grid not allowed) class KwargsDict(TypedDict): device_id: int @@ -46,10 +42,10 @@ class SolaredgeBat(AbstractBat): "Battery2InstantaneousPower": (0xe274, ModbusDataType.FLOAT_32,), "StorageControlMode": (0xe004, ModbusDataType.UINT_16,), "StorageBackupReserved": (0xe008, ModbusDataType.FLOAT_32,), - "StorageChargeDischargeDefaultMode": (0xe00a, ModbusDataType.UINT_16,), + "RemoteControlCommandModeDefault": (0xe00a, ModbusDataType.UINT_16,), "RemoteControlCommandMode": (0xe00d, ModbusDataType.UINT_16,), - "RemoteControlCommandChargeLimit": (0xe00e, ModbusDataType.FLOAT_32,), - "RemoteControlCommandDischargeLimit": (0xe010, ModbusDataType.FLOAT_32,), + "RemoteControlChargeLimit": (0xe00e, ModbusDataType.FLOAT_32,), + "RemoteControlDischargeLimit": (0xe010, ModbusDataType.FLOAT_32,), } def __init__(self, component_config: SolaredgeBatSetup, **kwargs: Any) -> None: @@ -63,7 +59,7 @@ 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.min_soc = 13 - self.StorageControlMode_Read = CONTROL_MODE_DEFAULT + self.StorageControlMode_Read = CONTROL_MODE_MSC # Default Control Mode Set to MSC if not Read self.last_mode = 'undefined' def update(self) -> None: @@ -126,30 +122,15 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: # Use 1 as fallback if battery_index is not set battery_index = getattr(self.component_config.configuration, "battery_index", 1) - try: - power_limit_mode = data.data.bat_all_data.data.config.power_limit_mode - except AttributeError: - log.warning("power_limit_mode not found, assuming 'no_limit'") - power_limit_mode = 'no_limit' - - if power_limit_mode == 'no_limit' and self.last_mode in ('undefined', None): - """ - Keine Speichersteuerung, andere Steuerungen zulassen (SolarEdge One, ioBroker, Node-Red etc.). - Falls andere Steuerungen vorhanden sind, sollten diese nicht beeinflusst werden, - daher erfolgt im Modus "Immer" der Speichersteuerung keine Steuerung. - """ - return - - if power_limit is None: - # Keine Speichersteuerung. + if power_limit is None: # No Bat Control should be used. if self.last_mode in ('discharge-mode', 'charge-mode'): - # Steuerung deaktivieren. + # Disable Bat Control log.debug(f"Speicher{battery_index}:Keine Steuerung gefordert, Steuerung deaktivieren.") values_to_write = { - "RemoteControlCommandChargeLimit": MAX_CHARGEDISCHARGE_LIMIT, - "RemoteControlCommandDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, - "StorageChargeDischargeDefaultMode": COMMAND_MODE_DEFAULT, - "RemoteControlCommandMode": COMMAND_MODE_DEFAULT, + "RemoteControlChargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "RemoteControlDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, + "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, "StorageControlMode": self.StorageControlMode_Read, } self._write_registers(values_to_write, unit) @@ -157,17 +138,16 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: else: return - elif power_limit <= 0: + elif power_limit <= 0: # Limit Discharge Mode should be used. """ - Autoladung mit Speichersteuerung. - SolarEdge entlaedt den Speicher immer nur bis zur SoC-Reserve. - Steuerung beenden, wenn der SoC vom Speicher die SoC-Reserve unterschreitet. + SolarEdge discharges the battery only to SoC-Reserve. + Disable Remote Control if SoC of battery is lower than SoC-Reserve. """ registers_to_read = [ f"Battery{battery_index}StateOfEnergy", "StorageControlMode", "StorageBackupReserved", - "RemoteControlCommandDischargeLimit", + "RemoteControlDischargeLimit", ] try: values = self._read_registers(registers_to_read, unit) @@ -180,52 +160,49 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: log.warning(f"Speicher{battery_index}: Invalid SoC: {soc}") soc_reserve = max(int(self.min_soc + 2), int(values["StorageBackupReserved"])) log.debug(f"SoC-Reserve Speicher{battery_index}: {int(soc_reserve)}%.") - discharge_limit = int(values["RemoteControlCommandDischargeLimit"]) + discharge_limit = int(values["RemoteControlDischargeLimit"]) - if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Speichersteuerung ist aktiv. + if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Remote Control active. if soc_reserve > soc: - # Speichersteuerung erst deaktivieren, wenn SoC-Reserve unterschritten wird. - # Darf wegen 2 Speichern nicht bereits bei SoC-Reserve deaktiviert werden! + # Disable Remote Control if SOC is lower than SOC-RESERVE. + # toDo: Problem with 2 batteries is unsolved. log.debug(f"Speicher{battery_index}: Steuerung deaktivieren. SoC-Reserve unterschritten") values_to_write = { - "RemoteControlCommandDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, - "StorageChargeDischargeDefaultMode": COMMAND_MODE_DEFAULT, - "RemoteControlCommandMode": COMMAND_MODE_DEFAULT, + "RemoteControlDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, + "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, "StorageControlMode": self.StorageControlMode_Read, } self._write_registers(values_to_write, unit) self.last_mode = None elif discharge_limit not in range(int(abs(power_limit)) - 10, int(abs(power_limit)) + 10): - # Limit nur bei Abweichung von mehr als 10W, um Konflikte bei 2 Speichern zu verhindern. + # Limit only if difference is more than 10W, needed with more than 1 battery. log.debug(f"Discharge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") values_to_write = { - "RemoteControlCommandDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + "RemoteControlDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) self.last_mode = 'discharge-mode' - else: # Speichersteuerung ist inaktiv. + else: # Remote Control not active. if soc_reserve < soc: - # Speichersteuerung nur aktivieren, wenn SoC ueber SoC-Reserve. + # Enable Remote Control if SoC above SoC-Reserve. log.debug(f"Discharge-Limit aktivieren, Speicher{battery_index}: {int(abs(power_limit))}W.") self.StorageControlMode_Read = values["StorageControlMode"] values_to_write = { "StorageControlMode": CONTROL_MODE_REMOTE, - "StorageChargeDischargeDefaultMode": COMMAND_MODE_DISCHARGE, - "RemoteControlCommandMode": COMMAND_MODE_DISCHARGE, - "RemoteControlCommandDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DISCHARGE, + "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DISCHARGE, + "RemoteControlDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) self.last_mode = 'discharge-mode' - elif power_limit > 0: - """ - Aktive Speicherladung. - """ + elif power_limit > 0: # Charge Mode should be used registers_to_read = [ "StorageControlMode", - "RemoteControlCommandChargeLimit", + "RemoteControlChargeLimit", ] try: values = self._read_registers(registers_to_read, unit) @@ -234,22 +211,22 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: self.fault_state.error(f"Modbus read error: {e}") return - if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Speichersteuerung ist aktiv. - log.debug(f"Charge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") + if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Remote Control active. + log.debug(f"Ladung Speicher{battery_index}: {int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT))}W.") values_to_write = { - "RemoteControlCommandChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) self.last_mode = 'charge-mode' - else: # Speichersteuerung ist inaktiv. - log.debug(f"Charge-Limit aktivieren, Speicher{battery_index}: {int(abs(power_limit))}W.") + else: # Remote Control inactive. + log.debug(f"Aktivierung Laden Speicher{battery_index}: {int(abs(power_limit))}W.") self.StorageControlMode_Read = values["StorageControlMode"] values_to_write = { "StorageControlMode": CONTROL_MODE_REMOTE, - "StorageChargeDischargeDefaultMode": COMMAND_MODE_CHARGE, - "RemoteControlCommandMode": COMMAND_MODE_CHARGE, - "RemoteControlCommandChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_CHARGE, + "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_CHARGE, + "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) self.last_mode = 'charge-mode' From a203571adc1c8c04c6147d2d064c2dd3c72d1382 Mon Sep 17 00:00:00 2001 From: cr0i Date: Sun, 25 Jan 2026 22:19:42 +0100 Subject: [PATCH 3/8] Update bat.py --- packages/modules/devices/solaredge/solaredge/bat.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index fea5e0934b..667cc7b54a 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -25,9 +25,10 @@ CONTROL_MODE_MSC = 1 # Storage Control Mode Maximize Self Consumption CONTROL_MODE_REMOTE = 4 # Control Mode Remotesteuerung REMOTE_CONTROL_COMMAND_MODE_DEFAULT = 0 # Default RC Command Mode ohne Steuerung -REMOTE_CONTROL_COMMAND_MODE_CHARGE = 3 # RC Command Mode Charge from PV+AC +REMOTE_CONTROL_COMMAND_MODE_CHARGE = 3 # RC Command Mode Charge from PV+AC REMOTE_CONTROL_COMMAND_MODE_DISCHARGE = 5 # RC Command Mode Discharge (Discharge to Grid not allowed) + class KwargsDict(TypedDict): device_id: int client: modbus.ModbusTcpClient_ @@ -59,7 +60,7 @@ 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.min_soc = 13 - self.StorageControlMode_Read = CONTROL_MODE_MSC # Default Control Mode Set to MSC if not Read + self.StorageControlMode_Read = CONTROL_MODE_MSC # Default Control Mode Set to MSC if not Read self.last_mode = 'undefined' def update(self) -> None: @@ -122,7 +123,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: # Use 1 as fallback if battery_index is not set battery_index = getattr(self.component_config.configuration, "battery_index", 1) - if power_limit is None: # No Bat Control should be used. + if power_limit is None: # No Bat Control should be used. if self.last_mode in ('discharge-mode', 'charge-mode'): # Disable Bat Control log.debug(f"Speicher{battery_index}:Keine Steuerung gefordert, Steuerung deaktivieren.") @@ -138,7 +139,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: else: return - elif power_limit <= 0: # Limit Discharge Mode should be used. + elif power_limit <= 0: # Limit Discharge Mode should be used. """ SolarEdge discharges the battery only to SoC-Reserve. Disable Remote Control if SoC of battery is lower than SoC-Reserve. @@ -199,7 +200,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: self._write_registers(values_to_write, unit) self.last_mode = 'discharge-mode' - elif power_limit > 0: # Charge Mode should be used + elif power_limit > 0: # Charge Mode should be used registers_to_read = [ "StorageControlMode", "RemoteControlChargeLimit", From 9d402c66b2f3f76b8928c181c1e1dead41cd6e03 Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 26 Jan 2026 06:51:10 +0100 Subject: [PATCH 4/8] Update bat.py --- packages/modules/devices/solaredge/solaredge/bat.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index 667cc7b54a..8cbcf8c5a1 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -26,7 +26,7 @@ CONTROL_MODE_REMOTE = 4 # Control Mode Remotesteuerung REMOTE_CONTROL_COMMAND_MODE_DEFAULT = 0 # Default RC Command Mode ohne Steuerung REMOTE_CONTROL_COMMAND_MODE_CHARGE = 3 # RC Command Mode Charge from PV+AC -REMOTE_CONTROL_COMMAND_MODE_DISCHARGE = 5 # RC Command Mode Discharge (Discharge to Grid not allowed) +REMOTE_CONTROL_COMMAND_MODE_MSC = 7 # RC Command Mode Maximize Self Consumtion class KwargsDict(TypedDict): @@ -193,8 +193,8 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: self.StorageControlMode_Read = values["StorageControlMode"] values_to_write = { "StorageControlMode": CONTROL_MODE_REMOTE, - "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DISCHARGE, - "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DISCHARGE, + "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_MSC, + "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_MSC, "RemoteControlDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) From d1efe920a9316d83516ad7498311238093062ac7 Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 26 Jan 2026 13:15:53 +0100 Subject: [PATCH 5/8] Update bat.py --- packages/modules/devices/solaredge/solaredge/bat.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index 8cbcf8c5a1..683b95d4e8 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -148,6 +148,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: f"Battery{battery_index}StateOfEnergy", "StorageControlMode", "StorageBackupReserved", + "RemoteControlCommandMode", "RemoteControlDischargeLimit", ] try: @@ -163,7 +164,9 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: log.debug(f"SoC-Reserve Speicher{battery_index}: {int(soc_reserve)}%.") discharge_limit = int(values["RemoteControlDischargeLimit"]) - if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Remote Control active. + if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and + values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_MSC): + # RC Discharge Mode active. if soc_reserve > soc: # Disable Remote Control if SOC is lower than SOC-RESERVE. # toDo: Problem with 2 batteries is unsolved. @@ -203,6 +206,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: elif power_limit > 0: # Charge Mode should be used registers_to_read = [ "StorageControlMode", + "RemoteControlCommandMode", "RemoteControlChargeLimit", ] try: @@ -212,7 +216,9 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: self.fault_state.error(f"Modbus read error: {e}") return - if values["StorageControlMode"] == CONTROL_MODE_REMOTE: # Remote Control active. + if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and + values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_CHARGE): + # Remote Control Charge Mode active. log.debug(f"Ladung Speicher{battery_index}: {int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT))}W.") values_to_write = { "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) @@ -220,7 +226,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: self._write_registers(values_to_write, unit) self.last_mode = 'charge-mode' - else: # Remote Control inactive. + else: # Remote Control Charge Mode inactive. log.debug(f"Aktivierung Laden Speicher{battery_index}: {int(abs(power_limit))}W.") self.StorageControlMode_Read = values["StorageControlMode"] values_to_write = { From 2e34cd6391ec2f4d07e4d6c276d60e09a19199f2 Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 26 Jan 2026 13:23:44 +0100 Subject: [PATCH 6/8] Update bat.py --- .../devices/solaredge/solaredge/bat.py | 59 ++++++++++--------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index 683b95d4e8..38b1b43aa6 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -166,28 +166,28 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_MSC): - # RC Discharge Mode active. - if soc_reserve > soc: - # Disable Remote Control if SOC is lower than SOC-RESERVE. - # toDo: Problem with 2 batteries is unsolved. - log.debug(f"Speicher{battery_index}: Steuerung deaktivieren. SoC-Reserve unterschritten") - values_to_write = { - "RemoteControlDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, - "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, - "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, - "StorageControlMode": self.StorageControlMode_Read, - } - self._write_registers(values_to_write, unit) - self.last_mode = None - - elif discharge_limit not in range(int(abs(power_limit)) - 10, int(abs(power_limit)) + 10): - # Limit only if difference is more than 10W, needed with more than 1 battery. - log.debug(f"Discharge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") - values_to_write = { - "RemoteControlDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) - } - self._write_registers(values_to_write, unit) - self.last_mode = 'discharge-mode' + # RC Discharge Mode active. + if soc_reserve > soc: + # Disable Remote Control if SOC is lower than SOC-RESERVE. + # toDo: Problem with 2 batteries is unsolved. + log.debug(f"Speicher{battery_index}: Steuerung deaktivieren. SoC-Reserve unterschritten") + values_to_write = { + "RemoteControlDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, + "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, + "StorageControlMode": self.StorageControlMode_Read, + } + self._write_registers(values_to_write, unit) + self.last_mode = None + + elif discharge_limit not in range(int(abs(power_limit)) - 10, int(abs(power_limit)) + 10): + # Limit only if difference is more than 10W, needed with more than 1 battery. + log.debug(f"Discharge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") + values_to_write = { + "RemoteControlDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + } + self._write_registers(values_to_write, unit) + self.last_mode = 'discharge-mode' else: # Remote Control not active. if soc_reserve < soc: @@ -218,13 +218,14 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_CHARGE): - # Remote Control Charge Mode active. - log.debug(f"Ladung Speicher{battery_index}: {int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT))}W.") - values_to_write = { - "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) - } - self._write_registers(values_to_write, unit) - self.last_mode = 'charge-mode' + # Remote Control Charge Mode active. + log.debug( + f"Ladung Speicher.{battery_index}: {int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT))}W.") + values_to_write = { + "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + } + self._write_registers(values_to_write, unit) + self.last_mode = 'charge-mode' else: # Remote Control Charge Mode inactive. log.debug(f"Aktivierung Laden Speicher{battery_index}: {int(abs(power_limit))}W.") From 2c41de77448baee62d610e07c57e4c8825574021 Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 26 Jan 2026 13:29:03 +0100 Subject: [PATCH 7/8] Update bat.py --- packages/modules/devices/solaredge/solaredge/bat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index 38b1b43aa6..e1c20d4096 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -165,7 +165,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: discharge_limit = int(values["RemoteControlDischargeLimit"]) if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and - values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_MSC): + values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_MSC): # RC Discharge Mode active. if soc_reserve > soc: # Disable Remote Control if SOC is lower than SOC-RESERVE. @@ -217,7 +217,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: return if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and - values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_CHARGE): + values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_CHARGE): # Remote Control Charge Mode active. log.debug( f"Ladung Speicher.{battery_index}: {int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT))}W.") From 1ace1170f88f3d89542c89bf8c7aa9c3b1d1b9b4 Mon Sep 17 00:00:00 2001 From: cr0i Date: Mon, 26 Jan 2026 13:38:13 +0100 Subject: [PATCH 8/8] Update bat.py --- .../devices/solaredge/solaredge/bat.py | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index e1c20d4096..53a6b82615 100644 --- a/packages/modules/devices/solaredge/solaredge/bat.py +++ b/packages/modules/devices/solaredge/solaredge/bat.py @@ -166,27 +166,27 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_MSC): - # RC Discharge Mode active. - if soc_reserve > soc: - # Disable Remote Control if SOC is lower than SOC-RESERVE. - # toDo: Problem with 2 batteries is unsolved. - log.debug(f"Speicher{battery_index}: Steuerung deaktivieren. SoC-Reserve unterschritten") - values_to_write = { - "RemoteControlDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, - "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, - "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, - "StorageControlMode": self.StorageControlMode_Read, - } - self._write_registers(values_to_write, unit) - self.last_mode = None - - elif discharge_limit not in range(int(abs(power_limit)) - 10, int(abs(power_limit)) + 10): - # Limit only if difference is more than 10W, needed with more than 1 battery. - log.debug(f"Discharge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") - values_to_write = { - "RemoteControlDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) - } - self._write_registers(values_to_write, unit) + # RC Discharge Mode active. + if soc_reserve > soc: + # Disable Remote Control if SOC is lower than SOC-RESERVE. + # toDo: Problem with 2 batteries is unsolved. + log.debug(f"Speicher{battery_index}: Steuerung deaktivieren. SoC-Reserve unterschritten") + values_to_write = { + "RemoteControlDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, + "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, + "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, + "StorageControlMode": self.StorageControlMode_Read, + } + self._write_registers(values_to_write, unit) + self.last_mode = None + + elif discharge_limit not in range(int(abs(power_limit)) - 10, int(abs(power_limit)) + 10): + # Limit only if difference is more than 10W, needed with more than 1 battery. + log.debug(f"Discharge-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") + values_to_write = { + "RemoteControlDischargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + } + self._write_registers(values_to_write, unit) self.last_mode = 'discharge-mode' else: # Remote Control not active. @@ -218,14 +218,14 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_CHARGE): - # Remote Control Charge Mode active. - log.debug( - f"Ladung Speicher.{battery_index}: {int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT))}W.") - values_to_write = { - "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) - } - self._write_registers(values_to_write, unit) - self.last_mode = 'charge-mode' + # Remote Control Charge Mode active. + log.debug( + f"Ladung Speicher.{battery_index}: {int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT))}W.") + values_to_write = { + "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + } + self._write_registers(values_to_write, unit) + self.last_mode = 'charge-mode' else: # Remote Control Charge Mode inactive. log.debug(f"Aktivierung Laden Speicher{battery_index}: {int(abs(power_limit))}W.")