diff --git a/common/params_keys.h b/common/params_keys.h index 44584c911..f2a63ec1b 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -249,7 +249,7 @@ inline static std::unordered_map keys = { {"OsmStateTitle", {PERSISTENT, STRING}}, {"OsmWayTest", {PERSISTENT, STRING}}, {"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING}}, - {"RoadNameToggle", {PERSISTENT, STRING}}, + {"RoadNameToggle", {PERSISTENT | BACKUP, BOOL, "0"}}, // Speed Limit {"SpeedLimitMode", {PERSISTENT | BACKUP, INT, "1"}}, diff --git a/selfdrive/ui/sunnypilot/layouts/settings/visuals.py b/selfdrive/ui/sunnypilot/layouts/settings/visuals.py index 1036af3e5..84be5a26a 100644 --- a/selfdrive/ui/sunnypilot/layouts/settings/visuals.py +++ b/selfdrive/ui/sunnypilot/layouts/settings/visuals.py @@ -5,9 +5,18 @@ 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 openpilot.common.params import Params +from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.system.ui.lib.multilang import tr, tr_noop +from openpilot.system.ui.sunnypilot.widgets.list_view import toggle_item_sp, multiple_button_item_sp from openpilot.system.ui.widgets.scroller_tici import Scroller from openpilot.system.ui.widgets import Widget +CHEVRON_INFO_DESCRIPTION = { + "enabled": tr_noop("Display useful metrics below the chevron that tracks the lead car " + + "only applicable to cars with sunnypilot longitudinal control."), + "disabled": tr_noop("This feature requires sunnypilot longitudinal control to be available.") +} + class VisualsLayout(Widget): def __init__(self): @@ -18,13 +27,128 @@ class VisualsLayout(Widget): self._scroller = Scroller(items, line_separator=True, spacing=0) def _initialize_items(self): - items = [ + self._toggle_defs = { + "BlindSpot": ( + lambda: tr("Show Blind Spot Warnings"), + tr("Enabling this will display warnings when a vehicle is detected in your " + + "blind spot as long as your car has BSM supported."), + None, + ), + "TorqueBar": ( + lambda: tr("Steering Arc"), + tr("Display steering arc on the driving screen when lateral control is enabled."), + None, + ), + "RainbowMode": ( + lambda: tr("Enable Tesla Rainbow Mode"), + tr("A beautiful rainbow effect on the path the model wants to take. " + + "It does not affect driving in any way."), + None, + ), + "StandstillTimer": ( + lambda: tr("Enable Standstill Timer"), + tr("Show a timer on the HUD when the car is at a standstill."), + None, + ), + "RoadNameToggle": ( + lambda: tr("Display Road Name"), + tr("Displays the name of the road the car is traveling on." + + "
The OpenStreetMap database of the location must be downloaded from " + + "the OSM panel to fetch the road name."), + None, + ), + "GreenLightAlert": ( + lambda: tr("Green Traffic Light Alert (Beta)"), + tr("A chime and on-screen alert will play when the traffic light you are waiting for " + + "turns green and you have no vehicle in front of you." + + "
Note: This chime is only designed as a notification. " + + "It is the driver's responsibility to observe their environment and make decisions accordingly."), + None, + ), + "LeadDepartAlert": ( + lambda: tr("Lead Departure Alert (Beta)"), + tr("A chime and on-screen alert will play when you are stopped, and the vehicle in front of you start moving." + + "
Note: This chime is only designed as a notification. " + + "It is the driver's responsibility to observe their environment and make decisions accordingly."), + None, + ), + "TrueVEgoUI": ( + lambda: tr("Speedometer: Always Display True Speed"), + tr("For applicable vehicles, always display the true vehicle current speed from wheel speed sensors."), + None, + ), + "HideVEgoUI": ( + lambda: tr("Speedometer: Hide from Onroad Screen"), + tr("When enabled, the speedometer on the onroad screen is not displayed."), + None, + ), + "ShowTurnSignals": ( + lambda: tr("Display Turn Signals"), + tr("When enabled, visual turn indicators are drawn on the HUD."), + None, + ), + "RocketFuel": ( + lambda: tr("Real-time Acceleration Bar"), + tr("Show an indicator on the left side of the screen to display real-time vehicle acceleration and deceleration. " + + "This displays what the car is currently doing, not what the planner is requesting."), + None, + ), + } + self._toggles = {} + for param, (title, desc, callback) in self._toggle_defs.items(): + toggle = toggle_item_sp( + title=title, + description=desc, + param=param, + initial_state=ui_state.params.get_bool(param), + callback=callback, + ) + self._toggles[param] = toggle + self._chevron_info = multiple_button_item_sp( + title=lambda: tr("Display Metrics Below Chevron"), + description="", + buttons=[lambda: tr("Off"), lambda: tr("Distance"), lambda: tr("Speed"), lambda: tr("Time"), lambda: tr("All")], + param="ChevronInfo", + inline=False + ) + self._dev_ui_info = multiple_button_item_sp( + title=lambda: tr("Developer UI"), + description=lambda: tr("Display real-time parameters and metrics from various sources."), + buttons=[lambda: tr("Off"), lambda: tr("Bottom"), lambda: tr("Right"), lambda: tr("Right & Bottom")], + param="DevUIInfo", + button_width=350, + inline=False + ) + + items = list(self._toggles.values()) + [ + self._chevron_info, + self._dev_ui_info, ] return items + def _update_state(self): + super()._update_state() + + for param in self._toggle_defs: + self._toggles[param].action_item.set_state(self._params.get_bool(param)) + + self._dev_ui_info.action_item.set_selected_button(ui_state.params.get("DevUIInfo", return_default=True)) + + if ui_state.has_longitudinal_control: + self._chevron_info.set_description(tr(CHEVRON_INFO_DESCRIPTION["enabled"])) + self._chevron_info.action_item.set_selected_button(ui_state.params.get("ChevronInfo", return_default=True)) + self._chevron_info.action_item.set_enabled(True) + else: + self._chevron_info.set_description(tr(CHEVRON_INFO_DESCRIPTION["disabled"])) + self._chevron_info.action_item.set_enabled(False) + ui_state.params.put("ChevronInfo", 0) + def _render(self, rect): self._scroller.render(rect) def show_event(self): self._scroller.show_event() + if not ui_state.has_longitudinal_control: + self._chevron_info.set_description(tr(CHEVRON_INFO_DESCRIPTION["disabled"])) + self._chevron_info.show_description(True) diff --git a/selfdrive/ui/sunnypilot/onroad/blind_spot_indicators.py b/selfdrive/ui/sunnypilot/onroad/blind_spot_indicators.py index 1087579fe..61aa52537 100644 --- a/selfdrive/ui/sunnypilot/onroad/blind_spot_indicators.py +++ b/selfdrive/ui/sunnypilot/onroad/blind_spot_indicators.py @@ -31,6 +31,9 @@ class BlindSpotIndicators: return self._blind_spot_left_alpha_filter.x > 0.01 or self._blind_spot_right_alpha_filter.x > 0.01 def render(self, rect: rl.Rectangle) -> None: + if not ui_state.blindspot: + return + BLIND_SPOT_MARGIN_X = 20 # Distance from edge of screen BLIND_SPOT_Y_OFFSET = 100 # Distance from top of screen diff --git a/selfdrive/ui/sunnypilot/onroad/circular_alerts.py b/selfdrive/ui/sunnypilot/onroad/circular_alerts.py index 965ce7fe7..8aa4c71d0 100644 --- a/selfdrive/ui/sunnypilot/onroad/circular_alerts.py +++ b/selfdrive/ui/sunnypilot/onroad/circular_alerts.py @@ -23,7 +23,6 @@ class CircularAlertsRenderer: self._e2e_alert_frame = 0 self._green_light_alert = False self._lead_depart_alert = False - self._standstill_timer = False self._standstill_elapsed_time = 0.0 self._is_standstill = False self._alert_text = "" @@ -36,7 +35,6 @@ class CircularAlertsRenderer: car_state = sm['carState'] self._green_light_alert = lp_sp.e2eAlerts.greenLightAlert self._lead_depart_alert = lp_sp.e2eAlerts.leadDepartAlert - self._standstill_timer = ui_state.standstill_timer self._is_standstill = car_state.standstill if not ui_state.started: @@ -61,7 +59,7 @@ class CircularAlertsRenderer: self._alert_text = "LEAD VEHICLE\nDEPARTING" self._alert_img = self._lead_depart_alert_img - elif self._standstill_timer and self._is_standstill: + elif ui_state.standstill_timer and self._is_standstill: self._alert_img = None self._standstill_elapsed_time += 1.0 / gui_app.target_fps minute = int(self._standstill_elapsed_time / 60) @@ -75,7 +73,7 @@ class CircularAlertsRenderer: self._standstill_elapsed_time = 0.0 def render(self, rect: rl.Rectangle) -> None: - if not self._allow_e2e_alerts or (self._e2e_alert_display_timer <= 0 and not (self._standstill_timer and self._is_standstill)): + if not self._allow_e2e_alerts or (self._e2e_alert_display_timer <= 0 and not (ui_state.standstill_timer and self._is_standstill)): return e2e_alert_size = 250 @@ -91,7 +89,7 @@ class CircularAlertsRenderer: is_pulsing = (self._e2e_alert_frame % gui_app.target_fps) < (gui_app.target_fps / 2.5) # Standstill Timer (STOPPED) should be static white - if self._e2e_alert_display_timer == 0 and self._standstill_timer and self._is_standstill: + if self._e2e_alert_display_timer == 0 and ui_state.standstill_timer and self._is_standstill: frame_color = rl.Color(255, 255, 255, 75) else: frame_color = rl.Color(255, 255, 255, 75) if is_pulsing else rl.Color(0, 255, 0, 75) @@ -121,7 +119,7 @@ class CircularAlertsRenderer: # Draw lines upwards from bottom current_y = bottom_y - (len(lines) * text_size * FONT_SCALE) - if self._e2e_alert_display_timer == 0 and self._standstill_timer and self._is_standstill: + if self._e2e_alert_display_timer == 0 and ui_state.standstill_timer and self._is_standstill: # Standstill Timer Text alert_alt_text = "STOPPED" top_text_size = 80 diff --git a/selfdrive/ui/sunnypilot/onroad/hud_renderer.py b/selfdrive/ui/sunnypilot/onroad/hud_renderer.py index 3b810d62e..d8ba4b8bf 100644 --- a/selfdrive/ui/sunnypilot/onroad/hud_renderer.py +++ b/selfdrive/ui/sunnypilot/onroad/hud_renderer.py @@ -59,6 +59,4 @@ class HudRendererSP(HudRenderer): self.smart_cruise_control_renderer.render(rect) self.turn_signal_controller.render(rect) self.circular_alerts_renderer.render(rect) - - if ui_state.rocket_fuel: - self.rocket_fuel.render(rect, ui_state.sm) + self.rocket_fuel.render(rect, ui_state.sm) diff --git a/selfdrive/ui/sunnypilot/onroad/road_name.py b/selfdrive/ui/sunnypilot/onroad/road_name.py index 652e620ad..f85285ef5 100644 --- a/selfdrive/ui/sunnypilot/onroad/road_name.py +++ b/selfdrive/ui/sunnypilot/onroad/road_name.py @@ -31,7 +31,7 @@ class RoadNameRenderer(Widget): self.road_name = lmd.roadName def _render(self, rect: rl.Rectangle): - if not self.road_name: + if not self.road_name or not ui_state.road_name_toggle: return text = self.road_name diff --git a/selfdrive/ui/sunnypilot/onroad/rocket_fuel.py b/selfdrive/ui/sunnypilot/onroad/rocket_fuel.py index af25711a9..cb1012890 100644 --- a/selfdrive/ui/sunnypilot/onroad/rocket_fuel.py +++ b/selfdrive/ui/sunnypilot/onroad/rocket_fuel.py @@ -6,12 +6,17 @@ See the LICENSE.md file in the root directory for more details. """ import pyray as rl +from openpilot.selfdrive.ui.ui_state import ui_state + class RocketFuel: def __init__(self): self.vc_accel = 0.0 def render(self, rect: rl.Rectangle, sm) -> None: + if not ui_state.rocket_fuel: + return + vc_accel0 = sm['carState'].aEgo # Smooth the acceleration diff --git a/selfdrive/ui/sunnypilot/onroad/turn_signal.py b/selfdrive/ui/sunnypilot/onroad/turn_signal.py index 3a66ffeb0..04fff7db7 100644 --- a/selfdrive/ui/sunnypilot/onroad/turn_signal.py +++ b/selfdrive/ui/sunnypilot/onroad/turn_signal.py @@ -137,6 +137,9 @@ class TurnSignalController: self._right_signal.deactivate() def render(self, rect: rl.Rectangle): + if not ui_state.turn_signals: + return + x = rect.x + rect.width / 2 left_x = x - self._config.left_x - self._config.size diff --git a/selfdrive/ui/sunnypilot/ui_state.py b/selfdrive/ui/sunnypilot/ui_state.py index 6d7eab51c..6403157d5 100644 --- a/selfdrive/ui/sunnypilot/ui_state.py +++ b/selfdrive/ui/sunnypilot/ui_state.py @@ -120,22 +120,23 @@ class UIStateSP: CP_SP_bytes = self.params.get("CarParamsSPPersistent") if CP_SP_bytes is not None: self.CP_SP = messaging.log_from_bytes(CP_SP_bytes, custom.CarParamsSP) - self.sunnylink_enabled = self.params.get_bool("SunnylinkEnabled") - self.developer_ui = self.params.get("DevUIInfo") - self.rocket_fuel = self.params.get_bool("RocketFuel") - self.rainbow_path = self.params.get_bool("RainbowMode") - self.chevron_metrics = self.params.get("ChevronInfo") - self.torque_bar = self.params.get_bool("TorqueBar") self.active_bundle = self.params.get("ModelManager_ActiveBundle") + self.blindspot = self.params.get_bool("BlindSpot") + self.chevron_metrics = self.params.get("ChevronInfo") self.custom_interactive_timeout = self.params.get("InteractivityTimeout", return_default=True) - self.speed_limit_mode = self.params.get("SpeedLimitMode", return_default=True) - self.standstill_timer = self.params.get_bool("StandstillTimer") - self.true_v_ego_ui = self.params.get_bool("TrueVEgoUI") + self.developer_ui = self.params.get("DevUIInfo") self.hide_v_ego_ui = self.params.get_bool("HideVEgoUI") - - # 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) + self.rainbow_path = self.params.get_bool("RainbowMode") + self.road_name_toggle = self.params.get_bool("RoadNameToggle") + self.rocket_fuel = self.params.get_bool("RocketFuel") + self.speed_limit_mode = self.params.get("SpeedLimitMode", return_default=True) + self.standstill_timer = self.params.get_bool("StandstillTimer") + self.sunnylink_enabled = self.params.get_bool("SunnylinkEnabled") + self.torque_bar = self.params.get_bool("TorqueBar") + self.true_v_ego_ui = self.params.get_bool("TrueVEgoUI") + self.turn_signals = self.params.get_bool("ShowTurnSignals") class DeviceSP: diff --git a/sunnypilot/sunnylink/params_metadata.json b/sunnypilot/sunnylink/params_metadata.json index 090beb49f..c0c84eac0 100644 --- a/sunnypilot/sunnylink/params_metadata.json +++ b/sunnypilot/sunnylink/params_metadata.json @@ -90,8 +90,8 @@ "description": "" }, "BlindSpot": { - "title": "Blind Spot Detection", - "description": "" + "title": "[TIZI/TICI only] Blind Spot Detection", + "description": "Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported." }, "BlinkerMinLateralControlSpeed": { "title": "Blinker Min Lateral Control Speed", @@ -339,8 +339,8 @@ "description": "" }, "GreenLightAlert": { - "title": "Green Light Alert", - "description": "" + "title": "Green Traffic Light Alert (Beta)", + "description": "A chime and on-screen alert (TIZI/TICI only) will play when the traffic light you are waiting for turns green and you have no vehicle in front of you.
Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly." }, "GsmApn": { "title": "GSM APN", @@ -367,8 +367,8 @@ "description": "" }, "HideVEgoUI": { - "title": "Hide vEgo UI", - "description": "" + "title": "[TIZI/TICI only] Speedometer: Hide from Onroad Screen", + "description": "When enabled, the speedometer on the onroad screen is not displayed." }, "HyundaiLongitudinalTuning": { "title": "Hyundai Longitudinal Tuning", @@ -585,8 +585,8 @@ "description": "" }, "LeadDepartAlert": { - "title": "Lead Depart Alert", - "description": "" + "title": "Lead Departure Alert (Beta)", + "description": "A chime and on-screen alert (TIZI/TICI only) will play when you are stopped, and the vehicle in front of you start moving.
Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly." }, "LiveDelay": { "title": "Live Delay", @@ -1079,12 +1079,12 @@ "description": "" }, "RoadNameToggle": { - "title": "Display Road Name", - "description": "" + "title": "[TIZI/TICI only] Display Road Name", + "description": "Displays the name of the road the car is traveling on.
The OpenStreetMap database of the location must be downloaded to fetch the road name." }, "RocketFuel": { - "title": "Display Rocket Fuel Bar", - "description": "Show an indicator on the left side of the screen to display real-time vehicle acceleration and deceleration." + "title": "[TIZI/TICI only] Real-time Acceleration Bar", + "description": "Show an indicator on the left side of the screen to display real-time vehicle acceleration and deceleration. This displays what the car is currently doing, not what the planner is requesting." }, "RouteCount": { "title": "Route Count", @@ -1103,8 +1103,8 @@ "description": "" }, "ShowTurnSignals": { - "title": "Show Turn Signals", - "description": "" + "title": "[TIZI/TICI only] Display Turn Signals", + "description": "When enabled, visual turn indicators are drawn on the HUD." }, "SmartCruiseControlMap": { "title": "Smart Cruise Control - Map", @@ -1196,8 +1196,8 @@ "description": "" }, "StandstillTimer": { - "title": "Standstill Timer", - "description": "" + "title": "[TIZI/TICI only] Standstill Timer", + "description": "Show a timer on the HUD when the car is at a standstill." }, "SubaruStopAndGo": { "title": "Subaru Stop and Go", @@ -1240,8 +1240,8 @@ "description": "" }, "TorqueBar": { - "title": "Steering Arc", - "description": "[TIZI/TICI only] Display steering arc on the driving screen when lateral control is enabled." + "title": "[TIZI/TICI only] Steering Arc", + "description": "Display steering arc on the driving screen when lateral control is enabled." }, "TorqueParamsOverrideEnabled": { "title": "Manual Real-Time Tuning", @@ -1271,8 +1271,8 @@ "description": "" }, "TrueVEgoUI": { - "title": "True vEgo UI", - "description": "" + "title": "[TIZI/TICI only] Speedometer: Always Display True Speed", + "description": "For applicable vehicles, always display the true vehicle current speed from wheel speed sensors." }, "UbloxAvailable": { "title": "Ublox Available",