Read dbus property with Python

Viewed 273

I am trying to read the Bluetooth address of a Raspberry Pi from dbus. I can do it with busctl from the command line as detailed below, but the Python code that seems like it should run the same procedure fails. I get the same failure when reading other properties from dbus. I can get the address by the unsatisfactory method of running hciconfig as a sub process, but what's wrong with the Python code?

1. List dbus bluez with busctl 

  busctl introspect org.bluez /org/bluez/hci0
  produces this (edited) result:

  NAME                                TYPE      SIGNATURE RESULT/VALUE           FLAGS
  org.bluez.Adapter1                  interface -         -                      -
  .GetDiscoveryFilters                method    -         as                     -
  .Address                            property  s         "DC:A6:32:04:DB:56"    emits-change
  .AddressType                        property  s         "public"               emits-change
  org.freedesktop.DBus.Introspectable interface -         -                      -
  .Introspect                         method    -         s                      -
  org.freedesktop.DBus.Properties     interface -         -                      -
  .Get                                method    ss        v                      -
  .GetAll                             method    s         a{sv}                  -
  .Set                                method    ssv       -                      -
  .PropertiesChanged                  signal    sa{sv}as  -                      -


2. Read Address with busctl

  busctl get-property org.bluez /org/bluez/hci0 org.bluez.Adapter1 Address

  produces this correct result:
    s "DC:A6:32:04:DB:56"

  this is from dbus-monitor:
  
  method call time=1653300359.259826 sender=:1.43 ->
       destination=org.bluez serial=2 
       path=/org/bluez/hci0;
       interface=org.freedesktop.DBus.Properties;
       member=Get
          string "org.bluez.Adapter1"
          string "Address"
  method return time=1653300359.259940 sender=:1.8 ->
     destination=:1.43 serial=85 reply_serial=2
     variant       string "DC:A6:32:04:DB:56"



3. Python3 code to do the same thing as follows:

  bus = dbus.SystemBus() 
  obj = bus.get_object("org.bluez","/org/bluez/hci0") 
  interface = dbus.Interface(obj,"org.freedesktop.Dbus.Properties")
  address = interface.Get("org.bluez.Adapter1","Address")

  produces this result:
  
  bus = runs OK
  obj = runs OK
  interface = runs OK
  address = fails with following error:  
    Method "Get" with signature "ss" on interface "org.freedesktop.DBus.Properties"  doesn't exist

  BUT IT DOES! and it works for busctl 

  address = interface.Get()
  address = interface.Get("org.bluez.Adapter1")
  address = interface.GetAll()
  address = interface.GetAll("org.bluez.Adapter1")
  address = obj.Get("org.bluez.Adapter1","Address",dbus_interface="org.freedesktop.Dbus.Properties")
    also fail with the same error 

2 Answers

This line of your code:

interface = dbus.Interface(obj,"org.freedesktop.Dbus.Properties")

should actually be

interface = dbus.Interface(obj,"org.freedesktop.DBus.Properties")

For the python code you might find it easier to use D-Bus bindings that are more Pythonic.

I find pydbus easy to use.

Below is your example with Pydbus:

(venv) pi@raspberry:~$ python3
Python 3.9.2 (default, Mar 12 2021, 04:06:34) 
[GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pydbus
>>> bus = pydbus.SystemBus() 
>>> adapter = bus.get('org.bluez', '/org/bluez/hci0')
>>> adapter.Address
'B8:27:EB:22:57:E0'
>>> dir(adapter)
['ActiveInstances', 'Address', 'AddressType', 'Alias', 'Class', 'Discoverable', 'DiscoverableTimeout', 'Discovering', 'Get', 'GetAll', 'GetDiscoveryFilters', 'Introspect', 'Modalias', 'Name', 'Pairable', 'PairableTimeout', 'Powered', 'PropertiesChanged', 'Register', 'RegisterAdvertisement', 'RegisterApplication', 'RegisterEndpoint', 'RegisterPlayer', 'RemoveDevice', 'Roles', 'Set', 'SetDiscoveryFilter', 'StartDiscovery', 'StopDiscovery', 'SupportedIncludes', 'SupportedInstances', 'SupportedSecondaryChannels', 'UUIDs', 'Unregister', 'UnregisterAdvertisement', 'UnregisterApplication', 'UnregisterEndpoint', 'UnregisterPlayer', '_Introspect', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_bus', '_bus_name', '_object', '_path', 'onPropertiesChanged']
>>> adapter.GetDiscoveryFilters()
['UUIDs', 'RSSI', 'Pathloss', 'Transport', 'DuplicateData', 'Discoverable', 'Pattern']
>>> 

If you want to continue using the dbus library then there are lots of example in the BlueZ source tree at: https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/test

Related