Files
onepilot/system/timed.py
T
2026-06-06 13:28:56 -05:00

75 lines
2.4 KiB
Python
Executable File

#!/usr/bin/env python3
import datetime
import subprocess
import time
from typing import NoReturn
import cereal.messaging as messaging
from openpilot.common.time_helpers import min_date, system_time_valid
from openpilot.common.swaglog import cloudlog
from openpilot.common.params import Params
from openpilot.common.gps import get_gps_location_service
def set_time(new_time):
diff = datetime.datetime.now() - new_time
if abs(diff) < datetime.timedelta(seconds=10):
cloudlog.debug(f"Time diff too small: {diff}")
return
cloudlog.debug(f"Setting time to {new_time}")
try:
subprocess.run(f"TZ=UTC date -s '{new_time}'", shell=True, check=True)
except subprocess.CalledProcessError:
cloudlog.exception("timed.failed_setting_time")
def main() -> NoReturn:
"""
timed has three responsibilities:
- getting the current time from GPS (primary)
- seeding the time from the vehicle cluster clock as a fallback (RTC-less devices);
the clock is parsed in the car port and published on carState.vehicleClockSeconds
- publishing the time in the logs
AGNOS will also use NTP to update the time, which always wins.
"""
params = Params()
gps_location_service = get_gps_location_service(params)
pm = messaging.PubMaster(['clocks'])
sm = messaging.SubMaster([gps_location_service, 'carState'])
while True:
sm.update(1000)
msg = messaging.new_message('clocks')
msg.valid = system_time_valid()
msg.clocks.wallTimeNanos = time.time_ns()
pm.send('clocks', msg)
# Fallback: seed from the vehicle cluster clock (e.g. VW PQ) only while the time
# is still invalid (no NTP/GPS yet). Once set, system_time_valid() is True and
# this is skipped, leaving GPS/NTP to refine.
if not system_time_valid() and sm.updated['carState']:
secs = sm['carState'].vehicleClockSeconds
if secs > 0:
veh_time = datetime.datetime.fromtimestamp(secs, datetime.timezone.utc).replace(tzinfo=None)
if veh_time >= min_date():
set_time(veh_time)
gps = sm[gps_location_service]
gps_time = datetime.datetime.fromtimestamp(gps.unixTimestampMillis / 1000.)
if not sm.updated[gps_location_service] or (time.monotonic() - sm.logMonoTime[gps_location_service] / 1e9) > 2.0:
continue
if not gps.hasFix:
continue
if gps_time < min_date():
continue
set_time(gps_time)
time.sleep(10)
if __name__ == "__main__":
main()