129129COMM_BLOCK_FAILURE_WINDOW = 600
130130COMM_RECOVERY_INTERVAL = 300
131131INFLIGHT_CANCEL_TIMEOUT = 2.0
132- CONNECT_RETRY_DELAY = 1.0
133132
134133
135134try :
@@ -530,8 +529,6 @@ def __init__(
530529 # Fallback dummy client for unrecognized interface types
531530 self ._client = SimpleNamespace (connected = False , comm_params = SimpleNamespace (host = "" , port = "" ))
532531 self ._lock = asyncio .Lock ()
533- self ._connect_lock = asyncio .Lock ()
534- self ._next_connect_attempt = 0.0
535532 self ._name : str = name
536533 # following call will modify and extend client in case old modbus API needs to be used
537534 _LOGGER .debug (f"{ name } : using pymodbus version { pymodbus_version_info ()} " )
@@ -1228,31 +1225,11 @@ def _is_expected_shutdown_modbus_error(self, ex: BaseException) -> bool:
12281225 async def _check_connection (self ) -> bool :
12291226 if getattr (self , "_stopping" , False ):
12301227 return False
1231- if self ._client .connected :
1232- return True
1233- now = _mtime .monotonic ()
1234- if now < self ._next_connect_attempt :
1235- return False
1236- async with self ._connect_lock :
1237- if getattr (self , "_stopping" , False ):
1238- return False
1239- if self ._client .connected :
1240- return True
1241- now = _mtime .monotonic ()
1242- if now < self ._next_connect_attempt :
1243- return False
1228+ if not self ._client .connected :
12441229 _LOGGER .debug (f"{ self ._name } : Inverter is not connected, trying to connect" )
1245- try :
1246- await self .async_connect ()
1247- except Exception as ex :
1248- self ._next_connect_attempt = _mtime .monotonic () + CONNECT_RETRY_DELAY
1249- _LOGGER .debug (f"{ self ._name } : connect attempt failed: { ex } " )
1250- return False
1251- if not self ._client .connected :
1252- self ._next_connect_attempt = _mtime .monotonic () + CONNECT_RETRY_DELAY
1253- return False
1254- self ._next_connect_attempt = 0.0
1255- return True
1230+ await self .async_connect ()
1231+ await asyncio .sleep (1 )
1232+ return self ._client .connected
12561233
12571234 async def is_online (self ) -> bool :
12581235 return self ._client .connected and (self .slowdown == 1 )
@@ -1270,11 +1247,10 @@ async def async_connect(self) -> None:
12701247
12711248 async def async_read_holding_registers (self , unit : int , address : int , count : int ) -> Any :
12721249 """Read holding registers using high-level pymodbus API."""
1273- if not await self ._check_connection ():
1274- return None
12751250 async with self ._lock :
12761251 if getattr (self , "_stopping" , False ):
12771252 return None
1253+ await self ._check_connection ()
12781254 if not self ._client .connected :
12791255 return None
12801256 try :
@@ -1293,17 +1269,15 @@ async def async_read_holding_registers(self, unit: int, address: int, count: int
12931269 return None
12941270 _LOGGER .debug (f"{ self ._name } : ModbusException – closing transport and deferring reconnect" )
12951271 self ._client .close ()
1296- self ._next_connect_attempt = _mtime .monotonic () + CONNECT_RETRY_DELAY
12971272 return None
12981273 return resp
12991274
13001275 async def async_read_input_registers (self , unit : int , address : int , count : int ) -> Any :
13011276 """Read input registers using high-level pymodbus API."""
1302- if not await self ._check_connection ():
1303- return None
13041277 async with self ._lock :
13051278 if getattr (self , "_stopping" , False ):
13061279 return None
1280+ await self ._check_connection ()
13071281 if not self ._client .connected :
13081282 return None
13091283 try :
@@ -1322,7 +1296,6 @@ async def async_read_input_registers(self, unit: int, address: int, count: int)
13221296 return None
13231297 _LOGGER .debug (f"{ self ._name } : ModbusException – closing transport and deferring reconnect" )
13241298 self ._client .close ()
1325- self ._next_connect_attempt = _mtime .monotonic () + CONNECT_RETRY_DELAY
13261299 return None
13271300 return resp
13281301
@@ -1332,11 +1305,8 @@ async def async_lowlevel_write_register(self, unit: int, address: int, payload:
13321305 regs = convert_to_registers (int (payload ), DataType .UINT16 , self .plugin .order32 ) # type: ignore[attr-defined]
13331306 else :
13341307 regs = convert_to_registers (int (payload ), DataType .INT16 , self .plugin .order32 ) # type: ignore[attr-defined]
1335- if not await self ._check_connection ():
1336- return None
13371308 async with self ._lock :
1338- if not self ._client .connected :
1339- return None
1309+ await self ._check_connection ()
13401310 try :
13411311 resp = await self ._track_task (self ._client .write_register (address = address , value = regs [0 ], ** kwargs )) # type: ignore[arg-type]
13421312 # Plugin-level logging hook
@@ -1381,11 +1351,8 @@ async def async_write_registers_single(
13811351 else :
13821352 regs = convert_to_registers (int (payload ), DataType .INT16 , self .plugin .order32 ) # type: ignore[attr-defined]
13831353 kwargs = {ADDR_KW : unit } if unit is not None else {}
1384- if not await self ._check_connection ():
1385- return None
13861354 async with self ._lock :
1387- if not self ._client .connected :
1388- return None
1355+ await self ._check_connection ()
13891356 try :
13901357 resp = await self ._track_task (self ._client .write_registers (address = address , values = regs , ** kwargs )) # type: ignore[arg-type]
13911358 except (ConnectionException , ModbusIOException ) as e :
@@ -2346,53 +2313,67 @@ def _hub_closed_now(self, ref_obj: Any) -> None:
23462313 self ._hub = None
23472314
23482315 async def async_connect (self , hub : Any = None ) -> Any :
2349- if getattr (self , "_stopping" , False ):
2350- return None
2351- now = _mtime .monotonic ()
2352- if now < self ._next_connect_attempt :
2353- return None
2354- async with self ._connect_lock :
2355- if getattr (self , "_stopping" , False ):
2356- return None
2357- now = _mtime .monotonic ()
2358- if now < self ._next_connect_attempt :
2359- return None
2360- if hub is None and self ._hub is not None :
2361- hub = self ._hub ()
2362- if hub is None :
2316+ delay = True
2317+ while True :
2318+ # check if strong reference to
2319+ # get one.
2320+ if hub is not None or (self ._hub is not None and (hub := self ._hub ()) is not None ):
2321+ port = hub ._pb_params .get ("port" , 0 )
2322+ host = hub ._pb_params .get ("host" , port )
2323+ # TODO just wait some time and recheck again if client connected before
2324+ # giving up
2325+ await hub ._lock .acquire ()
2326+ try :
2327+ if hub ._client and hub ._client .connected :
2328+ hub ._lock .release ()
2329+ _LOGGER .debug (
2330+ "Inverter connected at %s:%s" ,
2331+ host ,
2332+ port ,
2333+ )
2334+ return hub
2335+ except (TypeError , AttributeError ):
2336+ pass
2337+ hub ._lock .release ()
2338+ if not delay :
2339+ reason = " core modbus hub '{self._core_hub}' not ready" if hub ._config_delay else ""
2340+ _LOGGER .warning (f"Unable to connect to Inverter at { host } :{ port } .{ reason } " )
2341+ return None
2342+ else :
2343+ # get hold of current CoreModbusHub object with
2344+ # provided entity name
23632345 try :
23642346 hub = get_core_hub (self ._hass , self ._core_hub )
23652347 except KeyError :
2366- _LOGGER .warning (f"CoreModbusHub '{ self ._core_hub } ' not available" )
2367- self ._next_connect_attempt = _mtime .monotonic () + CONNECT_RETRY_DELAY
2348+ _LOGGER .warning (
2349+ f"CoreModbusHub '{ self ._core_hub } ' not available" ,
2350+ )
23682351 return None
2369- if not hub :
2370- _LOGGER .warning ("Unable to join core modbus %s" , self ._core_hub )
2371- self ._next_connect_attempt = _mtime .monotonic () + CONNECT_RETRY_DELAY
2352+ else :
2353+ if hub :
2354+ # update weak reference handle to refer to
2355+ # the actual CoreModbusHub object
2356+ self ._hub = WeakRef (hub , self ._hub_closed_now )
2357+ continue
2358+ if not delay :
2359+ _LOGGER .warning (
2360+ "Unable to join core modbus %s" ,
2361+ self ._core_hub ,
2362+ )
23722363 return None
2373- self ._hub = WeakRef (hub , self ._hub_closed_now )
2374-
2375- port = hub ._pb_params .get ("port" , 0 )
2376- host = hub ._pb_params .get ("host" , port )
2377- try :
2378- async with hub ._lock :
2379- if hub ._client and hub ._client .connected :
2380- _LOGGER .debug ("Inverter connected at %s:%s" , host , port )
2381- self ._next_connect_attempt = 0.0
2382- return hub
2383- except (TypeError , AttributeError ):
2384- pass
2385- reason = f" core modbus hub '{ self ._core_hub } ' not ready" if getattr (hub , "_config_delay" , False ) else ""
2386- _LOGGER .debug (f"Unable to connect to Inverter at { host } :{ port } .{ reason } " )
2387- self ._next_connect_attempt = _mtime .monotonic () + CONNECT_RETRY_DELAY
2388- return None
2364+ # wait some time (TODO make configurable) before
2365+ # rechecking if CoreModbusHub object has been created and
2366+ # connected
2367+ delay = False
2368+ await asyncio .sleep (10 )
23892369
23902370 async def async_read_holding_registers (self , unit : int , address : int , count : int ) -> Any :
23912371 """Read holding registers."""
23922372 kwargs = {ADDR_KW : unit } if unit is not None else {}
23932373 if getattr (self , "_stopping" , False ):
23942374 return None
2395- hub = await self ._check_connection ()
2375+ async with self ._lock :
2376+ hub = await self ._check_connection ()
23962377 try :
23972378 if not hub or getattr (hub , "_config_delay" , False ):
23982379 return None
@@ -2414,7 +2395,8 @@ async def async_read_input_registers(self, unit: int, address: int, count: int)
24142395 kwargs = {ADDR_KW : unit } if unit is not None else {}
24152396 if getattr (self , "_stopping" , False ):
24162397 return None
2417- hub = await self ._check_connection ()
2398+ async with self ._lock :
2399+ hub = await self ._check_connection ()
24182400 try :
24192401 if not hub or getattr (hub , "_config_delay" , False ):
24202402 return None
@@ -2442,7 +2424,8 @@ async def async_lowlevel_write_register(self, unit: int, address: int, payload:
24422424 kwargs = {ADDR_KW : unit } if unit is not None else {}
24432425 if getattr (self , "_stopping" , False ):
24442426 return None
2445- hub = await self ._check_connection ()
2427+ async with self ._lock :
2428+ hub = await self ._check_connection ()
24462429 try :
24472430 if not hub or getattr (hub , "_config_delay" , False ):
24482431 return None
@@ -2471,13 +2454,14 @@ async def async_write_registers_single(
24712454 else :
24722455 regs = convert_to_registers (int (payload ), DataType .INT16 , self .plugin .order32 ) # type: ignore[attr-defined]
24732456 kwargs : dict [str , int ] = {ADDR_KW : unit } if unit is not None else {}
2474- hub = await self ._check_connection ()
2457+ async with self ._lock :
2458+ hub = await self ._check_connection ()
24752459 try :
2476- if not hub or hub ._config_delay :
2460+ if hub ._config_delay :
24772461 return None
24782462 async with hub ._lock :
24792463 try :
2480- resp = await self ._track_task ( hub . _client .write_registers (address = address , values = regs , ** kwargs ))
2464+ resp = await self ._client .write_registers (address = address , values = regs , ** kwargs ) # type: ignore[arg-type]
24812465 except (ConnectionException , ModbusIOException ) as e :
24822466 original_message = str (e )
24832467 raise HomeAssistantError (f"Error writing single Modbus registers: { original_message } " ) from e
@@ -2536,13 +2520,14 @@ async def async_write_registers_multi(self, unit: int, address: int, payload: li
25362520 _LOGGER .error (f"unsupported unit type: { typ } for { key } " )
25372521 # for easier debugging, make next line a _LOGGER.info line
25382522 _LOGGER .debug (f"Ready to write multiple registers at 0x{ address :02x} : { regs_out } " )
2539- hub = await self ._check_connection ()
2523+ async with self ._lock :
2524+ hub = await self ._check_connection ()
25402525 try :
2541- if not hub or hub ._config_delay :
2526+ if hub ._config_delay :
25422527 return None
25432528 async with hub ._lock :
25442529 try :
2545- resp = await self ._track_task ( hub . _client .write_registers (address = address , values = regs_out , ** kwargs ))
2530+ resp = await self ._client .write_registers (address = address , values = regs_out , ** kwargs ) # type: ignore[arg-type]
25462531 except (ConnectionException , ModbusIOException ) as e :
25472532 original_message = str (e )
25482533 raise HomeAssistantError (f"Error writing multiple Modbus registers: { original_message } " ) from e
0 commit comments