Created
December 31, 2019 23:20
-
-
Save dzfranklin/bb4848ffda1d44b437e2a9d7c8a8f3f5 to your computer and use it in GitHub Desktop.
Wrapper around bluetoothctl
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import sys | |
import re | |
import pexpect | |
class QuitError(Exception): | |
pass | |
class InvalidInputError(Exception): | |
pass | |
def decode(bstr): | |
if bstr: | |
return bstr.decode("ascii") | |
return "" | |
PROMPT_PREFIX = "\x1b[0;94m[" | |
PROMPT_ALIAS_END = "]" | |
PROMPT_SUFFIX = "\x1b[0m# " | |
def get_output(proc): | |
try: | |
proc.expect_exact(PROMPT_PREFIX) | |
stdout = decode(proc.before) | |
alias_chars = [] | |
while True: | |
char = decode(proc.read(1)) | |
if char == PROMPT_ALIAS_END: | |
break | |
alias_chars.append(char) | |
alias = "".join(alias_chars) | |
proc.expect_exact(PROMPT_SUFFIX) | |
except pexpect.EOF: | |
raise QuitError() | |
except pexpect.TIMEOUT: | |
print("[btctl] Error: bluetootctl timed out") | |
raise QuitError() | |
try: | |
while True: | |
proc.expect("\n", timeout=0.01) | |
stdout += decode(proc.before) | |
except pexpect.EOF: | |
raise QuitError() | |
except pexpect.TIMEOUT: | |
pass | |
return alias, stdout | |
def get_stdin(proc, alias, stdin=False): | |
if not stdin: | |
stdin = input(f"{PROMPT_PREFIX}{alias}{PROMPT_ALIAS_END}{PROMPT_SUFFIX}") | |
if "{" in stdin: | |
proc.sendline("paired-devices") | |
_, out = get_output(proc) | |
aliases = {} | |
for line in out.split("\r\n"): | |
if not line.startswith("Device "): | |
continue | |
parts = line.split(" ") | |
line_addr = parts[1] | |
line_alias = " ".join(parts[2:]) | |
aliases[line_alias] = line_addr | |
def replace_alias(match): | |
to_replace = match.group(1) | |
if to_replace in aliases: | |
return aliases[to_replace] | |
raise InvalidInputError(f"Alias \"{to_replace}\" does not exist") | |
try: | |
stdin = re.sub(r"\{(.*?)\}", replace_alias, stdin) | |
except InvalidInputError as err: | |
print(f"Invalid input: {err}") | |
stdin = get_stdin(proc, alias) | |
if stdin.strip() == "exit": | |
raise QuitError() | |
return stdin | |
proc = pexpect.spawn("bluetoothctl") | |
if __name__ == "__main__": | |
try: | |
if sys.__stdin__.isatty(): | |
while True: | |
alias, stdout = get_output(proc) | |
print(stdout) | |
stdin = get_stdin(proc, alias) | |
proc.sendline(stdin) | |
else: | |
for stdin in sys.__stdin__.readlines(): | |
alias, stdout = get_output(proc) | |
print(stdout) | |
proc.sendline(get_stdin(proc, alias, stdin=stdin)) | |
while "successful" not in stdout.lower() and "failed" not in stdout.lower(): | |
alias, stdout = get_output(proc) | |
print(stdout.strip()) | |
except KeyboardInterrupt: | |
pass | |
except QuitError: | |
pass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Necroing from, with my take on the issue, pure shell script to utilize the aliases.