I am running a sequence of Bluetoothctl commands on the terminal each time before I want to run a python script on my pi. I want to connect to a BLE Device automatically from the pi without any pairing confirmation or user interaction. Here are the commands I have to type each time I reboot the pi before I run another python script(the script will keep running for days after that until I stop or reboot the pi):
$sudo bluetoothctl
[Bluetooth]power on
[Bluetooth]discoverable on
[Bluetooth]pairable on
[Bluetooth]agent NoInputNoOutput
[Bluetooth]default-agent
I want to automate this process. So, I tried to use the bluetoothctl wrapper and modified it, but doesn't seem to work. No errors either.
import time
import pexpect
import subprocess
import sys
import re
class BluetoothctlError(Exception):
"""This exception is raised, when bluetoothctl fails to start."""
pass
class Bluetoothctl:
def __init__(self):
out = subprocess.check_output("rfkill unblock bluetooth", shell = True)
self.child = pexpect.spawn("bluetoothctl", echo = False)
print("bluetoothctl")
def get_output(self, command, pause = 0):
"""Run a command in bluetoothctl prompt, return output as a list of lines."""
self.child.send(command + "\n")
time.sleep(pause)
start_failed = self.child.expect(["bluetooth", pexpect.EOF])
if start_failed:
raise BluetoothctlError("Bluetoothctl failed after running " + command)
return self.child.before.split(b"\r\n")
def make_discoverable(self):
"""Make device discoverable."""
try:
out = self.get_output("discoverable on")
print("discoverable on")
except BluetoothctlError as e:
print(e)
return None
def power_on(self):
"""Start agent"""
try:
out = self.get_output("power on")
print("power on")
except BluetoothctlError as e:
print(e)
return None
def pairable_on(self):
"""Start agent"""
try:
out = self.get_output("pairable on")
print("pairable on")
except BluetoothctlError as e:
print(e)
return None
def agent_noinputnooutput(self):
"""Start agent"""
try:
out = self.get_output("agent NoInputNoOutput")
print("agent Registered Successfully")
except BluetoothctlError as e:
print(e)
return None
def default_agent(self):
"""Start default agent"""
try:
out = self.get_output("default-agent")
print("set as default agent")
except BluetoothctlError as e:
print(e)
return None
if __name__ == "__main__":
print("Init bluetooth...")
bl = Bluetoothctl()
bl.power_on()
bl.make_discoverable()
bl.pairable_on()
bl.agent_noinputnooutput()
bl.default_agent()
I wrote a python3 script to auto-connect my gamepads on my game cabinet. You have to run it for each device you want to connect, but no user interaction is needed. It uses the expect python module. I found it a little easier to use than expect/tcl scripts. If python can't find pexpect, you would need to install python3-pexpect.
sudo apt install python3-pexpect
You'll want to change the mylist list variable to search for the MACs that match the first 3 bytes (the vendor part) of your bluetooth devices. So, for example, if the first 3 bytes of the MACs on your devices start with AA:BB:CC:, then change the EF\:17\:D8\: part to AA\:BB\:CC\:
You can add as many devices you want to scan for in the mylist variable. My example searches for two different vendors, one starting with EF\:17\:D8\:, and one starting with 16\:04\:18\: The script will reject all other bluetooth devices that may be transmitting, and only connect the gamepad MACs you've configured in the mylist variable.
mylist = ['E4\:17\:D8\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].', '16\:04\:18\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].',pexpect.EOF]
Here is the python3 script:
#!/usr/bin/python3
import os,sys,time,pexpect
def findaddress():
address=''
p = pexpect.spawn('hcitool scan', encoding='utf-8')
p.logfile_read = sys.stdout
mylist = ['E4\:17\:D8\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].', '16\:04\:18\:[0-9A-F].[:][0-9A-F].[:][0-9A-F].',pexpect.EOF]
p.expect(mylist)
address=p.after
if address==pexpect.EOF:
return ''
else:
return address
def setbt(address):
response=''
p = pexpect.spawn('bluetoothctl', encoding='utf-8')
p.logfile_read = sys.stdout
p.expect('#')
p.sendline("remove "+address)
p.expect("#")
p.sendline("scan on")
mylist = ["Discovery started","Failed to start discovery","Device "+address+" not available","Failed to connect","Connection successful"]
while response != "Connection successful":
p.expect(mylist)
response=p.after
p.sendline("connect "+address)
time.sleep(1)
p.sendline("quit")
p.close()
#time.sleep(1)
return
address=''
while address=='':
address=findaddress()
time.sleep(1)
print (address," found")
setbt(address)
I wrote another python3 script that wraps the entire process in a Vte and shows the process as it is happening, and lets you to exit it, if needed. If you want to see that, just let me know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With