Skip to content

Instantly share code, notes, and snippets.

@dzfranklin
Created December 31, 2019 23:20
Show Gist options
  • Save dzfranklin/bb4848ffda1d44b437e2a9d7c8a8f3f5 to your computer and use it in GitHub Desktop.
Save dzfranklin/bb4848ffda1d44b437e2a9d7c8a8f3f5 to your computer and use it in GitHub Desktop.
Wrapper around bluetoothctl
#!/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
@octvs
Copy link

octvs commented Jan 25, 2023

Necroing from, with my take on the issue, pure shell script to utilize the aliases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment