timed: always pull time and timezone from GPS (#31112)
* timed * rm timezoned * just gps * ok * little more * fix * datetime * sleep a little --------- Co-authored-by: Comma Device <device@comma.ai>pull/31118/head
parent
389b8ca30d
commit
827aa2e4fa
6 changed files with 97 additions and 74 deletions
@ -0,0 +1,94 @@ |
|||||||
|
#!/usr/bin/env python3 |
||||||
|
import datetime |
||||||
|
import os |
||||||
|
import subprocess |
||||||
|
import time |
||||||
|
from typing import NoReturn |
||||||
|
|
||||||
|
from timezonefinder import TimezoneFinder |
||||||
|
|
||||||
|
import cereal.messaging as messaging |
||||||
|
from openpilot.common.params import Params |
||||||
|
from openpilot.common.swaglog import cloudlog |
||||||
|
from openpilot.system.hardware import AGNOS |
||||||
|
|
||||||
|
|
||||||
|
def set_timezone(timezone): |
||||||
|
valid_timezones = subprocess.check_output('timedatectl list-timezones', shell=True, encoding='utf8').strip().split('\n') |
||||||
|
if timezone not in valid_timezones: |
||||||
|
cloudlog.error(f"Timezone not supported {timezone}") |
||||||
|
return |
||||||
|
|
||||||
|
cloudlog.debug(f"Setting timezone to {timezone}") |
||||||
|
try: |
||||||
|
if AGNOS: |
||||||
|
tzpath = os.path.join("/usr/share/zoneinfo/", timezone) |
||||||
|
subprocess.check_call(f'sudo su -c "ln -snf {tzpath} /data/etc/tmptime && \ |
||||||
|
mv /data/etc/tmptime /data/etc/localtime"', shell=True) |
||||||
|
subprocess.check_call(f'sudo su -c "echo \"{timezone}\" > /data/etc/timezone"', shell=True) |
||||||
|
else: |
||||||
|
subprocess.check_call(f'sudo timedatectl set-timezone {timezone}', shell=True) |
||||||
|
except subprocess.CalledProcessError: |
||||||
|
cloudlog.exception(f"Error setting timezone to {timezone}") |
||||||
|
|
||||||
|
|
||||||
|
def set_time(new_time): |
||||||
|
diff = datetime.datetime.now() - new_time |
||||||
|
if 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 two responsibilities: |
||||||
|
- getting the current time |
||||||
|
- getting the current timezone |
||||||
|
|
||||||
|
GPS directly gives time, and timezone is looked up from GPS position. |
||||||
|
AGNOS will also use NTP to update the time. |
||||||
|
""" |
||||||
|
|
||||||
|
params = Params() |
||||||
|
tf = TimezoneFinder() |
||||||
|
|
||||||
|
# Restore timezone from param |
||||||
|
tz = params.get("Timezone", encoding='utf8') |
||||||
|
tf = TimezoneFinder() |
||||||
|
if tz is not None: |
||||||
|
cloudlog.debug("Restoring timezone from param") |
||||||
|
set_timezone(tz) |
||||||
|
|
||||||
|
sm = messaging.SubMaster(['liveLocationKalman']) |
||||||
|
while True: |
||||||
|
sm.update(1000) |
||||||
|
|
||||||
|
llk = sm['liveLocationKalman'] |
||||||
|
if not llk.gpsOK or (time.monotonic() - sm.logMonoTime['liveLocationKalman']/1e9) > 0.2: |
||||||
|
continue |
||||||
|
|
||||||
|
# set time |
||||||
|
# TODO: account for unixTimesatmpMillis being a (usually short) time in the past |
||||||
|
gps_time = datetime.datetime.fromtimestamp(llk.unixTimestampMillis / 1000.) |
||||||
|
set_time(gps_time) |
||||||
|
|
||||||
|
# set timezone |
||||||
|
pos = llk.positionGeodetic.value |
||||||
|
if len(pos) == 3: |
||||||
|
gps_timezone = tf.timezone_at(lat=pos[0], lng=pos[1]) |
||||||
|
if gps_timezone is None: |
||||||
|
cloudlog.critical(f"No timezone found based on {pos=}") |
||||||
|
else: |
||||||
|
set_timezone(gps_timezone) |
||||||
|
params.put_nonblocking("Timezone", gps_timezone) |
||||||
|
|
||||||
|
time.sleep(10) |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
@ -1,70 +0,0 @@ |
|||||||
#!/usr/bin/env python3 |
|
||||||
import json |
|
||||||
import os |
|
||||||
import time |
|
||||||
import subprocess |
|
||||||
from typing import NoReturn |
|
||||||
|
|
||||||
from timezonefinder import TimezoneFinder |
|
||||||
|
|
||||||
from openpilot.common.params import Params |
|
||||||
from openpilot.system.hardware import AGNOS |
|
||||||
from openpilot.common.swaglog import cloudlog |
|
||||||
from openpilot.system.version import get_version |
|
||||||
|
|
||||||
REQUEST_HEADERS = {'User-Agent': "openpilot-" + get_version()} |
|
||||||
|
|
||||||
|
|
||||||
def set_timezone(valid_timezones, timezone): |
|
||||||
if timezone not in valid_timezones: |
|
||||||
cloudlog.error(f"Timezone not supported {timezone}") |
|
||||||
return |
|
||||||
|
|
||||||
cloudlog.info(f"Setting timezone to {timezone}") |
|
||||||
try: |
|
||||||
if AGNOS: |
|
||||||
tzpath = os.path.join("/usr/share/zoneinfo/", timezone) |
|
||||||
subprocess.check_call(f'sudo su -c "ln -snf {tzpath} /data/etc/tmptime && \ |
|
||||||
mv /data/etc/tmptime /data/etc/localtime"', shell=True) |
|
||||||
subprocess.check_call(f'sudo su -c "echo \"{timezone}\" > /data/etc/timezone"', shell=True) |
|
||||||
else: |
|
||||||
subprocess.check_call(f'sudo timedatectl set-timezone {timezone}', shell=True) |
|
||||||
except subprocess.CalledProcessError: |
|
||||||
cloudlog.exception(f"Error setting timezone to {timezone}") |
|
||||||
|
|
||||||
|
|
||||||
def main() -> NoReturn: |
|
||||||
params = Params() |
|
||||||
tf = TimezoneFinder() |
|
||||||
|
|
||||||
# Get allowed timezones |
|
||||||
valid_timezones = subprocess.check_output('timedatectl list-timezones', shell=True, encoding='utf8').strip().split('\n') |
|
||||||
|
|
||||||
timezone = params.get("Timezone", encoding='utf8') |
|
||||||
if timezone is not None: |
|
||||||
cloudlog.debug("Setting timezone based on param") |
|
||||||
set_timezone(valid_timezones, timezone) |
|
||||||
|
|
||||||
while True: |
|
||||||
time.sleep(60) |
|
||||||
|
|
||||||
location = params.get("LastGPSPosition", encoding='utf8') |
|
||||||
|
|
||||||
# Find timezone by reverse geocoding the last known gps location |
|
||||||
if location is not None: |
|
||||||
cloudlog.debug("Setting timezone based on GPS location") |
|
||||||
try: |
|
||||||
location = json.loads(location) |
|
||||||
except Exception: |
|
||||||
cloudlog.exception("Error parsing location") |
|
||||||
continue |
|
||||||
|
|
||||||
timezone = tf.timezone_at(lng=location['longitude'], lat=location['latitude']) |
|
||||||
if timezone is None: |
|
||||||
cloudlog.error(f"No timezone found based on location, {location}") |
|
||||||
continue |
|
||||||
set_timezone(valid_timezones, timezone) |
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__": |
|
||||||
main() |
|
Loading…
Reference in new issue