Compare commits

...

3 Commits

Author SHA1 Message Date
3f4c49ccf2 add priority mac 2026-04-01 04:05:22 +03:00
126e27e29f add priority mac 2026-04-01 04:00:52 +03:00
9ae9e7873a add bl music_mac 2026-04-01 03:54:26 +03:00
3 changed files with 62 additions and 9 deletions

2
app.py
View File

@ -34,6 +34,8 @@ def _apply_startup_sound_defaults():
settings.setValue("sound/premute_volume", premute_volume) settings.setValue("sound/premute_volume", premute_volume)
if not settings.contains("sound/ducking_volume"): if not settings.contains("sound/ducking_volume"):
settings.setValue("sound/ducking_volume", ducking_volume) settings.setValue("sound/ducking_volume", ducking_volume)
if not settings.contains("bluetooth/music_mac"):
settings.setValue("bluetooth/music_mac", "")
applied_volume = settings.value("sound/base_volume", base_volume) applied_volume = settings.value("sound/base_volume", base_volume)
try: try:

View File

@ -4,7 +4,7 @@ from abc import ABC, abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
from typing import Any from typing import Any
from PySide6.QtCore import QObject, Signal from PySide6.QtCore import QObject, Signal, QSettings
@dataclass @dataclass
@ -71,9 +71,21 @@ class MediaSourceController(ABC):
class BluetoothController(MediaSourceController): class BluetoothController(MediaSourceController):
"""Контроллер для Bluetooth аудио.""" """Контроллер для Bluetooth аудио."""
def __init__(self, bt_service: Any): def __init__(self, bt_service: Any):
self._bt_service = bt_service self._bt_service = bt_service
self._music_mac: str | None = None
def set_music_mac(self, mac: str | None) -> None:
"""Установить приоритетный MAC для музыки."""
self._music_mac = mac
# Синхронизируем с сервисом
if self._bt_service:
self._bt_service.set_music_mac(mac)
def get_music_mac(self) -> str | None:
"""Получить приоритетный MAC для музыки."""
return self._music_mac
@property @property
def name(self) -> str: def name(self) -> str:
@ -184,15 +196,21 @@ class MediaController(QObject):
def __init__(self, bt_service: Any = None, parent: QObject = None): def __init__(self, bt_service: Any = None, parent: QObject = None):
super().__init__(parent) super().__init__(parent)
self._bt_service = bt_service self._bt_service = bt_service
self._settings = QSettings("car_ui", "ui")
self._controllers: dict[str, MediaSourceController] = {} self._controllers: dict[str, MediaSourceController] = {}
self._current_mode: str = "bluetooth" self._current_mode: str = "bluetooth"
# Регистрируем контроллеры # Регистрируем контроллеры
self._register_controllers() self._register_controllers()
def _register_controllers(self) -> None: def _register_controllers(self) -> None:
"""Зарегистрировать все доступные контроллеры.""" """Зарегистрировать все доступные контроллеры."""
self._controllers["bluetooth"] = BluetoothController(self._bt_service) bt_controller = BluetoothController(self._bt_service)
# Читаем приоритетный MAC из настроек
music_mac = self._settings.value("bluetooth/music_mac", "")
if music_mac:
bt_controller.set_music_mac(music_mac)
self._controllers["bluetooth"] = bt_controller
self._controllers["carplay"] = CarPlayController() self._controllers["carplay"] = CarPlayController()
# В будущем можно добавить: # В будущем можно добавить:
# self._controllers["aux"] = AuxController() # self._controllers["aux"] = AuxController()
@ -203,8 +221,15 @@ class MediaController(QObject):
# Если переключаемся с Bluetooth на CarPlay - ставим паузу # Если переключаемся с Bluetooth на CarPlay - ставим паузу
if self._current_mode == "bluetooth" and mode == "carplay": if self._current_mode == "bluetooth" and mode == "carplay":
self._controllers["bluetooth"].pause() self._controllers["bluetooth"].pause()
elif self._current_mode == "carplay" and mode == "bluetooth":
self._controllers["bluetooth"].play() # Если переключаемся на Bluetooth - подключаем приоритетное устройство
elif mode == "bluetooth":
bt_controller = self._controllers["bluetooth"]
music_mac = bt_controller.get_music_mac()
if music_mac:
# Пытаемся подключить приоритетное устройство
bt_controller.connect_device(music_mac)
self._current_mode = mode self._current_mode = mode
# Сигнал о смене режима для обновления UI # Сигнал о смене режима для обновления UI
self.metadata_changed.emit(self.get_metadata()) self.metadata_changed.emit(self.get_metadata())

