From f35bd34706c6e9e614e27fceeab0f5043b87d46504d2e120b97d328821718c55 Mon Sep 17 00:00:00 2001 From: ranomier Date: Thu, 16 Jan 2025 00:36:40 +0100 Subject: [PATCH] nmcli wifi parser --- wifi.py | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100755 wifi.py diff --git a/wifi.py b/wifi.py new file mode 100755 index 0000000..6401354 --- /dev/null +++ b/wifi.py @@ -0,0 +1,114 @@ +#!/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 + + +CFG = { + "nmcli": { + #"device": "", + "fields": ["ssid", "signal", "security", "chan", "rate", "mode", "bssid"], + }, + "rfkill": { + "device": "wlan" + } +} + +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") + + +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(): + try: + 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()