Skip to content

Commit 8421699

Browse files
wip
Signed-off-by: Patrick José Pereira <patrickelectric@gmail.com>
1 parent e9b4dd8 commit 8421699

File tree

2 files changed

+103
-21
lines changed

2 files changed

+103
-21
lines changed

core/services/wifi/main.py

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -291,21 +291,43 @@ async def initialize_wpa_supplicant_managers(args: argparse.Namespace) -> bool:
291291

292292

293293
async def initialize_network_manager(args: argparse.Namespace) -> bool:
294-
"""Initialize NetworkManager-based wifi manager."""
294+
"""Initialize NetworkManager-based wifi manager for all available WiFi interfaces."""
295295
global wifi_manager # pylint: disable=global-statement
296296

297-
manager = NetworkManagerWifi()
298-
manager.configure(args)
297+
# First check if NetworkManager is available
298+
test_manager = NetworkManagerWifi()
299+
test_manager.configure(args)
300+
if not await test_manager.can_work():
301+
return False
299302

300-
if not await manager.can_work():
303+
# Get all WiFi interfaces
304+
available_interfaces = await NetworkManagerWifi.get_all_wifi_interfaces()
305+
if not available_interfaces:
306+
logger.warning("No WiFi interfaces found via NetworkManager")
301307
return False
302308

303-
await manager.start()
304-
interface_name = manager.interface_name
305-
wifi_managers[interface_name] = manager
306-
wifi_manager = manager
307-
logger.info(f"Initialized NetworkManagerWifi for interface: {interface_name}")
308-
return True
309+
logger.info(f"Found WiFi interfaces: {available_interfaces}")
310+
311+
for iface_name in available_interfaces:
312+
try:
313+
manager = NetworkManagerWifi(target_interface=iface_name)
314+
manager.configure(args)
315+
await manager.start()
316+
317+
if manager._device_path is None:
318+
logger.warning(f"Could not initialize manager for {iface_name}")
319+
continue
320+
321+
wifi_managers[iface_name] = manager
322+
logger.info(f"Initialized NetworkManagerWifi for interface: {iface_name}")
323+
324+
# Set first one as primary manager for backwards compatibility
325+
if wifi_manager is None:
326+
wifi_manager = manager
327+
except Exception as error:
328+
logger.warning(f"Could not initialize NetworkManagerWifi for {iface_name}: {error}")
329+
330+
return len(wifi_managers) > 0
309331

310332

311333
async def main() -> None:

core/services/wifi/wifi_handlers/networkmanager/networkmanager.py

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,26 @@ class NetworkManagerWifi(AbstractWifiManager):
3939
both client and access point (hotspot) modes.
4040
"""
4141

42-
def __init__(self) -> None:
43-
"""Initialize NetworkManager WiFi handler."""
42+
def __init__(self, target_interface: Optional[str] = None) -> None:
43+
"""Initialize NetworkManager WiFi handler.
44+
45+
Args:
46+
target_interface: Specific interface name to manage (e.g., 'wlan0', 'wlan1').
47+
If None, will use the first WiFi device found.
48+
"""
4449
super().__init__()
4550
self._bus = sdbus.sd_bus_open_system()
4651
self._nm: Optional[NetworkManager] = None
4752
self._nm_settings: Optional[NetworkManagerSettings] = None
4853
self._device_path: Optional[str] = None
54+
self._target_interface: Optional[str] = target_interface
55+
self._interface_name: str = target_interface or "wlan0"
4956
self._create_ap_process: Optional[subprocess.Popen[str]] = None
5057
self._ap_interface = "uap0"
5158
self._tasks: List[asyncio.Task[Any]] = []
5259
self._nm = NetworkManager(self._bus)
5360
self._nm_settings = NetworkManagerSettings(self._bus)
54-
logger.info("NetworkManagerWifi initialized")
61+
logger.info(f"NetworkManagerWifi initialized for interface: {target_interface or 'auto'}")
5562

5663
async def _create_virtual_interface(self) -> bool:
5764
"""Create virtual AP interface using iw"""
@@ -113,8 +120,24 @@ async def start(self) -> None:
113120
for device_path in devices:
114121
device = NetworkDeviceWireless(device_path, self._bus)
115122
if await device.device_type == DeviceType.WIFI:
116-
self._device_path = device_path
117-
break
123+
iface_name = await device.interface
124+
# If target interface specified, only use that one
125+
if self._target_interface is not None:
126+
if iface_name == self._target_interface:
127+
self._device_path = device_path
128+
self._interface_name = iface_name
129+
break
130+
else:
131+
# Use first WiFi device found
132+
self._device_path = device_path
133+
self._interface_name = iface_name
134+
break
135+
136+
if self._device_path is None:
137+
logger.warning(f"No WiFi device found for interface: {self._target_interface or 'any'}")
138+
return
139+
140+
logger.info(f"Using WiFi device: {self._interface_name} ({self._device_path})")
118141

119142
# Create virtual AP interface if needed
120143
await self._create_virtual_interface()
@@ -584,7 +607,28 @@ def enable_smart_hotspot(self) -> None:
584607
logger.info("Smart hotspot enabled")
585608

586609
async def get_current_network(self) -> Optional[SavedWifiNetwork]:
587-
raise NotImplementedError
610+
if not self._device_path:
611+
return None
612+
613+
try:
614+
device = NetworkDeviceWireless(self._device_path, self._bus)
615+
state = await device.state
616+
617+
if state != DeviceState.ACTIVATED:
618+
return None
619+
620+
ap = AccessPoint(await device.active_access_point, self._bus)
621+
ssid = (await ap.ssid).decode("utf-8")
622+
623+
saved_networks = await self.get_saved_wifi_network()
624+
for network in saved_networks:
625+
if network.ssid == ssid:
626+
return network
627+
628+
return SavedWifiNetwork(networkid=0, ssid=ssid, bssid=await ap.hw_address)
629+
except Exception as e:
630+
logger.error(f"Error getting current network: {e}")
631+
return None
588632

589633
def is_smart_hotspot_enabled(self) -> bool:
590634
return self._settings_manager.settings.smart_hotspot_enabled is True
@@ -619,11 +663,27 @@ async def hotspot_watchdog(self) -> None:
619663
@property
620664
def interface_name(self) -> str:
621665
"""Get the current interface name."""
622-
if self._device_path is None:
623-
return "wlan0"
624-
# Extract interface name from device path asynchronously is complex,
625-
# so we return a default for now
626-
return "wlan0"
666+
return self._interface_name
667+
668+
@staticmethod
669+
async def get_all_wifi_interfaces() -> List[str]:
670+
"""Get list of all WiFi interface names from NetworkManager."""
671+
interfaces: List[str] = []
672+
try:
673+
bus = sdbus.sd_bus_open_system()
674+
nm = NetworkManager(bus)
675+
devices = await nm.get_devices()
676+
for device_path in devices:
677+
device = NetworkDeviceWireless(device_path, bus)
678+
if await device.device_type == DeviceType.WIFI:
679+
iface_name = await device.interface
680+
# Exclude virtual AP interfaces
681+
if not iface_name.startswith("uap"):
682+
interfaces.append(iface_name)
683+
bus.close()
684+
except Exception as e:
685+
logger.warning(f"Could not enumerate WiFi interfaces: {e}")
686+
return sorted(interfaces)
627687

628688
def get_available_interfaces(self) -> List[str]:
629689
"""Get list of available WLAN interfaces, excluding virtual AP interfaces."""

0 commit comments

Comments
 (0)