From 745b1e94de92311f45df18c9353358d37c49f666 Mon Sep 17 00:00:00 2001 From: dirwin31 <83434411+dirwin31@users.noreply.github.com> Date: Sun, 1 Nov 2026 13:26:31 -0800 Subject: [PATCH] Send the comma's Bluetooth address in the head unit pairing request LeaseAwarePhone (used for every wireless session) had no adapter() method, so Supervisor._adapter_address() hit AttributeError, swallowed it, and returned "". The Bluetooth-service pairing request was therefore never sent (bluetooth_opened always logged phone_address: ""). A 2020 myChevrolet (head unit 2.46.1.6) through an AAWireless Two+ then accepted and acknowledged video but never showed it. A real phone sends the pairing request about 1 s into the session; the car shows Android Auto once its hands-free link to that address is up. Pass adapter() through to the wrapped BluezPhone. It is a read-only property lookup, so it needs no phone-role lease, like devices() and device(). _adapter_address() now logs adapter_address_unavailable instead of failing silently. Tested on the car (session-000052): phone_address sent, pairing response received, picture displayed, touch input worked, 20-29 fps fully acked. Co-authored-by: droobah <34214975+droobah@users.noreply.github.com> --- openpilot/starpilot/system/starport/bluetooth_bridge.py | 1 + openpilot/starpilot/system/starport/supervisor.py | 4 +++- .../starpilot/system/starport/tests/test_bluetooth_bridge.py | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/openpilot/starpilot/system/starport/bluetooth_bridge.py b/openpilot/starpilot/system/starport/bluetooth_bridge.py index 4a8dc08883..7d09cb748b 100644 --- a/openpilot/starpilot/system/starport/bluetooth_bridge.py +++ b/openpilot/starpilot/system/starport/bluetooth_bridge.py @@ -830,6 +830,7 @@ class LeaseAwarePhone: def devices(self): return self.phone.devices() def device(self, address): return self.phone.device(address) def snapshot(self, address): return self.phone.snapshot(address) + def adapter(self): return self.phone.adapter() # this comma's address, for the head unit's pairing request def acquire(self, phone_class: bool = True) -> None: if self.lease is None: diff --git a/openpilot/starpilot/system/starport/supervisor.py b/openpilot/starpilot/system/starport/supervisor.py index e7673e2b69..8e69a8f5c4 100644 --- a/openpilot/starpilot/system/starport/supervisor.py +++ b/openpilot/starpilot/system/starport/supervisor.py @@ -1489,7 +1489,9 @@ class Supervisor: """This comma's Bluetooth address for the head unit's pairing request; empty when BlueZ is not up.""" try: return str(self._bluez.adapter()[1].get("Address", "")).upper() if self._bluez is not None else "" - except Exception: # DBus errors vary; the pairing request is optional + except Exception as error: # DBus errors vary; the pairing request is optional + # Never silent: a missing adapter() once left every wireless session without the request (no address, no picture). + self.log("adapter_address_unavailable", kind=type(error).__name__, error=str(error)[:120]) return "" def _project(self, result, lease, ident, connect=None, fragment_acks: bool = False) -> None: diff --git a/openpilot/starpilot/system/starport/tests/test_bluetooth_bridge.py b/openpilot/starpilot/system/starport/tests/test_bluetooth_bridge.py index 893f630b30..f65e913621 100644 --- a/openpilot/starpilot/system/starport/tests/test_bluetooth_bridge.py +++ b/openpilot/starpilot/system/starport/tests/test_bluetooth_bridge.py @@ -261,8 +261,12 @@ def test_donor_phone_uses_same_lease_and_does_not_take_over_independently(tmp_pa def devices(self): return [] + def adapter(self): + return '/org/bluez/hci0', {'Address': '39:90:21:64:07:00'} + phone = FakePhone() wrapper = LeaseAwarePhone(shared, state['session'], lambda *a, **k: None, lambda log: phone) + assert wrapper.adapter()[1]['Address'] == '39:90:21:64:07:00' # read before any lease, for the pairing request with pytest.raises(BluetoothAdmissionError, match='not active'): wrapper.register_hfp() wrapper.acquire_pairing()