2016-03-25 22:21:53

by Travis Griggs

[permalink] [raw]
Subject: Seeking some bluez dbus enlightenment

I have gotten a python3 (mostly) abstracted versions of the example-gatt-server and example-advertise working. Basically had to add the “Application” thing from the previous 5.37 based versions. They are relatively small and attached. Hardest part was throwing darts at the difference between the python3 dbus interface and the python2 dbus interface. It works, but who knows how idiomatic it is.

I’m confused by many things (at least 6) though.

Right after startup, without running any of my own code:

~# mdbus2 --system org.bluez / org.freedesktop.DBus.ObjectManager.GetManagedObjects
({'/org/bluez': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.AgentManager1': {}, 'org.bluez.ProfileManager1': {}, 'org.bluez.Alert1': {}, 'org.bluez.HealthManager1': {}}, '/org/bluez/hci0': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.Adapter1': {'Address': <'5C:F3:70:68:C1:F9'>, 'Name': <'nelson'>, 'Alias': <'PILOT-FF0021'>, 'Class': <uint32 0>, 'Powered': <true>, 'Discoverable': <false>, 'DiscoverableTimeout': <uint32 180>, 'Pairable': <true>, 'PairableTimeout': <uint32 0>, 'Discovering': <false>, 'UUIDs': <['00001801-0000-1000-8000-00805f9b34fb', '0000110e-0000-1000-8000-00805f9b34fb', '00001200-0000-1000-8000-00805f9b34fb', '00001800-0000-1000-8000-00805f9b34fb', '0000110c-0000-1000-8000-00805f9b34fb']>, 'Modalias': <'usb:v1D6Bp0246d0526'>}, 'org.freedesktop.DBus.Properties': {}, 'org.bluez.GattManager1': {}, 'org.bluez.Media1': {}, 'org.bluez.CyclingSpeedManager1': {}, 'org.bluez.HeartRateManager1': {}, 'org.bluez.ThermometerManager1': {}, 'org.bluez.LEAdvertisingManager1': {}}},)

1) A GattManager and a LEAdvertisingManager are things I expected. But a CycleSpeedManager? And a HeartRateManager? I don’t understand why these are there. Is it because I have the -E turned on. Are they just temporary during the development phase while that is experimental? I thought there was quite a few of these predefined services and characteristics, and here see a few, but far from all. I *think* those UUIDs match up with some of the manager things?

2) How does it know that my Alias is ‘PILOT-FF0021’ ? My code does set that, but this was after I had pulled the dongle out, shutdown the SBC, plugged it back in, and then started it up. Is that being written into the dongle’s non volatile memory somehow??



Now, I run some python code that turns on advertising, but register no services:

class PilotAdvertisement(ble_advertise.Advertisement):
def __init__(self, bus):
super().__init__(bus, 'peripheral')
self.add_service_uuid(MainService.UUID)
self.include_tx_power = True

Adapter = '/org/bluez/hci0'

def main():
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SystemBus()
advertisingManager = dbus.Interface(bus.get_object('org.bluez', Adapter), ble_advertise.LE_ADVERTISING_MANAGER_IFACE)
advertisement = PilotAdvertisement(bus)
advertisingManager.RegisterAdvertisement(advertisement.get_path(), {}, reply_handler=registerAdvertisementSuccess, error_handler=registerAdvertisementFail)
mainloop = glib.MainLoop()
try:
mainloop.run()
except KeyboardInterrupt:
mainloop.quit()

And then connect to the device using the LightBlue iOS app...

3) Suddenly, I have all kinds of object paths in org.bluez that I can’t identify

# mdbus2 --system org.bluez
/
/org
/org/bluez
/org/bluez/hci0
/org/bluez/hci0/dev_5E_41_16_18_F6_37
/org/bluez/hci0/dev_5E_41_16_18_F6_37/service000a
/org/bluez/hci0/dev_5E_41_16_18_F6_37/service000a/char000b
/org/bluez/hci0/dev_5E_41_16_18_F6_37/service000a/char000b/desc000d
/org/bluez/hci0/dev_5E_41_16_18_F6_37/service000a/char000b/desc000e
<snipped 10+ lines>
/org/bluez/hci0/dev_5E_41_16_18_F6_37/service0028/char0031
/org/bluez/hci0/dev_5E_41_16_18_F6_37/service0028/char0031/desc0033

