Galaxy and Konik

This commit is contained in:
firestar5683
2026-04-14 19:17:10 -05:00
parent 93cebacebf
commit 8c00f0a33f
5 changed files with 96 additions and 16 deletions
+67 -5
View File
@@ -2,15 +2,18 @@ import os
import threading
import pyray as rl
from enum import IntEnum
from pathlib import Path
from collections.abc import Callable
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.common.time_helpers import system_time_valid
from openpilot.system.hardware import PC
from openpilot.system.hardware.hw import Paths
from openpilot.system.ui.widgets.scroller import NavRawScrollPanel, NavScroller
from openpilot.selfdrive.ui.mici.widgets.button import BigButton, BigCircleButton, BigParamControl
from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigConfirmationDialog
from openpilot.selfdrive.ui.mici.widgets.pairing_dialog import PairingDialog
from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigConfirmationDialog, BigMultiOptionDialog
from openpilot.selfdrive.ui.mici.widgets.pairing_dialog import PairingDialog, get_pairing_backend_name, get_pairing_host
from openpilot.selfdrive.ui.mici.onroad.driver_camera_dialog import DriverCameraDialog
from openpilot.selfdrive.ui.mici.layouts.onboarding import TrainingGuide, TermsPage
from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos
@@ -128,9 +131,66 @@ class UpdaterState(IntEnum):
UPDATER_RESPONDING = 2
def _konik_toggle_path() -> Path:
return Path(Paths.comma_home()) / "starpilot" / "cache" / "use_konik" if PC else Path("/cache/use_konik")
class ConnectServerBigButton(BigButton):
_COMMA_OPTION = "comma connect"
_KONIK_OPTION = "konik connect"
def __init__(self):
self._params = Params()
self._reboot_icon = gui_app.texture("icons_mici/settings/device/reboot.png", 64, 70)
super().__init__("connect\nserver", get_pairing_host(self._params), gui_app.texture("icons_mici/settings/comma_icon.png", 33, 60))
def _get_label_font_size(self):
return 52
def _selected_option(self) -> str:
return self._KONIK_OPTION if self._params.get_bool("UseKonikServer") else self._COMMA_OPTION
def _apply_selection(self, selection: str):
use_konik = selection == self._KONIK_OPTION
self._params.put_bool("UseKonikServer", use_konik)
toggle_path = _konik_toggle_path()
toggle_path.parent.mkdir(parents=True, exist_ok=True)
if use_konik:
toggle_path.touch(exist_ok=True)
else:
try:
toggle_path.unlink(missing_ok=True)
except TypeError:
if toggle_path.exists():
toggle_path.unlink()
ui_state.params.put_bool("DoReboot", True)
def _handle_mouse_release(self, mouse_pos: MousePos):
super()._handle_mouse_release(mouse_pos)
dialog_holder: dict[str, BigMultiOptionDialog] = {}
def on_confirm():
selection = dialog_holder["dialog"].get_selected_option()
if selection == self._selected_option():
return
gui_app.push_widget(BigConfirmationDialog("slide to\nreboot", self._reboot_icon, lambda: self._apply_selection(selection)))
dialog = BigMultiOptionDialog(options=[self._COMMA_OPTION, self._KONIK_OPTION], default=self._selected_option(), right_btn_callback=on_confirm)
dialog_holder["dialog"] = dialog
gui_app.push_widget(dialog)
def _update_state(self):
super()._update_state()
self.set_value(get_pairing_host(self._params))
class PairBigButton(BigButton):
def __init__(self):
super().__init__("pair", "connect.comma.ai", gui_app.texture("icons_mici/settings/comma_icon.png", 33, 60))
super().__init__("pair", get_pairing_host(ui_state.params), gui_app.texture("icons_mici/settings/comma_icon.png", 33, 60))
def _get_label_font_size(self):
return 64
@@ -146,7 +206,7 @@ class PairBigButton(BigButton):
self.set_value("upgrade to prime")
else:
self.set_text("pair")
self.set_value("connect.comma.ai")
self.set_value(get_pairing_host(ui_state.params))
def _handle_mouse_release(self, mouse_pos: MousePos):
super()._handle_mouse_release(mouse_pos)
@@ -158,7 +218,7 @@ class PairBigButton(BigButton):
if not system_time_valid():
dlg = BigDialog("", tr("Please connect to Wi-Fi to complete initial pairing."))
elif UNREGISTERED_DONGLE_ID == (ui_state.params.get("DongleId") or UNREGISTERED_DONGLE_ID):
dlg = BigDialog("", tr("Device must be registered with the comma.ai backend to pair."))
dlg = BigDialog("", f"Device must be registered with the {get_pairing_backend_name(ui_state.params)} backend to pair.")
else:
dlg = PairingDialog()
gui_app.push_widget(dlg)
@@ -338,6 +398,7 @@ class DeviceLayoutMici(NavScroller):
regulatory_btn = BigButton("regulatory info", "", gui_app.texture("icons_mici/settings/device/info.png", 64, 64))
regulatory_btn.set_click_callback(self._on_regulatory)
self._connect_server_btn = ConnectServerBigButton()
self._simple_mode_btn = BigParamControl("simple mode", "SimpleMode")
driver_cam_btn = BigButton("driver\ncamera preview", "", gui_app.texture("icons_mici/settings/device/cameras.png", 64, 64))
@@ -354,6 +415,7 @@ class DeviceLayoutMici(NavScroller):
self._scroller.add_widgets([
DeviceInfoLayoutMici(),
UpdateOpenpilotBigButton(),
self._connect_server_btn,
PairBigButton(),
self._simple_mode_btn,
review_training_guide_btn,
+6 -6
View File
@@ -99,15 +99,15 @@ class GalaxyBigButton(BigButton):
return
gui_app.push_widget(GalaxyQRDialog(f"https://galaxy.firestar.link/{slug}"))
def _pair_with_pin(self, pin: str):
clean_pin = str(pin or "").strip()
if len(clean_pin) < 6:
gui_app.push_widget(BigDialog("", "PIN must be at least 6 characters."))
def _pair_with_password(self, password: str):
clean_password = str(password or "").strip()
if len(clean_password) < 6:
gui_app.push_widget(BigDialog("", "Password must be at least 6 characters."))
return
try:
self._galaxy_dir.mkdir(parents=True, exist_ok=True)
self._auth_path.write_text(hashlib.sha256(clean_pin.encode("utf-8")).hexdigest(), encoding="utf-8")
self._auth_path.write_text(hashlib.sha256(clean_password.encode("utf-8")).hexdigest(), encoding="utf-8")
self._session_path.write_text(secrets.token_hex(32), encoding="utf-8")
slug = "".join(secrets.choice(self._SLUG_CHARS) for _ in range(16))
self._slug_path.write_text(slug, encoding="utf-8")
@@ -153,7 +153,7 @@ class GalaxyBigButton(BigButton):
gui_app.push_widget(dialog)
return
gui_app.push_widget(BigInputDialog("create galaxy pin...", default_text="", minimum_length=6, confirm_callback=self._pair_with_pin))
gui_app.push_widget(BigInputDialog("set galaxy password...", default_text="", minimum_length=6, confirm_callback=self._pair_with_password))
def _update_state(self):
self.set_value("paired" if self._is_paired() else "pair")
+20 -2
View File
@@ -12,6 +12,23 @@ from openpilot.system.ui.lib.application import FontWeight, gui_app
from openpilot.system.ui.widgets.label import UnifiedLabel
def use_konik_server(params: Params | None = None) -> bool:
params = params or Params()
return params.get_bool("UseKonikServer")
def get_pairing_host(params: Params | None = None) -> str:
return "stable.konik.ai" if use_konik_server(params) else "connect.comma.ai"
def get_pairing_service_label(params: Params | None = None) -> str:
return "konik connect" if use_konik_server(params) else "comma connect"
def get_pairing_backend_name(params: Params | None = None) -> str:
return "Konik" if use_konik_server(params) else "comma.ai"
class PairingDialog(NavWidget):
"""Dialog for device pairing with QR code."""
@@ -24,7 +41,8 @@ class PairingDialog(NavWidget):
self._last_qr_generation = float("-inf")
self._txt_pair = gui_app.texture("icons_mici/settings/device/pair.png", 33, 60)
self._pair_label = UnifiedLabel("pair with comma connect", font_size=48, font_weight=FontWeight.BOLD, line_height=0.8)
self._pair_label = UnifiedLabel(f"pair with {get_pairing_service_label(self._params)}", font_size=48, font_weight=FontWeight.BOLD,
line_height=0.8)
def _get_pairing_url(self) -> str:
try:
@@ -33,7 +51,7 @@ class PairingDialog(NavWidget):
except Exception as e:
cloudlog.warning(f"Failed to get pairing token: {e}")
token = ""
return f"https://connect.comma.ai/?pair={token}"
return f"https://{get_pairing_host(self._params)}/?pair={token}"
def _generate_qr_code(self) -> None:
try:
+2 -2
View File
@@ -344,8 +344,8 @@ DevicePanel::DevicePanel(SettingsWindow *parent) : ListWidget(parent) {
const std::string current_password = util::read_file(galaxy_auth_path);
if (current_password.empty()) {
QString new_password = InputDialog::getText(
tr("Enter Password"), this,
tr("Please enter a password to secure your Galaxy access. (Min 6 characters)"),
tr("Set Galaxy Password"), this,
tr("Set a password to secure your Galaxy access. (Min 6 characters)"),
false, 6);
if (new_password.isEmpty()) {
return;
@@ -140,7 +140,7 @@ export function GalaxyPairing() {
</div>
<p class="galaxy-text">
Pair your device with Galaxy to access The Pond remotely from anywhere.
Enter a password to secure your connection.
Set a password to secure your connection.
</p>
<div class="galaxy-input-group">
<input