Files
StarPilot/system/ui/lib/bluetooth_manager.py
T
firestar5683 147b9df247 bluey
2026-08-29 21:12:45 -05:00

105 lines
3.0 KiB
Python

import math
import threading
import time
from openpilot.starpilot.system.bluetooth import BluetoothClient, BluetoothStatus
class BluetoothManager:
def __init__(self):
self._client = BluetoothClient(timeout=5.0)
self._lock = threading.Lock()
self._status = BluetoothStatus()
self._active = False
self._exit = False
self._operation_error = ""
self._audio_test_deadline = 0.0
self._thread = threading.Thread(target=self._poll, daemon=True)
self._thread.start()
@property
def status(self) -> BluetoothStatus:
with self._lock:
return self._status
def set_active(self, active: bool) -> None:
self._active = active
def stop(self) -> None:
self._exit = True
def consume_error(self) -> str:
with self._lock:
error = self._operation_error
self._operation_error = ""
return error
def audio_test_phase(self) -> str:
with self._lock:
deadline = self._audio_test_deadline
if deadline <= 0:
return "starting"
remaining = deadline - time.monotonic()
if remaining > 0:
return str(max(1, math.ceil(remaining)))
if remaining > -3.0:
return "NOW"
return "complete"
def _poll(self) -> None:
while not self._exit:
if self._active:
try:
status = self._client.status()
with self._lock:
self._status = status
except Exception as error:
with self._lock:
self._status = BluetoothStatus(error=str(error))
time.sleep(1.0 if self._active else 2.0)
def _run(self, fn, *args) -> None:
def worker():
try:
fn(*args)
except Exception as error:
with self._lock:
self._operation_error = str(error)
threading.Thread(target=worker, daemon=True).start()
def set_power(self, enabled: bool) -> None:
self._run(self._client.set_power, enabled)
def set_scanning(self, scanning: bool) -> None:
self._run(self._client.start_scan if scanning else self._client.stop_scan)
def pair(self, address: str) -> None:
self._run(self._client.pair, address)
def connect(self, address: str) -> None:
self._run(self._client.connect, address)
def disconnect(self, address: str) -> None:
self._run(self._client.disconnect, address)
def forget(self, address: str) -> None:
self._run(self._client.forget, address)
def select_audio(self, address: str) -> None:
self._run(self._client.select_audio, address)
def test_audio(self, address: str) -> None:
def worker():
try:
delay = self._client.test_audio(address)
with self._lock:
self._audio_test_deadline = time.monotonic() + delay
except Exception as error:
with self._lock:
self._operation_error = str(error)
self._audio_test_deadline = 0.0
threading.Thread(target=worker, daemon=True).start()
def respond(self, prompt_id: str, accepted: bool, value: str = "") -> None:
self._run(self._client.respond, prompt_id, accepted, value)