From 5d440cf62a9909c6654dadffd94315bc543818c1 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Sun, 16 Jun 2024 20:36:05 +0200 Subject: [PATCH 01/16] Refactor Sunnylink integration and add dongle registration check The Sunnylink integration has been refactored to improve handling of scenarios where Sunnylink is enabled but the dongle is not registered. Added checks for the registration status of the Sunnylink dongle and updated related defaults and UI indicators correspondingly. Additionally, moved the execution of the sunnylink.py script to the background during launch to prevent blocking other tasks. --- common/api/sunnylink.py | 3 ++- launch_chffrplus.sh | 3 ++- selfdrive/ui/qt/sidebar.cc | 3 +++ selfdrive/ui/qt/sidebar.h | 1 + system/manager/manager.py | 4 +++- system/manager/process_config.py | 3 ++- system/manager/sunnylink.py | 8 ++++---- 7 files changed, 17 insertions(+), 8 deletions(-) diff --git a/common/api/sunnylink.py b/common/api/sunnylink.py index e2761cc29f..fe8627ceab 100644 --- a/common/api/sunnylink.py +++ b/common/api/sunnylink.py @@ -23,7 +23,8 @@ class SunnylinkApi(BaseApi): self.params = Params() def api_get(self, endpoint, method='GET', timeout=10, access_token=None, **kwargs): - if not self.params.get_bool("SunnylinkEnabled"): + sunnylink_dongle_id, comma_dongle_id = self._resolve_dongle_ids() + if not self.params.get_bool("SunnylinkEnabled") or sunnylink_dongle_id in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID): return None return super().api_get(endpoint, method, timeout, access_token, **kwargs) diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index c5fedf68a8..ed8d5e37fc 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -87,7 +87,8 @@ function launch { ./build.py fi - ./sunnylink.py; ./mapd_installer.py; ./manager.py + ./sunnylink.py & + ./mapd_installer.py; ./manager.py # if broken, keep on screen error while true; do sleep 1; done diff --git a/selfdrive/ui/qt/sidebar.cc b/selfdrive/ui/qt/sidebar.cc index 5d8245acc5..9463843ab2 100644 --- a/selfdrive/ui/qt/sidebar.cc +++ b/selfdrive/ui/qt/sidebar.cc @@ -155,6 +155,7 @@ void Sidebar::updateState(const UIState &s) { setProperty("pandaStatus", QVariant::fromValue(pandaStatus)); ItemStatus sunnylinkStatus; + auto sl_dongle_id = getSunnylinkDongleId(); auto last_sunnylink_ping_str = params.get("LastSunnylinkPingTime"); auto last_sunnylink_ping = std::stoull(last_sunnylink_ping_str.empty() ? "0" : last_sunnylink_ping_str); auto current_nanos = nanos_since_boot(); @@ -162,6 +163,8 @@ void Sidebar::updateState(const UIState &s) { auto sunnylink_enabled = params.getBool("SunnylinkEnabled"); if (!sunnylink_enabled) { sunnylinkStatus = ItemStatus{{tr("SUNNYLINK"), tr("DISABLED")}, disabled_color}; + } else if(!sl_dongle_id.has_value()) { + sunnylinkStatus = ItemStatus{{tr("SUNNYLINK"), tr("REGIST...")}, progress_color}; } else if (last_sunnylink_ping == 0) { sunnylinkStatus = ItemStatus{{tr("SUNNYLINK"), tr("OFFLINE")}, warning_color}; } else { diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h index be2c34cae0..9012f25135 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -52,6 +52,7 @@ protected: const QRect home_btn = QRect(60, 860, 180, 180); const QRect settings_btn = QRect(50, 35, 200, 117); const QColor good_color = QColor(255, 255, 255); + const QColor progress_color = QColor(3, 132, 252); const QColor warning_color = QColor(218, 202, 37); const QColor danger_color = QColor(201, 34, 49); const QColor disabled_color = QColor(128, 128, 128); diff --git a/system/manager/manager.py b/system/manager/manager.py index 07ebe0d38f..33ebcd73e6 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -8,6 +8,7 @@ import traceback from cereal import custom import cereal.messaging as messaging import openpilot.system.sentry as sentry +from openpilot.common.api.sunnylink import UNREGISTERED_SUNNYLINK_DONGLE_ID from openpilot.common.params import Params, ParamKeyType from openpilot.common.text_window import TextWindow from openpilot.system.hardware import HARDWARE, PC @@ -105,7 +106,8 @@ def manager_init() -> None: ("OsmDownloadedDate", "0"), ("OSMDownloadProgress", "{}"), ("SidebarTemperatureOptions", "0"), - ("SunnylinkEnabled", "0"), + ("SunnylinkEnabled", "1"), + {"SunnylinkDongleId", UNREGISTERED_SUNNYLINK_DONGLE_ID}, ("CustomDrivingModel", "0"), ("DrivingModelGeneration", "4"), ("LastSunnylinkPingTime", "0"), diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 3ac3e1648b..89618eac1b 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -1,6 +1,7 @@ import os from cereal import car +from openpilot.common.api.sunnylink import UNREGISTERED_SUNNYLINK_DONGLE_ID from openpilot.common.params import Params from openpilot.system.hardware import PC, TICI from openpilot.selfdrive.sunnypilot import get_model_generation @@ -104,7 +105,7 @@ procs = [ PythonProcess("webjoystick", "tools.bodyteleop.web", notcar), ] -if Params().get_bool("SunnylinkEnabled"): +if Params().get_bool("SunnylinkEnabled") and Params().get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID): if os.path.exists("../athena/manage_sunnylinkd.py"): procs += [ DaemonProcess("manage_sunnylinkd", "system.athena.manage_sunnylinkd", "SunnylinkdPid"), diff --git a/system/manager/sunnylink.py b/system/manager/sunnylink.py index b329132bc2..47017094b7 100755 --- a/system/manager/sunnylink.py +++ b/system/manager/sunnylink.py @@ -7,12 +7,12 @@ from openpilot.system.version import is_prebuilt if __name__ == "__main__": - spinner = Spinner() + # spinner = Spinner() extra_args = {} if not Params().get_bool("SunnylinkEnabled"): print("Sunnylink is not enabled. Exiting.") - spinner.close() + # spinner.close() exit(0) if not is_prebuilt(): @@ -21,6 +21,6 @@ if __name__ == "__main__": "timeout": 60 } - sunnylink_id = SunnylinkApi(None).register_device(spinner, **extra_args) + sunnylink_id = SunnylinkApi(None).register_device(None, **extra_args) print(f"SunnyLinkId: {sunnylink_id}") - spinner.close() + # spinner.close() From 65edbe4f47c0a00fa6b79b904dbcecdcb2acf8b1 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Sun, 16 Jun 2024 20:51:06 +0200 Subject: [PATCH 02/16] Update Sunnylink dongle ID handling The Sunnylink dongle ID is now being formatted directly in the manager.py file, reducing redundancy. Also, the check for sunnylink_dongle_id in sunnylink.py was removed to simplify the SunnlinkEnabled conditional. --- common/api/sunnylink.py | 3 +-- system/manager/manager.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/common/api/sunnylink.py b/common/api/sunnylink.py index fe8627ceab..e2761cc29f 100644 --- a/common/api/sunnylink.py +++ b/common/api/sunnylink.py @@ -23,8 +23,7 @@ class SunnylinkApi(BaseApi): self.params = Params() def api_get(self, endpoint, method='GET', timeout=10, access_token=None, **kwargs): - sunnylink_dongle_id, comma_dongle_id = self._resolve_dongle_ids() - if not self.params.get_bool("SunnylinkEnabled") or sunnylink_dongle_id in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID): + if not self.params.get_bool("SunnylinkEnabled"): return None return super().api_get(endpoint, method, timeout, access_token, **kwargs) diff --git a/system/manager/manager.py b/system/manager/manager.py index 33ebcd73e6..3155d28da3 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -107,7 +107,7 @@ def manager_init() -> None: ("OSMDownloadProgress", "{}"), ("SidebarTemperatureOptions", "0"), ("SunnylinkEnabled", "1"), - {"SunnylinkDongleId", UNREGISTERED_SUNNYLINK_DONGLE_ID}, + {"SunnylinkDongleId", f"{UNREGISTERED_SUNNYLINK_DONGLE_ID}"}, ("CustomDrivingModel", "0"), ("DrivingModelGeneration", "4"), ("LastSunnylinkPingTime", "0"), From 7fcdcf64d82471c1029a14d66fe01d2a1ddfe5ba Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Mon, 17 Jun 2024 17:16:17 +0200 Subject: [PATCH 03/16] Fix format error in SunnylinkDongleId variable The format of the SunnylinkDongleId variable was incorrect in system manager code. It used a dictionary format instead of a tuple. This commit replaces it back with a tuple appropriately to avoid inconsistencies. --- system/manager/manager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/manager/manager.py b/system/manager/manager.py index 3155d28da3..1944a05ba6 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -107,7 +107,7 @@ def manager_init() -> None: ("OSMDownloadProgress", "{}"), ("SidebarTemperatureOptions", "0"), ("SunnylinkEnabled", "1"), - {"SunnylinkDongleId", f"{UNREGISTERED_SUNNYLINK_DONGLE_ID}"}, + ("SunnylinkDongleId", f"{UNREGISTERED_SUNNYLINK_DONGLE_ID}"), ("CustomDrivingModel", "0"), ("DrivingModelGeneration", "4"), ("LastSunnylinkPingTime", "0"), From 00fb20e28c05a3f72d229022840c6138ff837fca Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 20:34:14 +0200 Subject: [PATCH 04/16] Refactor sunnylink process configuration logic The code for managing sunnylink processes has been refactored and improved. A function, use_sunnylink, has been added to check if sunnylink is both enabled and registered appropriately. Additionally, the launching of process logic for 'sunnylink_uploader' and 'manage_sunnylinkd' has been adjusted to use this new function. The main function of 'sunnylinkd.py' now also checks if the sunnylink is enabled before running. --- system/athena/sunnylinkd.py | 18 +++++++++++++++++- system/manager/process_config.py | 23 ++++++++++++++--------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index 67ae8a95af..cf67f3c82b 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -8,6 +8,7 @@ import os import threading import time +from openpilot.common.api.sunnylink import UNREGISTERED_SUNNYLINK_DONGLE_ID from openpilot.system.athena.athenad import ws_send, jsonrpc_handler, \ recv_queue, UploadQueueCache, upload_queue, cur_upload_items, backoff, ws_manage, log_handler from jsonrpc import dispatcher @@ -52,6 +53,11 @@ def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None: thread.start() try: while not end_event.wait(0.1): + if not params.get_bool("SunnylinkEnabled"): + cloudlog.warning("Exiting sunnylinkd.handle_long_poll as SunnylinkEnabled is False") + exit_event = exit_event or threading.Event() + exit_event.set() + sm.update(0) if exit_event is not None and exit_event.is_set(): end_event.set() @@ -223,4 +229,14 @@ def main(exit_event: threading.Event = None): if __name__ == "__main__": - main() + is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") + is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) + while is_sunnylink_enabled and not is_registered: + cloudlog.info("Waiting for sunnylink registration to complete") + time.sleep(60) + + if is_sunnylink_enabled: + main() + else: + cloudlog.info("Exiting sunnylinkd as SunnylinkEnabled is False") + exit(0) diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 89618eac1b..85fed770a0 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -48,6 +48,12 @@ def model_use_nav(started, params, CP: car.CarParams) -> bool: custom_model, model_gen = get_model_generation(params) return started and custom_model and model_gen not in (0, 4) + +def use_sunnylink(started, params, CP: car.CarParams) -> bool: + is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") + is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) + return is_sunnylink_enabled and is_registered + procs = [ DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), @@ -105,15 +111,14 @@ procs = [ PythonProcess("webjoystick", "tools.bodyteleop.web", notcar), ] -if Params().get_bool("SunnylinkEnabled") and Params().get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID): - if os.path.exists("../athena/manage_sunnylinkd.py"): - procs += [ - DaemonProcess("manage_sunnylinkd", "system.athena.manage_sunnylinkd", "SunnylinkdPid"), - ] - if os.path.exists("../loggerd/sunnylink_uploader.py"): - procs += [ - PythonProcess("sunnylink_uploader", "system.loggerd.sunnylink_uploader", always_run), - ] +if os.path.exists("../athena/manage_sunnylinkd.py"): + procs += [ + DaemonProcess("manage_sunnylinkd", "system.athena.manage_sunnylinkd", "SunnylinkdPid"), + ] +if os.path.exists("../loggerd/sunnylink_uploader.py"): + procs += [ + PythonProcess("sunnylink_uploader", "system.loggerd.sunnylink_uploader", use_sunnylink), + ] if os.path.exists("./gitlab_runner.sh") and not PC: # Only devs! From b18987a5f7ef5743febc5105a38cdc627d61a51d Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 20:42:30 +0200 Subject: [PATCH 05/16] Remove setting exit_event in sunnylinkd.py The code has been updated to remove the conditional that sets exit_event in the sunnylinkd.py file. This change simplifies control flow by immediately returning to the top of the loop when Sunnylink is not enabled, instead of managing an additional event. --- system/athena/sunnylinkd.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index cf67f3c82b..d269a3596a 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -55,8 +55,7 @@ def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None: while not end_event.wait(0.1): if not params.get_bool("SunnylinkEnabled"): cloudlog.warning("Exiting sunnylinkd.handle_long_poll as SunnylinkEnabled is False") - exit_event = exit_event or threading.Event() - exit_event.set() + continue sm.update(0) if exit_event is not None and exit_event.is_set(): From 1f63d633986b2abc93f275ad6c1a0f4a7fb2a392 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 20:43:30 +0200 Subject: [PATCH 06/16] Change loop control from 'continue' to 'break' The loop control in sunnylinkd.py was changed from 'continue' to 'break' when Sunnylink is disabled. This prevents unnecessary iterations and makes the code more efficient when the Sunnylink functionality is not in use. --- system/athena/sunnylinkd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index d269a3596a..35eb828d51 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -55,7 +55,7 @@ def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None: while not end_event.wait(0.1): if not params.get_bool("SunnylinkEnabled"): cloudlog.warning("Exiting sunnylinkd.handle_long_poll as SunnylinkEnabled is False") - continue + break sm.update(0) if exit_event is not None and exit_event.is_set(): From c7464fc615d1e7614deccbec5faf39dba3e47c1d Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 20:50:23 +0200 Subject: [PATCH 07/16] Add Sunnylink registration check in main function The code has been adjusted to perform a check for Sunnylink registration in the main function of the sunnylinkd script. Previously, the script was checking for the SunnylinkEnabled state and if the dongle is registered at the beginning of the script. Now, these checks are executed within the main function, allowing the script to exit with a warning log if Sunnylink is not enabled. --- system/athena/sunnylinkd.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index 35eb828d51..b61da2833c 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -190,6 +190,13 @@ def main(exit_event: threading.Event = None): except Exception: cloudlog.exception("failed to set core affinity") + is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") + is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) + + while is_sunnylink_enabled and not is_registered: + cloudlog.info("Waiting for sunnylink registration to complete") + time.sleep(60) + UploadQueueCache.initialize(upload_queue) ws_uri = SUNNYLINK_ATHENA_HOST @@ -197,6 +204,10 @@ def main(exit_event: threading.Event = None): conn_retries = 0 while exit_event is None or not exit_event.is_set(): try: + if not is_sunnylink_enabled: + cloudlog.warning("Exiting sunnylinkd.main as SunnylinkEnabled is False") + break + if conn_start is None: conn_start = time.monotonic() @@ -228,14 +239,4 @@ def main(exit_event: threading.Event = None): if __name__ == "__main__": - is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") - is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) - while is_sunnylink_enabled and not is_registered: - cloudlog.info("Waiting for sunnylink registration to complete") - time.sleep(60) - - if is_sunnylink_enabled: - main() - else: - cloudlog.info("Exiting sunnylinkd as SunnylinkEnabled is False") - exit(0) + main() From 62b0c9f8be2d1620b01101ca8d0def8b4de28382 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 20:52:15 +0200 Subject: [PATCH 08/16] Add delay before retrying sunnylinkd main The update introduces a 60-second delay before retrying the execution of sunnylinkd main when SunnylinkEnabled is false. This aims to prevent the immediate termination of the process when SunnylinkEnabled is turned off, allowing for a smoother transition. --- system/athena/sunnylinkd.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index b61da2833c..4715994e48 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -205,7 +205,8 @@ def main(exit_event: threading.Event = None): while exit_event is None or not exit_event.is_set(): try: if not is_sunnylink_enabled: - cloudlog.warning("Exiting sunnylinkd.main as SunnylinkEnabled is False") + cloudlog.debug("Exiting sunnylinkd.main as SunnylinkEnabled is False but will retry in 60 seconds") + time.sleep(60) break if conn_start is None: From 524b97f8d4d7174ae18e8badef118bc93cd961e5 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:00:02 +0200 Subject: [PATCH 09/16] Refactor sunnylinkd.main exit conditions The checks for the sunnylink_enabled flag have been restructured to eliminate unnecessary loop iterations. The check has been moved out of the loop to do the evaluation only once, when exiting the loop. This significantly increases the efficiency of the code. --- system/athena/sunnylinkd.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index 4715994e48..0bb4c28e16 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -202,13 +202,8 @@ def main(exit_event: threading.Event = None): ws_uri = SUNNYLINK_ATHENA_HOST conn_start = None conn_retries = 0 - while exit_event is None or not exit_event.is_set(): + while exit_event is None or not exit_event.is_set() and is_sunnylink_enabled: try: - if not is_sunnylink_enabled: - cloudlog.debug("Exiting sunnylinkd.main as SunnylinkEnabled is False but will retry in 60 seconds") - time.sleep(60) - break - if conn_start is None: conn_start = time.monotonic() @@ -238,6 +233,10 @@ def main(exit_event: threading.Event = None): time.sleep(backoff(conn_retries)) + if not is_sunnylink_enabled: + cloudlog.debug("Reached end of sunnylinkd.main while SunnylinkEnabled is False so will wait for 60 seconds before exiting") + time.sleep(60) + if __name__ == "__main__": main() From 583699509712a0cb5b1768eeeb141e268cb41486 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:07:03 +0200 Subject: [PATCH 10/16] Refactor sunnylinkd.py for dynamic Sunnylink check Removed the static check for Sunnylink's enabled status, allowing the feature to be checked dynamically within while loops. This change ensures that if the Sunnylink feature status changes, it can immediately affect the decision-making within the process. This is particularly useful for smooth enabling or disabling of the Sunnylink feature. --- system/athena/sunnylinkd.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index 0bb4c28e16..f999f1eb2f 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -190,10 +190,8 @@ def main(exit_event: threading.Event = None): except Exception: cloudlog.exception("failed to set core affinity") - is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) - - while is_sunnylink_enabled and not is_registered: + while params.get_bool("SunnylinkEnabled") and not is_registered: cloudlog.info("Waiting for sunnylink registration to complete") time.sleep(60) @@ -202,7 +200,7 @@ def main(exit_event: threading.Event = None): ws_uri = SUNNYLINK_ATHENA_HOST conn_start = None conn_retries = 0 - while exit_event is None or not exit_event.is_set() and is_sunnylink_enabled: + while (exit_event is None or not exit_event.is_set()) and params.get_bool("SunnylinkEnabled"): try: if conn_start is None: conn_start = time.monotonic() @@ -233,7 +231,7 @@ def main(exit_event: threading.Event = None): time.sleep(backoff(conn_retries)) - if not is_sunnylink_enabled: + if not params.get_bool("SunnylinkEnabled"): cloudlog.debug("Reached end of sunnylinkd.main while SunnylinkEnabled is False so will wait for 60 seconds before exiting") time.sleep(60) From 7dc412fcf1932e7f6d53ec83609a95afcbd65643 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:24:01 +0200 Subject: [PATCH 11/16] Refactor encoding method and reduce sleep time The decoding method in the manage_athenad file has been refactored for parameter retrieval. Instead of decoding after receiving the parameter, decoding is now integrated in the parameter retrieval process. Also, the waiting time in the sunnylinkd.py has been reduced from 60 seconds to 10 to enhance performance and reduce lag. --- system/athena/manage_athenad.py | 2 +- system/athena/sunnylinkd.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/athena/manage_athenad.py b/system/athena/manage_athenad.py index fb514bc1ca..7158cd9220 100755 --- a/system/athena/manage_athenad.py +++ b/system/athena/manage_athenad.py @@ -18,7 +18,7 @@ def main(): def manage_athenad(dongle_id_param, pid_param, process_name, target): params = Params() - dongle_id = params.get(dongle_id_param).decode('utf-8') + dongle_id = params.get(dongle_id_param, encoding='utf-8') build_metadata = get_build_metadata() cloudlog.bind_global(dongle_id=dongle_id, diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index f999f1eb2f..2f19983198 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -193,7 +193,7 @@ def main(exit_event: threading.Event = None): is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) while params.get_bool("SunnylinkEnabled") and not is_registered: cloudlog.info("Waiting for sunnylink registration to complete") - time.sleep(60) + time.sleep(10) UploadQueueCache.initialize(upload_queue) From 61843ee71c1661095da80ab5f44a236d488c8981 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:28:31 +0200 Subject: [PATCH 12/16] Refactor Sunnylink registration condition The condition for Sunnylink registration has been simplified and refactored within the main loop. Previously, the "is_registered" variable was being set outside the registration loop. Now, the checking process of the dongle ID in regard to the registration status is directly integrated into the while condition. This makes the code more concise and the process flow clearer. --- system/athena/sunnylinkd.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/system/athena/sunnylinkd.py b/system/athena/sunnylinkd.py index 2f19983198..529d1b2059 100755 --- a/system/athena/sunnylinkd.py +++ b/system/athena/sunnylinkd.py @@ -190,8 +190,7 @@ def main(exit_event: threading.Event = None): except Exception: cloudlog.exception("failed to set core affinity") - is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) - while params.get_bool("SunnylinkEnabled") and not is_registered: + while params.get_bool("SunnylinkEnabled") and not params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID): cloudlog.info("Waiting for sunnylink registration to complete") time.sleep(10) From cd8d07dddd2f40c1ce2a108db0b9f5d9e1042f8a Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:38:39 +0200 Subject: [PATCH 13/16] Add Sunnylink registration check and process The commit introduces a new function, sunnylink_need_register, to check if the Sunnylink feature is registered. It also updates the process list to always include the manage_sunnylinkd process and introduces a new process for Sunnylink registration if it's enabled but not registered. --- system/manager/process_config.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/system/manager/process_config.py b/system/manager/process_config.py index 85fed770a0..5e709eae52 100644 --- a/system/manager/process_config.py +++ b/system/manager/process_config.py @@ -54,6 +54,11 @@ def use_sunnylink(started, params, CP: car.CarParams) -> bool: is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) return is_sunnylink_enabled and is_registered +def sunnylink_need_register(started, params, CP: car.CarParams) -> bool: + is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") + is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) + return is_sunnylink_enabled and not is_registered + procs = [ DaemonProcess("manage_athenad", "system.athena.manage_athenad", "AthenadPid"), @@ -109,12 +114,12 @@ procs = [ NativeProcess("bridge", "cereal/messaging", ["./bridge"], notcar), PythonProcess("webrtcd", "system.webrtc.webrtcd", notcar), PythonProcess("webjoystick", "tools.bodyteleop.web", notcar), + + # Sunnylink <3 + DaemonProcess("manage_sunnylinkd", "system.athena.manage_sunnylinkd", "SunnylinkdPid"), + PythonProcess("sunnylink_registration", "system.manager.sunnylink", sunnylink_need_register), ] -if os.path.exists("../athena/manage_sunnylinkd.py"): - procs += [ - DaemonProcess("manage_sunnylinkd", "system.athena.manage_sunnylinkd", "SunnylinkdPid"), - ] if os.path.exists("../loggerd/sunnylink_uploader.py"): procs += [ PythonProcess("sunnylink_uploader", "system.loggerd.sunnylink_uploader", use_sunnylink), From b80f6442bd85243f766a0fd6f285528838d7d52c Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:39:11 +0200 Subject: [PATCH 14/16] Remove unnecessary sunnylink.py launch command The sunnylink.py file was unnecessarily initiated in the launch_chffrplus.sh script. This initiation was removed to streamline the script and potentially increase overall runtime efficiency. --- launch_chffrplus.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index ed8d5e37fc..8b213c0972 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -87,7 +87,6 @@ function launch { ./build.py fi - ./sunnylink.py & ./mapd_installer.py; ./manager.py # if broken, keep on screen error From 7e7d98f0c0b9b042e3b6b515c82a361f443a8475 Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:41:46 +0200 Subject: [PATCH 15/16] addming main --- system/manager/sunnylink.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system/manager/sunnylink.py b/system/manager/sunnylink.py index 47017094b7..a530ddab10 100755 --- a/system/manager/sunnylink.py +++ b/system/manager/sunnylink.py @@ -6,7 +6,7 @@ from openpilot.common.spinner import Spinner from openpilot.system.version import is_prebuilt -if __name__ == "__main__": +def main(): # spinner = Spinner() extra_args = {} @@ -24,3 +24,7 @@ if __name__ == "__main__": sunnylink_id = SunnylinkApi(None).register_device(None, **extra_args) print(f"SunnyLinkId: {sunnylink_id}") # spinner.close() + + +if __name__ == "__main__": + main() From c4037ece24c79430e6c4f12efe59122230a8537b Mon Sep 17 00:00:00 2001 From: DevTekVE Date: Wed, 19 Jun 2024 21:52:57 +0200 Subject: [PATCH 16/16] Update sunnylink registration processes Removed spinner from sunnylink.py and stopped reboot prompt in sunnylink_settings.cc. The spinner was unnecessary and the reboot, instead of being prompted, will be handled differently. Additionally, timestamp of the last successful ping is now recorded upon registration in the Sunnylink service. --- selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc | 8 ++++---- system/manager/sunnylink.py | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc index 118aa42159..3b1f1b64b9 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc +++ b/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc @@ -45,10 +45,10 @@ SunnylinkPanel::SunnylinkPanel(QWidget* parent) : QFrame(parent) { sunnylinkEnabledBtn->setDescription(shame_description); } - auto dialog_text = tr("A reboot is required to") + " " + (enabled ? tr("start") : tr("stop")) +" "+ tr("all connections and processes from sunnylink.") + "
"+ tr("If that's not a problem for you, you can ignore this.")+ ""; - if (ConfirmationDialog::confirm(dialog_text, tr("Reboot Now!"), this)) { - Hardware::reboot(); - } + //auto dialog_text = tr("A reboot is required to") + " " + (enabled ? tr("start") : tr("stop")) +" "+ tr("all connections and processes from sunnylink.") + "
"+ tr("If that's not a problem for you, you can ignore this.")+ ""; + //if (ConfirmationDialog::confirm(dialog_text, tr("Reboot Now!"), this)) { + // Hardware::reboot(); + //} updateLabels(); }); diff --git a/system/manager/sunnylink.py b/system/manager/sunnylink.py index a530ddab10..17384f14b8 100755 --- a/system/manager/sunnylink.py +++ b/system/manager/sunnylink.py @@ -2,12 +2,11 @@ from openpilot.common.api.sunnylink import SunnylinkApi from openpilot.common.params import Params -from openpilot.common.spinner import Spinner from openpilot.system.version import is_prebuilt +import time def main(): - # spinner = Spinner() extra_args = {} if not Params().get_bool("SunnylinkEnabled"): @@ -23,7 +22,10 @@ def main(): sunnylink_id = SunnylinkApi(None).register_device(None, **extra_args) print(f"SunnyLinkId: {sunnylink_id}") - # spinner.close() + + # Set the last ping time to the current time since we just registered + last_ping = int(time.monotonic() * 1e9) + Params().put("LastSunnylinkPingTime", str(last_ping)) if __name__ == "__main__":