33import re
44
55def wifi (ifname ):
6- data = HOST .run (tuple (f"wpa_cli -i { ifname } status" .split ()), default = "" )
76 wifi_data = {}
87
9- if data != "" :
10- for line in data .splitlines ():
11- k ,v = line .split ("=" )
12- if k == "ssid" :
13- wifi_data ["ssid" ] = v
14- if k == "wpa_state" and v == "DISCONNECTED" : # wpa_suppicant has most likely restarted, restart scanning
15- HOST .run (tuple (f"wpa_cli -i { ifname } scan" .split ()), default = "" )
8+ try :
9+ data = HOST .run (tuple (f"wpa_cli -i { ifname } status" .split ()), default = "" )
1610
17- data = HOST .run (tuple (f"wpa_cli -i { ifname } signal_poll" .split ()), default = "FAIL" )
18-
19- # signal_poll return FAIL not connected
20- if data .strip () != "FAIL" :
11+ if data != "" :
2112 for line in data .splitlines ():
22- k ,v = line .strip ().split ("=" )
23- if k == "RSSI" :
24- wifi_data ["rssi" ]= int (v )
25- data = HOST .run (tuple (f"wpa_cli -i { ifname } scan_result" .split ()), default = "FAIL" )
26-
27- if data != "FAIL" :
28- wifi_data ["scan-results" ] = parse_wpa_scan_result (data )
13+ try :
14+ if "=" not in line :
15+ continue
16+ k ,v = line .split ("=" , 1 )
17+ if k == "ssid" :
18+ wifi_data ["ssid" ] = v
19+ if k == "wpa_state" and v == "DISCONNECTED" : # wpa_suppicant has most likely restarted, restart scanning
20+ HOST .run (tuple (f"wpa_cli -i { ifname } scan" .split ()), default = "" )
21+ except ValueError :
22+ # Skip malformed lines
23+ continue
24+
25+ try :
26+ data = HOST .run (tuple (f"wpa_cli -i { ifname } signal_poll" .split ()), default = "FAIL" )
27+
28+ # signal_poll return FAIL not connected
29+ if data .strip () != "FAIL" :
30+ for line in data .splitlines ():
31+ try :
32+ if "=" not in line :
33+ continue
34+ k ,v = line .strip ().split ("=" , 1 )
35+ if k == "RSSI" :
36+ wifi_data ["rssi" ]= int (v )
37+ except (ValueError , KeyError ):
38+ # Skip malformed lines or invalid integers
39+ continue
40+ except Exception :
41+ # If signal_poll fails, continue without RSSI
42+ pass
43+ except Exception :
44+ # If status query fails entirely, continue with scan results
45+ pass
46+
47+ try :
48+ data = HOST .run (tuple (f"wpa_cli -i { ifname } scan_result" .split ()), default = "FAIL" )
49+ if data != "FAIL" :
50+ wifi_data ["scan-results" ] = parse_wpa_scan_result (data )
51+ except Exception :
52+ # If scan results fail, just omit them
53+ pass
2954
3055 return wifi_data
3156
@@ -36,39 +61,49 @@ def parse_wpa_scan_result(scan_output):
3661
3762 # Skip header line and any empty lines
3863 for line in lines :
39- line = line .strip ()
40- if not line or 'bssid / frequency' in line .lower ():
41- continue
42-
43- # Split by tabs or multiple spaces
44- parts = re .split (r'\t+|\s{2,}' , line )
45-
46- if len (parts ) >= 5 :
47- bssid = parts [0 ].strip ()
48- frequency = int (parts [1 ].strip ())
49- rssi = int (parts [2 ].strip ())
50- flags = parts [3 ].strip ()
51- ssid = parts [4 ].strip () if len (parts ) > 4 else ""
52-
53- # Skip hidden SSIDs (empty or whitespace only)
54- if not ssid or ssid .isspace () or '\\ x00' in ssid :
64+ try :
65+ line = line .strip ()
66+ if not line or 'bssid / frequency' in line .lower ():
5567 continue
5668
57- # Extract encryption information from flags
58- encryption = extract_encryption (flags )
59-
60- # Convert frequency to channel
61- channel = frequency_to_channel (frequency )
62-
63- # Keep only the network with best (highest) RSSI per SSID
64- if ssid not in networks or rssi < networks [ssid ]['rssi' ]:
65- networks [ssid ] = {
66- 'bssid' : bssid ,
67- 'ssid' : ssid ,
68- 'rssi' : rssi ,
69- 'encryption' : encryption ,
70- 'channel' : channel
71- }
69+ # Split by tabs or multiple spaces
70+ parts = re .split (r'\t+|\s{2,}' , line )
71+
72+ if len (parts ) >= 5 :
73+ bssid = parts [0 ].strip ()
74+ try :
75+ frequency = int (parts [1 ].strip ())
76+ rssi = int (parts [2 ].strip ())
77+ except ValueError :
78+ # Skip lines with invalid frequency or RSSI
79+ continue
80+
81+ flags = parts [3 ].strip ()
82+ ssid = parts [4 ].strip () if len (parts ) > 4 else ""
83+
84+ # Skip hidden SSIDs (empty or whitespace only)
85+ if not ssid or ssid .isspace () or '\\ x00' in ssid :
86+ continue
87+
88+ # Extract encryption information from flags
89+ encryption = extract_encryption (flags )
90+
91+ # Convert frequency to channel
92+ channel = frequency_to_channel (frequency )
93+
94+ # Keep only the network with best (highest) RSSI per SSID
95+ if ssid not in networks or rssi < networks [ssid ]['rssi' ]:
96+ networks [ssid ] = {
97+ 'bssid' : bssid ,
98+ 'ssid' : ssid ,
99+ 'rssi' : rssi ,
100+ 'encryption' : encryption ,
101+ 'channel' : channel
102+ }
103+ except Exception :
104+ # Skip any malformed scan result lines
105+ continue
106+
72107 # Convert to list and sort by RSSI (best first)
73108 result = list (networks .values ())
74109 result .sort (key = lambda x : x ['rssi' ], reverse = False )
0 commit comments