diff --git a/common/params_keys.h b/common/params_keys.h index a559d411e..e04211392 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -168,7 +168,6 @@ inline static std::unordered_map keys = { {"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}}, {"Offroad_TiciSupport", {CLEAR_ON_MANAGER_START, JSON}}, {"OnroadScreenOffBrightness", {PERSISTENT | BACKUP, INT, "0"}}, - {"OnroadScreenOffControl", {PERSISTENT | BACKUP, BOOL}}, {"OnroadScreenOffTimer", {PERSISTENT | BACKUP, INT, "15"}}, {"OnroadUploads", {PERSISTENT | BACKUP, BOOL, "1"}}, {"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}}, diff --git a/selfdrive/ui/mici/onroad/alert_renderer.py b/selfdrive/ui/mici/onroad/alert_renderer.py index b5f796bb0..5c93e5e42 100644 --- a/selfdrive/ui/mici/onroad/alert_renderer.py +++ b/selfdrive/ui/mici/onroad/alert_renderer.py @@ -222,6 +222,9 @@ class AlertRenderer(Widget): self._alert_y_filter.update(self._rect.y - 50 if alert is None else self._rect.y) self._alpha_filter.update(0 if alert is None else 1) + if gui_app.sunnypilot_ui(): + ui_state.onroad_brightness_handle_alerts(ui_state.started, alert) + if alert is None: # If still animating out, keep the previous alert if self._alpha_filter.x > 0.01 and self._prev_alert is not None: diff --git a/selfdrive/ui/mici/onroad/augmented_road_view.py b/selfdrive/ui/mici/onroad/augmented_road_view.py index 5fe33a7e4..0546920e5 100644 --- a/selfdrive/ui/mici/onroad/augmented_road_view.py +++ b/selfdrive/ui/mici/onroad/augmented_road_view.py @@ -19,6 +19,9 @@ from openpilot.common.transformations.camera import DEVICE_CAMERAS, DeviceCamera from openpilot.common.transformations.orientation import rot_from_euler from enum import IntEnum +if gui_app.sunnypilot_ui(): + from openpilot.selfdrive.ui.sunnypilot.ui_state import OnroadTimerStatus + OpState = log.SelfdriveState.OpenpilotState CALIBRATED = log.LiveCalibrationData.Status.calibrated ROAD_CAM = VisionStreamType.VISION_STREAM_ROAD @@ -351,6 +354,14 @@ class AugmentedRoadView(CameraView): return self._cached_matrix + def show_event(self): + if gui_app.sunnypilot_ui(): + ui_state.reset_onroad_sleep_timer(OnroadTimerStatus.RESUME) + + def hide_event(self): + if gui_app.sunnypilot_ui(): + ui_state.reset_onroad_sleep_timer(OnroadTimerStatus.PAUSE) + if __name__ == "__main__": gui_app.init_window("OnRoad Camera View") diff --git a/selfdrive/ui/onroad/alert_renderer.py b/selfdrive/ui/onroad/alert_renderer.py index 1e5f99cc6..2c21b4006 100644 --- a/selfdrive/ui/onroad/alert_renderer.py +++ b/selfdrive/ui/onroad/alert_renderer.py @@ -116,6 +116,10 @@ class AlertRenderer(Widget): def _render(self, rect: rl.Rectangle): alert = self.get_alert(ui_state.sm) + + if gui_app.sunnypilot_ui(): + ui_state.onroad_brightness_handle_alerts(ui_state.started, alert) + if not alert: return diff --git a/selfdrive/ui/onroad/augmented_road_view.py b/selfdrive/ui/onroad/augmented_road_view.py index a1d10193a..bcbcb2dcf 100644 --- a/selfdrive/ui/onroad/augmented_road_view.py +++ b/selfdrive/ui/onroad/augmented_road_view.py @@ -15,10 +15,10 @@ from openpilot.common.transformations.camera import DEVICE_CAMERAS, DeviceCamera from openpilot.common.transformations.orientation import rot_from_euler if gui_app.sunnypilot_ui(): - from openpilot.selfdrive.ui.sunnypilot.onroad.hud_renderer import HudRendererSP as HudRenderer + from openpilot.selfdrive.ui.sunnypilot.onroad.augmented_road_view import BORDER_COLORS_SP from openpilot.selfdrive.ui.sunnypilot.onroad.driver_state import DriverStateRendererSP as DriverStateRenderer - -from openpilot.selfdrive.ui.sunnypilot.onroad.augmented_road_view import BORDER_COLORS_SP + from openpilot.selfdrive.ui.sunnypilot.onroad.hud_renderer import HudRendererSP as HudRenderer + from openpilot.selfdrive.ui.sunnypilot.ui_state import OnroadTimerStatus OpState = log.SelfdriveState.OpenpilotState CALIBRATED = log.LiveCalibrationData.Status.calibrated @@ -224,6 +224,14 @@ class AugmentedRoadView(CameraView): return self._cached_matrix + def show_event(self): + if gui_app.sunnypilot_ui(): + ui_state.reset_onroad_sleep_timer(OnroadTimerStatus.RESUME) + + def hide_event(self): + if gui_app.sunnypilot_ui(): + ui_state.reset_onroad_sleep_timer(OnroadTimerStatus.PAUSE) + if __name__ == "__main__": gui_app.init_window("OnRoad Camera View") diff --git a/selfdrive/ui/sunnypilot/layouts/settings/display.py b/selfdrive/ui/sunnypilot/layouts/settings/display.py index d1d0a661b..abbfbe7c9 100644 --- a/selfdrive/ui/sunnypilot/layouts/settings/display.py +++ b/selfdrive/ui/sunnypilot/layouts/settings/display.py @@ -4,9 +4,21 @@ 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. """ +from enum import IntEnum + from openpilot.common.params import Params -from openpilot.system.ui.widgets.scroller_tici import Scroller +from openpilot.system.ui.sunnypilot.widgets.option_control import OptionControlSP from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.lib.multilang import tr +from openpilot.system.ui.widgets.scroller_tici import Scroller +from openpilot.system.ui.sunnypilot.widgets.list_view import option_item_sp, ToggleActionSP + +ONROAD_BRIGHTNESS_TIMER_VALUES = {0: 15, 1: 30, **{i: (i - 1) * 60 for i in range(2, 12)}} + + +class OnroadBrightness(IntEnum): + AUTO = 0 + AUTO_DARK = 1 class DisplayLayout(Widget): @@ -18,11 +30,55 @@ class DisplayLayout(Widget): self._scroller = Scroller(items, line_separator=True, spacing=0) def _initialize_items(self): + self._onroad_brightness = option_item_sp( + param="OnroadScreenOffBrightness", + title=lambda: tr("Onroad Brightness"), + description="", + min_value=0, + max_value=21, + value_change_step=1, + label_callback=lambda value: self.update_onroad_brightness(value), + inline=True + ) + self._onroad_brightness_timer = option_item_sp( + param="OnroadScreenOffTimer", + title=lambda: tr("Onroad Brightness Delay"), + description="", + min_value=0, + max_value=11, + value_change_step=1, + value_map=ONROAD_BRIGHTNESS_TIMER_VALUES, + label_callback=lambda value: f"{value} s" if value < 60 else f"{int(value/60)} m", + inline=True + ) items = [ - + self._onroad_brightness, + self._onroad_brightness_timer, ] return items + @staticmethod + def update_onroad_brightness(val): + if val == OnroadBrightness.AUTO: + return tr("Auto (Default)") + + if val == OnroadBrightness.AUTO_DARK: + return tr("Auto (Dark)") + + return f"{(val - 1) * 5} %" + + def _update_state(self): + super()._update_state() + + for _item in self._scroller._items: + if isinstance(_item.action_item, ToggleActionSP) and _item.action_item.toggle.param_key is not None: + _item.action_item.set_state(self._params.get_bool(_item.action_item.toggle.param_key)) + elif isinstance(_item.action_item, OptionControlSP) and _item.action_item.param_key is not None: + _item.action_item.set_value(self._params.get(_item.action_item.param_key, return_default=True)) + + brightness_val = self._params.get("OnroadScreenOffBrightness", return_default=True) + self._onroad_brightness_timer.action_item.set_enabled(brightness_val not in (OnroadBrightness.AUTO, OnroadBrightness.AUTO_DARK)) + def _render(self, rect): self._scroller.render(rect) diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index fe7124e5c..2644c157a 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -4,13 +4,25 @@ 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. """ +from enum import Enum + from cereal import messaging, log, custom from openpilot.common.params import Params +from openpilot.selfdrive.ui.sunnypilot.layouts.settings.display import OnroadBrightness from openpilot.sunnypilot.sunnylink.sunnylink_state import SunnylinkState +from openpilot.system.ui.lib.application import gui_app OpenpilotState = log.SelfdriveState.OpenpilotState MADSState = custom.ModularAssistiveDrivingSystem.ModularAssistiveDrivingSystemState +ONROAD_BRIGHTNESS_TIMER_PAUSED = -1 + + +class OnroadTimerStatus(Enum): + NONE = 0 + PAUSE = 1 + RESUME = 2 + class UIStateSP: def __init__(self): @@ -21,8 +33,11 @@ class UIStateSP: ] self.sunnylink_state = SunnylinkState() + self.update_params() + self.onroad_brightness_timer: int = 0 self.custom_interactive_timeout: int = self.params.get("InteractivityTimeout", return_default=True) + self.reset_onroad_sleep_timer() def update(self) -> None: if self.sunnylink_enabled: @@ -30,6 +45,40 @@ class UIStateSP: else: self.sunnylink_state.stop() + def onroad_brightness_handle_alerts(self, started: bool, alert): + has_alert = started and self.onroad_brightness != OnroadBrightness.AUTO and alert is not None + + self.update_onroad_brightness(has_alert) + if has_alert: + self.reset_onroad_sleep_timer() + + def update_onroad_brightness(self, has_alert: bool) -> None: + if has_alert: + return + + if self.onroad_brightness_timer > 0: + self.onroad_brightness_timer -= 1 + + def reset_onroad_sleep_timer(self, timer_status: OnroadTimerStatus = OnroadTimerStatus.NONE) -> None: + # Toggling from active state to inactive + if timer_status == OnroadTimerStatus.PAUSE and self.onroad_brightness_timer != ONROAD_BRIGHTNESS_TIMER_PAUSED: + self.onroad_brightness_timer = ONROAD_BRIGHTNESS_TIMER_PAUSED + # Toggling from a previously inactive state or resetting an active timer + elif (self.onroad_brightness_timer_param >= 0 and self.onroad_brightness != OnroadBrightness.AUTO and + self.onroad_brightness_timer != ONROAD_BRIGHTNESS_TIMER_PAUSED) or timer_status == OnroadTimerStatus.RESUME: + if self.onroad_brightness == OnroadBrightness.AUTO_DARK: + self.onroad_brightness_timer = 15 * gui_app.target_fps + else: + self.onroad_brightness_timer = self.onroad_brightness_timer_param * gui_app.target_fps + + @property + def onroad_brightness_timer_expired(self) -> bool: + return self.onroad_brightness != OnroadBrightness.AUTO and self.onroad_brightness_timer == 0 + + @property + def auto_onroad_brightness(self) -> bool: + return self.onroad_brightness in (OnroadBrightness.AUTO, OnroadBrightness.AUTO_DARK) + @staticmethod def update_status(ss, ss_sp, onroad_evt) -> str: state = ss.state @@ -78,6 +127,10 @@ class UIStateSP: self.active_bundle = self.params.get("ModelManager_ActiveBundle") self.custom_interactive_timeout = self.params.get("InteractivityTimeout", return_default=True) + # Onroad Screen Brightness + self.onroad_brightness = int(float(self.params.get("OnroadScreenOffBrightness", return_default=True))) + self.onroad_brightness_timer_param = self.params.get("OnroadScreenOffTimer", return_default=True) + class DeviceSP: def __init__(self): @@ -86,3 +139,38 @@ class DeviceSP: def _set_awake(self, on: bool): if on and self._params.get("DeviceBootMode", return_default=True) == 1: self._params.put_bool("OffroadMode", True) + + @staticmethod + def set_onroad_brightness(_ui_state, awake: bool, cur_brightness: float) -> float: + if not awake or not _ui_state.started: + return cur_brightness + + if _ui_state.onroad_brightness_timer != 0: + if _ui_state.onroad_brightness == OnroadBrightness.AUTO_DARK: + return max(30.0, cur_brightness) + # For AUTO (Default) and Manual modes (while timer running), use standard brightness + return cur_brightness + + # 0: Auto (Default), 1: Auto (Dark) + if _ui_state.onroad_brightness == OnroadBrightness.AUTO: + return cur_brightness + elif _ui_state.onroad_brightness == OnroadBrightness.AUTO_DARK: + return cur_brightness + + # 2-21: 5% - 100% + return float((_ui_state.onroad_brightness - 1) * 5) + + @staticmethod + def set_min_onroad_brightness(_ui_state, min_brightness: int) -> int: + if _ui_state.onroad_brightness == OnroadBrightness.AUTO_DARK: + min_brightness = 10 + + return min_brightness + + @staticmethod + def wake_from_dimmed_onroad_brightness(_ui_state, evs) -> None: + if _ui_state.started and (_ui_state.onroad_brightness_timer_expired or _ui_state.onroad_brightness == OnroadBrightness.AUTO_DARK): + if any(ev.left_down for ev in evs): + if _ui_state.onroad_brightness_timer_expired: + gui_app.mouse_events.clear() + _ui_state.reset_onroad_sleep_timer() diff --git a/selfdrive/ui/ui_state.py b/selfdrive/ui/ui_state.py index 11e0cce74..a9127ac3c 100644 --- a/selfdrive/ui/ui_state.py +++ b/selfdrive/ui/ui_state.py @@ -258,9 +258,17 @@ class Device(DeviceSP): else: clipped_brightness = ((clipped_brightness + 16.0) / 116.0) ** 3.0 - clipped_brightness = float(np.interp(clipped_brightness, [0, 1], [30, 100])) + min_brightness = 30 + if gui_app.sunnypilot_ui(): + min_brightness = DeviceSP.set_min_onroad_brightness(ui_state, min_brightness) + + clipped_brightness = float(np.interp(clipped_brightness, [0, 1], [min_brightness, 100])) brightness = round(self._brightness_filter.update(clipped_brightness)) + + if gui_app.sunnypilot_ui(): + brightness = DeviceSP.set_onroad_brightness(ui_state, self._awake, brightness) + if not self._awake: brightness = 0 @@ -276,6 +284,9 @@ class Device(DeviceSP): self._ignition = ui_state.ignition if ignition_just_turned_off or any(ev.left_down for ev in gui_app.mouse_events): + if gui_app.sunnypilot_ui(): + DeviceSP.wake_from_dimmed_onroad_brightness(ui_state, gui_app.mouse_events) + self._reset_interactive_timeout() interaction_timeout = time.monotonic() > self._interaction_time diff --git a/sunnypilot/sunnylink/params_metadata.json b/sunnypilot/sunnylink/params_metadata.json index 1fc3f991b..0c1c9016f 100644 --- a/sunnypilot/sunnylink/params_metadata.json +++ b/sunnypilot/sunnylink/params_metadata.json @@ -777,13 +777,100 @@ "OnroadScreenOffBrightness": { "title": "Onroad Brightness", "description": "", - "min": 0, - "max": 100, - "step": 5 + "options": [ + { + "value": 0, + "label": "Auto (Default)" + }, + { + "value": 1, + "label": "Auto (Dark)" + }, + { + "value": 2, + "label": "5 %" + }, + { + "value": 3, + "label": "10 %" + }, + { + "value": 4, + "label": "15 %" + }, + { + "value": 5, + "label": "20 %" + }, + { + "value": 6, + "label": "25 %" + }, + { + "value": 7, + "label": "30 %" + }, + { + "value": 8, + "label": "35 %" + }, + { + "value": 9, + "label": "40 %" + }, + { + "value": 10, + "label": "45 %" + }, + { + "value": 11, + "label": "50 %" + }, + { + "value": 12, + "label": "55 %" + }, + { + "value": 13, + "label": "60 %" + }, + { + "value": 14, + "label": "65 %" + }, + { + "value": 15, + "label": "70 %" + }, + { + "value": 16, + "label": "75 %" + }, + { + "value": 17, + "label": "80 %" + }, + { + "value": 18, + "label": "85 %" + }, + { + "value": 19, + "label": "90 %" + }, + { + "value": 20, + "label": "95 %" + }, + { + "value": 21, + "label": "100 %" + } + ] }, "OnroadScreenOffControl": { - "title": "Onroad Screen: Reduced Brightness", - "description": "Turn off device screen or reduce brightness after driving starts" + "title": "Onroad Brightness", + "description": "Adjusts the screen brightness while it's in onroad state." }, "OnroadScreenOffTimer": { "title": "Onroad Brightness Delay",