From 21beea51ecc86522433290b70975d0138f6fcfa0 Mon Sep 17 00:00:00 2001 From: nayan Date: Tue, 18 Nov 2025 16:26:48 -0500 Subject: [PATCH 1/8] introducing ui_state_sp for py --- selfdrive/ui/sunnypilot/ui_state.py | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 selfdrive/ui/sunnypilot/ui_state.py diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py new file mode 100644 index 0000000000..718e5f706c --- /dev/null +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -0,0 +1,32 @@ +from openpilot.selfdrive.ui.ui_state import UIState +from cereal import messaging +from openpilot.common.params import Params + + +class UIStateSP(UIState): + _instance: 'UIStateSP | None' = None + + def _initialize(self): + UIState._initialize(self) + self.params = Params() + self.sm = messaging.SubMaster( + [ + "modelV2", "controlsState", "liveCalibration", "deviceState", "carParams", + "driverMonitoringState", "carState", "roadCameraState", "managerState", + "selfdriveState", "longitudinalPlan", "rawAudioData", + "modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP", + "carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters", + "carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP" + ]) + + def update(self) -> None: + UIState.update(self) + + def _update_status(self) -> None: + UIState._update_status(self) + + def update_params(self) -> None: + UIState.update_params(self) + +# Global instance +ui_state_sp = UIStateSP() From 01aa6c4204cf270d8d23ffde607ee3aa82e61a4a Mon Sep 17 00:00:00 2001 From: nayan Date: Sat, 15 Nov 2025 09:28:43 -0500 Subject: [PATCH 2/8] param to control stock vs sp ui --- common/params_keys.h | 1 + 1 file changed, 1 insertion(+) diff --git a/common/params_keys.h b/common/params_keys.h index 38578d7ddc..fe08062987 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -173,6 +173,7 @@ inline static std::unordered_map keys = { {"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}}, {"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}}, {"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"sunnypilot_ui", {PERSISTENT, BOOL, "1"}}, {"TrueVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}}, // MADS params From 48202652688a8d72b198973e16ab33780bfafe5b Mon Sep 17 00:00:00 2001 From: nayan Date: Tue, 18 Nov 2025 19:09:46 -0500 Subject: [PATCH 3/8] better --- selfdrive/ui/sunnypilot/ui_state.py | 16 +++++++--------- selfdrive/ui/ui.py | 3 +++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index 718e5f706c..1c350a0e6f 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -9,15 +9,13 @@ class UIStateSP(UIState): def _initialize(self): UIState._initialize(self) self.params = Params() - self.sm = messaging.SubMaster( - [ - "modelV2", "controlsState", "liveCalibration", "deviceState", "carParams", - "driverMonitoringState", "carState", "roadCameraState", "managerState", - "selfdriveState", "longitudinalPlan", "rawAudioData", - "modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP", - "carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters", - "carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP" - ]) + op_services = self.sm.services + sp_services = [ + "modelManagerSP", "selfdriveStateSP", "longitudinalPlanSP", "backupManagerSP", + "carControl", "gpsLocationExternal", "gpsLocation", "liveTorqueParameters", + "carStateSP", "liveParameters", "liveMapDataSP", "carParamsSP" + ] + self.sm = messaging.SubMaster(op_services + sp_services) def update(self) -> None: UIState.update(self) diff --git a/selfdrive/ui/ui.py b/selfdrive/ui/ui.py index a4b99825e9..e68442aba1 100755 --- a/selfdrive/ui/ui.py +++ b/selfdrive/ui/ui.py @@ -8,6 +8,9 @@ from openpilot.system.ui.lib.application import gui_app from openpilot.selfdrive.ui.layouts.main import MainLayout from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.common.params import Params +if Params().get_bool("sunnypilot_ui"): + from openpilot.selfdrive.ui.sunnypilot.ui_state import ui_state_sp as ui_state def main(): cores = {5, } From 4da32cc0097434aab0aa6a3c35465eabb23c8958 Mon Sep 17 00:00:00 2001 From: nayan Date: Wed, 19 Nov 2025 23:03:56 -0500 Subject: [PATCH 4/8] add ui_update callback --- selfdrive/ui/sunnypilot/ui_state.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index 1c350a0e6f..3f7e87ab9a 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -1,3 +1,5 @@ +from collections.abc import Callable + from openpilot.selfdrive.ui.ui_state import UIState from cereal import messaging from openpilot.common.params import Params @@ -17,8 +19,16 @@ class UIStateSP(UIState): ] self.sm = messaging.SubMaster(op_services + sp_services) + # Callbacks + self._ui_update_callbacks: list[Callable[[], None]] = [] + + def add_ui_update_callback(self, callback: Callable[[], None]): + self._ui_update_callbacks.append(callback) + def update(self) -> None: UIState.update(self) + for callback in self._ui_update_callbacks: + callback() def _update_status(self) -> None: UIState._update_status(self) From ffa78eabaa7e8489075425b7f4fc6a9492f2e65b Mon Sep 17 00:00:00 2001 From: nayan Date: Thu, 20 Nov 2025 17:58:19 -0500 Subject: [PATCH 5/8] Revert "add ui_update callback" This reverts commit 4da32cc0097434aab0aa6a3c35465eabb23c8958. --- selfdrive/ui/sunnypilot/ui_state.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index 3f7e87ab9a..1c350a0e6f 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -1,5 +1,3 @@ -from collections.abc import Callable - from openpilot.selfdrive.ui.ui_state import UIState from cereal import messaging from openpilot.common.params import Params @@ -19,16 +17,8 @@ class UIStateSP(UIState): ] self.sm = messaging.SubMaster(op_services + sp_services) - # Callbacks - self._ui_update_callbacks: list[Callable[[], None]] = [] - - def add_ui_update_callback(self, callback: Callable[[], None]): - self._ui_update_callbacks.append(callback) - def update(self) -> None: UIState.update(self) - for callback in self._ui_update_callbacks: - callback() def _update_status(self) -> None: UIState._update_status(self) From 91f2bf345956e0710e75a4f94a440d0986a0dc1d Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Fri, 21 Nov 2025 16:23:01 -0500 Subject: [PATCH 6/8] ui: `GuiApplicationExt` --- system/ui/lib/application.py | 4 +++- system/ui/sunnypilot/lib/application.py | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 system/ui/sunnypilot/lib/application.py diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index e3370a5f74..7271127838 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -19,6 +19,8 @@ from openpilot.system.hardware import HARDWARE, PC from openpilot.system.ui.lib.multilang import multilang from openpilot.common.realtime import Ratekeeper +from openpilot.system.ui.sunnypilot.lib.application import GuiApplicationExt + _DEFAULT_FPS = int(os.getenv("FPS", {'tizi': 20}.get(HARDWARE.get_device_type(), 60))) FPS_LOG_INTERVAL = 5 # Seconds between logging FPS drops FPS_DROP_THRESHOLD = 0.9 # FPS drop threshold for triggering a warning @@ -186,7 +188,7 @@ class MouseState: self._prev_mouse_event[slot] = ev -class GuiApplication: +class GuiApplication(GuiApplicationExt): def __init__(self, width: int | None = None, height: int | None = None): self._fonts: dict[FontWeight, rl.Font] = {} self._width = width if width is not None else GuiApplication._default_width() diff --git a/system/ui/sunnypilot/lib/application.py b/system/ui/sunnypilot/lib/application.py new file mode 100644 index 0000000000..b39bf31e9d --- /dev/null +++ b/system/ui/sunnypilot/lib/application.py @@ -0,0 +1,15 @@ +""" +Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. + +This file is part of sunnypilot and is licensed under the MIT License. +See the LICENSE.md file in the root directory for more details. +""" +import os + +SUNNYPILOT_UI = os.getenv("SUNNYPILOT_UI", "1") == "1" + + +class GuiApplicationExt: + @staticmethod + def sunnypilot_ui() -> bool: + return SUNNYPILOT_UI From a33497ed19a413931ea4053c4903f15f2ae71d50 Mon Sep 17 00:00:00 2001 From: Jason Wen Date: Fri, 21 Nov 2025 16:42:49 -0500 Subject: [PATCH 7/8] add to readme --- system/ui/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/system/ui/README.md b/system/ui/README.md index f81cb5573a..796d298626 100644 --- a/system/ui/README.md +++ b/system/ui/README.md @@ -10,6 +10,7 @@ Quick start: * set `BURN_IN=1` to get a burn-in heatmap version of the UI * set `GRID=50` to show a 50-pixel alignment grid overlay * set `MAGIC_DEBUG=1` to show every dropped frames (only on device) +* set `SUNNYPILOT_UI=0` to run the stock UI instead of the sunnypilot UI * https://www.raylib.com/cheatsheet/cheatsheet.html * https://electronstudio.github.io/raylib-python-cffi/README.html#quickstart From e8ab9d812d2be1bdbe5ac27af43707e16e9829e4 Mon Sep 17 00:00:00 2001 From: nayan Date: Fri, 21 Nov 2025 17:55:00 -0500 Subject: [PATCH 8/8] use gui_app.sunnypilot_ui() --- common/params_keys.h | 1 - selfdrive/ui/ui.py | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/common/params_keys.h b/common/params_keys.h index fe08062987..38578d7ddc 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -173,7 +173,6 @@ inline static std::unordered_map keys = { {"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}}, {"ShowTurnSignals", {PERSISTENT | BACKUP, BOOL, "0"}}, {"StandstillTimer", {PERSISTENT | BACKUP, BOOL, "0"}}, - {"sunnypilot_ui", {PERSISTENT, BOOL, "1"}}, {"TrueVEgoUI", {PERSISTENT | BACKUP, BOOL, "0"}}, // MADS params diff --git a/selfdrive/ui/ui.py b/selfdrive/ui/ui.py index 11fc4e3b95..5e0ba6d1ae 100755 --- a/selfdrive/ui/ui.py +++ b/selfdrive/ui/ui.py @@ -9,8 +9,7 @@ from openpilot.selfdrive.ui.layouts.main import MainLayout from openpilot.selfdrive.ui.mici.layouts.main import MiciMainLayout from openpilot.selfdrive.ui.ui_state import ui_state -from openpilot.common.params import Params -if Params().get_bool("sunnypilot_ui"): +if gui_app.sunnypilot_ui(): from openpilot.selfdrive.ui.sunnypilot.ui_state import ui_state_sp as ui_state def main():