Skip to content

Commit a4dd395

Browse files
authored
feat: improve recovery when adapter has gone silent and needs a USB reset (#222)
1 parent a7b19ef commit a4dd395

File tree

7 files changed

+24
-16
lines changed

7 files changed

+24
-16
lines changed

poetry.lock

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ bleak = ">=0.21.1"
3939
bleak-retry-connector = ">=3.9.0"
4040
bluetooth-data-tools = ">=1.28.0"
4141
bluetooth-adapters = ">=0.16.1"
42-
bluetooth-auto-recovery = ">=1.2.3"
42+
bluetooth-auto-recovery = ">=1.5.0"
4343
async-interrupt = ">=1.1.1"
4444
dbus-fast = { version = ">=2.30.2", markers = "platform_system == 'Linux'" }
4545

src/habluetooth/manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ async def _async_recover_failed_adapters(self) -> None:
301301
for adapter, details in adapters.items()
302302
if details[ADAPTER_ADDRESS] == FAILED_ADAPTER_MAC
303303
]:
304-
await async_reset_adapter(adapter, FAILED_ADAPTER_MAC)
304+
await async_reset_adapter(adapter, FAILED_ADAPTER_MAC, False)
305305
await self._async_refresh_adapters()
306306

307307
async def async_setup(self) -> None:

src/habluetooth/scanner.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ async def _async_start_attempt(self, attempt: int) -> bool:
357357
except asyncio.TimeoutError as ex:
358358
await self._async_stop_scanner()
359359
if attempt == 2:
360-
await self._async_reset_adapter()
360+
await self._async_reset_adapter(False)
361361
if attempt < START_ATTEMPTS:
362362
self._log_start_timeout(attempt)
363363
return False
@@ -373,7 +373,7 @@ async def _async_start_attempt(self, attempt: int) -> bool:
373373
# If discovery is stuck on, try to force stop it
374374
await self._async_force_stop_discovery()
375375
if attempt == 2 and _error_indicates_reset_needed(error_str):
376-
await self._async_reset_adapter()
376+
await self._async_reset_adapter(False)
377377
elif (
378378
attempt != START_ATTEMPTS
379379
and _error_indicates_wait_for_adapter_to_init(error_str)
@@ -537,7 +537,7 @@ async def _async_restart_scanner(self) -> None:
537537
self._start_time == self._last_detection
538538
or self.time_since_last_detection() > SCANNER_WATCHDOG_MULTIPLE
539539
):
540-
await self._async_reset_adapter()
540+
await self._async_reset_adapter(True)
541541
try:
542542
await self._async_start()
543543
except ScannerStartError as ex:
@@ -547,13 +547,13 @@ async def _async_restart_scanner(self) -> None:
547547
ex,
548548
)
549549

550-
async def _async_reset_adapter(self) -> None:
550+
async def _async_reset_adapter(self, gone_silent: bool) -> None:
551551
"""Reset the adapter."""
552552
# There is currently nothing the user can do to fix this
553553
# so we log at debug level. If we later come up with a repair
554554
# strategy, we will change this to raise a repair issue as well.
555555
_LOGGER.debug("%s: adapter stopped responding; executing reset", self.name)
556-
result = await async_reset_adapter(self.adapter, self.mac_address)
556+
result = await async_reset_adapter(self.adapter, self.mac_address, gone_silent)
557557
_LOGGER.debug("%s: adapter reset result: %s", self.name, result)
558558

559559
async def async_stop(self) -> None:

src/habluetooth/util.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
from bluetooth_auto_recovery import recover_adapter
77

88

9-
async def async_reset_adapter(adapter: str | None, mac_address: str) -> bool | None:
9+
async def async_reset_adapter(
10+
adapter: str | None, mac_address: str, gone_silent: bool
11+
) -> bool | None:
1012
"""Reset the adapter."""
1113
if adapter and adapter.startswith("hci"):
1214
adapter_id = int(adapter[3:])
13-
return await recover_adapter(adapter_id, mac_address)
15+
return await recover_adapter(adapter_id, mac_address, gone_silent)
1416
return False
1517

1618

tests/test_manager.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ def adapters(self) -> dict[str, Any]:
143143

144144
assert mock_async_reset_adapter.call_count == 2
145145
assert mock_async_reset_adapter.call_args_list == [
146-
(("hci1", "00:00:00:00:00:00"),),
147-
(("hci2", "00:00:00:00:00:00"),),
146+
(("hci1", "00:00:00:00:00:00", False),),
147+
(("hci2", "00:00:00:00:00:00", False),),
148148
]
149149

150150

tests/test_scanner.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,12 @@ def register_detection_callback(
451451
await asyncio.sleep(0)
452452

453453
assert len(mock_recover_adapter.mock_calls) == 1
454+
assert mock_recover_adapter.call_args_list[0][0] == (
455+
0,
456+
"AA:BB:CC:DD:EE:FF",
457+
True,
458+
)
459+
454460
assert called_start == 2
455461
await scanner.async_stop()
456462

0 commit comments

Comments
 (0)