View File

@ -47,6 +47,7 @@ class BluetoothService(QObject):
super().__init__(parent) super().__init__(parent)
self._log_path = Path("~/.cache/car_ui/bluetooth.log").expanduser() self._log_path = Path("~/.cache/car_ui/bluetooth.log").expanduser()
self._last_error = "" self._last_error = ""
self._settings = QSettings("car_ui", "ui")
# === Public API === # === Public API ===
@ -95,32 +96,57 @@ class BluetoothService(QObject):
return info.get("Connected", "no") == "yes" return info.get("Connected", "no") == "yes"
def connect_device(self, mac: str) -> bool: def connect_device(self, mac: str) -> bool:
"""Подключиться к устройству.""" """Подключиться к устройству.
При успешном подключении обновляет bluetooth/music_mac.
"""
self._last_error = "" self._last_error = ""
self._run_cmd(["bluetoothctl", "trust", mac]) self._run_cmd(["bluetoothctl", "trust", mac])
result = self._run_cmd(["bluetoothctl", "connect", mac]) result = self._run_cmd(["bluetoothctl", "connect", mac])
success = not self._last_error success = not self._last_error
if success:
# Обновляем приоритетный MAC
self._settings.setValue("bluetooth/music_mac", mac)
self.connected_changed.emit(mac, success) self.connected_changed.emit(mac, success)
return success return success
def disconnect_device(self, mac: str) -> bool: def disconnect_device(self, mac: str) -> bool:
"""Отключить устройство.""" """Отключить устройство.
Если это устройство было в bluetooth/music_mac, обнуляем настройку.
"""
self._last_error = "" self._last_error = ""
result = self._run_cmd(["bluetoothctl", "disconnect", mac]) result = self._run_cmd(["bluetoothctl", "disconnect", mac])
success = not self._last_error success = not self._last_error
# Если отключаем приоритетное устройство, обнуляем настройку
if success and self._settings.value("bluetooth/music_mac") == mac:
self._settings.setValue("bluetooth/music_mac", "")
self.connected_changed.emit(mac, False) self.connected_changed.emit(mac, False)
return success return success
def remove_device(self, mac: str) -> bool: def remove_device(self, mac: str) -> bool:
"""Удалить устройство из списка сопряженных.""" """Удалить устройство из списка сопряженных.
Если это устройство было в bluetooth/music_mac, обнуляем настройку.
"""
self._last_error = "" self._last_error = ""
# Сначала отключаем, если подключено # Сначала отключаем, если подключено
if self.is_connected(mac): if self.is_connected(mac):
self._run_cmd(["bluetoothctl", "disconnect", mac]) self._run_cmd(["bluetoothctl", "disconnect", mac])
result = self._run_cmd(["bluetoothctl", "remove", mac]) result = self._run_cmd(["bluetoothctl", "remove", mac])
success = not self._last_error success = not self._last_error
# Если удаляем приоритетное устройство, обнуляем настройку
if success and self._settings.value("bluetooth/music_mac") == mac:
self._settings.setValue("bluetooth/music_mac", "")
return success return success
def set_music_mac(self, mac: str | None) -> None:
"""Установить приоритетный MAC для музыки."""
if mac:
self._settings.setValue("bluetooth/music_mac", mac)
else:
self._settings.setValue("bluetooth/music_mac", "")
def make_discoverable(self, timeout_sec: int = 10) -> bool: def make_discoverable(self, timeout_sec: int = 10) -> bool:
"""Сделать устройство видимым для сопряжения. """Сделать устройство видимым для сопряжения.