diff --git a/openpilot/starpilot/galaxy/server.py b/openpilot/starpilot/galaxy/server.py index 3e8c951465..d705c60b3d 100644 --- a/openpilot/starpilot/galaxy/server.py +++ b/openpilot/starpilot/galaxy/server.py @@ -2015,9 +2015,10 @@ def make_server(*, port=8082, host='127.0.0.1', monitor=None, owner=None, crashe runtime = aa_client().call('status')['status'] if runtime.get('pairing_ready'): raise ValueError('Finish or cancel pairing first') - if command == 'start' and ((not runtime.get('receiver_address') and runtime.get('connection') != 'wired') or - not aa_setup_owner().identity_status().get('installed')): - raise ValueError('Select a car and verify your Android Auto package first') + if command == 'start' and not runtime.get('receiver_address') and runtime.get('connection') != 'wired': + raise ValueError('Select a car first') + if command == 'start' and not aa_setup_owner().identity_status().get('installed'): + raise ValueError('Verify your Android Auto package first') self.aa_command(identity, command, **arguments) current = aa_client().call('status')['status'] except ValueError as error: diff --git a/openpilot/starpilot/galaxy/test_android_auto_http.py b/openpilot/starpilot/galaxy/test_android_auto_http.py index c5bfc33870..a3b4b7997c 100644 --- a/openpilot/starpilot/galaxy/test_android_auto_http.py +++ b/openpilot/starpilot/galaxy/test_android_auto_http.py @@ -72,6 +72,7 @@ def api(tmp_path): self.receiver = '' self.running = False self.auto_connect = False + self.connection = 'wireless' self.available = True self.stop_error = False self.stop_completes = True @@ -80,13 +81,16 @@ def api(tmp_path): self.calls.append((command, dict(kwargs))) if command == 'status': return {'status': {'receiver_address': self.receiver, 'receiver_name': 'My car', 'state': 'streaming' if self.running else 'idle', - 'running': self.running, 'auto_connect': self.auto_connect, 'pairing_ready': False}} + 'running': self.running, 'auto_connect': self.auto_connect, 'pairing_ready': False, + 'connection': self.connection}} if command == 'devices': return {'devices': [{'address': 'AA:BB:CC:DD:EE:FF', 'name': 'Saved car', 'paired': True, 'android_auto': True}]} if command == 'select_receiver': self.receiver = kwargs['address'] if command == 'set_auto_connect': self.auto_connect = kwargs['enabled'] + if command == 'set_connection': + self.connection = kwargs['connection'] if command == 'start': self.running = True if command == 'stop': @@ -399,6 +403,29 @@ def test_existing_paired_car_controls_are_local_authenticated_and_source_bound(a cookie=cookie, content_type='application/json')[0] == 401 +def test_wired_connection_requires_park_but_not_a_paired_receiver(api): + request, _, state, client = api + code, _, headers = request('POST', '/api/auth/login', json.dumps({'password': 'password123'}), + content_type='application/json') + assert code == 200 + cookie = headers['Set-Cookie'].split(';', 1)[0] + payload = json.dumps({'action': 'connection', 'connection': 'wired'}) + state['parked'] = False + assert request('POST', '/api/android-auto/control', payload, cookie=cookie, content_type='application/json')[0] == 403 + state['parked'] = True + code, result, _ = request('POST', '/api/android-auto/control', payload, cookie=cookie, content_type='application/json') + assert code == 200 and result['status']['connection'] == 'wired' + assert request('POST', '/api/android-auto/control', json.dumps({'action': 'start'}), cookie=cookie, + content_type='application/json')[0] == 200 + assert client.running + + client.running = False + state['identity_installed'] = False + code, result, _ = request('POST', '/api/android-auto/control', json.dumps({'action': 'start'}), cookie=cookie, + content_type='application/json') + assert code == 409 and result['error'] == 'Verify your Android Auto package first' + + def test_local_enable_then_upload_bundle_preserves_binary_bytes(api): import io import zipfile diff --git a/openpilot/starpilot/galaxy/web/js/android-auto.js b/openpilot/starpilot/galaxy/web/js/android-auto.js index 7f8f7684e0..aa3d16466b 100644 --- a/openpilot/starpilot/galaxy/web/js/android-auto.js +++ b/openpilot/starpilot/galaxy/web/js/android-auto.js @@ -454,7 +454,17 @@ export const AndroidAutoPage = { }, supportReady() { return !!(this.setup?.enabled && this.setup.identity.installed) }, // Returning drivers see a status card; the setup steps fold away below it. - setupDone() { return !!(this.supportReady && this.selected && !this.pairing?.active) }, + wired() { return this.runtime?.connection === "wired" }, + connectionName() { return this.wired ? "car" : this.selected?.name || "car" }, + setupDone() { return !!(this.supportReady && (this.selected || this.wired) && !this.pairing?.active) }, + wiredRow() { + const detail = "Project over a USB cable from the car to the comma’s USB-C port instead of Bluetooth and Wi-Fi." + return switchRow("Wired USB Connection", this.wired, detail + (this.runtime?.wired_blocked ? ` ${this.runtime.wired_blocked}.` : "")) + }, + wiredDisabled() { + return !this.setup?.enabled || !this.setup.parked || !!this.pairing?.active || !!this.runtime?.running || + (!!this.runtime?.wired_blocked && !this.wired) + }, download() { return downloadLink(this.setup?.download, this.setup?.downloadPending === true) }, uploadPercent() { const { loaded, total } = this.uploadProgress || {} @@ -637,15 +647,15 @@ export const AndroidAutoPage = {

