4

As the title suggests.

I am having hard time in finding a decent python dbus module for this one. There was a lot of smoke, mirrors & traps on the way.

First, let' see what I did.

The first booby-trap was dbus-python. Couldn't make it to work at all. Even the examples are broken.

It seems to be outdated, and replaced by pydbus

(The copyright owners / authors for both of them seem to be the same)

Let's see pydbus then. Also there, the examples don't work that great:

from pydbus import SystemBus
bus = SystemBus()
dev = bus.get('.NetworkManager', 'Devices/0')

gives

KeyError: 'object does not export any interfaces; you might need to pass object path as the 2nd argument for get()'

However, if we try something completely contrary to that error message..

dev = bus.get('.NetworkManager')

we get a nice object with lots of methods:

dir(dev)
['ActivateConnection',
 'ActivatingConnection',
 'ActiveConnections',
 'AddAndActivateConnection',
 'AllDevices',
 'Capabilities',
 'CheckConnectivity',
 'CheckPermissions',
 'CheckpointCreate',
 'CheckpointDestroy',
 'CheckpointRollback',
 'Connectivity',
 ....
 ]

So far so good. Let's see if we can get our hands on bluetooth with that one:

dev = bus.get('org.bluez')
dir(dev)
['Introspect',
 'RegisterAgent',
 'RegisterProfile',
 'RequestDefaultAgent',
 'UnregisterAgent',
 'UnregisterProfile'
 ]

So, again a nice object with some methods. However most of the things are missing. Let's take a look for example at this:

https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/device-api.txt

Can't get that mentioned "Connect" method with pydbus..?

Please don't suggest me to use subprocess.Popen with bluetoothctl - how lame is that. Besides, I want to learn dbus.

Questions:

  • How to get access to all bluetooth methods?
  • What would be the correct dbus python binding to use (that actually works)?
  • Any working example would be highly appreciated.
  • I want to achieve bt pairing using python

Some references:

EDIT:

There is, of course, the python bluez library. But that's GPL licensed. And there is no way to pair devices with bluez, right?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
El Sampsa
  • 1,673
  • 3
  • 17
  • 33

2 Answers2

8

EDIT: I created a demo for all of this (python + dbus + bluetooth) here: https://github.com/elsampsa/btdemo

Have fun.

no need to go further from here - just use that repo

Some more libraries & tutorials I found on the way:

An article at Medium: https://medium.com/@trstringer/talking-to-systemd-through-dbus-with-python-53b903ee88b1

Bluetool library: https://github.com/emlid/bluetool

dbus specs: https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces

My comments about dbus-python were premature. Bluetool uses it, and by following bluetool's code I was able to go forward a bit:

import dbus

def my_pprint(obj, intend = 0):
    if isinstance(obj, dict):
        for key, value in obj.items():
            print(intend*" "+str(key)+" : ")
            my_pprint(value, intend = intend + 4)
        print()
    elif isinstance(obj, list):
        for value in obj:
            my_pprint(value, intend = intend + 4)
        print()
    elif isinstance(obj, dbus.Byte ):
         print(intend*" "+ hex(obj) )
    else:
        print(intend*" "+str(obj))
    

bus = dbus.SystemBus()
proxy_object = bus.get_object("org.bluez","/")
manager = dbus.Interface(proxy_object, "org.freedesktop.DBus.ObjectManager")
objects = manager.GetManagedObjects()
my_pprint(objects) # see DUMP 1 in the end of this answer

i.e., the bluez dbus interface implements an object manager, giving a nice nested structure of objects (see the dump below)

What is (not) implemented at the bluez dbus interface, can be confirmed with this:

gdbus introspect --system --dest [Service] --object-path [Object path]

where Server & Object path come from the API docs here

For example:

gdbus introspect --system --dest org.bluez --object-path /org/bluez
gdbus introspect --system --dest org.bluez --object-path /
gdbus introspect --system --dest org.bluez --object-path /org/bluez/hci0

I'll update this answer once I achieve pairing..

DUMP1 from the code snippet

/org/bluez : 
    org.freedesktop.DBus.Introspectable : 

    org.bluez.AgentManager1 : 

    org.bluez.ProfileManager1 : 

/org/bluez/hci0 : 
    org.freedesktop.DBus.Introspectable : 

    org.bluez.Adapter1 : 
        Address : 
            9C:B6:D0:8C:5D:D6
        AddressType : 
            public
        Name : 
            sampsa-xps13
        ...
        ...
        
    org.freedesktop.DBus.Properties : 

    org.bluez.GattManager1 : 

    org.bluez.LEAdvertisingManager1 : 
        ActiveInstances : 
            
        SupportedInstances : 
            
        SupportedIncludes : 
                tx-power
                appearance
                local-name


    org.bluez.Media1 : 

    org.bluez.NetworkServer1 : 
    
/org/bluez/hci0/dev_58_C9_35_2F_A1_EF : 
    org.freedesktop.DBus.Introspectable : 

    org.bluez.Device1 : 
        Address : 
            58:C9:35:2F:A1:EF
        AddressType : 
            public
        Name : 
            Nokia 5
        Alias : 
            Nokia 5
        Class : 
            5898764
        Icon : 
            phone
        Paired : 
            1
        Trusted : 
            0
        Blocked : 
            0
        ...
        ...

    org.freedesktop.DBus.Properties : 

    org.bluez.Network1 : 
        Connected : 
            0

    org.bluez.MediaControl1 : 
        Connected : 
            0

[any other devices follow]
mksteve
  • 12,614
  • 3
  • 28
  • 50
El Sampsa
  • 1,673
  • 3
  • 17
  • 33
0

I managed to do it with bluetool (on a Raspberry Pi zero w 2), since I needed only functions to scan, pair, connect, disconnect, trust bluetooth devices I just copied bluetool.py and bluezutils.py to my project. This way I did not need to add the tcpbridge dependency and the code is working fine with Python 3. Note that there might be other quirks with Python 3, check this thread: https://github.com/emlid/bluetool/issues/4

Then this is how I use it:

from bluetool import Bluetooth

b = Bluetooth()
print("starting scan")
b.scan(timeout = 10)
print("PAIR")
print(str(b.get_devices_to_pair()))# not paired devices
# print(str(b.get_available_devices()))
s1 = b.pair("XX:XX:XX:XX:XX:XX")# your BT device's MAC
ss = b.trust("XX:XX:XX:XX:XX:XX")# prevents yes/no prompt
s2 = b.connect("XX:XX:XX:XX:XX:XX")
print(str(s1) + " :::::::: " + str(s2))
print("connected:" + str(b.get_connected_devices()))

Debugging

First try to connect with bluetoothctl. If it fails then this script wont work either.

If it does not work it can be because of multiple causes, most common ones are pulseaudio not running, not able to connect with a2dp profile (if this is the case it will connect and immediately disconnect) and permissions (try running as sudo)

sydd
  • 1,824
  • 2
  • 30
  • 54