Skip to content

Commit

Permalink
Improve Linux Bluez Pairing Robustness (#382)
Browse files Browse the repository at this point in the history
* Handle more bluetoothctl use cases
* Check for pairing differently on newer bluez versions
  • Loading branch information
tcamise-gpsw committed Aug 15, 2023
1 parent 5baddd0 commit 4579dc7
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from typing import Pattern, Any, Callable, Optional

import pexpect
from packaging.version import Version
from bleak import BleakScanner, BleakClient
from bleak.backends.device import BLEDevice as BleakDevice
from bleak.backends.characteristic import BleakGATTCharacteristic
Expand Down Expand Up @@ -302,24 +303,36 @@ def pair(self, handle: BleakClient) -> None:
async def _async_def_pair() -> None:
logger.debug("Attempting to pair...")
if (OS := platform.system()) == "Linux":
logger.info("Pairing with bluetoothctl")
# Manually control bluetoothctl on Linux
bluetoothctl = pexpect.spawn("bluetoothctl")
if logger.level == logging.DEBUG:
bluetoothctl.logfile = sys.stdout.buffer
bluetoothctl.expect("Agent registered")
# Get the version
bluetoothctl.sendline("version")
bluetoothctl.expect(r"Version")
bluetoothctl.expect(r"\n")
version = Version(bluetoothctl.before.decode("utf-8").strip())
# First see if we are already paired
bluetoothctl.sendline("paired-devices")
bluetoothctl.expect("paired-devices")
if version >= Version("5.66"):
bluetoothctl.sendline("devices Paired")
bluetoothctl.expect("devices Paired")
else:
bluetoothctl.sendline("paired-devices")
bluetoothctl.expect("paired-devices")
bluetoothctl.expect(r"#")
for device in bluetoothctl.before.decode("utf-8").splitlines():
if "Device" in device and device.split()[1] == handle.address:
break # The device is already paired
else:
# We're not paired so do it now
bluetoothctl.sendline(f"pair {handle.address}")
bluetoothctl.expect("Accept pairing")
bluetoothctl.sendline("yes")
bluetoothctl.expect("Pairing successful")
if (match := bluetoothctl.expect(["Accept pairing", "Pairing successful"])) == 0:
bluetoothctl.sendline("yes")
bluetoothctl.expect("Pairing successful")
elif match == 1: # We received pairing successful so nothing else to do
pass

elif OS == "Darwin":
# No pairing on Mac
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def __init__(
"open_gopro.api.http_commands": logging.DEBUG,
"open_gopro.api.ble_commands": logging.DEBUG,
"open_gopro.communication_client": logging.DEBUG,
"open_gopro.ble.adapters.bleak_wrapper": logging.INFO,
"open_gopro.ble.adapters.bleak_wrapper": logging.INFO, # DEBUG for pexpect communication
"open_gopro.ble.client": logging.DEBUG,
"open_gopro.wifi.adapters.wireless": logging.DEBUG,
"open_gopro.responses": logging.DEBUG,
Expand Down

0 comments on commit 4579dc7

Please sign in to comment.