mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-20 07:43:48 +08:00
optimize
This commit is contained in:
@@ -4,13 +4,16 @@ from pathlib import Path
|
||||
MIN_DATE = datetime.datetime(year=2025, month=2, day=21)
|
||||
MAX_DATE = datetime.datetime(year=2035, month=1, day=1)
|
||||
|
||||
def _utc_now_naive():
|
||||
return datetime.datetime.now(datetime.UTC).replace(tzinfo=None)
|
||||
|
||||
def min_date():
|
||||
# on systemd systems, the default time is the systemd build time
|
||||
systemd_path = Path("/lib/systemd/systemd")
|
||||
if systemd_path.exists():
|
||||
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime)
|
||||
d = datetime.datetime.fromtimestamp(systemd_path.stat().st_mtime, datetime.UTC).replace(tzinfo=None)
|
||||
return max(MIN_DATE, d + datetime.timedelta(days=1))
|
||||
return MIN_DATE
|
||||
|
||||
def system_time_valid():
|
||||
return min_date() < datetime.datetime.now() < MAX_DATE
|
||||
return min_date() < _utc_now_naive() < MAX_DATE
|
||||
|
||||
+2
-1
@@ -43,7 +43,8 @@ if __name__ == '__main__':
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
for directory in DIRS:
|
||||
shutil.copytree(BASEDIR + '/' + directory, tmp + '/' + directory, symlinks=False, dirs_exist_ok=True, copy_function=copy)
|
||||
shutil.copytree(BASEDIR + '/' + directory, tmp + '/' + directory, symlinks=False, ignore_dangling_symlinks=True,
|
||||
dirs_exist_ok=True, copy_function=copy)
|
||||
entry = f'{args.module}:{args.entrypoint}'
|
||||
zipapp.create_archive(tmp, target=args.output, interpreter=INTERPRETER, main=entry)
|
||||
|
||||
|
||||
@@ -584,6 +584,23 @@ def test_route_listing_uses_all_segment_times_when_segment_zero_was_touched(tmp_
|
||||
assert end == "2026-07-18T07:22:00"
|
||||
|
||||
|
||||
def test_route_listing_prefers_logged_time_after_offline_clock_reset(tmp_path, monkeypatch):
|
||||
route_start = utilities.datetime(2026, 7, 18, 7, 19, 0)
|
||||
route_name = "000011e3--6e01289631"
|
||||
segment = tmp_path / f"{route_name}--0"
|
||||
segment.mkdir()
|
||||
(segment / "qlog.zst").write_bytes(b"placeholder")
|
||||
|
||||
stale_time = utilities.datetime(2025, 7, 18, 7, 20, 0).timestamp()
|
||||
os.utime(segment, (stale_time, stale_time))
|
||||
monkeypatch.setattr(utilities, "_route_logged_start_time", lambda _path: route_start)
|
||||
|
||||
routes = utilities._list_dashboard_routes([tmp_path])
|
||||
|
||||
assert routes[0]["startedAt"] == route_start
|
||||
assert routes[0]["timeSource"] == utilities.DASHBOARD_TIME_SOURCE_LOG
|
||||
|
||||
|
||||
def test_top_models_are_ranked_from_persisted_usage_not_favorites():
|
||||
params = FakeParams({
|
||||
"AvailableModels": "orion,vega,atlas,nova",
|
||||
|
||||
@@ -994,9 +994,18 @@ def _select_dashboard_segment_candidate(candidates):
|
||||
return next((candidate for candidate in candidates if _segment_has_dashboard_log(candidate)), candidates[0])
|
||||
|
||||
|
||||
def _estimate_route_started_at(segments):
|
||||
def _estimate_route_start_details(segments):
|
||||
estimates = []
|
||||
time_source = DASHBOARD_TIME_SOURCE_FILESYSTEM
|
||||
for segment in segments:
|
||||
log_path = get_route_log_path(segment.get("path"))
|
||||
if log_path is not None:
|
||||
logged_time = _route_logged_start_time(log_path)
|
||||
if logged_time is not None and _dashboard_time_is_valid(logged_time, require_recent=True):
|
||||
estimates.append(logged_time.timestamp())
|
||||
time_source = DASHBOARD_TIME_SOURCE_LOG
|
||||
continue
|
||||
|
||||
segment_num = max(0, _safe_int(segment.get("num", 0), 0))
|
||||
# Segment directory mtimes normally land at the end of their one-minute segment.
|
||||
estimate = _segment_mtime(segment.get("path")) - (segment_num + 1) * 60
|
||||
@@ -1004,7 +1013,11 @@ def _estimate_route_started_at(segments):
|
||||
if parsed is not None:
|
||||
estimates.append(parsed.timestamp())
|
||||
# Dashboard analysis can touch a segment directory later, but cannot make it older.
|
||||
return datetime.fromtimestamp(min(estimates)) if estimates else None
|
||||
return (datetime.fromtimestamp(min(estimates)), time_source) if estimates else (None, "")
|
||||
|
||||
|
||||
def _estimate_route_started_at(segments):
|
||||
return _estimate_route_start_details(segments)[0]
|
||||
|
||||
|
||||
def _list_dashboard_routes(footage_paths, limit=DASHBOARD_ROUTE_SCAN_LIMIT):
|
||||
@@ -1049,7 +1062,7 @@ def _list_dashboard_routes(footage_paths, limit=DASHBOARD_ROUTE_SCAN_LIMIT):
|
||||
if not segments:
|
||||
continue
|
||||
|
||||
started_at = _estimate_route_started_at(segments)
|
||||
started_at, time_source = _estimate_route_start_details(segments)
|
||||
|
||||
route_infos.append({
|
||||
"name": route["name"],
|
||||
@@ -1057,7 +1070,7 @@ def _list_dashboard_routes(footage_paths, limit=DASHBOARD_ROUTE_SCAN_LIMIT):
|
||||
"segmentCount": len(segments),
|
||||
"startedAt": started_at,
|
||||
"modifiedAt": route["modified_at"],
|
||||
"timeSource": DASHBOARD_TIME_SOURCE_FILESYSTEM if started_at is not None else "",
|
||||
"timeSource": time_source,
|
||||
})
|
||||
|
||||
route_infos.sort(key=lambda route: (
|
||||
@@ -2901,6 +2914,37 @@ def get_route_log_path(path):
|
||||
return None
|
||||
|
||||
|
||||
def _route_logged_start_time(log_path, reader=None):
|
||||
"""Recover a route's wall-clock start when filesystem time was reset at boot."""
|
||||
try:
|
||||
if reader is None:
|
||||
from openpilot.tools.lib.logreader import _LogFileReader
|
||||
reader = _LogFileReader(str(log_path))
|
||||
|
||||
first_mono_time = None
|
||||
for message in reader:
|
||||
mono_time = _safe_float(getattr(message, "logMonoTime", 0), 0.0) / 1e9
|
||||
if mono_time <= 0.0:
|
||||
continue
|
||||
first_mono_time = mono_time if first_mono_time is None else min(first_mono_time, mono_time)
|
||||
|
||||
message_type = _message_type(message)
|
||||
payload = _message_payload(message, message_type)
|
||||
wall_time = _wall_time_seconds_from_payload(payload)
|
||||
if wall_time is None:
|
||||
wall_time = _wall_time_seconds_from_payload(message)
|
||||
if wall_time is None:
|
||||
continue
|
||||
|
||||
start_seconds = wall_time - (mono_time - first_mono_time)
|
||||
start_time = datetime.fromtimestamp(start_seconds)
|
||||
if _dashboard_time_is_valid(start_time):
|
||||
return start_time
|
||||
except Exception:
|
||||
return None
|
||||
return None
|
||||
|
||||
|
||||
def get_route_start_time(path):
|
||||
log_path = get_route_log_path(path)
|
||||
if log_path is None:
|
||||
@@ -2917,6 +2961,10 @@ def get_route_start_time(path):
|
||||
if modified_time <= 0:
|
||||
return None
|
||||
|
||||
logged_time = _route_logged_start_time(log_path)
|
||||
if logged_time is not None:
|
||||
return logged_time
|
||||
|
||||
return datetime.fromtimestamp(modified_time)
|
||||
|
||||
def get_routes_names(footage_path):
|
||||
|
||||
@@ -85,6 +85,11 @@ def snapshot(allow_existing=False, include_front=None):
|
||||
set_offroad_alert("Offroad_IsTakingSnapshot", True)
|
||||
time.sleep(2.0) # Give hardwared time to read the param, or if just started give camerad time to start
|
||||
|
||||
if not params.get_bool("IsOffroad"):
|
||||
params.put_bool("IsTakingSnapshot", False)
|
||||
set_offroad_alert("Offroad_IsTakingSnapshot", False)
|
||||
return None, None
|
||||
|
||||
# Check if camerad is already started
|
||||
camerad_already_running = False
|
||||
try:
|
||||
@@ -106,6 +111,8 @@ def snapshot(allow_existing=False, include_front=None):
|
||||
frame = "wideRoadCameraState"
|
||||
front_frame = "driverCameraState" if front_camera_allowed else None
|
||||
rear, front = get_snapshots(frame, front_frame)
|
||||
if not params.get_bool("IsOffroad"):
|
||||
rear, front = None, None
|
||||
finally:
|
||||
if not camerad_already_running:
|
||||
managed_processes['camerad'].stop()
|
||||
|
||||
@@ -69,7 +69,7 @@ def sensord_run(started: bool, params: Params, CP: car.CarParams, starpilot_togg
|
||||
return started or params.get_bool("SentryModeEnabled")
|
||||
|
||||
def camera_run(started: bool, params: Params, CP: car.CarParams, starpilot_toggles: SimpleNamespace) -> bool:
|
||||
return driverview(started, params, CP, starpilot_toggles) or params.get_bool("SentryModeCapture")
|
||||
return driverview(started, params, CP, starpilot_toggles) or (not started and params.get_bool("SentryModeCapture"))
|
||||
|
||||
def livestream(started: bool, params: Params, CP: car.CarParams, starpilot_toggles: SimpleNamespace) -> bool:
|
||||
return params.get_bool("IsLiveStreaming")
|
||||
|
||||
@@ -3,7 +3,7 @@ from types import SimpleNamespace
|
||||
import pytest
|
||||
|
||||
from cereal import car
|
||||
from openpilot.system.manager.process_config import allow_uploads, managed_processes
|
||||
from openpilot.system.manager.process_config import allow_uploads, camera_run, managed_processes, sentry_mode
|
||||
|
||||
|
||||
class FakeParams:
|
||||
@@ -36,3 +36,38 @@ def test_allow_uploads(started, no_uploads, no_onroad_uploads, always_allow_uplo
|
||||
|
||||
def test_uploader_runs_at_background_priority():
|
||||
assert managed_processes["uploader"].nice == 19
|
||||
|
||||
|
||||
class CameraParams:
|
||||
def __init__(self, capture: bool):
|
||||
self.capture = capture
|
||||
|
||||
def get_bool(self, key: str) -> bool:
|
||||
assert key in {"IsDriverViewEnabled", "SentryModeCapture"}
|
||||
return self.capture if key == "SentryModeCapture" else False
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"started,capture,expected",
|
||||
[
|
||||
(False, True, True),
|
||||
(False, False, False),
|
||||
(True, False, True),
|
||||
],
|
||||
)
|
||||
def test_camera_run_preserves_onroad_camera_and_offroad_sentry_capture(started, capture, expected):
|
||||
assert camera_run(started, CameraParams(capture), car.CarParams.new_message(), SimpleNamespace()) is expected
|
||||
|
||||
|
||||
class SentryParams:
|
||||
def __init__(self, enabled: bool):
|
||||
self.enabled = enabled
|
||||
|
||||
def get_bool(self, key: str) -> bool:
|
||||
assert key == "SentryModeEnabled"
|
||||
return self.enabled
|
||||
|
||||
|
||||
@pytest.mark.parametrize("started,enabled,expected", [(True, True, False), (False, True, True), (False, False, False)])
|
||||
def test_sentry_process_is_offroad_only(started, enabled, expected):
|
||||
assert sentry_mode(started, SentryParams(enabled), car.CarParams.new_message(), SimpleNamespace()) is expected
|
||||
|
||||
@@ -49,7 +49,7 @@ def _utc_now() -> str:
|
||||
class SentryMode:
|
||||
def __init__(self, params: Params | None = None, sm=None, clock=time.monotonic):
|
||||
self.params = params or Params(return_defaults=True)
|
||||
self.sm = sm or messaging.SubMaster(["accelerometer"])
|
||||
self.sm = sm if sm is not None else messaging.SubMaster(["accelerometer", "deviceState"])
|
||||
self.clock = clock
|
||||
self.detector = MotionDetector(
|
||||
sensitivity=SENSITIVITY,
|
||||
@@ -63,6 +63,13 @@ class SentryMode:
|
||||
self.armed = False
|
||||
self._last_status = None
|
||||
|
||||
def _is_onroad(self) -> bool:
|
||||
try:
|
||||
device_state = self.sm["deviceState"]
|
||||
except (KeyError, TypeError, AttributeError):
|
||||
return False
|
||||
return device_state is not None and bool(getattr(device_state, "started", False))
|
||||
|
||||
def _write_status(self, state: str, **extra) -> None:
|
||||
status_values = {"state": state, **extra}
|
||||
if status_values == self._last_status:
|
||||
@@ -132,6 +139,9 @@ class SentryMode:
|
||||
threading.Thread(target=publish, name="sentryd-galaxy-publish", daemon=True).start()
|
||||
|
||||
def _handle_detection(self, kind: str) -> None:
|
||||
if self._is_onroad():
|
||||
return
|
||||
|
||||
event_id = f"{int(time.time())}-{uuid4().hex[:8]}"
|
||||
event = {
|
||||
"eventId": event_id,
|
||||
@@ -147,6 +157,10 @@ class SentryMode:
|
||||
self._publish_event(event)
|
||||
|
||||
def update(self) -> None:
|
||||
if self._is_onroad():
|
||||
self._write_status("disabled", reason="onroad")
|
||||
return
|
||||
|
||||
now = self.clock()
|
||||
if now - self.started_at < ARM_DELAY_SECONDS:
|
||||
self._write_status("arming", secondsRemaining=max(0, int(ARM_DELAY_SECONDS - (now - self.started_at))))
|
||||
@@ -174,6 +188,9 @@ class SentryMode:
|
||||
self._write_status("starting")
|
||||
while self.params.get_bool("SentryModeEnabled"):
|
||||
self.sm.update(0)
|
||||
if self._is_onroad():
|
||||
self._write_status("disabled", reason="onroad")
|
||||
break
|
||||
self.update()
|
||||
time.sleep(LOOP_INTERVAL_SECONDS)
|
||||
self._write_status("disabled")
|
||||
|
||||
Reference in New Issue
Block a user