From 3233edec56e4fae37c7907f3991e946c82b5c8cc Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Wed, 10 May 2023 23:10:57 -0700 Subject: [PATCH 01/13] Coordinator timeout based on number of inverters --- custom_components/solaredge_modbus_multi/const.py | 2 ++ custom_components/solaredge_modbus_multi/hub.py | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/const.py b/custom_components/solaredge_modbus_multi/const.py index b784a976..d8534ea4 100644 --- a/custom_components/solaredge_modbus_multi/const.py +++ b/custom_components/solaredge_modbus_multi/const.py @@ -23,6 +23,8 @@ class StrEnum(str, Enum): ENERGY_VOLT_AMPERE_HOUR: Final = "VAh" ENERGY_VOLT_AMPERE_REACTIVE_HOUR: Final = "varh" +INVERTER_TIMEOUT = 5 + class RetrySettings(IntEnum): """Retry settings when opening a connection to the inverter fails.""" diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index c41e1920..c90e5461 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -15,7 +15,7 @@ except ImportError: raise ImportError("pymodbus is not installed, or pymodbus version is not supported") -from .const import DOMAIN, SunSpecNotImpl +from .const import DOMAIN, INVERTER_TIMEOUT, SunSpecNotImpl from .helpers import float_to_hex, parse_modbus_string _LOGGER = logging.getLogger(__name__) @@ -100,7 +100,6 @@ def __init__( self._battery_rating_adjust = battery_rating_adjust self._lock = threading.Lock() self._id = name.lower() - self._coordinator_timeout = 30 self._client = None self._id = name.lower() self._lock = threading.Lock() @@ -420,8 +419,9 @@ def keep_modbus_open(self, value: bool) -> None: @property def coordinator_timeout(self) -> int: - _LOGGER.debug(f"coordinator timeout is {self._coordinator_timeout}") - return self._coordinator_timeout + this_timeout = INVERTER_TIMEOUT * self._number_of_inverters + _LOGGER.debug(f"coordinator timeout is {this_timeout}") + return this_timeout async def disconnect(self) -> None: """Disconnect modbus client.""" From 4aa53f3e7f08ac3bb80169fb397d21528d04fe72 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Fri, 12 May 2023 10:25:25 -0700 Subject: [PATCH 02/13] Use milliseconds --- custom_components/solaredge_modbus_multi/const.py | 2 +- custom_components/solaredge_modbus_multi/hub.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/const.py b/custom_components/solaredge_modbus_multi/const.py index d8534ea4..ad51df8c 100644 --- a/custom_components/solaredge_modbus_multi/const.py +++ b/custom_components/solaredge_modbus_multi/const.py @@ -23,7 +23,7 @@ class StrEnum(str, Enum): ENERGY_VOLT_AMPERE_HOUR: Final = "VAh" ENERGY_VOLT_AMPERE_REACTIVE_HOUR: Final = "varh" -INVERTER_TIMEOUT = 5 +INVERTER_TIMEOUT = 5000 # milliseconds class RetrySettings(IntEnum): diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index c90e5461..6a83aa2b 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -419,7 +419,7 @@ def keep_modbus_open(self, value: bool) -> None: @property def coordinator_timeout(self) -> int: - this_timeout = INVERTER_TIMEOUT * self._number_of_inverters + this_timeout = (INVERTER_TIMEOUT / 1000) * self._number_of_inverters _LOGGER.debug(f"coordinator timeout is {this_timeout}") return this_timeout From 7446841b6c1d3a7c75f7f8fb14e5518382fbab41 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Tue, 27 Jun 2023 11:50:02 -0700 Subject: [PATCH 03/13] Update hub.py --- custom_components/solaredge_modbus_multi/hub.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index e1cfb490..5e3ed745 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -129,7 +129,6 @@ def __init__( self._sleep_after_write = sleep_after_write self._battery_rating_adjust = battery_rating_adjust self._battery_energy_reset_cycles = battery_energy_reset_cycles - self._coordinator_timeout = 30 self._client = None self._id = name.lower() self._lock = threading.Lock() From 3478796453e8998fdc685d4aacc7f8112db49017 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Tue, 27 Jun 2023 12:00:22 -0700 Subject: [PATCH 04/13] Add new properties --- custom_components/solaredge_modbus_multi/hub.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 5e3ed745..16b1e205 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -471,6 +471,14 @@ 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 self.meters.count() + + @property + def number_of_batteries(self) -> int: + return self.batteries.count() + @keep_modbus_open.setter def keep_modbus_open(self, value: bool) -> None: if value is True: From 572917bd44ccf52c6417462fc391050e35fcd056 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Tue, 27 Jun 2023 13:56:50 -0700 Subject: [PATCH 05/13] Change timeouts to class --- custom_components/solaredge_modbus_multi/const.py | 9 +++++++-- custom_components/solaredge_modbus_multi/hub.py | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/const.py b/custom_components/solaredge_modbus_multi/const.py index 0ff9201d..d78d4626 100644 --- a/custom_components/solaredge_modbus_multi/const.py +++ b/custom_components/solaredge_modbus_multi/const.py @@ -27,8 +27,6 @@ class StrEnum(str, Enum): ENERGY_VOLT_AMPERE_HOUR: Final = "VAh" ENERGY_VOLT_AMPERE_REACTIVE_HOUR: Final = "varh" -INVERTER_TIMEOUT = 5000 # milliseconds - # from voluptuous/validators.py DOMAIN_REGEX = re.compile( # start anchor, because fullmatch is not available in python 2.7 @@ -42,6 +40,13 @@ class StrEnum(str, Enum): ) +class SolarEdgeTimeouts(IntEnum): + """Timeouts in milliseconds.""" + + Inverter = 5000 + Device = 1200 + + class RetrySettings(IntEnum): """Retry settings when opening a connection to the inverter fails.""" diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 16b1e205..16cb313c 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, INVERTER_TIMEOUT, SunSpecNotImpl +from .const import DOMAIN, SolarEdgeTimeouts, SunSpecNotImpl from .helpers import float_to_hex, parse_modbus_string _LOGGER = logging.getLogger(__name__) @@ -479,6 +479,10 @@ def number_of_meters(self) -> int: def number_of_batteries(self) -> int: return self.batteries.count() + @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: @@ -490,7 +494,11 @@ def keep_modbus_open(self, value: bool) -> None: @property def coordinator_timeout(self) -> int: - this_timeout = (INVERTER_TIMEOUT / 1000) * self._number_of_inverters + 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 From e42c56efcdb68c900fa3f7ccc0f9c2dd02013bac Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Wed, 28 Jun 2023 10:23:20 -0700 Subject: [PATCH 06/13] Move async timeout within retry --- .../solaredge_modbus_multi/__init__.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/__init__.py b/custom_components/solaredge_modbus_multi/__init__.py index 692f17a0..270dd365 100644 --- a/custom_components/solaredge_modbus_multi/__init__.py +++ b/custom_components/solaredge_modbus_multi/__init__.py @@ -189,13 +189,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}") @@ -224,7 +223,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 From 917252b70006c9c534b9558ce91debcb2ee648e4 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Fri, 14 Jul 2023 15:37:38 -0700 Subject: [PATCH 07/13] Change retry timing Retry timing more in line with command write delays (as documented, anyway) --- custom_components/solaredge_modbus_multi/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/solaredge_modbus_multi/const.py b/custom_components/solaredge_modbus_multi/const.py index fd96f492..468430c2 100644 --- a/custom_components/solaredge_modbus_multi/const.py +++ b/custom_components/solaredge_modbus_multi/const.py @@ -51,7 +51,7 @@ 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 From f8c8bb2371ffbf29cf97fe6802cf2007c8a6c1df Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jul 2023 07:24:53 -0700 Subject: [PATCH 08/13] Include retry timeouts for coordinator --- custom_components/solaredge_modbus_multi/hub.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 0dbcb6fe..26143e9f 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, SolarEdgeTimeouts, SunSpecNotImpl +from .const import DOMAIN, RetrySettings, SolarEdgeTimeouts, SunSpecNotImpl from .helpers import float_to_hex, parse_modbus_string _LOGGER = logging.getLogger(__name__) @@ -522,6 +522,9 @@ def coordinator_timeout(self) -> int: 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 += ( + RetrySettings.Time * RetrySettings.Ratio * (RetrySettings.limit - 1) + ) this_timeout = this_timeout / 1000 _LOGGER.debug(f"coordinator timeout is {this_timeout}") From 33329c068355304ade0b3737625831ca8bb0c56c Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jul 2023 07:27:16 -0700 Subject: [PATCH 09/13] Revert "Include retry timeouts for coordinator" This reverts commit f8c8bb2371ffbf29cf97fe6802cf2007c8a6c1df. --- custom_components/solaredge_modbus_multi/hub.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 26143e9f..0dbcb6fe 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, RetrySettings, SolarEdgeTimeouts, SunSpecNotImpl +from .const import DOMAIN, SolarEdgeTimeouts, SunSpecNotImpl from .helpers import float_to_hex, parse_modbus_string _LOGGER = logging.getLogger(__name__) @@ -522,9 +522,6 @@ def coordinator_timeout(self) -> int: 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 += ( - RetrySettings.Time * RetrySettings.Ratio * (RetrySettings.limit - 1) - ) this_timeout = this_timeout / 1000 _LOGGER.debug(f"coordinator timeout is {this_timeout}") From 15aef454f93d8100dcc2924784c2da4a5c476043 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sat, 15 Jul 2023 07:33:11 -0700 Subject: [PATCH 10/13] Max timeout during discovery --- custom_components/solaredge_modbus_multi/hub.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 0dbcb6fe..6850d3dc 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -519,9 +519,16 @@ def keep_modbus_open(self, value: bool) -> None: @property def coordinator_timeout(self) -> int: - this_timeout = SolarEdgeTimeouts.Inverter * self.number_of_inverters - this_timeout += SolarEdgeTimeouts.Device * self.number_of_meters - this_timeout += SolarEdgeTimeouts.Device * self.number_of_batteries + if not self.initalized: + this_timeout = SolarEdgeTimeouts.Inverter * self.number_of_inverters + this_timeout += SolarEdgeTimeouts.Device * 3 # max 3 per inverter + this_timeout += SolarEdgeTimeouts.Device * 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}") From 293727f627da1d7bb32be48d8157871ce5de7c36 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sun, 16 Jul 2023 14:38:55 -0700 Subject: [PATCH 11/13] Update timing * 1200ms per inverter read * Extra init read on devices during init --- custom_components/solaredge_modbus_multi/const.py | 2 +- custom_components/solaredge_modbus_multi/hub.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/const.py b/custom_components/solaredge_modbus_multi/const.py index 8ac27b92..9ba719be 100644 --- a/custom_components/solaredge_modbus_multi/const.py +++ b/custom_components/solaredge_modbus_multi/const.py @@ -43,7 +43,7 @@ class StrEnum(str, Enum): class SolarEdgeTimeouts(IntEnum): """Timeouts in milliseconds.""" - Inverter = 5000 + Inverter = 8400 Device = 1200 diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 6850d3dc..2228d208 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -521,8 +521,9 @@ def keep_modbus_open(self, value: bool) -> None: def coordinator_timeout(self) -> int: if not self.initalized: this_timeout = SolarEdgeTimeouts.Inverter * self.number_of_inverters - this_timeout += SolarEdgeTimeouts.Device * 3 # max 3 per inverter - this_timeout += SolarEdgeTimeouts.Device * 2 # max 2 per inverter + this_timeout += SolarEdgeTimeouts.Device * 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 From cdaa5ba08caaef3743db849e183498f4b5a3a5a2 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sun, 16 Jul 2023 14:41:20 -0700 Subject: [PATCH 12/13] Add init const to timeouts --- custom_components/solaredge_modbus_multi/const.py | 1 + custom_components/solaredge_modbus_multi/hub.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/solaredge_modbus_multi/const.py b/custom_components/solaredge_modbus_multi/const.py index 9ba719be..a1f62dab 100644 --- a/custom_components/solaredge_modbus_multi/const.py +++ b/custom_components/solaredge_modbus_multi/const.py @@ -45,6 +45,7 @@ class SolarEdgeTimeouts(IntEnum): Inverter = 8400 Device = 1200 + Init = 1200 class RetrySettings(IntEnum): diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index 2228d208..dfb5e6b1 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -521,7 +521,7 @@ def keep_modbus_open(self, value: bool) -> None: def coordinator_timeout(self) -> int: if not self.initalized: this_timeout = SolarEdgeTimeouts.Inverter * self.number_of_inverters - this_timeout += SolarEdgeTimeouts.Device * 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 From e19a563c43a96835d6cf8b5704a3d5085586f689 Mon Sep 17 00:00:00 2001 From: WillCodeForCats <48533968+WillCodeForCats@users.noreply.github.com> Date: Sun, 16 Jul 2023 15:46:13 -0700 Subject: [PATCH 13/13] Fix incorrect method --- custom_components/solaredge_modbus_multi/hub.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/solaredge_modbus_multi/hub.py b/custom_components/solaredge_modbus_multi/hub.py index dfb5e6b1..c15c13fd 100644 --- a/custom_components/solaredge_modbus_multi/hub.py +++ b/custom_components/solaredge_modbus_multi/hub.py @@ -498,11 +498,11 @@ def battery_energy_reset_cycles(self) -> int: @property def number_of_meters(self) -> int: - return self.meters.count() + return len(self.meters) @property def number_of_batteries(self) -> int: - return self.batteries.count() + return len(self.batteries) @property def number_of_inverters(self) -> int: