diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index c5fedf68a8..8b213c0972 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -87,7 +87,7 @@ function launch { ./build.py fi - ./sunnylink.py; ./mapd_installer.py; ./manager.py + ./mapd_installer.py; ./manager.py # if broken, keep on screen error while true; do sleep 1; done diff --git a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc b/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc index 118aa42159..1ebaf4f14e 100644 --- a/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc +++ b/selfdrive/ui/qt/offroad/sunnypilot/sunnylink_settings.cc @@ -45,10 +45,6 @@ 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(); - } updateLabels(); }); 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/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 67ae8a95af..529d1b2059 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,10 @@ 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") + break + sm.update(0) if exit_event is not None and exit_event.is_set(): end_event.set() @@ -185,12 +190,16 @@ def main(exit_event: threading.Event = None): except Exception: cloudlog.exception("failed to set core affinity") + 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) + UploadQueueCache.initialize(upload_queue) 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 params.get_bool("SunnylinkEnabled"): try: if conn_start is None: conn_start = time.monotonic() @@ -221,6 +230,10 @@ def main(exit_event: threading.Event = None): time.sleep(backoff(conn_retries)) + 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) + if __name__ == "__main__": main() diff --git a/system/manager/manager.py b/system/manager/manager.py index 07ebe0d38f..f3269ee4c3 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", "0" if (build_metadata.release_channel or build_metadata.release_sp_channel) else "1"), + ("SunnylinkDongleId", f"{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..5e709eae52 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 @@ -47,6 +48,17 @@ 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 + +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"), @@ -102,17 +114,16 @@ 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 Params().get_bool("SunnylinkEnabled"): - 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("../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! diff --git a/system/manager/sunnylink.py b/system/manager/sunnylink.py index b329132bc2..9c396d25ea 100755 --- a/system/manager/sunnylink.py +++ b/system/manager/sunnylink.py @@ -2,17 +2,15 @@ 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 -if __name__ == "__main__": - spinner = Spinner() +def main(): extra_args = {} if not Params().get_bool("SunnylinkEnabled"): print("Sunnylink is not enabled. Exiting.") - spinner.close() exit(0) if not is_prebuilt(): @@ -21,6 +19,13 @@ 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() + + # 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__": + main()