EmacsInteractiveJson/wifi.py

133 lines
3.8 KiB
Python
Executable file

#!/usr/bin/env python
# allowed fields: NAME,SSID,SSID-HEX,BSSID,MODE,CHAN,FREQ,RATE,BANDWIDTH,SIGNAL,BARS,SECURITY,WPA-FLAGS,RSN-FLAGS,DEVICE,ACTIVE,IN-USE,DBUS-PATH
# TODO: can't connect to AP with empty ssid
import subprocess as sp
import sys
import argparse
from shutil import which
CFG = {
"nmcli": {
"fields": ["ssid", "signal", "security", "chan", "rate", "mode", "bssid"],
},
"rfkill": {
"device": "wlan"
}
}
def _startup_check():
#if not CFG["nmcli"]["fields"][0].lower() == "ssid":
# raise NotImplementedError("ssid must be the first element in fields, will hopefully be fixed in the future")
binary_depencies = ["nmcli", "rfkill"]
gathered_missing = []
for binary in binary_depencies:
if which(binary) is None:
gathered_missing.append(binary)
if gathered_missing:
raise OSError("missing the following binaries: " + str(gathered_missing).strip("[]"))
def _split_blocks(text: str) -> list:
lines_list = text.splitlines()
field_len = len(CFG["nmcli"]["fields"])
if len(lines_list) % field_len:
raise ValueError("The amount of field elements doesn't devide evenly by the number of fields")
return [ lines_list[i:i+field_len] for i in range(0, len(lines_list), field_len) ]
def _parse_blocks(block_list: list) -> list:
new_block_list = []
for block in block_list:
block_dict = {}
for element in block:
elm_split = element.split(":", 1)
block_dict[elm_split[0]] = elm_split[1]
new_block_list.append(block_dict)
return new_block_list
def _gather_wifi() -> str:
sp.run(["nmcli", "dev", "wifi", "rescan"])
wifi_text = sp.run(
[
"nmcli",
"--terse",
"--colors", "no",
"--escape", "yes",
"--mode", "multiline",
"--fields", ",".join(CFG["nmcli"]["fields"]),
"dev", "wifi"
],
capture_output=True,
text=True
)
return wifi_text.stdout
def query_ssid(ssid: str) -> list:
gathered_connections = []
for element in get_wifi():
if element["SSID"] == ssid:
gathered_connections.append(element)
return gathered_connections
def get_wifi() -> list:
return _parse_blocks(_split_blocks(_gather_wifi()))
def connect(ssid: str) -> bool:
gathered_connections = query_ssid(ssid)
if len(gathered_connections) == 0:
print("Found no matching wifi ssid")
return False # think about the return type later
#connect_cmd = ["nmcli", "connection", "up", "id", ssid, "iface", "wifi"]
connection_id = ssid
if len(gathered_connections) > 1:
print("Found multiple access points with the exact same name (ssid)")
print("bssid:")
for element in gathered_connections:
print(" " * 4 + element["BSSID"], element["SIGNAL"] + "%")
answer = input("Do you want to choose a specific BSSID? [y/N]: ").lower()
if answer == "y":
connection_id = input("Which bssid: ")
sp.run(["rfkill", "unblock", CFG["rfkill"]["device"]])
sp.run(["nmcli", "networking", "on"])
connect_cmd = ["nmcli", "--ask", "device", "wifi", "connect", connection_id]
sp.run(connect_cmd)
return True
def main():
_startup_check()
try:
ap = argparse.ArgumentParser()
ap.add_argument("-j", "--json", help="just output current scanned wifi as json", action="store_true")
args = ap.parse_args()
if args.json:
print(get_wifi())
else:
my_dict = get_wifi()
for element in my_dict:
print(element)
my_input = input("wifi_name: ")
connect(my_input)
except KeyboardInterrupt:
print("")
print(">>> Interrupted by user")
sys.exit(1)
if __name__ == "__main__":
main()