diff --git a/custom_components/solaredge_modbus_multi/__init__.py b/custom_components/solaredge_modbus_multi/__init__.py index 70ee8e0a..d2d43901 100644 --- a/custom_components/solaredge_modbus_multi/__init__.py +++ b/custom_components/solaredge_modbus_multi/__init__.py @@ -185,13 +185,12 @@ def __init__( async def _async_update_data(self): try: - async with async_timeout.timeout(self._hub.coordinator_timeout): - return await self._refresh_modbus_data_with_retry( - ex_type=DataUpdateFailed, - limit=RetrySettings.Limit, - wait_ms=RetrySettings.Time, - wait_ratio=RetrySettings.Ratio, - ) + return await self._refresh_modbus_data_with_retry( + ex_type=DataUpdateFailed, + limit=RetrySettings.Limit, + wait_ms=RetrySettings.Time, + wait_ratio=RetrySettings.Ratio, + ) except HubInitFailed as e: raise UpdateFailed(f"{e}") @@ -220,7 +219,8 @@ async def _refresh_modbus_data_with_retry( attempt = 1 while True: try: - return await self._hub.async_refresh_modbus_data() + async with async_timeout.timeout(self._hub.coordinator_timeout): + return await self._hub.async_refresh_modbus_data() except Exception as ex: if not isinstance(ex, ex_type): raise ex diff --git a/custom_components/solaredge_modbus_multi/const.py b/custom_components/solaredge_modbus_multi/const.py index 91ad8d22..a1f62dab 100644 --- a/custom_components/solaredge_modbus_multi/const.py +++ b/custom_components/solaredge_modbus_multi/const.py @@ -40,11 +40,19 @@ class StrEnum(str, Enum): ) +class SolarEdgeTimeouts(IntEnum): + """Timeouts in milliseconds.""" + + Inverter = 8400 + Device = 1200 + Init = 1200 + + class RetrySettings(IntEnum): """Retry settings when opening a connection to the inverter fails.""" Time = 800 # first attempt in milliseconds - Ratio = 2 # time multiplier between each attempt + Ratio = 3 # time multiplier between each attempt Limit = 4 # number of attempts before failing diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index fd1d2ec2..c15c13fd 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -18,7 +18,7 @@ except ImportError: raise ImportError("pymodbus is not installed, or pymodbus version is not supported") -from .const import DOMAIN, SunSpecNotImpl +from .const import DOMAIN, SolarEdgeTimeouts, SunSpecNotImpl from .helpers import float_to_hex, parse_modbus_string _LOGGER = logging.getLogger(__name__) @@ -125,7 +125,6 @@ def __init__( self._allow_battery_energy_reset = allow_battery_energy_reset self._battery_rating_adjust = battery_rating_adjust self._battery_energy_reset_cycles = battery_energy_reset_cycles - self._coordinator_timeout = 30 self._id = name.lower() self._lock = asyncio.Lock() self.inverters = [] @@ -497,10 +496,44 @@ def battery_rating_adjust(self) -> int: def battery_energy_reset_cycles(self) -> int: return self._battery_energy_reset_cycles + @property + def number_of_meters(self) -> int: + return len(self.meters) + + @property + def number_of_batteries(self) -> int: + return len(self.batteries) + + @property + def number_of_inverters(self) -> int: + return self._number_of_inverters + + @keep_modbus_open.setter + def keep_modbus_open(self, value: bool) -> None: + if value is True: + self._keep_modbus_open = True + else: + self._keep_modbus_open = False + + _LOGGER.debug(f"keep_modbus_open={self._keep_modbus_open}") + @property def coordinator_timeout(self) -> int: - _LOGGER.debug(f"coordinator timeout is {self._coordinator_timeout}") - return self._coordinator_timeout + if not self.initalized: + this_timeout = SolarEdgeTimeouts.Inverter * self.number_of_inverters + this_timeout += SolarEdgeTimeouts.Init * self.number_of_inverters + this_timeout += (SolarEdgeTimeouts.Device * 2) * 3 # max 3 per inverter + this_timeout += (SolarEdgeTimeouts.Device * 2) * 2 # max 2 per inverter + + else: + this_timeout = SolarEdgeTimeouts.Inverter * self.number_of_inverters + this_timeout += SolarEdgeTimeouts.Device * self.number_of_meters + this_timeout += SolarEdgeTimeouts.Device * self.number_of_batteries + + this_timeout = this_timeout / 1000 + + _LOGGER.debug(f"coordinator timeout is {this_timeout}") + return this_timeout @property def is_connected(self) -> bool: