Список ближайших/обнаруживаемых устройств Bluetooth, включая уже сопряженные, в Python, на Linux

Я пытаюсь перечислить все находящиеся поблизости/обнаруживаемые устройства Bluetooth, в том числе уже подключенные, используя Python для Linux.

Я знаю, как перечислить сервисы для устройства, использующего его адрес, и успешно подключиться:

services = bluetooth.find_service(address='...')

Чтение документов PyBluez, я ожидал бы, что какое-нибудь соседнее устройство появится, если я не укажу никаких критериев:

"Если критерии не указаны, то возвращается список всех обнаруженных поблизости сервисов".

"Единственное", что мне сейчас нужно, это иметь возможность перечислить уже сопряженные устройства, независимо от того, включены они, выключены или нет. Очень похоже на список, который я получаю во всех настройках → Bluetooth в Ubuntu/Unity.

Btw, следующее не отображает уже сопряженные устройства на моей машине, даже если они включены/рядом. Возможно, потому что они не могут быть обнаружены после спаривания:

import bluetooth
for d in bluetooth.discover_devices(flush_cache=True):
    print d

Любые идеи...?

Изменить: Я нашел и установил "bluez-tools".

bt-device --list

... дает мне необходимую мне информацию, то есть адреса добавленных устройств.

Я проверил источник C, выяснил, что это может быть не так просто, как я думал.

По-прежнему не знаю, как это сделать в Python...

Изменить: Я думаю, что DBUS может быть тем, что я должен читать. Кажется достаточно сложным. Если у кого-то есть код для обмена, я был бы действительно счастлив.:)

Ответ 1

С момента принятия версии 5 API Bluetooth большинство функций, используемых в решениях @Micke, были отброшены, и взаимодействие с шиной происходит через ObjectManager.GetManagedObjects [1].

import dbus


def proxyobj(bus, path, interface):
    """ commodity to apply an interface to a proxy object """
    obj = bus.get_object('org.bluez', path)
    return dbus.Interface(obj, interface)


def filter_by_interface(objects, interface_name):
    """ filters the objects based on their support
        for the specified interface """
    result = []
    for path in objects.keys():
        interfaces = objects[path]
        for interface in interfaces.keys():
            if interface == interface_name:
                result.append(path)
    return result


bus = dbus.SystemBus()

# we need a dbus object manager
manager = proxyobj(bus, "/", "org.freedesktop.DBus.ObjectManager")
objects = manager.GetManagedObjects()

# once we get the objects we have to pick the bluetooth devices.
# They support the org.bluez.Device1 interface
devices = filter_by_interface(objects, "org.bluez.Device1")

# now we are ready to get the informations we need
bt_devices = []
for device in devices:
    obj = proxyobj(bus, device, 'org.freedesktop.DBus.Properties')
    bt_devices.append({
        "name": str(obj.Get("org.bluez.Device1", "Name")),
        "addr": str(obj.Get("org.bluez.Device1", "Address"))
    })  

В списке bt_device есть словари с нужными данными: т.е.

например

[{
    'name': 'BBC micro:bit [zigiz]', 
    'addr': 'E0:7C:62:5A:B1:8C'
 }, {
    'name': 'BBC micro:bit [putup]',
    'addr': 'FC:CC:69:48:5B:32'
}]

Ссылка: [1] http://www.bluez.org/bluez-5-api-introduction-and-porting-guide/

Ответ 2

Мне удалось решить проблему самостоятельно. Следующий фрагмент списка адресов для всех сопряженных устройств, на моем адаптере bluetooth по умолчанию:

import dbus

bus = dbus.SystemBus()

manager = dbus.Interface(bus.get_object('org.bluez', '/'), 'org.bluez.Manager')

adapterPath = manager.DefaultAdapter()

adapter = dbus.Interface(bus.get_object('org.bluez', adapterPath), 'org.bluez.Adapter')

for devicePath in adapter.ListDevices():
    device = dbus.Interface(bus.get_object('org.bluez', devicePath),'org.bluez.Device')
    deviceProperties = device.GetProperties()
    print deviceProperties["Address"]

Ответ 3

Вы всегда можете выполнить его как команду оболочки и прочитать, что он возвращает:

import subprocess as sp
p = sp.Popen(["bt-device", "--list"], stdin=sp.PIPE, stdout=sp.PIPE, close_fds=True)
(stdout, stdin) = (p.stdout, p.stdin)
data = stdout.readlines()

Теперь data будет содержать список всех выходных строк, которые вы можете форматировать и воспроизводить по своему усмотрению.

Ответ 4

немного долго, но делает трюк в одну строку

bt-device -l | egrep '\(.*\)' | grep -oP '(?<=\()[^\)]+' | xargs -n1 bt-device -i