diff --git a/packages/modules/devices/solaredge/solaredge/bat.py b/packages/modules/devices/solaredge/solaredge/bat.py index 5561bc98ce..e61897c877 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_MSC = 7 # RC Command Mode Maximize Self Consumtion +REMOTE_CONTROL_COMMAND_MODE_MSC = 7 # RC Command Mode Maximize Self Consumtion used for Limit Discharge class KwargsDict(TypedDict): @@ -59,9 +59,6 @@ def initialize(self) -> None: self.sim_counter = SimCounter(self.__device_id, self.component_config.id, prefix="speicher") 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.last_mode = 'undefined' def update(self) -> None: self.store.set(self.read_state()) @@ -109,9 +106,6 @@ def get_values(self) -> Tuple[float, float]: power = 0 if soc == FLOAT32_UNSUPPORTED or not 0 <= soc <= 100: log.warning(f"Invalid SoC Speicher{battery_index}: {soc}") - else: - self.min_soc = min(int(soc), int(self.min_soc)) - log.debug(f"Min-SoC Speicher{battery_index}: {int(self.min_soc)}%.") return power, soc @@ -123,113 +117,73 @@ 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) + registers_to_read = [ + "StorageControlMode", + "RemoteControlCommandMode", + "RemoteControlChargeLimit", + "RemoteControlDischargeLimit", + ] + 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 power_limit is None: # No Bat Control should be used. - if self.last_mode in ('discharge-mode', 'charge-mode'): + if values["StorageControlMode"] == CONTROL_MODE_MSC: + log.debug(f"Speicher{battery_index}:Keine Steuerung gefordert, bereits deaktiviert.") + else: # Disable Bat Control - log.debug(f"Speicher{battery_index}:Keine Steuerung gefordert, Steuerung deaktivieren.") values_to_write = { "RemoteControlChargeLimit": MAX_CHARGEDISCHARGE_LIMIT, "RemoteControlDischargeLimit": MAX_CHARGEDISCHARGE_LIMIT, "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, "RemoteControlCommandMode": REMOTE_CONTROL_COMMAND_MODE_DEFAULT, - "StorageControlMode": self.StorageControlMode_Read, + "StorageControlMode": CONTROL_MODE_MSC, } self._write_registers(values_to_write, unit) - self.last_mode = None - else: - return + log.debug(f"Speicher{battery_index}:Keine Steuerung gefordert, Steuerung deaktiviert.") 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. - """ - registers_to_read = [ - f"Battery{battery_index}StateOfEnergy", - "StorageControlMode", - "StorageBackupReserved", - "RemoteControlCommandMode", - "RemoteControlDischargeLimit", - ] - 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 - soc = values[f"Battery{battery_index}StateOfEnergy"] - if soc == FLOAT32_UNSUPPORTED or not 0 <= soc <= 100: - 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["RemoteControlDischargeLimit"]) - 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' - - else: # Remote Control not active. - if soc_reserve < soc: - # 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"] + # Remote Control and Discharge Mode already active. + discharge_limit = int(values["RemoteControlDischargeLimit"]) + if discharge_limit not in range(int(abs(power_limit)) - 10, int(abs(power_limit)) + 10): + # Send Limit only if difference is more than 10W, needed with more than 1 battery. values_to_write = { - "StorageControlMode": CONTROL_MODE_REMOTE, - "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) - self.last_mode = 'discharge-mode' - - elif power_limit > 0: # Charge Mode should be used - registers_to_read = [ - "StorageControlMode", - "RemoteControlCommandMode", - "RemoteControlChargeLimit", - ] - 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 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.") + log.debug(f"Entlade-Limit Speicher{battery_index}: {int(abs(power_limit))}W.") + else: + log.debug(f"Entlade-Limit Speicher{battery_index}: Abweichung unter +/- 10W.") + else: # Enable Remote Control and Discharge Mode. values_to_write = { - "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + "StorageControlMode": CONTROL_MODE_REMOTE, + "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) - self.last_mode = 'charge-mode' + log.debug(f"Entlade-Limit aktiviert, Speicher{battery_index}: {int(abs(power_limit))}W.") - else: # Remote Control Charge Mode inactive. - log.debug(f"Aktivierung Laden Speicher{battery_index}: {int(abs(power_limit))}W.") - self.StorageControlMode_Read = values["StorageControlMode"] + elif power_limit > 0: # Charge Mode should be used + if (values["StorageControlMode"] == CONTROL_MODE_REMOTE and + values["RemoteControlCommandMode"] == REMOTE_CONTROL_COMMAND_MODE_CHARGE): + # Remote Control and Charge Mode already active. + charge_limit = int(values["RemoteControlChargeLimit"]) + if charge_limit not in range(int(abs(power_limit)) - 10, int(abs(power_limit)) + 10): + # Send Limit only if difference is more than 10W. + values_to_write = { + "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) + } + self._write_registers(values_to_write, unit) + log.debug(f"Ladung Speicher{battery_index}: {int(abs(power_limit))}W.") + else: + log.debug(f"Ladung Speicher{battery_index}: Abweichung unter +/- 10W.") + else: # Enable Remote Control and Charge Mode. values_to_write = { "StorageControlMode": CONTROL_MODE_REMOTE, "RemoteControlCommandModeDefault": REMOTE_CONTROL_COMMAND_MODE_CHARGE, @@ -237,7 +191,7 @@ def set_power_limit(self, power_limit: Optional[int]) -> None: "RemoteControlChargeLimit": int(min(abs(power_limit), MAX_CHARGEDISCHARGE_LIMIT)) } self._write_registers(values_to_write, unit) - self.last_mode = 'charge-mode' + log.debug(f"Aktivierung Ladung Speicher{battery_index}: {int(abs(power_limit))}W.") def _read_registers(self, register_names: list, unit: int) -> Dict[str, Union[int, float]]: values = {}