Are these related to those various predefined services I was asking about? Or are they just generalized meta data that comes along with any connection? What confuses me is that LightBlue on my phone shoes no characteristics to play with. But I can see that the advertising data does indeed include the single service UUID that _I_ added to it. It doesn’t seem to advertise any of these other services.



Now I add my own service with two characteristics (one write, one notify) by registering an Application that has the single service.

serviceManager = dbus.Interface(bus.get_object('org.bluez', Adapter), ble_gatt.GATT_MANAGER_IFACE)
application = ble_gatt.Application(bus)
application.add_service(MainService(bus, 0))
serviceManager.RegisterApplication(application.get_path(), {}, reply_handler=registerApplicationSuccess, error_handler=registerApplicationFail)

And then connect. LightBlue now sees 2 characteristics correctly identified.

4) The query shown above doesn’t change. It still has the same output. This further leads me to believe those are meta services/characteristics independent of the example ones? Is there any way to know what they are?

5) On line 60 of the attached ble_gatt.py, I am setting PATH_BASE = '/com/nelson_irrigation/pilot/service’. This is being used to construct the paths for the service, characteristics, and descriptors. But I don’t see this path anywhere in mdbus2 queries. Where is it at?

6) I can change the `write` characteristic value from LightBlue, and my subclass override of WriteValue successfully print()’s the newly arrived value. But with `dbus-monitor —system` running, I see no traffic there. Do I need to run dbus-monitor in a more specific fashion?

TIA



Attachments:
ble_advertise.py (2.91 kB)
ble_gatt.py (5.69 kB)
Download all attachments

2016-03-31 08:12:16

by Luiz Augusto von Dentz

[permalink] [raw]
Subject: Re: Async mismatch?

Hi Travis,

