diff --git a/common/params.cc b/common/params.cc index b1fc15e4c5..b416b801a8 100644 --- a/common/params.cc +++ b/common/params.cc @@ -161,6 +161,7 @@ std::unordered_map keys = { {"NavPastDestinations", PERSISTENT}, {"NavSettingLeftSide", PERSISTENT}, {"NavSettingTime24h", PERSISTENT}, + {"NetworkMetered", PERSISTENT}, {"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, {"Offroad_BadNvme", CLEAR_ON_MANAGER_START}, @@ -201,6 +202,7 @@ std::unordered_map keys = { {"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START}, {"UpdaterState", CLEAR_ON_MANAGER_START}, {"UpdaterTargetBranch", CLEAR_ON_MANAGER_START}, + {"UpdaterLastFetchTime", PERSISTENT}, {"Version", PERSISTENT}, {"VisionRadarToggle", PERSISTENT}, {"WheeledBody", PERSISTENT}, diff --git a/selfdrive/thermald/thermald.py b/selfdrive/thermald/thermald.py index 7011ff0a99..75e091febb 100755 --- a/selfdrive/thermald/thermald.py +++ b/selfdrive/thermald/thermald.py @@ -447,6 +447,8 @@ def thermald_thread(end_event, hw_queue) -> None: except Exception: cloudlog.exception("failed to save offroad status") + params.put_bool_nonblocking("NetworkMetered", (msg.deviceState.networkType != NetworkType.wifi)) + count += 1 should_start_prev = should_start diff --git a/selfdrive/updated.py b/selfdrive/updated.py index a623aaefc8..8a46a11a78 100755 --- a/selfdrive/updated.py +++ b/selfdrive/updated.py @@ -35,26 +35,42 @@ OVERLAY_INIT = Path(os.path.join(BASEDIR, ".overlay_init")) DAYS_NO_CONNECTIVITY_MAX = 14 # do not allow to engage after this many days DAYS_NO_CONNECTIVITY_PROMPT = 10 # send an offroad prompt after this many days +class UserRequest: + NONE = 0 + CHECK = 1 + FETCH = 2 + class WaitTimeHelper: def __init__(self): self.ready_event = threading.Event() - self.only_check_for_update = False + self.user_request = UserRequest.NONE signal.signal(signal.SIGHUP, self.update_now) signal.signal(signal.SIGUSR1, self.check_now) def update_now(self, signum: int, frame) -> None: cloudlog.info("caught SIGHUP, attempting to downloading update") - self.only_check_for_update = False + self.user_request = UserRequest.FETCH self.ready_event.set() def check_now(self, signum: int, frame) -> None: cloudlog.info("caught SIGUSR1, checking for updates") - self.only_check_for_update = True + self.user_request = UserRequest.CHECK self.ready_event.set() def sleep(self, t: float) -> None: self.ready_event.wait(timeout=t) +def write_time_to_param(params, param) -> None: + t = datetime.datetime.utcnow() + params.put(param, t.isoformat().encode('utf8')) + +def read_time_from_param(params, param) -> Optional[datetime.datetime]: + t = params.get(param, encoding='utf8') + try: + return datetime.datetime.fromisoformat(t) + except (TypeError, ValueError): + pass + return None def run(cmd: List[str], cwd: Optional[str] = None) -> str: return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8') @@ -266,14 +282,11 @@ class Updater: last_update = datetime.datetime.utcnow() if update_success: - t = last_update.isoformat() - self.params.put("LastUpdateTime", t.encode('utf8')) + write_time_to_param(self.params, "LastUpdateTime") else: - try: - t = self.params.get("LastUpdateTime", encoding='utf8') - last_update = datetime.datetime.fromisoformat(t) - except (TypeError, ValueError): - pass + t = read_time_from_param(self.params, "LastUpdateTime") + if t is not None: + last_update = t if exception is None: self.params.remove("LastUpdateException") @@ -421,10 +434,7 @@ def main() -> None: updater = Updater() update_failed_count = 0 # TODO: Load from param? - - # no fetch on the first time wait_helper = WaitTimeHelper() - wait_helper.only_check_for_update = True # invalidate old finalized update set_consistent_flag(False) @@ -458,10 +468,16 @@ def main() -> None: updater.check_for_update() # download update - if wait_helper.only_check_for_update: - cloudlog.info("skipping fetch this cycle") + last_fetch = read_time_from_param(params, "UpdaterLastFetchTime") + timed_out = last_fetch is None or (datetime.datetime.utcnow() - last_fetch > datetime.timedelta(days=3)) + user_requested_fetch = wait_helper.user_request == UserRequest.FETCH + if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch: + cloudlog.info("skipping fetch, connection metered") + elif wait_helper.user_request == UserRequest.CHECK: + cloudlog.info("skipping fetch, only checking") else: updater.fetch_update() + write_time_to_param(params, "UpdaterLastFetchTime") update_failed_count = 0 except subprocess.CalledProcessError as e: cloudlog.event( @@ -485,7 +501,7 @@ def main() -> None: cloudlog.exception("uncaught updated exception while setting params, shouldn't happen") # infrequent attempts if we successfully updated recently - wait_helper.only_check_for_update = False + wait_helper.user_request = UserRequest.NONE wait_helper.sleep(5*60 if update_failed_count > 0 else 1.5*60*60)