raylib: clean up networking (#36039)

* stasj

* remove one of many classes

* clean up and fix

* clean up

* stash/draft: oh this is sick

* so epic

* some clean up

* what the fuck, it doesn't even use these

* more epic initializers + make it kind of work

* so simple, wonder if we should further 2x reduce line count

* i've never ever seen this pattern b4, rm

* remove bs add niceness

* minor organization

* set security type and support listing and rming conns

* forget and connect

* jeepney is actually pretty good, it's 2x faster to get wifi device (0.005s to 0.002s)

* temp

* do blocking add in worker thread

* add jeepney

* lets finish with python-dbus first then evaluate - revert jeepney

This reverts commit 7de04b11c2.

and

* safe wrap

* missing

* saved connections

* set rest of callbacks

* skip hidden APs, simplify _running

* add state management

* either wrong password or disconnected for now

* i can't believe we didn't check this...

* disable button if unsupported!!!

* hide/show event no lag hopefully yayay

* fix hide event

* remove old wifi manager

* cache wifi device path + some clean up

* more clean up

* more clean up

* temp disable blocking prime thread

* hackily get device path once

* ok

* debug

* fix open networks

* debug

* clean up

* all threads wait for device path, and user functions dont ever attempt to get, just skip

* same place

* helper

* Revert "helper"

This reverts commit e237d9a720.

* organize?

* Revert "organize?"

This reverts commit 3aca3e5d62.

* c word is a bad word

* rk monitor debug for now

* nothing crazy

* improve checkmark responsiveness

* when forgetting: this is correct, but feels unresponsive

* this feels good

* need these two to keep forgetting and activating responsive

* sort by connected, strength, then name

* handle non-critical race condition

* log more

* unused

* oh jubilee is sick you can block on signals!!

* proof of concept to see if works on device

whoiops

* so sucking fick

* ah this is not generic, it's a filter on the return vals

* flip around to not drop

* oh thank god

* fix

* stash

* atomic replace

* clean up

* add old to keep track of what's moved over

* these are already moved

* so much junk

* so much junk

* more

* tethering wasn't used so we can ignore that for now

* no params now

* rm duplicate imports

* not used anymore

* move get wifi device over to jeepney! ~no additional lines

* request scan w/ keepney

* get_conns

* _connection_by_ssid_jeepney is 2x faster (0.01 vs 0.02s)

* do forget and activate

* _update_networks matches!

* rm old update_networks

* replace connect_to_network, about same time (yes i removed thread call)

* no more python-dbus!k

* doesn't hurt

* AP.from_dbus: actually handle incorrect paths w/ jeep + more efficient single call

* properly handle errors

* it's jeepney now

* less state

* using the thread safe router passes a race condition test that conn failed!

* bad to copy from old wifimanager

* fix conn usage

* clean up

* curious if locks are lagging

* not for now

* Revert "curious if locks are lagging"

This reverts commit 085dd185b0.

* clean up _monitor_state

* remove tests

* clean up dataclasses

* sort

* lint: okay fine it can be non by virtue of exiting right at the perfect time

* some network clean up

* some wifi manager clean up

* this is handled

* stop can be called manually, from deleting wifimanager, or exiting python. some protection

* its not mutable anymore

* scan on enter

* clean up

* back

* lint

* catch dbus fail to connect

catch dbus fail to connect
pull/36065/head
Shane Smiskol 2 days ago committed by GitHub
parent a70e4c3074
commit 5359f6d354
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      pyproject.toml
  2. 8
      selfdrive/ui/layouts/settings/settings.py
  3. 970
      system/ui/lib/wifi_manager.py
  4. 5
      system/ui/setup.py
  5. 5
      system/ui/updater.py
  6. 52
      system/ui/widgets/network.py
  7. 22
      uv.lock

@ -101,8 +101,8 @@ dev = [
"av",
"azure-identity",
"azure-storage-blob",
"dbus-next",
"dictdiffer",
"jeepney",
"matplotlib",
"opencv-python-headless",
"parameterized >=0.8, <0.9",

@ -9,7 +9,7 @@ from openpilot.selfdrive.ui.layouts.settings.software import SoftwareLayout
from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout
from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos
from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper
from openpilot.system.ui.lib.wifi_manager import WifiManager
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.network import WifiManagerUI
@ -54,12 +54,12 @@ class SettingsLayout(Widget):
self._current_panel = PanelType.DEVICE
# Panel configuration
self.wifi_manager = WifiManagerWrapper()
self.wifi_ui = WifiManagerUI(self.wifi_manager)
wifi_manager = WifiManager()
wifi_manager.set_active(False)
self._panels = {
PanelType.DEVICE: PanelInfo("Device", DeviceLayout()),
PanelType.NETWORK: PanelInfo("Network", self.wifi_ui),
PanelType.NETWORK: PanelInfo("Network", WifiManagerUI(wifi_manager)),
PanelType.TOGGLES: PanelInfo("Toggles", TogglesLayout()),
PanelType.SOFTWARE: PanelInfo("Software", SoftwareLayout()),
PanelType.FIREHOSE: PanelInfo("Firehose", FirehoseLayout()),

File diff suppressed because it is too large Load Diff

@ -19,7 +19,7 @@ from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.button import Button, ButtonStyle, ButtonRadio
from openpilot.system.ui.widgets.keyboard import Keyboard
from openpilot.system.ui.widgets.label import Label, TextAlignment
from openpilot.system.ui.widgets.network import WifiManagerUI, WifiManagerWrapper
from openpilot.system.ui.widgets.network import WifiManagerUI, WifiManager
NetworkType = log.DeviceState.NetworkType
@ -72,8 +72,7 @@ class Setup(Widget):
self.download_url = ""
self.download_progress = 0
self.download_thread = None
self.wifi_manager = WifiManagerWrapper()
self.wifi_ui = WifiManagerUI(self.wifi_manager)
self.wifi_ui = WifiManagerUI(WifiManager())
self.keyboard = Keyboard()
self.selected_radio = None
self.warning = gui_app.texture("icons/warning.png", 150, 150)

@ -7,7 +7,7 @@ from enum import IntEnum
from openpilot.system.hardware import HARDWARE
from openpilot.system.ui.lib.application import gui_app, FontWeight
from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper
from openpilot.system.ui.lib.wifi_manager import WifiManager
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.button import gui_button, ButtonStyle
from openpilot.system.ui.widgets.label import gui_text_box, gui_label
@ -43,8 +43,7 @@ class Updater(Widget):
self.show_reboot_button = False
self.process = None
self.update_thread = None
self.wifi_manager = WifiManagerWrapper()
self.wifi_manager_ui = WifiManagerUI(self.wifi_manager)
self.wifi_manager_ui = WifiManagerUI(WifiManager())
def install_update(self):
self.current_screen = Screen.PROGRESS

@ -6,7 +6,7 @@ from typing import cast
import pyray as rl
from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
from openpilot.system.ui.lib.wifi_manager import NetworkInfo, WifiManagerCallbacks, WifiManagerWrapper, SecurityType
from openpilot.system.ui.lib.wifi_manager import WifiManager, SecurityType, Network
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.button import ButtonStyle, Button
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog
@ -36,34 +36,35 @@ class UIState(IntEnum):
class WifiManagerUI(Widget):
def __init__(self, wifi_manager: WifiManagerWrapper):
def __init__(self, wifi_manager: WifiManager):
super().__init__()
self.wifi_manager = wifi_manager
self.state: UIState = UIState.IDLE
self._state_network: NetworkInfo | None = None # for CONNECTING / NEEDS_AUTH / SHOW_FORGET_CONFIRM / FORGETTING
self._state_network: Network | None = None # for CONNECTING / NEEDS_AUTH / SHOW_FORGET_CONFIRM / FORGETTING
self._password_retry: bool = False # for NEEDS_AUTH
self.btn_width: int = 200
self.scroll_panel = GuiScrollPanel()
self.keyboard = Keyboard(max_text_size=MAX_PASSWORD_LENGTH, min_text_size=MIN_PASSWORD_LENGTH, show_password_toggle=True)
self._load_icons()
self._networks: list[NetworkInfo] = []
self._networks: list[Network] = []
self._networks_buttons: dict[str, Button] = {}
self._forget_networks_buttons: dict[str, Button] = {}
self._lock = Lock()
self.wifi_manager = wifi_manager
self._confirm_dialog = ConfirmDialog("", "Forget", "Cancel")
self.wifi_manager.set_callbacks(
WifiManagerCallbacks(
need_auth=self._on_need_auth,
self.wifi_manager.set_callbacks(need_auth=self._on_need_auth,
activated=self._on_activated,
forgotten=self._on_forgotten,
networks_updated=self._on_network_updated,
connection_failed=self._on_connection_failed
)
)
self.wifi_manager.start()
self.wifi_manager.connect()
disconnected=self._on_disconnected)
def show_event(self):
# start/stop scanning when widget is visible
self.wifi_manager.set_active(True)
def hide_event(self):
self.wifi_manager.set_active(False)
def _load_icons(self):
for icon in STRENGTH_ICONS + ["icons/checkmark.png", "icons/circled_slash.png", "icons/lock_closed.png"]:
@ -78,7 +79,7 @@ class WifiManagerUI(Widget):
if self.state == UIState.NEEDS_AUTH and self._state_network:
self.keyboard.set_title("Wrong password" if self._password_retry else "Enter password", f"for {self._state_network.ssid}")
self.keyboard.reset()
gui_app.set_modal_overlay(self.keyboard, lambda result: self._on_password_entered(cast(NetworkInfo, self._state_network), result))
gui_app.set_modal_overlay(self.keyboard, lambda result: self._on_password_entered(cast(Network, self._state_network), result))
elif self.state == UIState.SHOW_FORGET_CONFIRM and self._state_network:
self._confirm_dialog.set_text(f'Forget Wi-Fi Network "{self._state_network.ssid}"?')
self._confirm_dialog.reset()
@ -86,7 +87,7 @@ class WifiManagerUI(Widget):
else:
self._draw_network_list(rect)
def _on_password_entered(self, network: NetworkInfo, result: int):
def _on_password_entered(self, network: Network, result: int):
if result == 1:
password = self.keyboard.text
self.keyboard.clear()
@ -121,7 +122,7 @@ class WifiManagerUI(Widget):
rl.end_scissor_mode()
def _draw_network_item(self, rect, network: NetworkInfo, clicked: bool):
def _draw_network_item(self, rect, network: Network, clicked: bool):
spacing = 50
ssid_rect = rl.Rectangle(rect.x, rect.y, rect.width - self.btn_width * 2, ITEM_HEIGHT)
signal_icon_rect = rl.Rectangle(rect.x + rect.width - ICON_SIZE, rect.y + (ITEM_HEIGHT - ICON_SIZE) / 2, ICON_SIZE, ICON_SIZE)
@ -174,10 +175,10 @@ class WifiManagerUI(Widget):
self.state = UIState.SHOW_FORGET_CONFIRM
self._state_network = network
def _draw_status_icon(self, rect, network: NetworkInfo):
def _draw_status_icon(self, rect, network: Network):
"""Draw the status icon based on network's connection state"""
icon_file = None
if network.is_connected:
if network.is_connected and self.state != UIState.CONNECTING:
icon_file = "icons/checkmark.png"
elif network.security_type == SecurityType.UNSUPPORTED:
icon_file = "icons/circled_slash.png"
@ -191,12 +192,12 @@ class WifiManagerUI(Widget):
icon_rect = rl.Vector2(rect.x, rect.y + (ICON_SIZE - texture.height) / 2)
rl.draw_texture_v(texture, icon_rect, rl.WHITE)
def _draw_signal_strength_icon(self, rect: rl.Rectangle, network: NetworkInfo):
def _draw_signal_strength_icon(self, rect: rl.Rectangle, network: Network):
"""Draw the Wi-Fi signal strength icon based on network's signal strength"""
strength_level = max(0, min(3, round(network.strength / 33.0)))
rl.draw_texture_v(gui_app.texture(STRENGTH_ICONS[strength_level], ICON_SIZE, ICON_SIZE), rl.Vector2(rect.x, rect.y), rl.WHITE)
def connect_to_network(self, network: NetworkInfo, password=''):
def connect_to_network(self, network: Network, password=''):
self.state = UIState.CONNECTING
self._state_network = network
if network.is_saved and not password:
@ -204,13 +205,12 @@ class WifiManagerUI(Widget):
else:
self.wifi_manager.connect_to_network(network.ssid, password)
def forget_network(self, network: NetworkInfo):
def forget_network(self, network: Network):
self.state = UIState.FORGETTING
self._state_network = network
network.is_saved = False
self.wifi_manager.forget_connection(network.ssid)
def _on_network_updated(self, networks: list[NetworkInfo]):
def _on_network_updated(self, networks: list[Network]):
with self._lock:
self._networks = networks
for n in self._networks:
@ -237,7 +237,7 @@ class WifiManagerUI(Widget):
if self.state == UIState.FORGETTING:
self.state = UIState.IDLE
def _on_connection_failed(self, ssid: str, error: str):
def _on_disconnected(self):
with self._lock:
if self.state == UIState.CONNECTING:
self.state = UIState.IDLE
@ -245,13 +245,11 @@ class WifiManagerUI(Widget):
def main():
gui_app.init_window("Wi-Fi Manager")
wifi_manager = WifiManagerWrapper()
wifi_ui = WifiManagerUI(wifi_manager)
wifi_ui = WifiManagerUI(WifiManager())
for _ in gui_app.render():
wifi_ui.render(rl.Rectangle(50, 50, gui_app.width - 100, gui_app.height - 100))
wifi_manager.shutdown()
gui_app.close()

@ -442,15 +442,6 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/56/c8/46ac27096684f33e27dab749ef43c6b0119c6a0d852971eaefb73256dc4c/cython-3.1.3-py3-none-any.whl", hash = "sha256:d13025b34f72f77bf7f65c1cd628914763e6c285f4deb934314c922b91e6be5a", size = 1225725, upload-time = "2025-08-13T06:19:09.593Z" },
]
[[package]]
name = "dbus-next"
version = "0.2.3"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/ce/45/6a40fbe886d60a8c26f480e7d12535502b5ba123814b3b9a0b002ebca198/dbus_next-0.2.3.tar.gz", hash = "sha256:f4eae26909332ada528c0a3549dda8d4f088f9b365153952a408e28023a626a5", size = 71112, upload-time = "2021-07-25T22:11:28.398Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d2/fc/c0a3f4c4eaa5a22fbef91713474666e13d0ea2a69c84532579490a9f2cc8/dbus_next-0.2.3-py3-none-any.whl", hash = "sha256:58948f9aff9db08316734c0be2a120f6dc502124d9642f55e90ac82ffb16a18b", size = 57885, upload-time = "2021-07-25T22:11:25.466Z" },
]
[[package]]
name = "dictdiffer"
version = "0.9.0"
@ -690,6 +681,15 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/15/aa/0aca39a37d3c7eb941ba736ede56d689e7be91cab5d9ca846bde3999eba6/isodate-0.7.2-py3-none-any.whl", hash = "sha256:28009937d8031054830160fce6d409ed342816b543597cece116d966c6d99e15", size = 22320, upload-time = "2024-10-08T23:04:09.501Z" },
]
[[package]]
name = "jeepney"
version = "0.9.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732", size = 106758, upload-time = "2025-02-27T18:51:01.684Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683", size = 49010, upload-time = "2025-02-27T18:51:00.104Z" },
]
[[package]]
name = "jinja2"
version = "3.1.6"
@ -1241,8 +1241,8 @@ dev = [
{ name = "av" },
{ name = "azure-identity" },
{ name = "azure-storage-blob" },
{ name = "dbus-next" },
{ name = "dictdiffer" },
{ name = "jeepney" },
{ name = "matplotlib" },
{ name = "opencv-python-headless" },
{ name = "parameterized" },
@ -1294,11 +1294,11 @@ requires-dist = [
{ name = "codespell", marker = "extra == 'testing'" },
{ name = "crcmod" },
{ name = "cython" },
{ name = "dbus-next", marker = "extra == 'dev'" },
{ name = "dictdiffer", marker = "extra == 'dev'" },
{ name = "future-fstrings" },
{ name = "hypothesis", marker = "extra == 'testing'", specifier = "==6.47.*" },
{ name = "inputs" },
{ name = "jeepney", marker = "extra == 'dev'" },
{ name = "jinja2", marker = "extra == 'docs'" },
{ name = "json-rpc" },
{ name = "libusb1" },

Loading…
Cancel
Save