IQ.Pilot Release Commit @ 67fd9c2

This commit is contained in:
IQ.Lvbs CI [bot]
2026-09-01 20:09:51 -05:00
parent f8f9335ba3
commit 4efaff4cb2
58 changed files with 494 additions and 92 deletions

View File

@@ -152,7 +152,7 @@ class MainLayout(Widget):
self._layouts[MainState.ROUTES].set_on_play(self.open_video)
self._layouts[MainState.VIDEO].set_on_back(self.open_routes)
self._layouts[MainState.ONROAD].set_click_callback(self._on_onroad_clicked)
device.add_interactive_timeout_callback(self._set_mode_for_state)
device.add_interactive_timeout_callback(self._on_interactive_timeout)
def _update_layout_rects(self):
self._sidebar_rect = rl.Rectangle(self._rect.x, self._rect.y, SIDEBAR_WIDTH, self._rect.height)
@@ -166,6 +166,20 @@ class MainLayout(Widget):
self._set_mode_for_state()
def _car_stationary(self) -> bool:
if not ui_state.sm.valid["carState"]:
return False
return ui_state.sm["carState"].vEgo < 0.1
def _on_interactive_timeout(self):
# The idle timeout normally returns the UI to the road view. Don't yank the user out of Settings
# while the car is stationary - e.g. a hybrid parked with the engine running to charge reads as
# onroad (ignition tracks the ICE), so this would otherwise make Settings unusable while parked.
# A moving car still returns to the road view.
if self._current_mode == MainState.SETTINGS and ui_state.started and self._car_stationary():
return
self._set_mode_for_state()
def _set_mode_for_state(self):
if ui_state.started:
# Don't hide sidebar from interactive timeout

View File

@@ -0,0 +1,56 @@
from types import SimpleNamespace
import pytest
from iqpilot.selfdrive.ui.layouts.main import MainLayout, MainState
def make_layout(current_mode):
layout = object.__new__(MainLayout)
layout._current_mode = current_mode
layout._set_mode_calls = []
layout._set_mode_for_state = lambda: layout._set_mode_calls.append(current_mode)
return layout
class FakeSm:
def __init__(self, v_ego, carstate_valid):
self.valid = {"carState": carstate_valid}
self._v_ego = v_ego
def __getitem__(self, key):
return SimpleNamespace(vEgo=self._v_ego)
class TestSettingsInteractiveTimeout:
def _run(self, current_mode, started, v_ego, carstate_valid=True):
layout = make_layout(current_mode)
fake = SimpleNamespace(started=started, sm=FakeSm(v_ego, carstate_valid))
monkeypatch = pytest.MonkeyPatch()
monkeypatch.setattr("iqpilot.selfdrive.ui.layouts.main.ui_state", fake)
try:
layout._on_interactive_timeout()
finally:
monkeypatch.undo()
return layout._set_mode_calls
def test_stationary_in_settings_stays(self):
# parked/charging hybrid reads onroad; the timeout must not eject from Settings
assert self._run(MainState.SETTINGS, started=True, v_ego=0.0) == []
def test_moving_in_settings_returns_to_road(self):
assert self._run(MainState.SETTINGS, started=True, v_ego=5.0) == [MainState.SETTINGS]
def test_onroad_layout_always_handled(self):
assert self._run(MainState.ONROAD, started=True, v_ego=0.0) == [MainState.ONROAD]
def test_home_layout_always_handled(self):
assert self._run(MainState.HOME, started=True, v_ego=0.0) == [MainState.HOME]
def test_offroad_in_settings_handled(self):
# car off (offroad): existing behavior is unchanged
assert self._run(MainState.SETTINGS, started=False, v_ego=0.0) == [MainState.SETTINGS]
def test_invalid_carstate_treated_as_moving(self):
# if speed is unknown, fail safe to the road view rather than trapping in settings
assert self._run(MainState.SETTINGS, started=True, v_ego=0.0, carstate_valid=False) == [MainState.SETTINGS]