diff --git a/sunnypilot/sunnylink/athena/sunnylinkd.py b/sunnypilot/sunnylink/athena/sunnylinkd.py index ce622bc5ad..fff6e1bfe6 100755 --- a/sunnypilot/sunnylink/athena/sunnylinkd.py +++ b/sunnypilot/sunnylink/athena/sunnylinkd.py @@ -41,7 +41,6 @@ LOCAL_PORT_WHITELIST = {8022} SUNNYLINK_LOG_ATTR_NAME = "user.sunny.upload" SUNNYLINK_RECONNECT_TIMEOUT_S = 70 # FYI changing this will also would require a change on sidebar.cc DISALLOW_LOG_UPLOAD = threading.Event() -METADATA_PATH = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "params_metadata.json") params = Params() @@ -170,39 +169,6 @@ def getParamsAllKeys() -> list[str]: return keys -@dispatcher.add_method -def getParamsAllKeysV1() -> dict[str, str]: - try: - with open(METADATA_PATH) as f: - metadata = json.load(f) - except Exception: - cloudlog.exception("sunnylinkd.getParamsAllKeysV1.metadata.exception") - metadata = {} - - try: - available_keys: list[str] = [k.decode('utf-8') for k in Params().all_keys()] - - params_dict: dict[str, list[dict[str, str | bool | int | object | dict | None]]] = {"params": []} - for key in available_keys: - value = get_param_as_byte(key, get_default=True) - - param_entry = { - "key": key, - "type": int(params.get_type(key).value), - "default_value": base64.b64encode(value).decode('utf-8') if value else None, - } - - if key in metadata: - meta_copy = metadata[key].copy() - param_entry["_extra"] = meta_copy - - params_dict["params"].append(param_entry) - return {"keys": json.dumps(params_dict.get("params", []))} - except Exception: - cloudlog.exception("sunnylinkd.getParamsAllKeysV1.exception") - raise - - @dispatcher.add_method def getParamsMetadata() -> str: """Return settings_ui.json + live capabilities as gzip-compressed, base64-encoded string. diff --git a/sunnypilot/sunnylink/docs/README.md b/sunnypilot/sunnylink/docs/README.md index 7327564ace..62d46677e6 100644 --- a/sunnypilot/sunnylink/docs/README.md +++ b/sunnypilot/sunnylink/docs/README.md @@ -97,12 +97,11 @@ The compiler splices a list-context `$ref` into its parent list. Macros may refe ``` 1. common/params_keys.h — add/remove the C++ param key -2. params_metadata.json — automated via update_params_metadata.py -3. settings_ui_src/pages/.yaml — add/edit/remove the item in the right section -4. python sunnypilot/sunnylink/tools/compile_settings_ui.py -5. python sunnypilot/sunnylink/tools/validate_settings_ui.py (or: --check on the compiler) -6. uv run python -m pytest sunnypilot/sunnylink/tests/ # run regression + compiler tests -7. commit +2. settings_ui_src/pages/.yaml — add/edit/remove the item in the right section +3. python sunnypilot/sunnylink/tools/compile_settings_ui.py +4. python sunnypilot/sunnylink/tools/validate_settings_ui.py (or: --check on the compiler) +5. uv run python -m pytest sunnypilot/sunnylink/tests/ # run regression + compiler tests +6. commit ``` CI runs `compile_settings_ui.py --check` to fail on hand-edited `settings_ui.json`. diff --git a/sunnypilot/sunnylink/params_metadata.json b/sunnypilot/sunnylink/params_metadata.json deleted file mode 100644 index 764f37ffde..0000000000 --- a/sunnypilot/sunnylink/params_metadata.json +++ /dev/null @@ -1,1411 +0,0 @@ -{ - "AccessToken": { - "title": "AccessTokenIsNice", - "description": "" - }, - "AdbEnabled": { - "title": "Enable ADB", - "description": "" - }, - "AlphaLongitudinalEnabled": { - "title": "Alpha Longitudinal", - "description": "" - }, - "AlwaysOnDM": { - "title": "Always-on Driver Monitor", - "description": "" - }, - "ApiCache_Device": { - "title": "Api Cache Device", - "description": "" - }, - "ApiCache_DriveStats": { - "title": "Api Cache Drive Stats", - "description": "" - }, - "ApiCache_FirehoseStats": { - "title": "Firehose Mode Stats", - "description": "" - }, - "AssistNowToken": { - "title": "Assist Now Token", - "description": "" - }, - "AthenadPid": { - "title": "Athenad Pid", - "description": "" - }, - "AthenadRecentlyViewedRoutes": { - "title": "Athenad Recently Viewed Routes", - "description": "" - }, - "AthenadUploadQueue": { - "title": "Athenad Upload Queue", - "description": "" - }, - "AutoLaneChangeBsmDelay": { - "title": "Auto Lane Change BSM Delay", - "description": "" - }, - "AutoLaneChangeTimer": { - "title": "Auto Lane Change Timer", - "description": "", - "options": [ - { - "value": -1, - "label": "Off" - }, - { - "value": 0, - "label": "Nudge" - }, - { - "value": 1, - "label": "Nudgeless" - }, - { - "value": 2, - "label": "0.5s" - }, - { - "value": 3, - "label": "1s" - }, - { - "value": 4, - "label": "2s" - }, - { - "value": 5, - "label": "3s" - } - ] - }, - "BackupManager_CreateBackup": { - "title": "Create Backup", - "description": "" - }, - "BackupManager_RestoreVersion": { - "title": "Restore Version", - "description": "" - }, - "BlindSpot": { - "title": "[TIZI/TICI only] Blind Spot Detection", - "description": "Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported." - }, - "BlinkerLateralReengageDelay": { - "title": "Post-Blinker Delay", - "description": "Delay before lateral control resumes after the turn signal ends." - }, - "BlinkerMinLateralControlSpeed": { - "title": "Blinker Min Lateral Control Speed", - "description": "" - }, - "BlinkerPauseLateralControl": { - "title": "Blinker Pause Lateral Control", - "description": "" - }, - "BootCount": { - "title": "Boot Count", - "description": "" - }, - "Brightness": { - "title": "Screen Brightness", - "description": "" - }, - "CalibrationParams": { - "title": "Calibration Params", - "description": "" - }, - "CameraDebugExpGain": { - "title": "Camera Debug Exp Gain", - "description": "" - }, - "CameraDebugExpTime": { - "title": "Camera Debug Exp Time", - "description": "" - }, - "CameraOffset": { - "title": "Adjust Camera Offset", - "description": "Virtually shift camera's perspective to move model's center to Left(+ values) or Right (- values)", - "min": -0.35, - "max": 0.35, - "step": 0.01, - "unit": "meters" - }, - "CarBatteryCapacity": { - "title": "Car Battery Capacity", - "description": "Battery Size", - "unit": "kWh" - }, - "CarList": { - "title": "Supported Car List", - "description": "All supported platform in sunnypilot" - }, - "CarParams": { - "title": "Car Params", - "description": "" - }, - "CarParamsCache": { - "title": "Car Params Cache", - "description": "" - }, - "CarParamsPersistent": { - "title": "Car Params Persistent", - "description": "" - }, - "CarParamsPrevRoute": { - "title": "Car Params Prev Route", - "description": "" - }, - "CarParamsSP": { - "title": "Car Params Sp", - "description": "" - }, - "CarParamsSPCache": { - "title": "Car Params Sp Cache", - "description": "" - }, - "CarParamsSPPersistent": { - "title": "Car Params Sp Persistent", - "description": "" - }, - "CarPlatformBundle": { - "title": "Car Platform Bundle", - "description": "" - }, - "ChevronInfo": { - "title": "Chevron Info", - "description": "" - }, - "CompletedSunnylinkConsentVersion": { - "title": "Completed sunnylink Consent Version", - "description": "" - }, - "CompletedTrainingVersion": { - "title": "Completed Training Version", - "description": "" - }, - "ControlsReady": { - "title": "Controls Ready", - "description": "" - }, - "CurrentBootlog": { - "title": "Current Bootlog", - "description": "" - }, - "CurrentRoute": { - "title": "Current Route", - "description": "" - }, - "CustomAccIncrementsEnabled": { - "title": "Custom ACC Increments", - "description": "" - }, - "CustomAccLongPressIncrement": { - "title": "Custom ACC Long Press Increment", - "description": "", - "min": 1, - "max": 10, - "step": 1 - }, - "CustomAccShortPressIncrement": { - "title": "Custom ACC Short Press Increment", - "description": "", - "min": 1, - "max": 10, - "step": 1 - }, - "CustomTorqueParams": { - "title": "Enable Custom Torque Tuning", - "description": "Enables custom tuning for Torque lateral control" - }, - "DevUIInfo": { - "title": "Developer UI Info", - "description": "" - }, - "DeviceBootMode": { - "title": "Device Boot Mode", - "description": "", - "options": [ - { - "value": 0, - "label": "Standard" - }, - { - "value": 1, - "label": "Always Offroad" - } - ] - }, - "DisableLogging": { - "title": "Disable Logging", - "description": "" - }, - "DisablePowerDown": { - "title": "Disable Power Down", - "description": "" - }, - "DisableUpdates": { - "title": "Disable Updates", - "description": "" - }, - "DisengageOnAccelerator": { - "title": "Disengage On Accelerator", - "description": "" - }, - "DoReboot": { - "title": "Reboot", - "description": "" - }, - "DoShutdown": { - "title": "Power Off", - "description": "" - }, - "DoUninstall": { - "title": "Uninstall sunnypilot", - "description": "" - }, - "DongleId": { - "title": "Device ID", - "description": "" - }, - "DriverTooDistracted": { - "title": "Driver Too Distracted", - "description": "" - }, - "DynamicExperimentalControl": { - "title": "Dynamic Experimental Control", - "description": "" - }, - "EnableCopyparty": { - "title": "copyparty Service", - "description": "" - }, - "EnableGithubRunner": { - "title": "GitHub Runner Service", - "description": "" - }, - "EnableSunnylinkUploader": { - "title": "Enable sunnylink Uploader", - "description": "" - }, - "EnforceTorqueControl": { - "title": "Enforce Torque Control", - "description": "Enable this to enforce sunnypilot to steer with Torque lateral control." - }, - "ExperimentalMode": { - "title": "Experimental Mode", - "description": "" - }, - "ExperimentalModeConfirmed": { - "title": "Experimental Mode Confirmed", - "description": "" - }, - "FirmwareQueryDone": { - "title": "Firmware Query Done", - "description": "" - }, - "ForcePowerDown": { - "title": "Force Power Down", - "description": "" - }, - "GitBranch": { - "title": "Git Branch", - "description": "" - }, - "GitCommit": { - "title": "Git Commit", - "description": "" - }, - "GitCommitDate": { - "title": "Git Commit Date", - "description": "" - }, - "GitDiff": { - "title": "Git Diff", - "description": "" - }, - "GitRemote": { - "title": "Git Remote", - "description": "" - }, - "GithubRunnerSufficientVoltage": { - "title": "Github Runner Sufficient Voltage", - "description": "" - }, - "GithubSshKeys": { - "title": "Github Ssh Keys", - "description": "" - }, - "GithubUsername": { - "title": "GitHub Username", - "description": "" - }, - "GreenLightAlert": { - "title": "Green Traffic Light Alert (Beta)", - "description": "A chime and on-screen alert (TIZI/TICI only) will play when the traffic light you are waiting for turns green and you have no vehicle in front of you.
Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly." - }, - "GsmApn": { - "title": "GSM APN", - "description": "" - }, - "GsmMetered": { - "title": "Gsm Metered", - "description": "" - }, - "GsmRoaming": { - "title": "GSM Roaming", - "description": "" - }, - "HardwareSerial": { - "title": "Serial Number", - "description": "" - }, - "HasAcceptedTerms": { - "title": "Has Accepted Terms", - "description": "" - }, - "HasAcceptedTermsSP": { - "title": "Has Accepted sunnypilot Terms", - "description": "" - }, - "HideVEgoUI": { - "title": "[TIZI/TICI only] Speedometer: Hide from Onroad Screen", - "description": "When enabled, the speedometer on the onroad screen is not displayed." - }, - "HyundaiLongitudinalTuning": { - "title": "Hyundai Longitudinal Tuning", - "description": "", - "options": [ - { - "value": 0, - "label": "Off" - }, - { - "value": 1, - "label": "Dynamic" - }, - { - "value": 2, - "label": "Predictive" - } - ] - }, - "InstallDate": { - "title": "Install Date", - "description": "" - }, - "IntelligentCruiseButtonManagement": { - "title": "Intelligent Cruise Button Management", - "description": "" - }, - "InteractivityTimeout": { - "title": "Interactivity Timeout", - "description": "Apply a custom timeout for settings UI. This is the time after which settings UI closes automatically if user is not interacting with the screen.", - "options": [ - { - "value": 0, - "label": "Default" - }, - { - "value": 10, - "label": "10 s" - }, - { - "value": 20, - "label": "20 s" - }, - { - "value": 30, - "label": "30 s" - }, - { - "value": 40, - "label": "40 s" - }, - { - "value": 50, - "label": "50 s" - }, - { - "value": 60, - "label": "1 m" - }, - { - "value": 70, - "label": "1 m" - }, - { - "value": 80, - "label": "1 m" - }, - { - "value": 90, - "label": "1 m" - }, - { - "value": 100, - "label": "1 m" - }, - { - "value": 110, - "label": "1 m" - }, - { - "value": 120, - "label": "2 m" - } - ] - }, - "IsDevelopmentBranch": { - "title": "Is Development Branch", - "description": "" - }, - "IsDriverViewEnabled": { - "title": "Is Driver View Enabled", - "description": "" - }, - "IsEngaged": { - "title": "Is Engaged", - "description": "" - }, - "IsLdwEnabled": { - "title": "Lane Departure Warnings", - "description": "" - }, - "IsMetric": { - "title": "Use Metric Units", - "description": "" - }, - "IsOffroad": { - "title": "Is Offroad", - "description": "" - }, - "IsOnroad": { - "title": "Is Onroad", - "description": "" - }, - "IsReleaseBranch": { - "title": "Is Release Branch", - "description": "" - }, - "IsReleaseSpBranch": { - "title": "Is Release Sp Branch", - "description": "" - }, - "IsRhdDetected": { - "title": "Is Rhd Detected", - "description": "" - }, - "IsTakingSnapshot": { - "title": "Is Taking Snapshot", - "description": "" - }, - "IsTestedBranch": { - "title": "Is Tested Branch", - "description": "" - }, - "JoystickDebugMode": { - "title": "Joystick Debug Mode", - "description": "" - }, - "LagdToggle": { - "title": "Live Learning Steer Delay", - "description": "Allow device to learn and adapt car's steering response time" - }, - "LagdToggleDelay": { - "title": "Manual Software Delay", - "description": "Software delay to use when Live Learning Steer Delay is toggled off", - "min": 0.05, - "max": 0.5, - "step": 0.01 - }, - "LagdValueCache": { - "title": "LaGD Value Cache", - "description": "" - }, - "LaneTurnDesire": { - "title": "Lane Turn Desire", - "description": "Force model to plan an intent to turn based on blinker" - }, - "LaneTurnValue": { - "title": "Lane Turn Speed", - "description": "Maximum speed for lane turn desire", - "min": 0, - "max": 20, - "step": 1 - }, - "LanguageSetting": { - "title": "Language", - "description": "" - }, - "LastAgnosPowerMonitorShutdown": { - "title": "Last AGNOS Power Monitor Shutdown", - "description": "" - }, - "LastAthenaPingTime": { - "title": "Last Athena Ping Time", - "description": "" - }, - "LastGPSPosition": { - "title": "Last Gps Position", - "description": "" - }, - "LastGPSPositionLLK": { - "title": "Last GPS Position LLK", - "description": "" - }, - "LastManagerExitReason": { - "title": "Last Manager Exit Reason", - "description": "" - }, - "LastOffroadStatusPacket": { - "title": "Last Offroad Status Packet", - "description": "" - }, - "LastPowerDropDetected": { - "title": "Last Power Drop Detected", - "description": "" - }, - "LastSunnylinkPingTime": { - "title": "Last sunnylink Ping Time", - "description": "" - }, - "LastUpdateException": { - "title": "Last Update Exception", - "description": "" - }, - "LastUpdateRouteCount": { - "title": "Last Update Route Count", - "description": "" - }, - "LastUpdateTime": { - "title": "Last Update Time", - "description": "" - }, - "LastUpdateUptimeOnroad": { - "title": "Last Update Uptime Onroad", - "description": "" - }, - "LateralManeuverMode": { - "title": "Lateral Maneuver Mode", - "description": "" - }, - "LeadDepartAlert": { - "title": "Lead Departure Alert (Beta)", - "description": "A chime and on-screen alert (TIZI/TICI only) will play when you are stopped, and the vehicle in front of you start moving.
Note: This chime is only designed as a notification. It is the driver's responsibility to observe their environment and make decisions accordingly." - }, - "LiveDelay": { - "title": "Live Delay", - "description": "" - }, - "LiveParameters": { - "title": "Live Parameters", - "description": "" - }, - "LiveParametersV2": { - "title": "Live Parameters V2", - "description": "" - }, - "LiveTorqueParameters": { - "title": "Live Torque Parameters", - "description": "" - }, - "LiveTorqueParamsRelaxedToggle": { - "title": "Less Restrict Settings for Self-Tune (Beta)", - "description": "Less strict settings when using Self-Tune. This allows torqued to be more forgiving when learning values." - }, - "LiveTorqueParamsToggle": { - "title": "Self-Tune", - "description": "Enables self-tune for Torque lateral control" - }, - "LivestreamEncoderBitrate": { - "title": "Livestream Encoder Bitrate", - "description": "" - }, - "LocationFilterInitialState": { - "title": "Location Filter Initial State", - "description": "" - }, - "LongitudinalManeuverMode": { - "title": "Longitudinal Maneuver Mode", - "description": "" - }, - "LongitudinalPersonality": { - "title": "Driving Personality", - "description": "", - "options": [ - { - "value": 0, - "label": "Aggressive" - }, - { - "value": 1, - "label": "Standard" - }, - { - "value": 2, - "label": "Relaxed" - } - ] - }, - "Mads": { - "title": "MADS Enabled", - "description": "" - }, - "MadsMainCruiseAllowed": { - "title": "MADS Main Cruise Allowed", - "description": "" - }, - "MadsSteeringMode": { - "title": "MADS Steering Mode", - "description": "", - "options": [ - { - "value": 0, - "label": "Remain Active" - }, - { - "value": 1, - "label": "Pause" - }, - { - "value": 2, - "label": "Disengage" - } - ] - }, - "MadsUnifiedEngagementMode": { - "title": "MADS Unified Engagement Mode", - "description": "" - }, - "MapAdvisorySpeedLimit": { - "title": "Map Advisory Speed Limit", - "description": "" - }, - "MapSpeedLimit": { - "title": "Map Speed Limit", - "description": "" - }, - "MapTargetVelocities": { - "title": "Map Target Velocities", - "description": "" - }, - "MapdVersion": { - "title": "Mapd Version", - "description": "" - }, - "MaxTimeOffroad": { - "title": "Max Time Offroad", - "description": "", - "unit": "minutes" - }, - "ModelManager_ActiveBundle": { - "title": "Model Manager Active Bundle", - "description": "" - }, - "ModelManager_ClearCache": { - "title": "Model Manager Clear Cache", - "description": "" - }, - "ModelManager_DownloadIndex": { - "title": "Model Manager Download Index", - "description": "" - }, - "ModelManager_Favs": { - "title": "Model Manager Favorites", - "description": "" - }, - "ModelManager_LastSyncTime": { - "title": "Model Manager Last Sync Time", - "description": "" - }, - "ModelManager_ModelsCache": { - "title": "Model Manager Models Cache", - "description": "" - }, - "ModelRunnerTypeCache": { - "title": "Model Runner Type Cache", - "description": "" - }, - "NetworkMetered": { - "title": "Network Usage", - "description": "", - "options": [ - { - "value": 0, - "label": "Default" - }, - { - "value": 1, - "label": "Metered" - }, - { - "value": 2, - "label": "Unmetered" - } - ] - }, - "NeuralNetworkLateralControl": { - "title": "Neural Network Lateral Control", - "description": "" - }, - "NextMapSpeedLimit": { - "title": "Next Map Speed Limit", - "description": "" - }, - "OSMDownloadBounds": { - "title": "OSM Download Bounds", - "description": "" - }, - "OSMDownloadLocations": { - "title": "OSM Download Locations", - "description": "" - }, - "OSMDownloadProgress": { - "title": "OSM Download Progress", - "description": "" - }, - "ObdMultiplexingChanged": { - "title": "Obd Multiplexing Changed", - "description": "" - }, - "ObdMultiplexingEnabled": { - "title": "Obd Multiplexing Enabled", - "description": "" - }, - "OffroadMode": { - "title": "Force Offroad Mode", - "description": "" - }, - "Offroad_CarUnrecognized": { - "title": "Offroad Car Unrecognized", - "description": "" - }, - "Offroad_ConnectivityNeeded": { - "title": "Offroad Connectivity Needed", - "description": "" - }, - "Offroad_ConnectivityNeededPrompt": { - "title": "Offroad Connectivity Needed Prompt", - "description": "" - }, - "Offroad_DriverMonitoringUncertain": { - "title": "Offroad Driver Monitoring Uncertain", - "description": "" - }, - "Offroad_ExcessiveActuation": { - "title": "Offroad Excessive Actuation", - "description": "" - }, - "Offroad_IsTakingSnapshot": { - "title": "Offroad Is Taking Snapshot", - "description": "" - }, - "Offroad_NeosUpdate": { - "title": "Offroad Neos Update", - "description": "" - }, - "Offroad_NoFirmware": { - "title": "Offroad No Firmware", - "description": "" - }, - "Offroad_OSMUpdateRequired": { - "title": "Offroad OSM Update Required", - "description": "" - }, - "Offroad_Recalibration": { - "title": "Offroad Recalibration", - "description": "" - }, - "Offroad_TemperatureTooHigh": { - "title": "Offroad Temperature Too High", - "description": "" - }, - "Offroad_TiciSupport": { - "title": "Offroad Tici Support", - "description": "" - }, - "Offroad_UnregisteredHardware": { - "title": "Offroad Unregistered Hardware", - "description": "" - }, - "Offroad_UpdateFailed": { - "title": "Offroad Update Failed", - "description": "" - }, - "OnroadCycleRequested": { - "title": "Onroad Cycle Requested", - "description": "" - }, - "OnroadScreenOffBrightness": { - "title": "Onroad Brightness", - "description": "", - "options": [ - { - "value": 0, - "label": "Auto (Default)" - }, - { - "value": 1, - "label": "Auto (Dark)" - }, - { - "value": 2, - "label": "Screen Off" - }, - { - "value": 3, - "label": "5 %" - }, - { - "value": 4, - "label": "10 %" - }, - { - "value": 5, - "label": "15 %" - }, - { - "value": 6, - "label": "20 %" - }, - { - "value": 7, - "label": "25 %" - }, - { - "value": 8, - "label": "30 %" - }, - { - "value": 9, - "label": "35 %" - }, - { - "value": 10, - "label": "40 %" - }, - { - "value": 11, - "label": "45 %" - }, - { - "value": 12, - "label": "50 %" - }, - { - "value": 13, - "label": "55 %" - }, - { - "value": 14, - "label": "60 %" - }, - { - "value": 15, - "label": "65 %" - }, - { - "value": 16, - "label": "70 %" - }, - { - "value": 17, - "label": "75 %" - }, - { - "value": 18, - "label": "80 %" - }, - { - "value": 19, - "label": "85 %" - }, - { - "value": 20, - "label": "90 %" - }, - { - "value": 21, - "label": "95 %" - }, - { - "value": 22, - "label": "100 %" - } - ] - }, - "OnroadScreenOffBrightnessMigrated": { - "title": "Onroad Brightness Migration Version", - "description": "This param is to track whether OnroadScreenOffBrightness needs to be migrated." - }, - "OnroadScreenOffControl": { - "title": "Onroad Brightness", - "description": "Adjusts the screen brightness while it's in onroad state." - }, - "OnroadScreenOffTimer": { - "title": "Onroad Brightness Delay", - "description": "", - "options": [ - { - "value": 3, - "label": "3s" - }, - { - "value": 5, - "label": "5s" - }, - { - "value": 7, - "label": "7s" - }, - { - "value": 10, - "label": "10s" - }, - { - "value": 15, - "label": "15s" - }, - { - "value": 30, - "label": "30s" - }, - { - "value": 60, - "label": "1m" - }, - { - "value": 120, - "label": "2m" - }, - { - "value": 180, - "label": "3m" - }, - { - "value": 240, - "label": "4m" - }, - { - "value": 300, - "label": "5m" - }, - { - "value": 360, - "label": "6m" - }, - { - "value": 420, - "label": "7m" - }, - { - "value": 480, - "label": "8m" - }, - { - "value": 540, - "label": "9m" - }, - { - "value": 600, - "label": "10m" - } - ] - }, - "OnroadScreenOffTimerMigrated": { - "title": "Onroad Brightness Delay Migration Version", - "description": "This param is to track whether OnroadScreenOffTimer needs to be migrated." - }, - "OnroadUploads": { - "title": "Onroad Uploads", - "description": "" - }, - "OpenpilotEnabledToggle": { - "title": "Enable sunnypilot", - "description": "" - }, - "OsmDbUpdatesCheck": { - "title": "OSM DB Updates Check", - "description": "" - }, - "OsmDownloadedDate": { - "title": "OSM Downloaded Date", - "description": "" - }, - "OsmLocal": { - "title": "OSM Local", - "description": "" - }, - "OsmLocationName": { - "title": "OSM Location Name", - "description": "" - }, - "OsmLocationTitle": { - "title": "OSM Location Title", - "description": "" - }, - "OsmLocationUrl": { - "title": "OSM Location URL", - "description": "" - }, - "OsmStateName": { - "title": "OSM State Name", - "description": "" - }, - "OsmStateTitle": { - "title": "OSM State Title", - "description": "" - }, - "OsmWayTest": { - "title": "OSM Way Test", - "description": "" - }, - "PandaHeartbeatLost": { - "title": "Panda Heartbeat Lost", - "description": "" - }, - "PandaSignatures": { - "title": "Panda Signatures", - "description": "" - }, - "PandaSomResetTriggered": { - "title": "Panda Som Reset Triggered", - "description": "" - }, - "ParamsVersion": { - "title": "Params Version", - "description": "" - }, - "PlanplusControl": { - "title": "Plan Plus Controls", - "description": "Adjust planplus model recentering strength. The higher this number the more aggressively the model will recover to lanecenter, too high and it will ping-pong", - "min": 0.0, - "max": 2.0, - "step": 0.1 - }, - "PrimeType": { - "title": "Prime Type", - "description": "" - }, - "QuickBootToggle": { - "title": "Quick Boot", - "description": "" - }, - "QuietMode": { - "title": "Quiet Mode", - "description": "" - }, - "RainbowMode": { - "title": "Rainbow Mode", - "description": "" - }, - "RecordAudio": { - "title": "Record & Upload Mic Audio", - "description": "" - }, - "RecordAudioFeedback": { - "title": "Record Audio Feedback", - "description": "" - }, - "RecordFront": { - "title": "Record & Upload Driver Camera", - "description": "" - }, - "RecordFrontLock": { - "title": "Record Front Lock", - "description": "" - }, - "RoadName": { - "title": "Road Name", - "description": "" - }, - "RoadNameToggle": { - "title": "[TIZI/TICI only] Display Road Name", - "description": "Displays the name of the road the car is traveling on.
The OpenStreetMap database of the location must be downloaded to fetch the road name." - }, - "RocketFuel": { - "title": "[TIZI/TICI only] Real-time Acceleration Bar", - "description": "Show an indicator on the left side of the screen to display real-time vehicle acceleration and deceleration. This displays what the car is currently doing, not what the planner is requesting." - }, - "RouteCount": { - "title": "Route Count", - "description": "" - }, - "SecOCKey": { - "title": "Sec Oc Key", - "description": "" - }, - "ShowAdvancedControls": { - "title": "Show Advanced Controls", - "description": "Enable to show advanced controls on device" - }, - "ShowDebugInfo": { - "title": "UI Debug Mode", - "description": "" - }, - "ShowTurnSignals": { - "title": "[TIZI/TICI only] Display Turn Signals", - "description": "When enabled, visual turn indicators are drawn on the HUD." - }, - "SmartCruiseControlMap": { - "title": "Smart Cruise Control - Map", - "description": "" - }, - "SmartCruiseControlVision": { - "title": "Smart Cruise Control - Vision", - "description": "" - }, - "SnoozeUpdate": { - "title": "Snooze Update", - "description": "" - }, - "SpeedLimitMode": { - "title": "Speed Limit Assist Mode", - "description": "", - "options": [ - { - "value": 0, - "label": "Off" - }, - { - "value": 1, - "label": "Information" - }, - { - "value": 2, - "label": "Warning" - }, - { - "value": 3, - "label": "Assist" - } - ] - }, - "SpeedLimitOffsetType": { - "title": "Speed Limit Offset Type", - "description": "", - "options": [ - { - "value": 0, - "label": "Off" - }, - { - "value": 1, - "label": "Fixed" - }, - { - "value": 2, - "label": "Percentage" - } - ] - }, - "SpeedLimitPolicy": { - "title": "Speed Limit Source", - "description": "", - "options": [ - { - "value": 0, - "label": "Car State Only" - }, - { - "value": 1, - "label": "Map Data Only" - }, - { - "value": 2, - "label": "Car State Priority" - }, - { - "value": 3, - "label": "Map Data Priority" - }, - { - "value": 4, - "label": "Combined" - } - ] - }, - "SpeedLimitValueOffset": { - "title": "Speed Limit Offset Value", - "description": "", - "min": -30, - "max": 30, - "step": 1 - }, - "SshEnabled": { - "title": "Enable SSH", - "description": "" - }, - "StandstillTimer": { - "title": "[TIZI/TICI only] Standstill Timer", - "description": "Show a timer on the HUD when the car is at a standstill." - }, - "SubaruStopAndGo": { - "title": "Subaru Stop and Go", - "description": "" - }, - "SubaruStopAndGoManualParkingBrake": { - "title": "Subaru Stop and Go Manual Parking Brake", - "description": "" - }, - "SunnylinkCache_Roles": { - "title": "sunnylink Cache Roles", - "description": "" - }, - "SunnylinkCache_Users": { - "title": "sunnylink Cache Users", - "description": "" - }, - "SunnylinkDongleId": { - "title": "sunnylink Dongle ID", - "description": "" - }, - "SunnylinkEnabled": { - "title": "sunnylink Enabled", - "description": "" - }, - "SunnylinkTempFault": { - "title": "sunnylink Temp Fault", - "description": "" - }, - "SunnylinkdPid": { - "title": "Sunnylinkd Pid", - "description": "" - }, - "TermsVersion": { - "title": "Terms Version", - "description": "" - }, - "TeslaCoopSteering": { - "title": "Tesla Coop Steering", - "description": "" - }, - "TorqueBar": { - "title": "[TIZI/TICI only] Steering Arc", - "description": "Display steering arc on the driving screen when lateral control is enabled." - }, - "TorqueControlTune": { - "title": "Torque Control Tune Version", - "description": "Select the version of Torque Control Tune to use.", - "options": [ - { - "value": "", - "label": "Default" - }, - { - "value": 1.0, - "label": "v1.0" - }, - { - "value": 0.0, - "label": "v0.0" - } - ] - }, - "TorqueParamsOverrideEnabled": { - "title": "Manual Real-Time Tuning", - "description": "" - }, - "TorqueParamsOverrideFriction": { - "title": "Manual Tune - Friction", - "description": "", - "min": 0.0, - "max": 1.0, - "step": 0.01 - }, - "TorqueParamsOverrideLatAccelFactor": { - "title": "Manual Tune - Lateral Acceleration Factor", - "description": "", - "min": 0.1, - "max": 5.0, - "step": 0.1, - "unit": "m/s\u00b2" - }, - "ToyotaEnforceStockLongitudinal": { - "title": "Toyota: Enforce Factory Longitudinal Control", - "description": "When enabled, sunnypilot will not take over control of gas and brakes. Factory Toyota longitudinal control will be used." - }, - "ToyotaStopAndGoHack": { - "title": "Toyota: Stop and Go Hack (Alpha)", - "description": "sunnypilot will allow some Toyota/Lexus cars to auto resume during stop and go traffic. This feature is only applicable to certain models that are able to use longitudinal control. This is an alpha feature. Use at your own risk." - }, - "TrainingVersion": { - "title": "Training Version", - "description": "" - }, - "TrueVEgoUI": { - "title": "[TIZI/TICI only] Speedometer: Always Display True Speed", - "description": "For applicable vehicles, always display the true vehicle current speed from wheel speed sensors." - }, - "UbloxAvailable": { - "title": "Ublox Available", - "description": "" - }, - "UpdateAvailable": { - "title": "Update Available", - "description": "" - }, - "UpdateFailedCount": { - "title": "Update Failed Count", - "description": "" - }, - "UpdaterAvailableBranches": { - "title": "Updater Available Branches", - "description": "" - }, - "UpdaterCurrentDescription": { - "title": "Updater Current Description", - "description": "" - }, - "UpdaterCurrentReleaseNotes": { - "title": "Updater Current Release Notes", - "description": "" - }, - "UpdaterFetchAvailable": { - "title": "Updater Fetch Available", - "description": "" - }, - "UpdaterLastFetchTime": { - "title": "Updater Last Fetch Time", - "description": "" - }, - "UpdaterNewDescription": { - "title": "Updater New Description", - "description": "" - }, - "UpdaterNewReleaseNotes": { - "title": "Updater New Release Notes", - "description": "" - }, - "UpdaterState": { - "title": "Updater State", - "description": "" - }, - "UpdaterTargetBranch": { - "title": "Updater Target Branch", - "description": "" - }, - "UptimeOffroad": { - "title": "Uptime Offroad", - "description": "" - }, - "UptimeOnroad": { - "title": "Uptime Onroad", - "description": "" - }, - "UsbGpuCompiled": { - "title": "Usb Gpu Compiled", - "description": "" - }, - "UsbGpuPresent": { - "title": "Usb Gpu Present", - "description": "" - }, - "Version": { - "title": "openpilot Version", - "description": "" - } -} diff --git a/sunnypilot/sunnylink/tests/test_params_metadata.py b/sunnypilot/sunnylink/tests/test_params_metadata.py deleted file mode 100644 index f4f1fbc4b1..0000000000 --- a/sunnypilot/sunnylink/tests/test_params_metadata.py +++ /dev/null @@ -1,86 +0,0 @@ -""" -Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - -This file is part of sunnypilot and is licensed under the MIT License. -See the LICENSE.md file in the root directory for more details. -""" -import json - -from openpilot.sunnypilot.sunnylink.athena.sunnylinkd import getParamsAllKeysV1, METADATA_PATH - - -def test_get_params_all_keys_v1(): - """ - Test the getParamsAllKeysV1 API endpoint. - - Why: - This endpoint is used by the UI (and potentially external tools) to fetch the list of - available parameters along with their metadata (titles, descriptions, options, constraints). - We need to ensure it returns the correct structure and that the metadata from - params_metadata.json is correctly merged into the response. - - Expected: - - The response should contain a "keys" field which is a JSON string of a list of parameters. - - Each parameter object should have "key", "type", "default_value", and optionally "_extra". - - The "_extra" field should contain the rich metadata (title, options, min/max, etc.) matching - the source of truth (params_metadata.json). - """ - response = getParamsAllKeysV1() - assert "keys" in response - - keys_json = response["keys"] - params_list = json.loads(keys_json) - - assert isinstance(params_list, list) - assert len(params_list) > 0 - - # Check structure of first item - first_param = params_list[0] - assert "key" in first_param - assert "type" in first_param - assert "default_value" in first_param - - if "_extra" in first_param: - assert isinstance(first_param["_extra"], dict) - assert "default" not in first_param["_extra"] - assert "type" not in first_param["_extra"] - - # Load the source of truth - with open(METADATA_PATH) as f: - metadata = json.load(f) - - # Verify that the API response matches the metadata file for a few sample keys - # This ensures the plumbing is working without being brittle to content changes - - # 1. Check a key that should have metadata - keys_with_metadata = [k for k in params_list if k["key"] in metadata] - assert len(keys_with_metadata) > 0, "No parameters found that match metadata keys" - - for param in keys_with_metadata[:5]: # Check first 5 matches - key = param["key"] - expected_meta = metadata[key] - - assert "_extra" in param, f"Parameter {key} should have _extra field" - actual_meta = param["_extra"] - - # Verify all fields in JSON are present in the API response - for meta_key, meta_val in expected_meta.items(): - assert meta_key in actual_meta, f"Missing {meta_key} in API response for {key}" - assert actual_meta[meta_key] == meta_val, f"Mismatch for {key}.{meta_key}: expected {meta_val}, got {actual_meta[meta_key]}" - - # 2. Check that we are correctly serving options if they exist - params_with_options = [k for k in keys_with_metadata if "options" in k.get("_extra", {})] - if params_with_options: - param = params_with_options[0] - key = param["key"] - assert isinstance(param["_extra"]["options"], list), f"Options for {key} should be a list" - assert param["_extra"]["options"] == metadata[key]["options"] - - # 3. Check that we are correctly serving numeric constraints if they exist - params_with_constraints = [k for k in keys_with_metadata if "min" in k.get("_extra", {})] - if params_with_constraints: - param = params_with_constraints[0] - key = param["key"] - assert param["_extra"]["min"] == metadata[key]["min"] - assert param["_extra"]["max"] == metadata[key]["max"] - assert param["_extra"]["step"] == metadata[key]["step"] diff --git a/sunnypilot/sunnylink/tests/test_params_sync.py b/sunnypilot/sunnylink/tests/test_params_sync.py deleted file mode 100644 index 05114de49a..0000000000 --- a/sunnypilot/sunnylink/tests/test_params_sync.py +++ /dev/null @@ -1,284 +0,0 @@ -""" -Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - -This file is part of sunnypilot and is licensed under the MIT License. -See the LICENSE.md file in the root directory for more details. -""" -import json -import os -import pytest - -from openpilot.common.params import Params -from openpilot.sunnypilot.sunnylink.athena.sunnylinkd import METADATA_PATH - - -def test_metadata_json_exists(): - """ - Test that the params_metadata.json file exists at the expected path. - - Why: - The metadata file is the source of truth for parameter descriptions, options, and constraints. - If it's missing, the UI will not be able to display rich information for parameters. - - Expected: - The file should exist at sunnypilot/sunnylink/params_metadata.json. - """ - assert os.path.exists(METADATA_PATH), f"Metadata file not found at {METADATA_PATH}" - - -def test_metadata_json_valid(): - """ - Test that the params_metadata.json file contains valid JSON. - - Why: - Invalid JSON will cause the metadata loading to fail, potentially crashing the UI or - resulting in missing metadata. - - Expected: - The file content should be parseable as a JSON object (dictionary). - """ - with open(METADATA_PATH) as f: - try: - data = json.load(f) - except json.JSONDecodeError: - pytest.fail("Metadata file is not valid JSON") - - assert isinstance(data, dict), "Metadata root must be a dictionary" - - -def test_all_params_have_metadata(): - """ - Test that every parameter in the codebase has a corresponding entry in params_metadata.json. - - Why: - We want to ensure 100% coverage of parameter metadata. Any parameter added to the codebase - should also be documented in the metadata file. - - Expected: - There should be no parameters in Params() that are missing from the metadata file. - If this fails, run 'python3 sunnypilot/sunnylink/tools/update_params_metadata.py'. - """ - params = Params() - all_keys = [k.decode('utf-8') for k in params.all_keys()] - - with open(METADATA_PATH) as f: - metadata = json.load(f) - - missing_keys = [key for key in all_keys if key not in metadata] - - if missing_keys: - pytest.fail( - f"The following parameters are missing from metadata: {missing_keys}. " - + "Please run 'python3 sunnypilot/sunnylink/tools/update_params_metadata.py' to update." - ) - - -def test_metadata_keys_exist_in_params(): - """ - Test that all keys in params_metadata.json actually exist in the codebase. - - Why: - We want to avoid stale metadata for parameters that have been removed or renamed. - This keeps the metadata file clean and relevant. - - Expected: - There should be no keys in the metadata file that are not present in Params(). - This prints a warning rather than failing, as it's less critical than missing metadata. - """ - params = Params() - all_keys = {k.decode('utf-8') for k in params.all_keys()} - - with open(METADATA_PATH) as f: - metadata = json.load(f) - - extra_keys = [key for key in metadata.keys() if key not in all_keys] - - if extra_keys: - print(f"Warning: The following keys in metadata do not exist in Params: {extra_keys}") - - -def test_no_default_titles(): - """ - Test that no parameter has a title that is identical to its key. - - Why: - The default behavior of the update script is to set the title equal to the key. - We want to force developers to provide human-readable, descriptive titles for all parameters. - - Expected: - No parameter metadata should have 'title' == 'key'. - """ - with open(METADATA_PATH) as f: - metadata = json.load(f) - - default_title_keys = [key for key, meta in metadata.items() if meta.get("title") == key] - - if default_title_keys: - pytest.fail( - f"The following parameters have default titles (title == key): {default_title_keys}. " - + "Please update 'params_metadata.json' with descriptive titles." - ) - - -def test_options_structure(): - """ - Test that the 'options' field in metadata follows the correct structure. - - Why: - The UI expects 'options' to be a list of objects with 'value' and 'label' keys. - Incorrect structure will break the UI rendering for dropdowns/toggles. - - Expected: - If 'options' is present, it must be a list of dicts, and each dict must have 'value' and 'label'. - """ - with open(METADATA_PATH) as f: - metadata = json.load(f) - - for key, meta in metadata.items(): - if "options" in meta: - options = meta["options"] - assert isinstance(options, list), f"Options for {key} must be a list" - for option in options: - assert isinstance(option, dict), f"Option in {key} must be a dictionary" - assert "value" in option, f"Option in {key} must have a 'value' key" - assert "label" in option, f"Option in {key} must have a 'label' key" - - -def test_numeric_constraints(): - """ - Test that numeric parameters have valid 'min', 'max', and 'step' constraints. - - Why: - The UI uses these constraints to validate user input and render sliders/steppers. - Missing or invalid constraints can lead to UI bugs or invalid parameter values. - - Expected: - If any of min/max/step is present, ALL of them must be present. - They must be numbers (int/float), and min must be less than max. - """ - with open(METADATA_PATH) as f: - metadata = json.load(f) - - for key, meta in metadata.items(): - if "min" in meta or "max" in meta or "step" in meta: - assert "min" in meta, f"Numeric param {key} must have 'min'" - assert "max" in meta, f"Numeric param {key} must have 'max'" - assert "step" in meta, f"Numeric param {key} must have 'step'" - - assert isinstance(meta["min"], (int, float)), f"Min for {key} must be number" - assert isinstance(meta["max"], (int, float)), f"Max for {key} must be number" - assert isinstance(meta["step"], (int, float)), f"Step for {key} must be number" - assert meta["min"] < meta["max"], f"Min must be less than max for {key}" - - -def test_known_params_metadata(): - """ - Test specific known parameters to ensure they have the expected rich metadata. - - Why: - This acts as a spot check to ensure that our rich metadata population logic is working correctly - and that critical parameters (like LongitudinalPersonality) have their options and constraints preserved. - - Expected: - 'LongitudinalPersonality' should have 3 options (Aggressive, Standard, Relaxed). - 'CustomAccLongPressIncrement' should have min=1, max=10, step=1. - """ - with open(METADATA_PATH) as f: - metadata = json.load(f) - - # Check an enum-like param - lp = metadata.get("LongitudinalPersonality") - assert lp is not None - assert "options" in lp - assert len(lp["options"]) == 3 - assert lp["options"][0]["label"] == "Aggressive" - assert lp["options"][0]["value"] == 0 - - # Check a numeric param - acc_long = metadata.get("CustomAccLongPressIncrement") - assert acc_long is not None - assert acc_long["min"] == 1 - assert acc_long["max"] == 10 - assert acc_long["step"] == 1 - - -def test_torque_control_tune_versions_in_sync(): - """ - Test that TorqueControlTune options in params_metadata.json match versions in latcontrol_torque_versions.json. - - Why: - The TorqueControlTune dropdown in the UI should always reflect the available torque tune versions. - If versions are added/removed from latcontrol_torque_versions.json, the metadata must be updated accordingly. - - Expected: - - TorqueControlTune should have a 'Default' option with empty string value - - All versions from latcontrol_torque_versions.json should be present in the options - - The version values and labels should match between both files - """ - from openpilot.common.basedir import BASEDIR - - versions_json_path = os.path.join(BASEDIR, "sunnypilot", "selfdrive", "controls", "lib", "latcontrol_torque_versions.json") - sync_script_path = "python3 sunnypilot/sunnylink/tools/sync_torque_versions.py" - - # Load both files - with open(METADATA_PATH) as f: - metadata = json.load(f) - - with open(versions_json_path) as f: - versions = json.load(f) - - # Get TorqueControlTune metadata - torque_tune = metadata.get("TorqueControlTune") - if torque_tune is None: - pytest.fail(f"TorqueControlTune not found in params_metadata.json. Please run '{sync_script_path}' to sync.") - - if "options" not in torque_tune: - pytest.fail(f"TorqueControlTune must have options. Please run '{sync_script_path}' to sync.") - - options = torque_tune["options"] - if not isinstance(options, list): - pytest.fail(f"TorqueControlTune options must be a list. Please run '{sync_script_path}' to sync.") - - if len(options) == 0: - pytest.fail(f"TorqueControlTune must have at least one option. Please run '{sync_script_path}' to sync.") - - # Check that Default option exists - default_option = next((opt for opt in options if opt.get("value") == ""), None) - if default_option is None: - pytest.fail(f"TorqueControlTune must have a 'Default' option with empty string value. Please run '{sync_script_path}' to sync.") - - if default_option.get("label") != "Default": - pytest.fail(f"Default option must have label 'Default'. Please run '{sync_script_path}' to sync.") - - # Build expected options from versions.json - expected_version_keys = set(versions.keys()) - actual_version_keys = set() - - for option in options: - if option.get("value") == "": - continue # Skip the default option - - label = option.get("label") - value = option.get("value") - - # Check that this option corresponds to a version - if label not in versions: - pytest.fail(f"Option label '{label}' not found in latcontrol_torque_versions.json. Please run '{sync_script_path}' to sync.") - - # Check that the value matches the version number - expected_value = float(versions[label]["version"]) - if value != expected_value: - pytest.fail(f"Option '{label}' has value {value}, expected {expected_value}. Please run '{sync_script_path}' to sync.") - - actual_version_keys.add(label) - - # Check that all versions are represented - missing_versions = expected_version_keys - actual_version_keys - if missing_versions: - pytest.fail(f"The following versions are missing from TorqueControlTune options: {missing_versions}. " + - f"Please run '{sync_script_path}' to sync.") - - extra_versions = actual_version_keys - expected_version_keys - if extra_versions: - pytest.fail("The following versions in TorqueControlTune options are not in latcontrol_torque_versions.json: " + - f"{extra_versions}. Please run '{sync_script_path}' to sync.") diff --git a/sunnypilot/sunnylink/tools/update_params_metadata.py b/sunnypilot/sunnylink/tools/update_params_metadata.py deleted file mode 100755 index ea3765420d..0000000000 --- a/sunnypilot/sunnylink/tools/update_params_metadata.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python3 -""" -Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. - -This file is part of sunnypilot and is licensed under the MIT License. -See the LICENSE.md file in the root directory for more details. -""" -import json -import os - -from openpilot.common.basedir import BASEDIR -from openpilot.common.params import Params -from openpilot.sunnypilot.system.params_migration import ONROAD_BRIGHTNESS_TIMER_VALUES - -METADATA_PATH = os.path.join(os.path.dirname(__file__), "../params_metadata.json") -TORQUE_VERSIONS_JSON = os.path.join(BASEDIR, "sunnypilot", "selfdrive", "controls", "lib", "latcontrol_torque_versions.json") - - -def main(): - params = Params() - all_keys = params.all_keys() - - if os.path.exists(METADATA_PATH): - with open(METADATA_PATH) as f: - try: - data = json.load(f) - except json.JSONDecodeError: - data = {} - else: - data = {} - - # Add new keys - for key in all_keys: - key_str = key.decode("utf-8") - if key_str not in data: - print(f"Adding new key: {key_str}") - data[key_str] = { - "title": key_str, - "description": "", - } - - # Remove deleted keys - # keys_to_remove = [k for k in data.keys() if k.encode("utf-8") not in all_keys] - # for k in keys_to_remove: - # print(f"Removing deleted key: {k}") - # del data[k] - - # Sort keys - sorted_data = dict(sorted(data.items())) - - with open(METADATA_PATH, "w") as f: - json.dump(sorted_data, f, indent=2) - f.write("\n") - - print(f"Updated {METADATA_PATH}") - - # update onroad screen brightness params - update_onroad_brightness_param() - - # update onroad screen brightness timer params - update_onroad_brightness_timer_param() - - # update torque versions param - update_torque_versions_param() - - -def update_onroad_brightness_param(): - try: - with open(METADATA_PATH) as f: - params_metadata = json.load(f) - if "OnroadScreenOffBrightness" in params_metadata: - options = [ - {"value": 0, "label": "Auto (Default)"}, - {"value": 1, "label": "Auto (Dark)"}, - {"value": 2, "label": "Screen Off"}, - ] - for i in range(3, 23): - options.append({"value": i, "label": f"{(i - 2) * 5} %"}) - params_metadata["OnroadScreenOffBrightness"]["options"] = options - with open(METADATA_PATH, 'w') as f: - json.dump(params_metadata, f, indent=2) - f.write('\n') - print(f"Updated OnroadScreenOffBrightness options in params_metadata.json with {len(options)} options.") - except Exception as e: - print(f"Failed to update OnroadScreenOffBrightness versions in params_metadata.json: {e}") - - -def update_onroad_brightness_timer_param(): - try: - with open(METADATA_PATH) as f: - params_metadata = json.load(f) - if "OnroadScreenOffTimer" in params_metadata: - options = [] - for _index, seconds in sorted(ONROAD_BRIGHTNESS_TIMER_VALUES.items()): - label = f"{seconds}s" if seconds < 60 else f"{seconds // 60}m" - options.append({"value": seconds, "label": label}) - params_metadata["OnroadScreenOffTimer"]["options"] = options - with open(METADATA_PATH, 'w') as f: - json.dump(params_metadata, f, indent=2) - f.write('\n') - print(f"Updated OnroadScreenOffTimer options in params_metadata.json with {len(options)} options.") - except Exception as e: - print(f"Failed to update OnroadScreenOffTimer options in params_metadata.json: {e}") - - -def update_torque_versions_param(): - with open(TORQUE_VERSIONS_JSON) as f: - current_versions = json.load(f) - - try: - with open(METADATA_PATH) as f: - params_metadata = json.load(f) - - options = [{"value": "", "label": "Default"}] - for version_key, version_data in current_versions.items(): - version_value = float(version_data["version"]) - options.append({"value": version_value, "label": str(version_key)}) - - if "TorqueControlTune" in params_metadata: - params_metadata["TorqueControlTune"]["options"] = options - - with open(METADATA_PATH, 'w') as f: - json.dump(params_metadata, f, indent=2) - f.write('\n') - - print(f"Updated TorqueControlTune options in params_metadata.json with {len(options)} options: \n{options}") - - except Exception as e: - print(f"Failed to update TorqueControlTune versions in params_metadata.json: {e}") - - -if __name__ == "__main__": - main()