Networking Pond

This commit is contained in:
firestar5683
2026-03-25 15:55:14 -05:00
parent 4b1dee2466
commit efb9884039
3 changed files with 120 additions and 1 deletions
+1
View File
@@ -8,6 +8,7 @@
inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}},
{"AdbEnabled", {PERSISTENT, BOOL}},
{"AlwaysAllowUploads", {PERSISTENT, BOOL, "0"}},
{"AlwaysOnDM", {PERSISTENT, BOOL}},
{"ApiCache_Device", {PERSISTENT, STRING}},
{"ApiCache_FirehoseStats", {PERSISTENT, JSON}},
@@ -1778,8 +1778,25 @@
"description": "WARNING: This will prevent your drives from being uploaded to comma connect which will impact debugging and official support from comma!\n\nPrevent the device from uploading driving data.",
"data_type": "bool",
"ui_type": "toggle",
"is_parent_toggle": true,
"parent_key": "DeviceManagement"
},
{
"key": "DisableOnroadUploads",
"label": "Disable Onroad Uploads",
"description": "When \"Disable Uploads\" is enabled, allow uploads only while parked (offroad).",
"data_type": "bool",
"ui_type": "toggle",
"parent_key": "NoUploads"
},
{
"key": "AlwaysAllowUploads",
"label": "Always Allow Uploads",
"description": "Override upload blocks and always keep uploader enabled. Advanced use only.",
"data_type": "bool",
"ui_type": "toggle",
"parent_key": "NoUploads"
},
{
"key": "HigherBitrate",
"label": "High-Quality Recording",
@@ -1788,6 +1805,14 @@
"ui_type": "toggle",
"parent_key": "DeviceManagement"
},
{
"key": "GsmMetered",
"label": "Cellular Metered",
"description": "Prevent large uploads on cellular. Turn this off to allow full/unfiltered uploads over mobile data.",
"data_type": "bool",
"ui_type": "toggle",
"parent_key": "DeviceManagement"
},
{
"key": "LowVoltageShutdown",
"label": "Low-Voltage Cutoff",
+94 -1
View File
@@ -1716,6 +1716,86 @@ def _serialize_param_write_value(raw_value):
return raw_value.decode("utf-8", errors="replace")
return str(raw_value or "")
def _apply_cellular_metered_setting(metered_enabled):
"""Apply GsmMetered changes to active NetworkManager GSM profiles."""
if not shutil.which("nmcli"):
return {"profiles": [], "warnings": ["nmcli not found; parameter saved but modem profile was not updated."]}
metered_mode = "unknown" if bool(metered_enabled) else "no"
updated_profiles = []
warnings = []
try:
list_result = subprocess.run(
["nmcli", "-t", "-f", "NAME,TYPE", "connection", "show"],
capture_output=True, text=True, timeout=10, check=False
)
except Exception as error:
return {"profiles": [], "warnings": [f"Failed to list network profiles: {error}"]}
if list_result.returncode != 0:
stderr = (list_result.stderr or "").strip()
return {"profiles": [], "warnings": [f"Failed to list network profiles: {stderr or 'unknown error'}"]}
gsm_profiles = []
for line in (list_result.stdout or "").splitlines():
line = line.strip()
if not line:
continue
try:
name, conn_type = line.rsplit(":", 1)
except ValueError:
continue
if conn_type.strip() == "gsm" and name.strip():
gsm_profiles.append(name.strip())
for profile_name in gsm_profiles:
try:
result = subprocess.run(
["nmcli", "connection", "modify", profile_name, "connection.metered", metered_mode],
capture_output=True, text=True, timeout=10, check=False
)
if result.returncode == 0:
updated_profiles.append(profile_name)
else:
stderr = (result.stderr or "").strip()
warnings.append(f"Failed to update '{profile_name}': {stderr or 'unknown error'}")
except Exception as error:
warnings.append(f"Failed to update '{profile_name}': {error}")
# Re-activate active GSM profiles so the new metered setting takes effect immediately.
try:
active_result = subprocess.run(
["nmcli", "-t", "-f", "NAME,TYPE,STATE", "connection", "show", "--active"],
capture_output=True, text=True, timeout=10, check=False
)
if active_result.returncode == 0:
for line in (active_result.stdout or "").splitlines():
line = line.strip()
if not line:
continue
try:
name, conn_type, state = line.rsplit(":", 2)
except ValueError:
continue
if conn_type.strip() != "gsm" or state.strip() != "activated":
continue
profile_name = name.strip()
if not profile_name:
continue
subprocess.run(["nmcli", "connection", "down", profile_name], capture_output=True, text=True, timeout=10, check=False)
subprocess.run(["nmcli", "connection", "up", profile_name], capture_output=True, text=True, timeout=20, check=False)
except Exception as error:
warnings.append(f"Failed to cycle active GSM connection: {error}")
return {"profiles": updated_profiles, "warnings": warnings}
def _format_longitudinal_personality(value):
mapping = {
"0": "Aggressive",
@@ -2718,9 +2798,22 @@ def setup(app):
else:
params.put(key, str_val)
gsm_metered_apply_result = None
if key == "GsmMetered":
metered_enabled = str_val.strip() in ("1", "true", "True")
gsm_metered_apply_result = _apply_cellular_metered_setting(metered_enabled)
update_frogpilot_toggles()
return jsonify({"message": f"Parameter '{key}' updated successfully."}), 200
response = {"message": f"Parameter '{key}' updated successfully."}
if gsm_metered_apply_result is not None:
response["updated"] = {"GsmMetered": str_val.strip() in ("1", "true", "True")}
response["networkProfilesUpdated"] = gsm_metered_apply_result.get("profiles", [])
warnings = gsm_metered_apply_result.get("warnings", [])
if warnings:
response["warning"] = " ".join(warnings)
return jsonify(response), 200
return params.get(request.args.get("key")) or "", 200