mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-09-10 18:23:44 +08:00
hi
This commit is contained in:
@@ -48,7 +48,7 @@ rerun with `--allow-runtime-changes` only after Firestar approves it.
|
||||
|
||||
The default resources checkout is `~/StarPilot-Resources` on branch `Models`.
|
||||
It must be clean and synchronized before starting. The default Hugging Face
|
||||
bucket is `firestar4430/StarPilot-Resources`; authenticate with `hf auth login`
|
||||
bucket is `StarPilot-Driving/StarPilot-Resources`; authenticate with `hf auth login`
|
||||
before use. Use `--dry-run` to test parsing and the runtime scan without
|
||||
touching the device or either resource store.
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ from pathlib import Path
|
||||
|
||||
OPENPILOT_REPO = "commaai/openpilot"
|
||||
RESOURCES_REPO = os.environ.get("STARPILOT_RESOURCES_REPO", "firestar5683/StarPilot-Resources")
|
||||
HF_BUCKET = os.environ.get("STARPILOT_HF_BUCKET", "firestar4430/StarPilot-Resources")
|
||||
HF_BUCKET = os.environ.get("STARPILOT_HF_BUCKET", "StarPilot-Driving/StarPilot-Resources")
|
||||
RESOURCE_BRANCH = "Models"
|
||||
MANIFEST_VERSION = "v24"
|
||||
DEFAULT_BEHAVIOR_VERSION = "v16"
|
||||
|
||||
@@ -7,7 +7,7 @@ from datetime import datetime, timezone
|
||||
from openpilot.starpilot.common.starpilot_utilities import delete_file, is_url_pingable
|
||||
from openpilot.starpilot.common.starpilot_variables import RESOURCES_REPO
|
||||
|
||||
HF_BUCKET = os.getenv("STARPILOT_HF_BUCKET", "firestar4430/StarPilot-Resources")
|
||||
HF_BUCKET = os.getenv("STARPILOT_HF_BUCKET", "StarPilot-Driving/StarPilot-Resources")
|
||||
HF_BUCKET_URL = f"https://huggingface.co/buckets/{HF_BUCKET}/resolve"
|
||||
GITHUB_URL = f"https://raw.githubusercontent.com/{RESOURCES_REPO}"
|
||||
|
||||
|
||||
@@ -99,7 +99,8 @@ class BluetoothController:
|
||||
prompt["name"] = device["name"] if device else self._pairing_address
|
||||
except Exception as error:
|
||||
result["error"] = str(error)
|
||||
self._reset_client()
|
||||
if not self._pairing_address:
|
||||
self._reset_client()
|
||||
return result
|
||||
|
||||
def _require_offroad(self, command: str) -> None:
|
||||
@@ -166,7 +167,6 @@ class BluetoothController:
|
||||
finally:
|
||||
self._reset_client()
|
||||
self._radio.stop()
|
||||
self.params.remove("BluetoothAudioAddress")
|
||||
self.params.put_bool("BluetoothEnabled", False)
|
||||
self._scan_deadline = 0.0
|
||||
elif command == "start_scan":
|
||||
|
||||
@@ -17,7 +17,7 @@ A2DP_SINK_UUID = "0000110b-0000-1000-8000-00805f9b34fb"
|
||||
HID_UUID = "00001124-0000-1000-8000-00805f9b34fb"
|
||||
HOG_UUID = "00001812-0000-1000-8000-00805f9b34fb"
|
||||
COMMAND_TIMEOUTS = {
|
||||
"set_power": 55.0,
|
||||
"set_power": 90.0,
|
||||
"start_scan": 20.0,
|
||||
"stop_scan": 20.0,
|
||||
"connect": 35.0,
|
||||
@@ -151,7 +151,6 @@ class _DesktopFakeBluetooth:
|
||||
self._enabled = bool(payload.get("enabled", False))
|
||||
self._discovering = False
|
||||
if not self._enabled:
|
||||
self._selected_audio = ""
|
||||
self._devices = tuple(replace(device, connected=False) for device in self._devices)
|
||||
elif command == "start_scan":
|
||||
self._require_enabled()
|
||||
@@ -265,7 +264,7 @@ class BluetoothClient:
|
||||
bootstrap = enabled and not os.path.exists(self.socket_path)
|
||||
if bootstrap:
|
||||
params.put_bool("BluetoothEnabled", True)
|
||||
deadline = time.monotonic() + max(self.timeout, 10.0)
|
||||
deadline = time.monotonic() + max(self.timeout, 45.0)
|
||||
while not os.path.exists(self.socket_path):
|
||||
if time.monotonic() >= deadline:
|
||||
params.put_bool("BluetoothEnabled", False)
|
||||
|
||||
@@ -201,10 +201,12 @@ def test_desktop_fake_bluetooth_is_stateful_and_interactive(monkeypatch, tmp_pat
|
||||
client.set_power(False)
|
||||
disabled = client.status()
|
||||
assert not disabled.enabled and not disabled.powered and not disabled.discovering
|
||||
assert disabled.selected_audio == speaker.address
|
||||
with pytest.raises(RuntimeError, match="Enable Bluetooth"):
|
||||
client.start_scan()
|
||||
client.set_power(True)
|
||||
assert client.status().enabled
|
||||
enabled = client.status()
|
||||
assert enabled.enabled and enabled.selected_audio == speaker.address
|
||||
|
||||
|
||||
def test_desktop_fake_bluetooth_cannot_activate_on_device(monkeypatch, tmp_path):
|
||||
@@ -265,6 +267,16 @@ def test_power_pair_audio_and_offroad_enforcement():
|
||||
assert not params.get_bool("BluetoothEnabled") and radio.stops == 1 and clients[0].closed
|
||||
|
||||
|
||||
def test_power_off_preserves_saved_audio_selection():
|
||||
params = FakeParams(IsOffroad=True, BluetoothEnabled=False, BluetoothAudioAddress="00:11:22:33:44:55")
|
||||
controller = BluetoothController(params, FakeBlueZ, FakeRadio())
|
||||
|
||||
controller.handle({"command": "set_power", "enabled": True})
|
||||
controller.handle({"command": "set_power", "enabled": False})
|
||||
|
||||
assert params.get("BluetoothAudioAddress") == "00:11:22:33:44:55"
|
||||
|
||||
|
||||
def test_status_does_not_restart_radio_during_disable():
|
||||
params = FakeParams(IsOffroad=True, BluetoothEnabled=True)
|
||||
radio = BlockingStopRadio()
|
||||
|
||||
@@ -2,7 +2,7 @@ import { html, reactive } from "/assets/vendor/arrow-core.js"
|
||||
import { createBrowserHistory, createRouter } from "/assets/vendor/remix-router-1.3.1.js"
|
||||
import { hideSidebar } from "/assets/js/utils.js"
|
||||
import { DeviceSettings } from "/assets/components/tools/device_settings.js?v=favorite-c4-hint-1"
|
||||
import { Bluetooth } from "/assets/components/tools/bluetooth.js?v=bluetooth-5"
|
||||
import { Bluetooth } from "/assets/components/tools/bluetooth.js?v=bluetooth-6"
|
||||
import { WheelControls } from "/assets/components/tools/wheel_controls.js?v=controllers-2"
|
||||
import { ErrorLogs } from "/assets/components/tools/error_logs.js"
|
||||
import { VehicleFeatures } from "/assets/components/tools/vehicle_features.js"
|
||||
|
||||
@@ -4,6 +4,7 @@ import { galaxyPath } from "/assets/js/utils.js"
|
||||
const state = reactive({
|
||||
loading: true,
|
||||
busy: "",
|
||||
powerTarget: null,
|
||||
available: false,
|
||||
enabled: false,
|
||||
powered: false,
|
||||
@@ -38,7 +39,8 @@ function pollDelay() {
|
||||
function schedulePoll(delay = pollDelay()) {
|
||||
if (pollTimer !== null) clearTimeout(pollTimer)
|
||||
pollTimer = setTimeout(async () => {
|
||||
if (bluetoothPageActive()) await refresh()
|
||||
pollTimer = null
|
||||
if (bluetoothPageActive() && state.busy !== "power") await refresh()
|
||||
schedulePoll()
|
||||
}, delay)
|
||||
}
|
||||
@@ -69,6 +71,7 @@ function startAudioTestCountdown(address, delayMs, requestStartedAt) {
|
||||
async function request(operation, body = {}) {
|
||||
const requestStartedAt = performance.now()
|
||||
state.busy = operation
|
||||
if (operation === "power") state.powerTarget = !!body.enabled
|
||||
schedulePoll(250)
|
||||
try {
|
||||
const response = await fetch(galaxyPath(`/api/bluetooth/${operation}`), {
|
||||
@@ -88,6 +91,7 @@ async function request(operation, body = {}) {
|
||||
state.error = error?.message || "Bluetooth operation failed"
|
||||
} finally {
|
||||
state.busy = ""
|
||||
if (operation === "power") state.powerTarget = null
|
||||
schedulePoll(250)
|
||||
}
|
||||
}
|
||||
@@ -155,7 +159,8 @@ async function refresh() {
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
if (!initialized) initialized = true
|
||||
if (initialized) return
|
||||
initialized = true
|
||||
schedulePoll(0)
|
||||
}
|
||||
|
||||
@@ -203,7 +208,7 @@ function deviceActions(device) {
|
||||
const pairing = () => isPairing(device)
|
||||
return html`
|
||||
<div class="bluetoothActions">
|
||||
${!device.paired ? html`
|
||||
${!device.paired && !device.connected ? html`
|
||||
<button disabled="${() => !state.offroad || !!state.busy || pairing()}" @click="${() => request("pair", { address: device.address })}">
|
||||
${() => pairing() ? "Pairing…" : "Pair"}
|
||||
</button>
|
||||
@@ -222,10 +227,10 @@ function deviceActions(device) {
|
||||
</button>
|
||||
` : ""}
|
||||
` : ""}
|
||||
<button class="bluetoothIconButton bluetoothForgetButton" title="Forget device" aria-label="Forget ${device.name}"
|
||||
${device.paired ? html`<button class="bluetoothIconButton bluetoothForgetButton" title="Forget device" aria-label="Forget ${device.name}"
|
||||
disabled="${() => !state.offroad || !!state.busy}" @click="${() => {
|
||||
if (window.confirm(`Forget ${device.name}?`)) request("forget", { address: device.address })
|
||||
}}"><i class="bi bi-trash3" aria-hidden="true"></i></button>
|
||||
}}"><i class="bi bi-trash3" aria-hidden="true"></i></button>` : ""}
|
||||
`}
|
||||
</div>
|
||||
`
|
||||
@@ -279,7 +284,9 @@ export function Bluetooth() {
|
||||
<label class="bluetoothSwitch">
|
||||
<input type="checkbox" checked="${() => state.enabled}" disabled="${() => !state.available || !state.offroad || !!state.busy}"
|
||||
@change="${(event) => request("power", { enabled: event.target.checked })}" />
|
||||
<span>${() => state.enabled ? "On" : "Off"}</span>
|
||||
<span>${() => state.busy === "power"
|
||||
? `Turning Bluetooth ${state.powerTarget ? "on" : "off"}…`
|
||||
: state.enabled ? "On" : "Off"}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -42,6 +42,9 @@ def test_bluetooth_actions_use_reactive_disabled_bindings():
|
||||
assert "bluetoothForgetButton" in source
|
||||
assert "bi-trash3" in source
|
||||
assert "state.pairingAddress" in source
|
||||
assert "state.busy !== \"power\"" in source
|
||||
assert "Turning Bluetooth" in source
|
||||
assert "!device.paired && !device.connected" in source
|
||||
assert 'galaxyPath("/bluetooth")' in source
|
||||
assert 'window.location.pathname === "/bluetooth"' not in source
|
||||
assert "schedulePoll(250)" in source
|
||||
|
||||
@@ -4969,7 +4969,7 @@ def setup(app):
|
||||
@app.route("/api/bluetooth/status", methods=["GET"])
|
||||
def bluetooth_status():
|
||||
try:
|
||||
status = BluetoothClient(timeout=3.0).status()
|
||||
status = BluetoothClient(timeout=10.0).status()
|
||||
return jsonify(BluetoothClient.serialize_status(status)), 200
|
||||
except Exception as error:
|
||||
return jsonify({
|
||||
|
||||
Reference in New Issue
Block a user