Skip to content

Commit 7c8d603

Browse files
authored
Merge pull request #2096 from rosenrot00/codex/handle-modbus-shutdown
Handle in-flight Modbus reads during Home Assistant shutdown
2 parents df591de + 228a120 commit 7c8d603

1 file changed

Lines changed: 37 additions & 1 deletion

File tree

custom_components/solax_modbus/__init__.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
CONF_NAME,
2222
CONF_PORT,
2323
EVENT_HOMEASSISTANT_STARTED,
24+
EVENT_HOMEASSISTANT_STOP,
2425
PERCENTAGE,
2526
Platform,
2627
UnitOfElectricCurrent,
@@ -257,6 +258,22 @@ async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
257258
else:
258259
hass.data[DOMAIN]["_debug_settings"] = {}
259260

261+
async def _stop_hubs_on_homeassistant_stop(event: Any) -> None:
262+
"""Stop active hubs before HA reaches final task cancellation."""
263+
domain_data = hass.data.get(DOMAIN, {})
264+
for name, rec in list(domain_data.items()):
265+
if not isinstance(rec, dict):
266+
continue
267+
hub = rec.get("hub")
268+
if hub:
269+
_LOGGER.debug(f"{name}: Home Assistant stop event - stopping hub")
270+
try:
271+
await hub.async_stop()
272+
except Exception as ex:
273+
_LOGGER.warning(f"{name}: error during Home Assistant stop: {ex}")
274+
275+
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _stop_hubs_on_homeassistant_stop)
276+
260277
# Register helper services to force-stop hubs
261278
async def _svc_stop_all(call: Any) -> None:
262279
"""Force-stop all SolaX hubs (kills timers/tasks/sockets)."""
@@ -1206,9 +1223,28 @@ def _track_task(self, coro: Any) -> asyncio.Task[Any]:
12061223
"""Wrap coroutines in a Task we can cancel during stop."""
12071224
task = asyncio.create_task(coro)
12081225
self._inflight_tasks.add(task)
1209-
task.add_done_callback(lambda t: self._inflight_tasks.discard(t))
1226+
task.add_done_callback(self._handle_tracked_task_done)
12101227
return task
12111228

1229+
def _handle_tracked_task_done(self, task: asyncio.Task[Any]) -> None:
1230+
"""Collect finished in-flight task results during shutdown."""
1231+
self._inflight_tasks.discard(task)
1232+
if not getattr(self, "_stopping", False):
1233+
return
1234+
try:
1235+
exc = task.exception()
1236+
except asyncio.CancelledError:
1237+
return
1238+
except Exception as ex:
1239+
_LOGGER.debug(f"{self._name}: failed to collect in-flight Modbus task result during shutdown: {ex}")
1240+
return
1241+
if exc is None:
1242+
return
1243+
if self._is_expected_shutdown_modbus_error(exc):
1244+
_LOGGER.debug(f"{self._name}: collected expected Modbus task cancellation during shutdown: {exc}")
1245+
return
1246+
_LOGGER.debug(f"{self._name}: in-flight Modbus task ended during shutdown: {exc}")
1247+
12121248
def _is_expected_shutdown_modbus_error(self, ex: BaseException) -> bool:
12131249
"""Return True for pymodbus cancellation errors caused by HA shutdown."""
12141250
if not getattr(self, "_stopping", False):

0 commit comments

Comments
 (0)