diff --git a/openpilot/selfdrive/ui/mici/layouts/settings/toggles.py b/openpilot/selfdrive/ui/mici/layouts/settings/toggles.py index 5ad548b163..8a1cc1f56c 100644 --- a/openpilot/selfdrive/ui/mici/layouts/settings/toggles.py +++ b/openpilot/selfdrive/ui/mici/layouts/settings/toggles.py @@ -40,6 +40,8 @@ class TogglesLayoutMici(NavScroller): "Set speed is a maximum, not a target.\n" + "These are alpha features. Expect mistakes.\n" + "The path colors show acceleration and braking.") + disengage_on_accelerator = BigParamControl("disengage on accelerator", "DisengageOnAccelerator", + description="When enabled, pressing the accelerator pedal will disengage openpilot.") self._initial_cruise_speed = InitialCruiseSpeedButton() self._initial_cruise_speed.set_visible(lambda: ui_state.CP is not None and ui_state.has_longitudinal_control and not ui_state.CP.pcmCruise) is_metric_toggle = BigToggle("use metric units", initial_state=ui_state.params.get_bool("IsMetric"), @@ -64,6 +66,7 @@ class TogglesLayoutMici(NavScroller): self._personality_toggle, self._safe_mode_btn, self._experimental_btn, + disengage_on_accelerator, self._initial_cruise_speed, is_metric_toggle, ldw_toggle, @@ -78,6 +81,7 @@ class TogglesLayoutMici(NavScroller): self._refresh_toggles = ( ("SafeMode", self._safe_mode_btn), ("ExperimentalMode", self._experimental_btn), + ("DisengageOnAccelerator", disengage_on_accelerator), ("IsMetric", is_metric_toggle), ("IsLdwEnabled", ldw_toggle), ("AlwaysOnDM", always_on_dm_toggle), diff --git a/openpilot/selfdrive/ui/tests/test_mici_button_layout.py b/openpilot/selfdrive/ui/tests/test_mici_button_layout.py index 3343e430b3..9c160d28d0 100644 --- a/openpilot/selfdrive/ui/tests/test_mici_button_layout.py +++ b/openpilot/selfdrive/ui/tests/test_mici_button_layout.py @@ -42,6 +42,7 @@ def drawn(monkeypatch): lambda: button.BigButton("long branch name that needs to scroll", "installed", scroll=True), lambda: button.BigButton("network", "connected", SimpleNamespace(width=76, height=56)), lambda: button.BigToggle("enable controls", "Off"), + lambda: button.BigToggle("disengage on accelerator"), lambda: button.BigMultiToggle("controller", ["Default", "Custom"]), lambda: button.GreyBigButton("saved settings", "unavailable while driving"), lambda: button.GreyBigButton("", "A full explanation that must retain enough room for several lines of readable text."), diff --git a/openpilot/starpilot/ui/tests/test_c4_toggles.py b/openpilot/starpilot/ui/tests/test_c4_toggles.py index b95521d6ab..b2c430a723 100644 --- a/openpilot/starpilot/ui/tests/test_c4_toggles.py +++ b/openpilot/starpilot/ui/tests/test_c4_toggles.py @@ -45,7 +45,7 @@ class TestC4SafeMode(unittest.TestCase): panel._personality_toggle.set_value.assert_called_once_with("relaxed") -class TestC4AudioToggle(unittest.TestCase): +class TestC4Toggles(unittest.TestCase): def setUp(self): directory = tempfile.TemporaryDirectory() self.addCleanup(directory.cleanup) @@ -62,6 +62,29 @@ class TestC4AudioToggle(unittest.TestCase): self.panel = toggles.TogglesLayoutMici() self.audio = next(item for key, item in self.panel._refresh_toggles if key == "RecordAudio") + def test_accelerator_toggle_saves_shared_param_without_restart(self): + accelerator = dict(self.panel._refresh_toggles)["DisengageOnAccelerator"] + self.assertIn(accelerator, self.panel._scroller.items) + self.assertFalse(accelerator._checked) + for desired in (True, False): + with patch.object(self.params, "put_bool", wraps=self.params.put_bool) as save: + accelerator._handle_mouse_release(MousePos(0, 0)) + save.assert_called_once_with("DisengageOnAccelerator", desired, block=True) + self.assertEqual(self.params.get_bool("DisengageOnAccelerator"), desired) + self.assertEqual(accelerator._checked, desired) + self.assertFalse(self.params.get_bool("OnroadCycleRequested")) + + def test_accelerator_toggle_loads_and_refreshes_saved_value(self): + self.params.put_bool("DisengageOnAccelerator", True, block=True) + panel = toggles.TogglesLayoutMici() + accelerator = dict(panel._refresh_toggles)["DisengageOnAccelerator"] + self.assertTrue(accelerator._checked) + self.params.put_bool("DisengageOnAccelerator", False, block=True) + panel._update_toggles() + self.assertFalse(accelerator._checked) + self.ui.engaged = True + self.assertTrue(accelerator.enabled) + def test_rhd_control_saves_shared_param_and_rejects_open_preview(self): from openpilot.starpilot.galaxy.localization_settings import LocalizationSettingsOwner self.panel._localization = LocalizationSettingsOwner(self.params, lambda: True, lambda: True)