diff --git a/selfdrive/ui/sunnypilot/layouts/settings/developer.py b/selfdrive/ui/sunnypilot/layouts/settings/developer.py new file mode 100644 index 0000000000..f3a2433373 --- /dev/null +++ b/selfdrive/ui/sunnypilot/layouts/settings/developer.py @@ -0,0 +1,106 @@ +""" +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 datetime +import os +from pathlib import Path + +from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.selfdrive.ui.layouts.settings.developer import DeveloperLayout +from openpilot.system.hardware import PC +from openpilot.system.hardware.hw import Paths +from openpilot.system.ui.lib.application import gui_app +from openpilot.system.ui.lib.multilang import tr +from openpilot.system.ui.widgets import DialogResult +from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog +from openpilot.system.ui.widgets.list_view import button_item + +from openpilot.system.ui.sunnypilot.widgets.html_render import HtmlModalSP +from openpilot.system.ui.sunnypilot.widgets.list_view import toggle_item_sp + +PREBUILT_PATH = os.path.join(Paths.comma_home(), "prebuilt") if PC else "/data/openpilot/prebuilt" + + +class DeveloperLayoutSP(DeveloperLayout): + def __init__(self): + super().__init__() + self.error_log_path = os.path.join(Paths.crash_log_root(), "error.log") + self._is_release_branch: bool = self._is_release or ui_state.params.get_bool("IsReleaseSpBranch") + self._is_development_branch: bool = ui_state.params.get_bool("IsTestedBranch") or ui_state.params.get_bool("IsDevelopmentBranch") + self._initialize_items() + + for item in self.items: + self._scroller.add_widget(item) + + def _initialize_items(self): + self.show_advanced_controls = toggle_item_sp(tr("Show Advanced Controls"), + tr("Toggle visibility of advanced sunnypilot controls.
This only changes the visibility of the toggles; " + + "it does not change the actual enabled/disabled state."), param="ShowAdvancedControls") + + self.enable_github_runner_toggle = toggle_item_sp(tr("GitHub Runner Service"), tr("Enables or disables the GitHub runner service."), + param="EnableGithubRunner") + + self.enable_copyparty_toggle = toggle_item_sp(tr("copyparty Service"), + tr("copyparty is a very capable file server, you can use it to download your routes, view your logs " + + "and even make some edits on some files from your browser. " + + "Requires you to connect to your comma locally via its IP address."), param="EnableCopyparty") + + self.prebuilt_toggle = toggle_item_sp(tr("Quickboot Mode"), "", param="QuickBootToggle", callback=self._on_prebuilt_toggled) + + self.error_log_btn = button_item(tr("Error Log"), tr("VIEW"), tr("View the error log for sunnypilot crashes."), callback=self._on_error_log_clicked) + + self.items: list = [self.show_advanced_controls, self.enable_github_runner_toggle, self.enable_copyparty_toggle, self.prebuilt_toggle, self.error_log_btn,] + + @staticmethod + def _on_prebuilt_toggled(state): + if state: + Path(PREBUILT_PATH).touch(exist_ok=True) + else: + os.remove(PREBUILT_PATH) + ui_state.params.put_bool("QuickBootToggle", state) + + def _on_delete_confirm(self, result): + if result == DialogResult.CONFIRM: + if os.path.exists(self.error_log_path): + os.remove(self.error_log_path) + + def _on_error_log_closed(self, result, log_exists): + if result == DialogResult.CONFIRM and log_exists: + dialog2 = ConfirmDialog(tr("Would you like to delete this log?"), tr("Yes"), tr("No"), rich=False) + gui_app.set_modal_overlay(dialog2, callback=self._on_delete_confirm) + + def _on_error_log_clicked(self): + text = "" + if os.path.exists(self.error_log_path): + text = f"{datetime.datetime.fromtimestamp(os.path.getmtime(self.error_log_path)).strftime('%d-%b-%Y %H:%M:%S').upper()}

" + try: + with open(self.error_log_path) as file: + text += file.read() + except Exception: + pass + dialog = HtmlModalSP(text=text, callback=lambda result: self._on_error_log_closed(result, os.path.exists(self.error_log_path))) + gui_app.set_modal_overlay(dialog) + + def _update_state(self): + disable_updates = ui_state.params.get_bool("DisableUpdates") + show_advanced = ui_state.params.get_bool("ShowAdvancedControls") + + if (prebuilt_file := os.path.exists(PREBUILT_PATH)) != ui_state.params.get_bool("QuickBootToggle"): + ui_state.params.put_bool("QuickBootToggle", prebuilt_file) + self.prebuilt_toggle.action_item.set_state(prebuilt_file) + + self.prebuilt_toggle.set_visible(show_advanced and not (self._is_release_branch or self._is_development_branch)) + self.prebuilt_toggle.action_item.set_enabled(disable_updates) + + if disable_updates: + self.prebuilt_toggle.set_description(tr("When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it " + + "removes the prebuilt file so compilation of locally edited cpp files can be made.")) + else: + self.prebuilt_toggle.set_description(tr("Quickboot mode requires updates to be disabled.
Enable 'Disable Updates' in the Software panel first.")) + + self.enable_copyparty_toggle.set_visible(show_advanced) + self.enable_github_runner_toggle.set_visible(show_advanced and not self._is_release_branch) + self.error_log_btn.set_visible(not self._is_release_branch) diff --git a/selfdrive/ui/sunnypilot/layouts/settings/settings.py b/selfdrive/ui/sunnypilot/layouts/settings/settings.py index 4de2cacafd..103dd99efd 100644 --- a/selfdrive/ui/sunnypilot/layouts/settings/settings.py +++ b/selfdrive/ui/sunnypilot/layouts/settings/settings.py @@ -9,7 +9,6 @@ from enum import IntEnum import pyray as rl from openpilot.selfdrive.ui.layouts.settings import settings as OP -from openpilot.selfdrive.ui.layouts.settings.developer import DeveloperLayout from openpilot.selfdrive.ui.sunnypilot.layouts.settings.device import DeviceLayoutSP from openpilot.selfdrive.ui.layouts.settings.firehose import FirehoseLayout from openpilot.selfdrive.ui.sunnypilot.layouts.settings.software import SoftwareLayoutSP @@ -31,6 +30,7 @@ from openpilot.selfdrive.ui.sunnypilot.layouts.settings.steering import Steering from openpilot.selfdrive.ui.sunnypilot.layouts.settings.cruise import CruiseLayout from openpilot.selfdrive.ui.sunnypilot.layouts.settings.visuals import VisualsLayout from openpilot.selfdrive.ui.sunnypilot.layouts.settings.display import DisplayLayout +from openpilot.selfdrive.ui.sunnypilot.layouts.settings.developer import DeveloperLayoutSP # from openpilot.selfdrive.ui.sunnypilot.layouts.settings.navigation import NavigationLayout @@ -125,7 +125,7 @@ class SettingsLayoutSP(OP.SettingsLayout): OP.PanelType.TRIPS: PanelInfo(tr_noop("Trips"), TripsLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_trips.png"), OP.PanelType.VEHICLE: PanelInfo(tr_noop("Vehicle"), VehicleLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_vehicle.png"), OP.PanelType.FIREHOSE: PanelInfo(tr_noop("Firehose"), FirehoseLayout(), icon="../../sunnypilot/selfdrive/assets/offroad/icon_firehose.png"), - OP.PanelType.DEVELOPER: PanelInfo(tr_noop("Developer"), DeveloperLayout(), icon="icons/shell.png"), + OP.PanelType.DEVELOPER: PanelInfo(tr_noop("Developer"), DeveloperLayoutSP(), icon="icons/shell.png"), } def _draw_sidebar(self, rect: rl.Rectangle): diff --git a/sunnypilot/sunnylink/params_metadata.json b/sunnypilot/sunnylink/params_metadata.json index 83ec3c7af8..4cc6b18089 100644 --- a/sunnypilot/sunnylink/params_metadata.json +++ b/sunnypilot/sunnylink/params_metadata.json @@ -258,11 +258,11 @@ "description": "" }, "EnableCopyparty": { - "title": "Enable Copyparty", + "title": "copyparty Service", "description": "" }, "EnableGithubRunner": { - "title": "Enable GitHub Runner", + "title": "GitHub Runner Service", "description": "" }, "EnableSunnylinkUploader": {