Le fichier core/wifi.py est responsable de la gestion des réseaux sans fil. En l'absence d'outils lourds comme NetworkManager, il s'interface directement avec l'outil système bas niveau wpa_supplicant pour scanner les réseaux, s'y connecter et vérifier le statut de la connexion.
_detect_iface() lit directement le dossier Linux /sys/class/net pour chercher une interface réseau dont le nom commence par wl (ex: wlan0 ou wlp2s0), s'assurant que le Wi-Fi fonctionnera indépendamment du nom donné par le noyau Linux.scan_networks() exécute la commande wpa_cli scan puis wpa_cli scan_results. La vraie difficulté réside dans le fait de découper la chaîne de caractères renvoyée (séparée par des tabulations) pour extraire le nom du réseau (SSID) et sa puissance de signal (en dBm), tout en filtrant les réseaux cachés ou invalides.connect_network() construit de toutes pièces une configuration temporaire en exécutant une suite de commandes add_network, set_network, puis enable_network via wpa_cli. Elle supporte aussi bien les réseaux ouverts (key_mgmt=NONE) que les réseaux protégés par mot de passe.connect_network pour injecter des paramètres identity et password via la norme 802.1x./etc/wpa_supplicant/wpa_supplicant.conf en python pour lister tous les réseaux déjà enregistrés et proposer à l'utilisateur de les "Oublier" via un menu dédié dans l'interface.import subprocess
import os
class WifiManager:
def __init__(self, desktop):
self.desktop = desktop
self.iface = self._detect_iface()
def _detect_iface(self):
try:
net_path = "/sys/class/net"
if os.path.exists(net_path):
for iface in os.listdir(net_path):
if iface.startswith("wl"):
return iface
except:
pass
return None
def scan_networks(self, sudo_pwd):
if not self.iface:
return []
try:
# Déclenchement du scan via wpa_cli (car wpa_supplicant tourne déjà)
subprocess.run(['sudo', '-S', '/sbin/wpa_cli', '-i', self.iface, 'scan'], input=sudo_pwd + '\n', text=True, capture_output=True)
import time
time.sleep(5) # Laisser le temps au scan complet de s'effectuer (souvent 3 à 5 secondes)
# Récupération des résultats
res = subprocess.run(['sudo', '-S', '/sbin/wpa_cli', '-i', self.iface, 'scan_results'], input=sudo_pwd + '\n', text=True, capture_output=True)
# DEBUG : Sauvegarder la sortie brute pour analyse
try:
with open('/tmp/wifi_debug.txt', 'w') as f:
f.write(res.stdout)
except:
pass
networks = {}
lines = res.stdout.strip().split('\n')
# Format attendu : bssid / frequency / signal level / flags / ssid (séparés par des tabulations)
for line in lines[1:]:
parts = line.split('\t')
if len(parts) >= 5:
signal = parts[2]
ssid = parts[4]
if ssid and not ssid.startswith('\\x00'):
try:
# Ne garder que le meilleur signal par SSID
sig_val = float(signal)
if ssid not in networks or networks[ssid]['signal'] < sig_val:
networks[ssid] = {'ssid': ssid, 'signal': sig_val}
except:
pass
valid_nets = sorted(networks.values(), key=lambda x: x['signal'], reverse=True)
return valid_nets
except Exception as e:
print("Scan error:", e)
return []
def connect_network(self, sudo_pwd, ssid, psk):
if not self.iface:
return False, "Aucune interface Wi-Fi détectée"
try:
def run_wpa_cmd(args):
cmd = ['sudo', '-S', '/sbin/wpa_cli', '-i', self.iface] + args
res = subprocess.run(cmd, input=sudo_pwd + '\n', text=True, capture_output=True)
return res.stdout.strip()
out = run_wpa_cmd(['add_network'])
# Output of add_network should be the network ID (integer as string)
# but sometimes it has leading/trailing debug info. Let's just grab the last line.
lines = out.split('\n')
net_id = lines[-1].strip()
if not net_id.isdigit():
return False, f"Erreur de création de réseau ({out})"
run_wpa_cmd(['set_network', net_id, 'ssid', f'"{ssid}"'])
if psk:
run_wpa_cmd(['set_network', net_id, 'psk', f'"{psk}"'])
else:
run_wpa_cmd(['set_network', net_id, 'key_mgmt', 'NONE'])
run_wpa_cmd(['enable_network', net_id])
run_wpa_cmd(['save_config'])
run_wpa_cmd(['select_network', net_id])
return True, "Connexion initiée."
except Exception as e:
return False, str(e)
def get_current_status(self, sudo_pwd):
if not self.iface:
return None, None
try:
res = subprocess.run(['sudo', '-S', '/sbin/wpa_cli', '-i', self.iface, 'status'], input=sudo_pwd + '\n', text=True, capture_output=True)
ssid = None
ip = None
wpa_state = None
for line in res.stdout.split('\n'):
if line.startswith('ssid='):
ssid = line.split('=', 1)[1]
elif line.startswith('ip_address='):
ip = line.split('=', 1)[1]
elif line.startswith('wpa_state='):
wpa_state = line.split('=', 1)[1]
if wpa_state == 'COMPLETED':
return ssid, ip
except:
pass
return None, None