I'm currently using pexpect in python to use bluetoothctl. I can get a list of all bluetooth devices, but is there a way to narrow down the list to only audio devices (bluetooth speakers, headphones).

Here is my code so far:

import time
import pexpect

#returns list of all availible bluetooth devices
def scan_bluetooth_agents():
    devices = {}

    child = pexpect.spawn('sudo bluetoothctl')
    child.sendline ('scan on')
    child.sendline ('scan off')

    line = child.readline()
    while b'scan off' not in line:
    if b'Device' in line:
            line = str(line.replace(b"\r\n", b'')).strip("b'").strip("'")
        address, name = line.split('Device ')[1].split(' ', 1)
        devices[name] = address

    line = child.readline()
    child.sendline ('exit')

    return devices

#this is the function that needs to return only audio devices
def valid_devices(devices):
    output = {}
    i = 0
    for device in devices:
        #if device contrains 'JBL' then output[i] = device

if __name__ == "__main__":
    devices = scan_bluetooth_agents()
    print('All Devices:')
    print('Valid Audio Devices:')
    audioDevices = valid_devices(devices)
  • how do you know the difference when you look at the list of devices? ... write the program to make the same distinction
    – jsotola
    Dec 31 '19 at 1:09

I don't think bluetoothctl was ever intended to work in this way. While I am sure you could get it to work, the BlueZ developers are free to change the commands in bluetoothctl so your script is likely to break for future versions of bluetoothctl.

A more programmatic way of doing this is using the documented DBus API.



The pydbus library is very helpful for accessing the BlueZ DBus API: https://pypi.org/project/pydbus/

Some useful things to know to get you started:

  1. The Dbus service for bluez is called 'org.bluez'
  2. The default Bluetooth adapter normally has '/org/bluez/hci0' as its DBus object path.
  3. BlueZ/DBus has an object manager which stores information about devices

To tell if it is an audio device, I would be tempted to look at the services the device is advertising. A list of these service UUIDs is available at: https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/

I did the following script to test the idea:

import pydbus
from gi.repository import GLib

discovery_time = 20

bus = pydbus.SystemBus()
mainloop = GLib.MainLoop()

# Connect to the DBus api for the Bluetooth adapter
adapter = bus.get('org.bluez', '/org/bluez/hci0')

def end_discovery():
    """Handler for end of discovery"""

# Run discovery
GLib.timeout_add_seconds(discovery_time, end_discovery)
print('Finding nearby devices...')

# Iterate around the devices to find audio devices
mngr = bus.get('org.bluez', '/')
mng_objs = mngr.GetManagedObjects()

for path in mng_objs:
    uuids = mng_objs[path].get('org.bluez.Device1', {}).get('UUIDs', [])
    # print(path, uuids)
    for uuid in uuids:
        # Service discovery UUIDs
        # https://www.bluetooth.com/specifications/assigned-numbers/service-discovery/
        # AudioSink - 0x110B - Advanced Audio Distribution Profile (A2DP)
        if uuid.startswith('0000110b'):
            print(mng_objs[path].get('org.bluez.Device1', {}).get('Name'),
                  mng_objs[path].get('org.bluez.Device1', {}).get('Address'))

This found a bluetooth speaker that ws in pairing mode. It will also report any devices that you have already in the list of known devices even if they are not in range.

(venv) pi@raspberrypi:~ $ python audio_devices.py 
Jabra SOLEMATE v1.27.0 50:C9:71:67:41:CD

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.