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>
old-commit-hash: 827aa2e4fa
chrysler-long2
parent
c03fe6bb13
commit
b8fbf60097
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