Android Auto

-

Show the StarPilot driving view on your car’s screen. Set up support, pair your car, then connect.

+

Show the StarPilot driving view on your car’s screen. Set up support, {{ wired ? 'plug in your car' : 'pair your car' }}, then connect.

- Android Auto uses the comma’s Wi-Fi to project to your car and disconnects it from your current Wi-Fi network. Use the Galaxy hotspot for local access during projection. Remote Galaxy access requires Internet on the comma. + Android Auto uses the comma’s Wi-Fi to project to your car and disconnects it from your current Wi-Fi network. Use the Galaxy hotspot for local access during projection. Remote Galaxy access requires Internet on the comma. {{ error }} {{ error || "Checking Android Auto setup… Reconnecting automatically…" }}
-

{{ projecting ? 'Connected to ' + selected.name : runtime?.running ? 'Connecting to ' + selected.name : selected.name }}

+

{{ projecting ? 'Connected to ' + connectionName : runtime?.running ? 'Connecting to ' + connectionName : connectionName }}

{{ runtime?.running && runtime.state !== 'streaming' && runtime.label ? runtime.label : runtime?.running ? 'Showing StarPilot on your car’s screen.' : runtime?.auto_connect ? 'Connects automatically when you start driving.' : 'Ready to connect.' }}

@@ -655,8 +665,7 @@ export const AndroidAutoPage = { -
Customize Layout @@ -785,13 +794,12 @@ export const AndroidAutoPage = { -

Car: {{ runtime.companion_name }}

Stuck connecting? Wi-Fi and screen troubleshooting
    -
  • How it connects: after Bluetooth, the car (or adapter) creates its own hidden 5 GHz Wi-Fi network and tells the comma how to join. The picture streams over that Wi-Fi.
  • +
  • How it connects: after Bluetooth, the car (or adapter) creates its own hidden 5 GHz Wi-Fi network and tells the comma how to join. The picture streams over that Wi-Fi.
  • First connection: stay in Park or offroad mode, and keep the car’s screen on.
  • Black or frozen screen: tap Disconnect, wait a few seconds, then connect again. If it keeps happening, turn the car off and on.
  • Car says the phone isn’t compatible: make sure wireless Android Auto (sometimes called “smartphone connection”) is turned on in the car’s settings, and that step 1 shows Ready.