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()