diff --git a/common/params.cc b/common/params.cc index 0f86435ee1..d02cd57380 100644 --- a/common/params.cc +++ b/common/params.cc @@ -255,8 +255,6 @@ std::unordered_map keys = { {"GapAdjustCruiseMode", PERSISTENT}, {"GapAdjustCruiseTr", PERSISTENT}, {"GmapKey", PERSISTENT}, - {"GpxDeleteAfterUpload", PERSISTENT}, - {"GpxDeleteIfUploaded", PERSISTENT}, {"HandsOnWheelMonitoring", PERSISTENT}, {"HideVEgoUi", PERSISTENT}, {"HkgSmoothStop", PERSISTENT}, diff --git a/selfdrive/gpxd/gpx_uploader.py b/selfdrive/gpxd/gpx_uploader.py deleted file mode 100644 index bb78c65d0b..0000000000 --- a/selfdrive/gpxd/gpx_uploader.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python3 -# The MIT License -# -# Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import os -import time -from common.params import Params -from common.realtime import Ratekeeper -from selfdrive.athena.registration import register -from system.version import get_version - -# for uploader -from system.loggerd.xattr_cache import getxattr, setxattr -import glob -import requests -import json - -RATE = 1 - -# customisable values -GPX_LOG_PATH = '/data/media/0/gpx_logs/' -LOG_HERTZ = 1/10 # 0.1 Hz = 10 sec, higher for higher accuracy, 10hz seems fine - -# uploader -UPLOAD_ATTR_NAME = 'user.upload' -UPLOAD_ATTR_VALUE = b'1' -LOG_PATH = '/data/media/0/gpx_logs/' - -# osm api -VERSION_URL = 'https://api.openstreetmap.org/api/versions' -UPLOAD_URL = 'https://sunnypilot.com/osm/gpx_uploader.php' - -_DEBUG = False - - -def _debug(msg): - if not _DEBUG: - return - print(msg, flush=True) - - -def _get_is_uploaded(filename): - _debug("%s is uploaded: %s" % (filename, getxattr(filename, UPLOAD_ATTR_NAME) is not None)) - return getxattr(filename, UPLOAD_ATTR_NAME) is not None - - -def _set_is_uploaded(filename): - _debug("%s set to uploaded" % filename) - setxattr(filename, UPLOAD_ATTR_NAME, UPLOAD_ATTR_VALUE) - - -def _get_files_to_be_uploaded(): - files = sorted(filter(os.path.isfile, glob.glob(LOG_PATH + '*'))) - files_to_be_uploaded = [] - for file in files: - if not _get_is_uploaded(file): - files_to_be_uploaded.append(file) - return files_to_be_uploaded - - -class GpxUploader(): - def __init__(self): - self.param_s = Params() - self.rk = Ratekeeper(RATE, print_delay_threshold=None) - - self._delete_after_upload = self.param_s.get_bool('GpxDeleteAfterUpload') - self._car_model = "Unknown Model" - # read model from LiveParameters - params = self.param_s.get("LiveParameters") - if params is not None: - params = json.loads(params) - self._car_model = params.get('carFingerprint', self._car_model) - self._sp_version = get_version() - _debug("GpxUploader init - _delete_after_upload = %s" % self._delete_after_upload) - _debug("GpxUploader init - _car_model = %s" % self._car_model) - self.api_headers = {"User-Agent": f"sunnypilot-{self._sp_version}-{register()}"} - - def update(self): - while True: - files = _get_files_to_be_uploaded() - if len(files) == 0 or not self._is_online(): - _debug("run - not online or no files") - elif not self.param_s.get_bool("DisableOnroadUploads") or self.param_s.get_bool("IsOffroad"): - for file in files: - if self._do_upload(file): - if self._delete_after_upload: - _debug("run - _delete_after_upload") - os.remove(file) - else: - _debug("run - set_is_uploaded") - _set_is_uploaded(file) - # sleep for 300 secs if offroad - # otherwise sleep 60 secs - time.sleep(300 if self.param_s.get_bool("IsOffroad") else 60) - self.rk.keep_time() - - def _is_online(self): - try: - r = requests.get(VERSION_URL, headers=self.api_headers) - _debug("is_online? status_code = %s" % r.status_code) - return r.status_code >= 200 - except Exception as e: - print(f'Online check error: {e}') - return False - - def _do_upload(self, filename): - fn = os.path.basename(filename) - data = { - 'description': "Routes from sunnypilot %s (%s)." % (self._sp_version, self._car_model), - 'visibility': 'identifiable' - } - files = { - "file": (fn, open(filename, 'rb')) - } - try: - r = requests.post(UPLOAD_URL, files=files, data=data, headers=self.api_headers) - _debug("do_upload - %s - %s" % (filename, r.status_code)) - return r.status_code == 200 - except Exception as e: - print(f'Upload error: {e}') - return False - - -def main(): - gpx_uploader = GpxUploader() - gpx_uploader.update() - - -if __name__ == "__main__": - main() diff --git a/selfdrive/gpxd/gpxd.py b/selfdrive/gpxd/gpxd.py deleted file mode 100644 index d1e1810b4a..0000000000 --- a/selfdrive/gpxd/gpxd.py +++ /dev/null @@ -1,174 +0,0 @@ -#!/usr/bin/env python3 -# The MIT License -# -# Copyright (c) 2019-, Rick Lan, dragonpilot community, and a number of other of contributors. -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -# THE SOFTWARE. - -import cereal.messaging as messaging -import os -import datetime -import signal -import threading -from common.realtime import Ratekeeper -from cereal import log -from system.swaglog import cloudlog - -# customisable values -GPX_LOG_PATH = '/data/media/0/gpx_logs/' -LOG_HERTZ = 10 # 10 hz = 0.1 sec, higher for higher accuracy, 10hz seems fine -LOG_LENGTH = 10 # mins, higher means it keeps more data in the memory, will take more time to write into a file too. -LOST_SIGNAL_COUNT_LENGTH = 10 # secs, output log file if we lost signal for this long - -# do not change -LOST_SIGNAL_COUNT_MAX = LOST_SIGNAL_COUNT_LENGTH * LOG_HERTZ # secs, -LOGS_PER_FILE = LOG_LENGTH * 60 * LOG_HERTZ # e.g. 10 * 60 * 10 = 6000 points per file - - -_DEBUG = False -_CLOUDLOG_DEBUG = True - - -def _debug(msg, log_to_cloud=True): - if _CLOUDLOG_DEBUG and log_to_cloud: - cloudlog.debug(msg) - if _DEBUG: - print(msg) - - -class WaitTimeHelper: - ready_event = threading.Event() - shutdown = False - - def __init__(self): - signal.signal(signal.SIGTERM, self.graceful_shutdown) - signal.signal(signal.SIGINT, self.graceful_shutdown) - signal.signal(signal.SIGHUP, self.graceful_shutdown) - - def graceful_shutdown(self, signum, frame): - self.shutdown = True - self.ready_event.set() - - -class GpxD: - def __init__(self, sm): - self.sm = sm - self.rk = Ratekeeper(LOG_HERTZ, print_delay_threshold=None) - - self.log_count = 0 - self.logs = list() - self.lost_signal_count = 0 - self.wait_helper = WaitTimeHelper() - self.started_time = datetime.datetime.utcnow().isoformat() - self.v_ego_prev = 0. - self.pause = True - - def log(self): - location = self.sm['liveLocationKalman'] - gps = self.sm['gpsLocationExternal'] - v_ego = self.sm['carState'].vEgo - - if abs(v_ego) > 0.: - self.pause = False - - location_valid = (location.status == log.LiveLocationKalman.Status.valid) and location.positionGeodetic.valid - _debug("gpxd: location_valid - %s" % location_valid) - if not location_valid or self.pause: - if self.log_count > 0: - self.lost_signal_count += 1 - else: - lat = location.positionGeodetic.value[0] - lon = location.positionGeodetic.value[1] - alt = gps.altitude - - _debug("gpxd: logged - %s %s %s %s" % (datetime.datetime.utcfromtimestamp(location.unixTimestampMillis*0.001).isoformat(), str(lat), str(lon), str(alt))) - self.logs.append([datetime.datetime.utcfromtimestamp(location.unixTimestampMillis*0.001).isoformat(), str(lat), str(lon), str(alt)]) - self.log_count += 1 - self.lost_signal_count = 0 - - if not self.pause and abs(v_ego) < 0.01: - _debug("gpxd: paused") - self.pause = True - - self.v_ego_prev = v_ego - - def write_log(self, force = False): - if self.log_count == 0: - return - - if force or (self.log_count >= LOGS_PER_FILE or self.lost_signal_count >= LOST_SIGNAL_COUNT_MAX): - _debug("gpxd: save to log") - self._write_gpx() - self.lost_signal_count = 0 - self.log_count = 0 - self.logs.clear() - self.started_time = datetime.datetime.utcnow().isoformat() - - def _write_gpx(self): - if len(self.logs) > 1: - if not os.path.exists(GPX_LOG_PATH): - os.makedirs(GPX_LOG_PATH) - filename = self.started_time.replace(':','-') - str = '' - str += "\n" - str += "\n" - str += "\n" - str += " " + self.started_time + "" - str += " \n" - for trkpt in self.logs: - str += self._trkpt_template(trkpt[1], trkpt[2], trkpt[3], trkpt[0]) - str += " \n" - str += "\n" - str += "\n" - try: - f = open('%s%sZ.gpx' % (GPX_LOG_PATH, filename), 'w') - f.write(str) - f.close() - except: - pass - - def _trkpt_template(self, lat, lon, ele, time): - str = "" - str += " \n" - str += " " + ele + "\n" - str += " \n" - str += " \n" - return str - - def gpxd_thread(self): - while True: - self.sm.update(0) - self.log() - self.write_log() - if self.wait_helper.shutdown: - self.write_log(True) - break - self.rk.keep_time() - - -def main(sm=None): - if sm is None: - sm = messaging.SubMaster(['liveLocationKalman', 'gpsLocationExternal', 'carState']) - - gpx = GpxD(sm) - gpx.gpxd_thread() - - -if __name__ == "__main__": - main() diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index ed84d9380d..66cb76b8db 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -75,8 +75,6 @@ def manager_init() -> None: ("GapAdjustCruiseMin", "0"), ("GapAdjustCruiseMode", "0"), ("GapAdjustCruiseTr", "3"), - ("GpxDeleteAfterUpload", "1"), - ("GpxDeleteIfUploaded", "1"), ("HandsOnWheelMonitoring", "0"), ("HideVEgoUi", "0"), ("LastSpeedLimitSignTap", "0"), diff --git a/selfdrive/manager/process_config.py b/selfdrive/manager/process_config.py index 4313ace969..7c232aa78a 100644 --- a/selfdrive/manager/process_config.py +++ b/selfdrive/manager/process_config.py @@ -82,8 +82,6 @@ procs = [ PythonProcess("uploader", "system.loggerd.uploader", always_run), PythonProcess("statsd", "selfdrive.statsd", always_run), - PythonProcess("gpxd", "selfdrive.gpxd.gpxd", only_onroad), - PythonProcess("gpxd_uploader", "selfdrive.gpxd.gpx_uploader", always_run), PythonProcess("fleet_manager", "system.fleetmanager.fleet_manager", only_offroad), # debug procs