Files
StarPilot/openpilot/starpilot/ui/onroad_stopped_timer.py
T
firestar5683 a82935f326 User interfaces and Android Auto
Integrate onroad views, configurable widgets, local settings, steering-profile contracts, Bluetooth and Android Auto with their device and runtime services.

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
Co-authored-by: Daniel Koepping <elkoled@gmail.com>
Co-authored-by: Danny <dannyirwin31@yahoo.com>
Co-authored-by: DimitriChrysafis <Dimitri.chrysafis@gmail.com>
Co-authored-by: Dom <168790843+firestar5683@users.noreply.github.com>
Co-authored-by: Harald Schäfer <harald.the.engineer@gmail.com>
Co-authored-by: Prabhaav Pillai <prabhaav@msu.edu>
Co-authored-by: Shane Smiskol <shane@smiskol.com>
Co-authored-by: dirwin31 <83434411+dirwin31@users.noreply.github.com>
Co-authored-by: firestarsdog <229254897+firestarsdog@users.noreply.github.com>
Co-authored-by: stef <19478336+stefpi@users.noreply.github.com>
Co-authored-by: whoisdomi <dcantu83@gmail.com>

Co-authored-by: Intelli <contact@intelli.software>
Co-authored-by: pharmacomaniac <blittle65@gmail.com>

Co-authored-by: prabhaavp <prabhaav@msu.edu>
2026-10-14 20:02:39 -05:00

71 lines
2.3 KiB
Python

"""Monotonic, drive-scoped standstill duration for native and Android Auto widgets."""
from dataclasses import dataclass
SHOW_AFTER_DRIVE_NS = 60_000_000_000
SECOND_NS = 1_000_000_000
ENGAGED = (22, 127, 64)
EXPERIMENTAL = (218, 111, 37)
TRAFFIC = (201, 34, 49)
PREVIEW_DURATION_S = 134
def timer_size(profile: str) -> tuple[int, int]:
return (660, 168) if profile == "large" else (440, 112)
@dataclass
class StoppedTimer:
drive_key: tuple[int, int] | None = None
drive_started_ns: int | None = None
standstill_started_ns: int | None = None
last_ns: int | None = None
def reset(self) -> None:
self.drive_key = None
self.drive_started_ns = None
self.standstill_started_ns = None
self.last_ns = None
def step(self, *, now_ns: int, drive_key: tuple[int, int] | None, car_fresh: bool,
standstill: bool, reverse: bool, enabled: bool) -> int | None:
if drive_key is None or (self.last_ns is not None and now_ns < self.last_ns):
self.reset()
if drive_key is None:
return None
self.last_ns = now_ns
if drive_key != self.drive_key:
self.drive_key = drive_key
self.drive_started_ns = now_ns
self.standstill_started_ns = None
if not enabled or not car_fresh or not standstill or reverse:
self.standstill_started_ns = None
return None
if self.standstill_started_ns is None:
self.standstill_started_ns = now_ns
if self.drive_started_ns is None or now_ns - self.drive_started_ns < SHOW_AFTER_DRIVE_NS:
return None
seconds = (now_ns - self.standstill_started_ns) // SECOND_NS
return seconds if seconds > 0 else None
def duration_text(seconds: int) -> tuple[str, str]:
minutes, remainder = divmod(seconds, 60)
return (f"{minutes} minute{'s' if minutes != 1 else ''}",
f"{remainder} second{'s' if remainder != 1 else ''}")
def duration_color(seconds: int) -> tuple[int, int, int]:
if seconds < 60:
return ENGAGED
if seconds < 150:
start, end, amount = ENGAGED, EXPERIMENTAL, (seconds - 60) / 90
elif seconds < 300:
start, end, amount = EXPERIMENTAL, TRAFFIC, (seconds - 150) / 150
else:
return TRAFFIC
return (int(start[0] + amount * (end[0] - start[0])),
int(start[1] + amount * (end[1] - start[1])),
int(start[2] + amount * (end[2] - start[2])))