Skip to content

Commit

Permalink
feat: improve error reporting when there is a poor connection (#10)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdraco authored Aug 5, 2022
1 parent 4871110 commit d022777
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/bleak_retry_connector/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,15 @@
# These errors are transient with dbus, and we should retry
TRANSIENT_ERRORS = {"le-connection-abort-by-local", "br-connection-canceled"}

# Currently the same as transient error
ABORT_ERRORS = TRANSIENT_ERRORS

ABORT_ADVICE = (
"Interference/range; "
"External Bluetooth adapter w/extension may help; "
"Extension cables reduce USB 3 port interference"
)


class BleakNotFoundError(BleakError):
"""The device was not found."""
Expand All @@ -46,6 +55,10 @@ class BleakConnectionError(BleakError):
"""The device was not found."""


class BleakAbortedError(BleakError):
"""The connection was aborted."""


async def establish_connection(
client_class: type[BleakClient],
device: BLEDevice,
Expand Down Expand Up @@ -75,6 +88,10 @@ def _raise_if_needed(name: str, exc: Exception) -> None:
# Sure would be nice if bleak gave us typed exceptions
if isinstance(exc, asyncio.TimeoutError) or "not found" in str(exc):
raise BleakNotFoundError(msg) from exc
if isinstance(exc, BleakError) and any(
error in str(exc) for error in ABORT_ERRORS
):
raise BleakAbortedError(f"{msg}: {ABORT_ADVICE}") from exc
raise BleakConnectionError(msg) from exc

while True:
Expand Down
29 changes: 29 additions & 0 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import bleak_retry_connector
from bleak_retry_connector import (
MAX_TRANSIENT_ERRORS,
BleakAbortedError,
BleakConnectionError,
BleakNotFoundError,
establish_connection,
Expand Down Expand Up @@ -112,6 +113,34 @@ async def disconnect(self, *args, **kwargs):
assert attempts == 9


@pytest.mark.asyncio
async def test_establish_connection_has_transient_error_had_advice():
class FakeBleakClient(BleakClient):
def __init__(self, *args, **kwargs):
pass

async def connect(self, *args, **kwargs):
raise BleakError("le-connection-abort-by-local")

async def disconnect(self, *args, **kwargs):
pass

try:
await establish_connection(FakeBleakClient, MagicMock(), "test")
except BleakError as e:
exc = e

assert isinstance(exc, BleakAbortedError)
assert str(exc) == (
"test: "
"Failed to connect: "
"le-connection-abort-by-local: "
"Interference/range; "
"External Bluetooth adapter w/extension may help; "
"Extension cables reduce USB 3 port interference"
)


@pytest.mark.asyncio
async def test_establish_connection_has_one_unknown_error():

Expand Down

0 comments on commit d022777

Please sign in to comment.