nix-files/pkgs/additional/sane-scripts/src/sane-ip-reconnect

97 lines
2.9 KiB
Plaintext
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages (ps: [ ])"
import re
import subprocess
import time
def rm_color(stdout: str) -> str:
" remove terminal control codes -- used by iwctl to colorize the output "
return re.sub("\\[[0-9;]*m", "", stdout)
def rm_heading(stdout: str) -> str:
return "\n".join(stdout.split("\n")[4:])
def extract_columns(stdout: str) -> list:
" split each line into two fields "
lines = stdout.split("\n")
items = []
for l in lines:
# XXX: this will fail for non-psk networks
# but i don't split on space because that would fail for networks that have names with spaces
if " psk " not in l: continue
split_at = l.find(" psk ")
first, second = l[:split_at], l[split_at+5:]
first, second = first.strip(), second.strip()
if first.startswith('> '):
# the `>` is formatting, indicating that it's the active network
first = first[2:].strip()
items.append((first, second))
return items
def iwctl(args: list, sudo: bool = False) -> str:
cmd = [ "iwctl" ] + args
if sudo:
cmd = [ "sudo" ] + cmd
res = subprocess.run(cmd, capture_output=True)
if res.returncode != 0:
print(f"iwctl failed:\n{res.stderr}")
res.check_returncode() # raise
return res.stdout.decode()
def scan():
iwctl(["station", "wlan0", "scan"], sudo=True)
time.sleep(5) # give time for adapter to see networks
def get_known() -> list:
stdout = iwctl(["known-networks", "list"])
stdout = rm_color(stdout)
stdout = rm_heading(stdout)
return [name for (name, date) in extract_columns(stdout)]
def get_visible() -> list:
stdout = iwctl(["station", "wlan0", "get-networks", "rssi-dbms"])
stdout = rm_color(stdout)
stdout = rm_heading(stdout)
return [(name, int(strength)) for (name, strength) in extract_columns(stdout)]
def choose_best(visible: list, known: list) -> str:
candidates = [(name, strength) for (name, strength) in visible if name in known]
# the least-negative RSSI is the best
return max(candidates, key=lambda c: c[1])[0]
def connect(network: str) -> str:
return iwctl(["station", "wlan0", "connect", network], sudo=True)
def restart() -> str:
return subprocess.check_output([
"sudo",
"systemctl",
"restart",
"iwd",
])
print("scanning for networks... ", end="", flush=True)
scan()
print("done")
print()
known = get_known()
print("known networks:", "".join(f"\n\t{name}" for name in known))
print()
visible = get_visible()
print("visible networks:", "".join(f"\n\t{name}: {rss}" for (name, rss) in visible))
print()
best = choose_best(visible, known)
try:
print(f"connecting to {best}")
result = connect(best)
except subprocess.CalledProcessError as e:
print("restarting iwd daemon")
restart()
else:
print("success", result)