mici network manager / allow uploads / long pitch / cruise offset

This commit is contained in:
firestar5683
2026-03-25 21:23:15 -05:00
parent 6a639c8619
commit 4046360299
55 changed files with 317 additions and 20 deletions
Binary file not shown.
+1
View File
@@ -250,6 +250,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"Fahrenheit", {PERSISTENT, BOOL, "0", "0", 3}},
{"FlashPanda", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"GMPedalLongitudinal", {PERSISTENT, BOOL, "1", "1", 2}},
{"LongPitch", {PERSISTENT, BOOL, "1", "0", 2}},
{"RemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0"}},
{"RemapCancelToDistance", {PERSISTENT, BOOL, "0", "0"}},
{"ForceAutoTune", {PERSISTENT, BOOL, "0", "0", 3}},
Binary file not shown.
+4
View File
@@ -878,6 +878,10 @@ class FrogPilotVariables:
"GMPedalLongitudinal",
condition=toggle.car_make == "gm" and toggle.has_pedal,
)
toggle.long_pitch = self.get_value(
"LongPitch",
condition=toggle.openpilot_longitudinal and toggle.car_make == "gm",
)
toggle.remote_start_boots_comma = self.get_value("RemoteStartBootsComma", condition=toggle.car_make == "gm")
toggle.remap_cancel_to_distance = self.get_value(
"RemapCancelToDistance",
+5 -2
View File
@@ -8,7 +8,7 @@ from openpilot.common.filter_simple import FirstOrderFilter
from openpilot.common.gps import get_gps_location_service
from openpilot.common.params import Params
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.car.cruise import V_CRUISE_MAX
from openpilot.selfdrive.car.cruise import V_CRUISE_MAX, V_CRUISE_UNSET
from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import A_CHANGE_COST, DANGER_ZONE_COST, J_EGO_COST, STOP_DISTANCE
from openpilot.frogpilot.common.frogpilot_utilities import calculate_lane_width, calculate_road_curvature
@@ -64,7 +64,10 @@ class FrogPilotPlanner:
controls_enabled = sm["selfdriveState"].enabled
planner_active = controls_enabled or long_control_active
v_cruise = min(sm["carState"].vCruise, V_CRUISE_MAX) * CV.KPH_TO_MS
v_cruise_kph = sm["carState"].vCruise
if 0 < v_cruise_kph < V_CRUISE_UNSET and frogpilot_toggles.set_speed_offset > 0:
v_cruise_kph += frogpilot_toggles.set_speed_offset
v_cruise = min(v_cruise_kph, V_CRUISE_MAX) * CV.KPH_TO_MS
v_ego = max(sm["carState"].vEgo, 0)
if planner_active:
@@ -1688,6 +1688,13 @@
"data_type": "bool",
"ui_type": "toggle"
},
{
"key": "LongPitch",
"label": "Smooth Pedal Response on Hills",
"description": "Smoothen acceleration and braking when driving downhill/uphill.",
"data_type": "bool",
"ui_type": "toggle"
},
{
"key": "RemoteStartBootsComma",
"label": "Remote Start Boots comma",
@@ -175,6 +175,7 @@ FrogPilotVehiclesPanel::FrogPilotVehiclesPanel(FrogPilotSettingsWindow *parent,
std::vector<std::tuple<QString, QString, QString, QString>> vehicleToggles {
{"GMToggles", tr("General Motors Settings"), tr("<b>FrogPilot features for General Motors vehicles.</b>"), ""},
{"GMPedalLongitudinal", tr("Use Pedal For Longitudinal"), tr("<b>Use the pedal interceptor for full longitudinal control</b> on supported GM vehicles."), ""},
{"LongPitch", tr("Smooth Pedal Response on Hills"), tr("<b>Smoothen acceleration and braking</b> when driving downhill/uphill."), ""},
{"RemoteStartBootsComma", tr("Remote Start Boots comma"), tr("<b>Use the remote-start GM panda firmware at boot.</b><br><br>Required for GM remote-start startup signal behavior."), ""},
{"RemapCancelToDistance", tr("Remap Cancel To Distance"), tr("<b>On pedal-interceptor Bolts, remap the steering-wheel CANCEL button to distance/personality input.</b>"), ""},
{"VoltSNG", tr("Stop-and-Go Hack"), tr("<b>Force stop-and-go</b> on the 2017 Chevy Volt."), ""},
+2 -2
View File
@@ -23,9 +23,9 @@ private:
std::map<QString, AbstractControl*> toggles;
QSet<QString> gmKeys = {"GMPedalLongitudinal", "RemoteStartBootsComma", "RemapCancelToDistance", "VoltSNG"};
QSet<QString> gmKeys = {"GMPedalLongitudinal", "LongPitch", "RemoteStartBootsComma", "RemapCancelToDistance", "VoltSNG"};
QSet<QString> hkgKeys = {"TacoTuneHacks"};
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "RemapCancelToDistance", "SNGHack", "VoltSNG"};
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "LongPitch", "RemapCancelToDistance", "SNGHack", "VoltSNG"};
QSet<QString> subaruKeys = {"SubaruSNG"};
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SDSUSupport", "SNGSupport"};
+10 -3
View File
@@ -370,8 +370,10 @@ class CarController(CarControllerBase):
self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = int(min(-100 * stop_accel, self.params.MAX_BRAKE))
else:
long_pitch_enabled = bool(getattr(frogpilot_toggles, "long_pitch", True))
if self.is_volt:
if len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping:
if long_pitch_enabled and len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping:
volt_pitch_accel = math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY
else:
volt_pitch_accel = 0.0
@@ -395,7 +397,7 @@ class CarController(CarControllerBase):
if self.apply_brake > 0:
self.apply_gas = self.params.INACTIVE_REGEN
else:
if len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping:
if long_pitch_enabled and len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping:
accel_due_to_pitch = math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY
else:
accel_due_to_pitch = 0.0
@@ -424,7 +426,12 @@ class CarController(CarControllerBase):
if self.CP.carFingerprint in CC_ONLY_CAR:
# gas interceptor only used for full long control on cars without ACC
interceptor_gas_cmd, press_regen_paddle = self.calc_pedal_command(actuators.accel, CC.longActive, CS.out.vEgo)
pedal_accel_cmd = actuators.accel
if (long_pitch_enabled and
len(CC.orientationNED) == 3 and CS.out.vEgo > self.CP.vEgoStopping):
pedal_accel_cmd += math.sin(CC.orientationNED[1]) * ACCELERATION_DUE_TO_GRAVITY
interceptor_gas_cmd, press_regen_paddle = self.calc_pedal_command(pedal_accel_cmd, CC.longActive, CS.out.vEgo)
if self.CP.enableGasInterceptorDEPRECATED and self.apply_gas > self.params.INACTIVE_REGEN and CS.out.cruiseState.standstill:
interceptor_gas_cmd = self.params.SNG_INTERCEPTOR_GAS
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-e9100341-DEBUG";
const uint8_t gitversion[19] = "DEV-6a639c86-DEBUG";
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
DEV-e9100341-DEBUG
DEV-6a639c86-DEBUG
-6
View File
@@ -112,12 +112,6 @@ class VCruiseHelper:
else:
self.v_cruise_kph += v_cruise_delta * CRUISE_INTERVAL_SIGN[button_type]
# FrogPilot variables
if long_press and frogpilot_toggles.set_speed_offset > 0:
self.v_cruise_kph += frogpilot_toggles.set_speed_offset
if button_type == ButtonType.decelCruise:
self.v_cruise_kph -= v_cruise_delta
# If set is pressed while overriding, clip cruise speed to minimum of vEgo
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise):
self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH)
Binary file not shown.
@@ -251,6 +251,14 @@ class StarPilotGMVehicleLayout(StarPilotPanel):
"color": "#FFC40D",
"key": "GMPedalLongitudinal",
},
{
"title": tr_noop("Smooth Pedal on Hills"),
"type": "toggle",
"get_state": lambda: self._params.get_bool("LongPitch"),
"set_state": lambda s: self._params.put_bool("LongPitch", s),
"color": "#FFC40D",
"key": "LongPitch",
},
{
"title": tr_noop("Remote Start Panda"),
"type": "toggle",
@@ -238,8 +238,8 @@ class NetworkInfoPage(NavWidget):
self._connect_btn.set_label("connecting...")
self._connect_btn.set_enabled(False)
elif self._network.is_connected:
self._connect_btn.set_label("connected")
self._connect_btn.set_enabled(False)
self._connect_btn.set_label("disconnect")
self._connect_btn.set_enabled(True)
elif self._network.security_type == SecurityType.UNSUPPORTED:
self._connect_btn.set_label("connect")
self._connect_btn.set_enabled(False)
@@ -409,6 +409,10 @@ class WifiUIMici(BigMultiOptionDialog):
cloudlog.warning(f"Trying to connect to unknown network: {ssid}")
return
if network.is_connected:
self._wifi_manager.disconnect_network(network.ssid)
return
if network.is_saved:
self._connecting = network.ssid
self._wifi_manager.activate_connection(network.ssid)
@@ -3,6 +3,7 @@ import numpy as np
import pyray as rl
from cereal import messaging, car, log
from msgq.visionipc import VisionStreamType
from openpilot.common.constants import CV
from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.selfdrive.ui.mici.onroad import SIDE_PANEL_WIDTH
from openpilot.selfdrive.ui.mici.onroad.alert_renderer import AlertRenderer
@@ -178,6 +179,93 @@ class ExperimentalModeBanner(Widget):
self._label.render(banner_rect)
class MinSteerSpeedBanner(Widget):
"""One-shot-per-drive banner shown for the full first below-min-steer interval."""
def __init__(self):
super().__init__()
self._shown_this_drive = False
self._showing_interval = False
self._has_been_above_min = False
self._was_under_min = False
self._last_started_frame = -1
self._label = UnifiedLabel(
"",
34,
FontWeight.BOLD,
text_color=rl.WHITE,
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
alignment_vertical=rl.GuiTextAlignmentVertical.TEXT_ALIGN_MIDDLE,
)
def _reset(self):
self._shown_this_drive = False
self._showing_interval = False
self._has_been_above_min = False
self._was_under_min = False
@staticmethod
def _get_message(min_steer_speed: float) -> str:
speed_units = CV.MS_TO_KPH if ui_state.is_metric else CV.MS_TO_MPH
speed = int(round(min_steer_speed * speed_units))
unit = "km/h" if ui_state.is_metric else "mph"
return f"Steer Unavailable Under {speed} {unit}"
def _update_state(self):
if not ui_state.started:
self._last_started_frame = -1
self._reset()
return
if ui_state.started_frame != self._last_started_frame:
self._last_started_frame = ui_state.started_frame
self._reset()
sm = ui_state.sm
if sm.recv_frame["carParams"] < ui_state.started_frame or sm.recv_frame["carState"] < ui_state.started_frame:
return
min_steer_speed = float(sm["carParams"].minSteerSpeed)
if min_steer_speed <= 0:
self._showing_interval = False
self._was_under_min = False
return
under_min = float(sm["carState"].vEgo) < min_steer_speed
if not under_min:
self._has_been_above_min = True
crossed_below = under_min and not self._was_under_min
if (not self._shown_this_drive) and crossed_below and self._has_been_above_min:
self._showing_interval = True
self._shown_this_drive = True
if self._showing_interval and not under_min:
self._showing_interval = False
self._was_under_min = under_min
if self._showing_interval:
self._label.set_text(self._get_message(min_steer_speed))
def _render(self, rect):
self._update_state()
if not self._showing_interval:
return
banner_width = min(rect.width - 120, 760)
banner_height = 72
banner_rect = rl.Rectangle(
rect.x + (rect.width - banner_width) / 2,
rect.y + 22,
banner_width,
banner_height,
)
rl.draw_rectangle_rounded(banner_rect, 0.3, 12, rl.Color(0, 0, 0, 185))
rl.draw_rectangle_rounded_lines_ex(banner_rect, 0.3, 12, 4, rl.Color(218, 111, 37, 255))
self._label.render(banner_rect)
class AugmentedRoadView(CameraView):
def __init__(self, bookmark_callback=None, stream_type: VisionStreamType = VisionStreamType.VISION_STREAM_ROAD):
super().__init__("camerad", stream_type)
@@ -204,6 +292,7 @@ class AugmentedRoadView(CameraView):
self._driver_state_renderer = DriverStateRenderer()
self._confidence_ball = ConfidenceBall()
self._experimental_mode_banner = ExperimentalModeBanner()
self._min_steer_speed_banner = MinSteerSpeedBanner()
self._offroad_label = UnifiedLabel("start the car to\nuse openpilot", 54, FontWeight.DISPLAY,
text_color=rl.Color(255, 255, 255, int(255 * 0.9)),
alignment=rl.GuiTextAlignment.TEXT_ALIGN_CENTER,
@@ -307,6 +396,8 @@ class AugmentedRoadView(CameraView):
self._hud_renderer.render(self._content_rect)
if (not in_reverse) and alert_to_render is None:
self._experimental_mode_banner.render(self._content_rect)
if not in_reverse:
self._min_steer_speed_banner.render(self._content_rect)
# End clipping region
rl.end_scissor_mode()
@@ -3,6 +3,7 @@ import numpy as np
import pyray as rl
from cereal import log, messaging
from msgq.visionipc import VisionStreamType
from openpilot.common.constants import CV
from openpilot.selfdrive.ui import UI_BORDER_SIZE
from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus
from openpilot.selfdrive.ui.onroad.alert_renderer import AlertRenderer
@@ -31,6 +32,95 @@ ROAD_CAM_MIN_SPEED = 15.0 # m/s (34 mph)
INF_POINT = np.array([1000.0, 0.0, 0.0])
class MinSteerSpeedBanner:
"""One-shot-per-drive banner that stays visible for the first below-min-steer interval."""
def __init__(self):
self._shown_this_drive = False
self._showing_interval = False
self._has_been_above_min = False
self._was_under_min = False
self._last_started_frame = -1
def _reset(self):
self._shown_this_drive = False
self._showing_interval = False
self._has_been_above_min = False
self._was_under_min = False
def _get_message(self, min_steer_speed: float) -> str:
speed_units = CV.MS_TO_KPH if ui_state.is_metric else CV.MS_TO_MPH
speed = int(round(min_steer_speed * speed_units))
unit = "km/h" if ui_state.is_metric else "mph"
return f"Steer Unavailable Under {speed} {unit}"
def _update_state(self):
if not ui_state.started:
self._last_started_frame = -1
self._reset()
return
if ui_state.started_frame != self._last_started_frame:
self._last_started_frame = ui_state.started_frame
self._reset()
sm = ui_state.sm
if sm.recv_frame["carParams"] < ui_state.started_frame or sm.recv_frame["carState"] < ui_state.started_frame:
return
min_steer_speed = float(sm["carParams"].minSteerSpeed)
if min_steer_speed <= 0:
self._showing_interval = False
self._was_under_min = False
return
under_min = float(sm["carState"].vEgo) < min_steer_speed
if not under_min:
self._has_been_above_min = True
crossed_below = under_min and not self._was_under_min
if (not self._shown_this_drive) and crossed_below and self._has_been_above_min:
self._showing_interval = True
self._shown_this_drive = True
if self._showing_interval and not under_min:
self._showing_interval = False
self._was_under_min = under_min
def render(self, rect: rl.Rectangle):
self._update_state()
if not self._showing_interval:
return
min_steer_speed = float(ui_state.sm["carParams"].minSteerSpeed)
if min_steer_speed <= 0:
return
banner_width = min(rect.width - 120, 760)
banner_height = 84
banner_rect = rl.Rectangle(
rect.x + (rect.width - banner_width) / 2,
rect.y + 24,
banner_width,
banner_height,
)
rl.draw_rectangle_rounded(banner_rect, 0.3, 12, rl.Color(0, 0, 0, 185))
rl.draw_rectangle_rounded_lines_ex(banner_rect, 0.3, 12, 4, rl.Color(218, 111, 37, 255))
text = self._get_message(min_steer_speed)
font = gui_app.font()
font_size = 44
text_size = rl.measure_text_ex(font, text, font_size, 0)
text_pos = rl.Vector2(
banner_rect.x + (banner_rect.width - text_size.x) / 2,
banner_rect.y + (banner_rect.height - text_size.y) / 2,
)
rl.draw_text_ex(font, text, text_pos, font_size, 0, rl.WHITE)
class AugmentedRoadView(CameraView):
def __init__(self, stream_type: VisionStreamType = VisionStreamType.VISION_STREAM_ROAD):
super().__init__("camerad", stream_type)
@@ -48,6 +138,7 @@ class AugmentedRoadView(CameraView):
self._hud_renderer = HudRenderer()
self.alert_renderer = AlertRenderer()
self.driver_state_renderer = DriverStateRenderer()
self._min_steer_speed_banner = MinSteerSpeedBanner()
# debug
self._pm = messaging.PubMaster(['uiDebug'])
@@ -88,6 +179,7 @@ class AugmentedRoadView(CameraView):
self._hud_renderer.render(self._content_rect)
self.alert_renderer.render(self._content_rect)
self.driver_state_renderer.render(self._content_rect)
self._min_steer_speed_banner.render(self._content_rect)
# Custom UI extension point - add custom overlays here
# Use self._content_rect for positioning within camera bounds
BIN
View File
Binary file not shown.
+7 -2
View File
@@ -134,6 +134,7 @@ log_recv_queue: Queue[str] = queue.Queue()
cancelled_uploads: set[str] = set()
cur_upload_items: dict[int, UploadItem | None] = {}
params_store = Params()
def strip_zst_extension(fn: str) -> str:
@@ -146,6 +147,10 @@ class AbortTransferException(Exception):
pass
def always_allow_uploads() -> bool:
return params_store.get_bool("AlwaysAllowUploads")
class UploadQueueCache:
@staticmethod
@@ -249,7 +254,7 @@ def cb(sm, item, tid, end_event: threading.Event, sz: int, cur: int) -> None:
if not item.allow_cellular:
if (time.monotonic() - sm.recv_time['deviceState']) > DEVICE_STATE_UPDATE_INTERVAL:
sm.update(0)
if sm['deviceState'].networkMetered:
if sm['deviceState'].networkMetered and not always_allow_uploads():
raise AbortTransferException
if end_event.is_set():
@@ -282,7 +287,7 @@ def upload_handler(end_event: threading.Event) -> None:
sm.update(0)
metered = sm['deviceState'].networkMetered
network_type = sm['deviceState'].networkType.raw
if metered and (not item.allow_cellular):
if metered and (not item.allow_cellular) and not always_allow_uploads():
retry_upload(tid, end_event, False)
continue
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -1
View File
@@ -251,6 +251,7 @@ def main(exit_event: threading.Event | None = None) -> None:
backoff = 0.1
while not exit_event.is_set():
sm.update(0)
always_allow_uploads = params.get_bool("AlwaysAllowUploads")
offroad = params.get_bool("IsOffroad")
network_type = sm['deviceState'].networkType if not force_wifi else NetworkType.wifi
if network_type == NetworkType.none:
@@ -258,7 +259,7 @@ def main(exit_event: threading.Event | None = None) -> None:
time.sleep(60 if offroad else 5)
continue
success = uploader.step(sm['deviceState'].networkType.raw, sm['deviceState'].networkMetered)
success = uploader.step(sm['deviceState'].networkType.raw, sm['deviceState'].networkMetered and not always_allow_uploads)
if success is None:
backoff = 60 if offroad else 5
elif success:
+79
View File
@@ -722,11 +722,86 @@ class WifiManager:
return
def is_tethering_active(self) -> bool:
if self._fake_networking:
for network in self._networks:
if network.is_connected:
return bool(network.ssid == self._tethering_ssid)
return False
if self._nmcli_networking:
try:
active = subprocess.run(
["nmcli", "-t", "-f", "NAME,TYPE,802-11-wireless.ssid", "connection", "show", "--active"],
check=False, capture_output=True, text=True,
)
for line in active.stdout.splitlines():
parts = self._parse_nmcli_line(line)
if len(parts) < 3 or parts[1] != "802-11-wireless":
continue
if _canonicalize_ssid(parts[2]) == _canonicalize_ssid(self._tethering_ssid):
return True
except Exception as e:
cloudlog.warning(f"nmcli tethering state lookup failed: {e}")
return False
if not self._dbus_available:
return False
def decode_ssid(value: Any) -> str:
if isinstance(value, bytes):
return value.decode("utf-8", "replace")
if isinstance(value, str):
return value
if isinstance(value, list):
try:
return bytes(value).decode("utf-8", "replace")
except Exception:
return str(value)
return str(value)
try:
for conn_path in self._get_active_connections():
conn_addr = DBusAddress(conn_path, bus_name=NM, interface=NM_ACTIVE_CONNECTION_IFACE)
conn_type = self._router_main.send_and_get_reply(Properties(conn_addr).get('Type')).body[0][1]
if conn_type != '802-11-wireless':
continue
settings_conn_path = self._router_main.send_and_get_reply(Properties(conn_addr).get('Connection')).body[0][1]
if settings_conn_path != "/":
settings = self._get_connection_settings(settings_conn_path)
ssid_value = settings.get('802-11-wireless', {}).get('ssid')
if isinstance(ssid_value, tuple) and len(ssid_value) > 1:
ssid = decode_ssid(ssid_value[1])
if _canonicalize_ssid(ssid) == _canonicalize_ssid(self._tethering_ssid):
return True
specific_obj_path = self._router_main.send_and_get_reply(Properties(conn_addr).get('SpecificObject')).body[0][1]
if specific_obj_path != "/":
ap_addr = DBusAddress(specific_obj_path, bus_name=NM, interface=NM_ACCESS_POINT_IFACE)
ap_ssid = decode_ssid(self._router_main.send_and_get_reply(Properties(ap_addr).get('Ssid')).body[0][1])
if _canonicalize_ssid(ap_ssid) == _canonicalize_ssid(self._tethering_ssid):
return True
except Exception as e:
cloudlog.warning(f"DBus tethering state lookup failed: {e}")
for network in self._networks:
if network.is_connected:
return bool(network.ssid == self._tethering_ssid)
return False
def disconnect_network(self, ssid: str, block: bool = False):
if not (self._dbus_available or self._fake_networking or self._nmcli_networking):
cloudlog.warning("disconnect_network called with no available networking backend")
return
def worker():
self._deactivate_connection(ssid)
if block:
worker()
else:
threading.Thread(target=worker, daemon=True).start()
def set_tethering_password(self, password: str):
if self._fake_networking:
self._tethering_password = password
@@ -863,6 +938,10 @@ class WifiManager:
self._enqueue_callbacks(self._networks_updated, self._networks)
return
# Keep UI state responsive while the DBus update completes.
self._current_network_metered = metered
self._enqueue_callbacks(self._networks_updated, self._networks)
def worker():
for active_conn in self._get_active_connections():
conn_addr = DBusAddress(active_conn, bus_name=NM, interface=NM_ACTIVE_CONNECTION_IFACE)