On Tue, Mar 29, 2016 at 2:38 AM, Travis Griggs <[email protected]> wrote:
> As I try to “read the source” to figure out why my python dbus callbacks aren’t working as expected, I noted that the C source code refers to a GDBUS_EXPERIMENTAL_ASYNC_METHOD for the WriteValue method.
>
> I also noticed when I looked at the documentation for the @dbus.service.method decorator, that one of the arguments is an async callback. It seemed odd to me that it wasn’t being set. Is this a funny coincidence, two different meanings of the async word, or would it explain why these two variants of a WriteValue behavior differently:
>
> 1) def WriteValue(self, value):
> print(value)
> seq = bytes(0 + x for x in value)
> myOtherModule.myFunction(seq)
> print("dispatched”)
>
> only prints
>
> dbus.Array([dbus.Byte(1), dbus.Byte(2), dbus.Byte(3), dbus.Byte(4), dbus.Byte(5), dbus.Byte(6), dbus.Byte(7), dbus.Byte(8)], signature=dbus.Signature('y’))

Perhaps it is blocking in your function for some reason?

>
> But 2) def WriteValue(self, value):
> print(value)
> seq = bytes(0 + x for x in value)
> # myOtherModule.myFunction(seq) <<— COMMENTED OUT
> print("dispatched”)
>
> now prints
>
> dbus.Array([dbus.Byte(1), dbus.Byte(2), dbus.Byte(3), dbus.Byte(4), dbus.Byte(5), dbus.Byte(6), dbus.Byte(7), dbus.Byte(8)], signature=dbus.Signature('y’))
> dispatched
>
> (it finished).
>
> I wondered if it was a timeout thing, but it appears that the timeout is set at 300 seconds? Which seems really long, I note that dbus appears to have a default timeout if you just pass -1 here, why not use that?--

The timeout is local to the caller so it makes no difference to the
receiving end since the timeout is not send within the message, and
yes the daemon uses the default timeout before giving up so I suppose
the 300 seconds is not related to bluetoothd.

--
Luiz Augusto von Dentz

2016-03-28 23:38:39

by Travis Griggs

[permalink] [raw]
Subject: Async mismatch?

As I try to “read the source” to figure out why my python dbus callbacks aren’t working as expected, I noted that the C source code refers to a GDBUS_EXPERIMENTAL_ASYNC_METHOD for the WriteValue method.

I also noticed when I looked at the documentation for the @dbus.service.method decorator, that one of the arguments is an async callback. It seemed odd to me that it wasn’t being set. Is this a funny coincidence, two different meanings of the async word, or would it explain why these two variants of a WriteValue behavior differently:

1) def WriteValue(self, value):
print(value)
seq = bytes(0 + x for x in value)
myOtherModule.myFunction(seq)
print("dispatched”)

only prints

dbus.Array([dbus.Byte(1), dbus.Byte(2), dbus.Byte(3), dbus.Byte(4), dbus.Byte(5), dbus.Byte(6), dbus.Byte(7), dbus.Byte(8)], signature=dbus.Signature('y’))

But 2) def WriteValue(self, value):
print(value)
seq = bytes(0 + x for x in value)
# myOtherModule.myFunction(seq) <<— COMMENTED OUT
print("dispatched”)

now prints

dbus.Array([dbus.Byte(1), dbus.Byte(2), dbus.Byte(3), dbus.Byte(4), dbus.Byte(5), dbus.Byte(6), dbus.Byte(7), dbus.Byte(8)], signature=dbus.Signature('y’))
dispatched

(it finished).

I wondered if it was a timeout thing, but it appears that the timeout is set at 300 seconds? Which seems really long, I note that dbus appears to have a default timeout if you just pass -1 here, why not use that?

2016-03-28 22:54:42

by Travis Griggs

[permalink] [raw]
Subject: Re: Seeking some bluez dbus enlightenment


> On Mar 25, 2016, at 3:21 PM, Travis Griggs <[email protected]> wrote:
>
> I have gotten a python3 (mostly) abstracted versions of the example-gatt-server and example-advertise working. Basically had to add the “Application” thing from the previous 5.37 based versions. They are relatively small and attached. Hardest part was throwing darts at the difference between the python3 dbus interface and the python2 dbus interface. It works, but who knows how idiomatic it is.
>
> I’m confused by many things (at least 6) though.
>
> Right after startup, without running any of my own code:
>
> ~# mdbus2 --system org.bluez / org.freedesktop.DBus.ObjectManager.GetManagedObjects
> ({'/org/bluez': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.AgentManager1': {}, 'org.bluez.ProfileManager1': {}, 'org.bluez.Alert1': {}, 'org.bluez.HealthManager1': {}}, '/org/bluez/hci0': {'org.freedesktop.DBus.Introspectable': {}, 'org.bluez.Adapter1': {'Address': <'5C:F3:70:68:C1:F9'>, 'Name': <'nelson'>, 'Alias': <'PILOT-FF0021'>, 'Class': <uint32 0>, 'Powered': <true>, 'Discoverable': <false>, 'DiscoverableTimeout': <uint32 180>, 'Pairable': <true>, 'PairableTimeout': <uint32 0>, 'Discovering': <false>, 'UUIDs': <['00001801-0000-1000-8000-00805f9b34fb', '0000110e-0000-1000-8000-00805f9b34fb', '00001200-0000-1000-8000-00805f9b34fb', '00001800-0000-1000-8000-00805f9b34fb', '0000110c-0000-1000-8000-00805f9b34fb']>, 'Modalias': <'usb:v1D6Bp0246d0526'>}, 'org.freedesktop.DBus.Properties': {}, 'org.bluez.GattManager1': {}, 'org.bluez.Media1': {}, 'org.bluez.CyclingSpeedManager1': {}, 'org.bluez.HeartRateManager1': {}, 'org.bluez.ThermometerManager1': {}, 'org.bluez.LEAdve
rtisingManager1': {}}},)
>
> 1) A GattManager and a LEAdvertisingManager are things I expected. But a CycleSpeedManager? And a HeartRateManager? I don’t understand why these are there. Is it because I have the -E turned on. Are they just temporary during the development phase while that is experimental? I thought there was quite a few of these predefined services and characteristics, and here see a few, but far from all. I *think* those UUIDs match up with some of the manager things?

<snip>

I have determined/guessed/inferred that things like CycleSpeedManager1 show up by virtue of the daemon’s plugins, which seem to all be enabled by default (at least with -E(experimental) on). Adding —noplugin=* causes them to all be skipped and no longer show up. The only UUIDs that remain when I do that are the 1801, 1800, and 1200 ones which are for GATT, GAP, and ANP respectively.

I would love any hints to any of the other 5 dilemmas I shared in there. Especially the last two.