From 6f280b2a531eba3f5eed49cc0be1460ba09902d9 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Thu, 2 Oct 2025 21:15:01 -0700 Subject: [PATCH 1/3] Remove asyncio.Lock() --- .../solaredge_modbus_multi/hub.py | 288 +++++++++--------- 1 file changed, 142 insertions(+), 146 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 54a42ed2..299bece0 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -177,7 +177,6 @@ def __init__( "retries", ModbusDefaults.Retries ) self._id = entry_data[CONF_NAME].lower() - self._lock = asyncio.Lock() self.inverters = [] self.meters = [] self.batteries = [] @@ -380,37 +379,16 @@ async def _async_init_solaredge(self) -> None: async def async_refresh_modbus_data(self) -> bool: """Refresh modbus data from inverters.""" - async with self._lock: - if not self.is_connected: - await self.connect() - - if not self.initalized: - try: - async with asyncio.timeout(self.coordinator_timeout): - await self._async_init_solaredge() - - except (ConnectionException, ModbusIOException, TimeoutError) as e: - self.disconnect() - ir.async_create_issue( - self._hass, - DOMAIN, - "check_configuration", - is_fixable=True, - severity=ir.IssueSeverity.ERROR, - translation_key="check_configuration", - data={"entry_id": self._entry_id}, - ) - raise HubInitFailed(f"Setup failed: {e}") - - ir.async_delete_issue(self._hass, DOMAIN, "check_configuration") - - if not self.keep_modbus_open: - self.disconnect() + if not self.is_connected: + await self.connect() - return True + if not self.initalized: + try: + async with asyncio.timeout(self.coordinator_timeout): + await self._async_init_solaredge() - if not self.is_connected: - self.online = False + except (ConnectionException, ModbusIOException, TimeoutError) as e: + self.disconnect() ir.async_create_issue( self._hass, DOMAIN, @@ -420,65 +398,85 @@ async def async_refresh_modbus_data(self) -> bool: translation_key="check_configuration", data={"entry_id": self._entry_id}, ) - raise DataUpdateFailed( - f"Modbus/TCP connect to {self.hub_host}:{self.hub_port} failed." - ) + raise HubInitFailed(f"Setup failed: {e}") - if not self.online: - ir.async_delete_issue(self._hass, DOMAIN, "check_configuration") + ir.async_delete_issue(self._hass, DOMAIN, "check_configuration") - self.online = True - - try: - async with asyncio.timeout(self.coordinator_timeout): - for inverter in self.inverters: - await inverter.read_modbus_data() - for meter in self.meters: - await meter.read_modbus_data() - for battery in self.batteries: - await battery.read_modbus_data() - - except ModbusReadError as e: + if not self.keep_modbus_open: self.disconnect() - raise DataUpdateFailed(f"Update failed: {e}") - except DeviceInvalid as e: - self.disconnect() - raise DataUpdateFailed(f"Invalid device: {e}") + return True - except ConnectionException as e: - self.disconnect() - raise DataUpdateFailed(f"Connection failed: {e}") + if not self.is_connected: + self.online = False + ir.async_create_issue( + self._hass, + DOMAIN, + "check_configuration", + is_fixable=True, + severity=ir.IssueSeverity.ERROR, + translation_key="check_configuration", + data={"entry_id": self._entry_id}, + ) + raise DataUpdateFailed( + f"Modbus/TCP connect to {self.hub_host}:{self.hub_port} failed." + ) - except ModbusIOException as e: - self.disconnect() - raise DataUpdateFailed(f"Modbus error: {e}") + if not self.online: + ir.async_delete_issue(self._hass, DOMAIN, "check_configuration") - except TimeoutError as e: - self.disconnect(clear_client=True) - self._timeout_counter += 1 + self.online = True - _LOGGER.debug( - f"Refresh timeout {self._timeout_counter} " - f"limit {self._retry_limit}" - ) + try: + async with asyncio.timeout(self.coordinator_timeout): + for inverter in self.inverters: + await inverter.read_modbus_data() + for meter in self.meters: + await meter.read_modbus_data() + for battery in self.batteries: + await battery.read_modbus_data() - if self._timeout_counter >= self._retry_limit: - self._timeout_counter = 0 - raise TimeoutError + except ModbusReadError as e: + self.disconnect() + raise DataUpdateFailed(f"Update failed: {e}") - raise DataUpdateFailed(f"Timeout error: {e}") + except DeviceInvalid as e: + self.disconnect() + raise DataUpdateFailed(f"Invalid device: {e}") - if self._timeout_counter > 0: - _LOGGER.debug( - f"Timeout count {self._timeout_counter} limit {self._retry_limit}" - ) + except ConnectionException as e: + self.disconnect() + raise DataUpdateFailed(f"Connection failed: {e}") + + except ModbusIOException as e: + self.disconnect() + raise DataUpdateFailed(f"Modbus error: {e}") + + except TimeoutError as e: + self.disconnect(clear_client=True) + self._timeout_counter += 1 + + _LOGGER.debug( + f"Refresh timeout {self._timeout_counter} " + f"limit {self._retry_limit}" + ) + + if self._timeout_counter >= self._retry_limit: self._timeout_counter = 0 + raise TimeoutError - if not self.keep_modbus_open: - self.disconnect() + raise DataUpdateFailed(f"Timeout error: {e}") - return True + if self._timeout_counter > 0: + _LOGGER.debug( + f"Timeout count {self._timeout_counter} limit {self._retry_limit}" + ) + self._timeout_counter = 0 + + if not self.keep_modbus_open: + self.disconnect() + + return True async def connect(self) -> None: """Connect to inverter.""" @@ -521,9 +519,8 @@ def disconnect(self, clear_client: bool = False) -> None: async def shutdown(self) -> None: """Shut down the hub and disconnect.""" - async with self._lock: - self.online = False - self.disconnect(clear_client=True) + self.online = False + self.disconnect(clear_client=True) async def modbus_read_holding_registers(self, unit, address, rcount): """Read modbus registers from inverter.""" @@ -588,93 +585,92 @@ async def modbus_read_holding_registers(self, unit, address, rcount): async def write_registers(self, unit: int, address: int, payload) -> None: """Write modbus registers to inverter.""" - async with self._lock: - self._wr_unit = unit - self._wr_address = address - self._wr_payload = payload + self._wr_unit = unit + self._wr_address = address + self._wr_payload = payload - try: - if not self.is_connected: - await self.connect() + try: + if not self.is_connected: + await self.connect() - sig = inspect.signature(self._client.write_registers) + sig = inspect.signature(self._client.write_registers) - if "device_id" in sig.parameters: - result = await self._client.write_registers( - address=self._wr_address, - values=self._wr_payload, - device_id=self._wr_unit, - ) - else: - result = await self._client.write_registers( - address=self._wr_address, - values=self._wr_payload, - slave=self._wr_unit, - ) + if "device_id" in sig.parameters: + result = await self._client.write_registers( + address=self._wr_address, + values=self._wr_payload, + device_id=self._wr_unit, + ) + else: + result = await self._client.write_registers( + address=self._wr_address, + values=self._wr_payload, + slave=self._wr_unit, + ) - self.has_write = address + self.has_write = address - if self.sleep_after_write > 0: - _LOGGER.debug( - f"Sleep {self.sleep_after_write} seconds after write {address}." - ) - await asyncio.sleep(self.sleep_after_write) + if self.sleep_after_write > 0: + _LOGGER.debug( + f"Sleep {self.sleep_after_write} seconds after write {address}." + ) + await asyncio.sleep(self.sleep_after_write) - self.has_write = None - _LOGGER.debug(f"Finished with write {address}.") + self.has_write = None + _LOGGER.debug(f"Finished with write {address}.") - except ModbusIOException as e: - self.disconnect() + except ModbusIOException as e: + self.disconnect() - raise HomeAssistantError( - f"Error sending command to inverter ID {self._wr_unit}: {e}." - ) + raise HomeAssistantError( + f"Error sending command to inverter ID {self._wr_unit}: {e}." + ) - except ConnectionException as e: - self.disconnect() + except ConnectionException as e: + self.disconnect() - _LOGGER.error(f"Connection failed: {e}") + _LOGGER.error(f"Connection failed: {e}") + raise HomeAssistantError( + f"Connection to inverter ID {self._wr_unit} failed." + ) + + if result.isError(): + if type(result) is ModbusIOException: + self.disconnect() + _LOGGER.error( + f"Write failed: No response from inverter ID {self._wr_unit}." + ) raise HomeAssistantError( - f"Connection to inverter ID {self._wr_unit} failed." + "No response from inverter ID {self._wr_unit}." ) - if result.isError(): - if type(result) is ModbusIOException: - self.disconnect() - _LOGGER.error( - f"Write failed: No response from inverter ID {self._wr_unit}." + if type(result) is ExceptionResponse: + if result.exception_code == ModbusExceptions.IllegalAddress: + _LOGGER.debug( + f"Unit {self._wr_unit} Write IllegalAddress: {result}" ) raise HomeAssistantError( - "No response from inverter ID {self._wr_unit}." + "Address not supported at device at ID {self._wr_unit}." ) - if type(result) is ExceptionResponse: - if result.exception_code == ModbusExceptions.IllegalAddress: - _LOGGER.debug( - f"Unit {self._wr_unit} Write IllegalAddress: {result}" - ) - raise HomeAssistantError( - "Address not supported at device at ID {self._wr_unit}." - ) - - if result.exception_code == ModbusExceptions.IllegalFunction: - _LOGGER.debug( - f"Unit {self._wr_unit} Write IllegalFunction: {result}" - ) - raise HomeAssistantError( - "Function not supported by device at ID {self._wr_unit}." - ) + if result.exception_code == ModbusExceptions.IllegalFunction: + _LOGGER.debug( + f"Unit {self._wr_unit} Write IllegalFunction: {result}" + ) + raise HomeAssistantError( + "Function not supported by device at ID {self._wr_unit}." + ) - if result.exception_code == ModbusExceptions.IllegalValue: - _LOGGER.debug( - f"Unit {self._wr_unit} Write IllegalValue: {result}" - ) - raise HomeAssistantError( - "Value invalid for device at ID {self._wr_unit}." - ) + if result.exception_code == ModbusExceptions.IllegalValue: + _LOGGER.debug( + f"Unit {self._wr_unit} Write IllegalValue: {result}" + ) + raise HomeAssistantError( + "Value invalid for device at ID {self._wr_unit}." + ) - self.disconnect() - raise ModbusWriteError(result) + self.disconnect() + raise ModbusWriteError(result) @staticmethod def _safe_version_tuple(version_str: str) -> tuple[int, ...]: From 7d0c13dfe29ecf74759590341ed78ae1e5766c74 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Thu, 2 Oct 2025 21:17:06 -0700 Subject: [PATCH 2/3] Format with ruff --- custom_components/solaredge_modbus_multi/hub.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 299bece0..37cd3d3c 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -110,7 +110,6 @@ class DeviceInvalid(SolarEdgeException): class SolarEdgeModbusMultiHub: - def __init__( self, hass: HomeAssistant, @@ -457,8 +456,7 @@ async def async_refresh_modbus_data(self) -> bool: self._timeout_counter += 1 _LOGGER.debug( - f"Refresh timeout {self._timeout_counter} " - f"limit {self._retry_limit}" + f"Refresh timeout {self._timeout_counter} " f"limit {self._retry_limit}" ) if self._timeout_counter >= self._retry_limit: @@ -662,9 +660,7 @@ async def write_registers(self, unit: int, address: int, payload) -> None: ) if result.exception_code == ModbusExceptions.IllegalValue: - _LOGGER.debug( - f"Unit {self._wr_unit} Write IllegalValue: {result}" - ) + _LOGGER.debug(f"Unit {self._wr_unit} Write IllegalValue: {result}") raise HomeAssistantError( "Value invalid for device at ID {self._wr_unit}." ) From e2709a80d655705bcb2df805b51613bb7191692f Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Fri, 3 Oct 2025 12:39:40 -0700 Subject: [PATCH 3/3] Bump version for pre-release --- custom_components/solaredge_modbus_multi/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/solaredge_modbus_multi/manifest.json b/custom_components/solaredge_modbus_multi/manifest.json index adf5a452..5d89260d 100644 --- a/custom_components/solaredge_modbus_multi/manifest.json +++ b/custom_components/solaredge_modbus_multi/manifest.json @@ -10,5 +10,5 @@ "issue_tracker": "https://github.com/WillCodeForCats/solaredge-modbus-multi/issues", "loggers": ["custom_components.solaredge_modbus_multi"], "requirements": ["pymodbus>=3.8.3"], - "version": "3.1.7" + "version": "3.2.0-pre.1" }