Pages

Saturday, February 20, 2016

I got the "Figurin' out DBus" BlueZ

I have been thinking about a context-aware framework for some time now. "Context aware", in the usage I mean, is about software having an idea of the location of things it is tracking, making it possible to do things based on the context, or location, where that thing is.

Though I am not fully convinced that Bluetooth Low Energy (BLE) is a good final solution for my context aware needs, it is an easy to use solution, particularly with nice platforms like the Intel Edison, TI Sensor Tag, and all the nice gadgets that Sparkfun and Adafruit are putting out. If I make use of Bluetooth's signal strength property (RSSI), I should be able to know when someone is within a given distance of a bluetooth master if they are carrying the bluetooth device around with them.

This has been an "interesting" project as I had to learn enough about Bluetooth to know what was possible. Then I had to sort out the BlueZ implementation that comes standard with Linux. And to do that I had to learn about DBus, particularly the Java version. Documentation was rather sparse for Bluez and DBus, so much of this has been banging my head against the table and wall, Googling anything to do with BlueZ, DBus, Java, PropertiesChanged signals, face palming, heavy sighing, elevated stress levels, and all. Fortunately I eventually figured it out and I will talk you through how I did it.

This post will not cover how to use the Bluetooth library I am creating, it will only discuss deciphering the DBus API for the BlueZ bluetooth library and how the code to use it all is written in Java. Later posts will discuss the API I am writing.

The BLE functionality was added into Bluez v5+, so make sure you have version 5 or higher.

If you are interested in taking a gander at the code, it can be found here: https://github.com/smartspaces-io/smartspaces-sandbox/tree/master/services/comm/bluetooth/smartspaces-sandbox-comm-bluetooth2

Do be aware it will be changing as I add more functionality and discover how clumsy some of the APIs will be.

Hardware for Experimenting


There are two kinds of Bluetooth hardware I used for learning the Bluez API.

The first was a TI Sensor Tag. This handy little gadget from Texas Instruments is a collection of sensors, such as accelerometers, gyroscopes, temperature, and humidity. You can get them with a variety of wireless technologies, I bought the one that did BLE. This is easy, you just push a button to make it start advertising, and push the button again to stop it from advertising.

I also used a Raspberry Pi and a Bluetooth 4 dongle. The dongle I got was this one. This is a little harder to use than the Sensor Tag where a button push starts advertising, but the dongle allowed experimenting with much more functionality.

To use the Dongle I had to install the Bluez 5 libraries on a Raspberry Pi. There are some nice instructions over at Adafruit on doing this as part of their directions for installing their Python library for working with BLE (https://learn.adafruit.com/bluefruit-le-python-library). Just be aware you will be compiling C++ code.

The Adafruit python BLE library is nice for experimenting and for learning some about DBus and BlueZ when reading the code. However, it mostly supports working with Bluetooth devices being used as UARTs, which is not my use case. But it provided invaluable information on things like the DBus ObjectManager. Thank you, Adafruit!

Once you have Bluez installed on the Pi, you need the following commands to make everything work.

sudo hciconfig hci0 up
sudo hciconfig hci0 leadv 0
sudo hciconfig hci0 piscan

The first command brings the bluetooth adapter up. The next tells it to start advertising itself on the Low Energy bands. The final makes the dongle discoverable.


DBus

The standard Linux implementation for Bluetooth makes use of DBus, so DBus is where we will start as none of the other code will make sense unless you have some understanding of DBus.

The following will be a lot of words, but it is best to wade through them. Things may not make sense the first time around, but once you go through the section about the Bluez DBus interface, you may find this section makes a lot more sense. I would read through each section at least a couple of times to make sure you understand the pieces.

What is DBus? It is framework found on Linux machines to support Inter-Process Communication (IPC) and Remote Procedure Calls (RPC). I won't discuss the sorts of things it was trying to consolidate and replace, things like CORBA and DCOP, you can find lots of web resources for that.

DBus makes it possible for processes running simultaneously on the same machine to talk with each other very efficiently and in a uniform way. If each process had a different mechanism for communicating with outside processes, it could rapidly get messy. If Process A used one system and Process B another, either the programs running in each would have to be modified to include each other's messaging protocols, or a 3rd process could potentially translate between the separate mechanisms.

An example of DBus usage would be that little icon at the top of your laptop screen that tells you how much battery power you have. The battery service is a DBus service that sends out signals giving the current amount of charge in the battery. It has no idea who is using this information, it just throws it out into the world hoping that someone cares. The program that controls the icon attaches itself to DBus and says it is interested in those battery events. Now, when the battery process sends out a signal giving the battery level, the icon program will receive that signal and update the image you see at the top of the screen.

DBus is a hub and spoke model. There is a DBus daemon that runs on the machine, providing the hub. Each process will create a connection to this hub. This connection is the spoke. For 2 processes to talk to each other, the process sending a message would send it to the hub which would then send it down the spoke for the destination process.

Each process that wants to use a DBus service ends up with at least 1 DBus bus of its own. This bus gives it access to the hub. Each bus has a unique name that is created when the computer boots up and processes start. These bus names have names like :1.15, which aren't particularly readable, but are what DBus uses internally. DBus also supports the concept of well-known names, which allow a program to access services exposed by a process without using names like :1.15 (which will potentially be different each time the system boots up), but rather a more easily remembered name. In the case of Bluez, the well known bus name is org.bluez.

Each process can then expose objects on a bus it owns. These objects will be a collection of methods that can be called remotely from another process. Each object will expose at least 1 DBus interface, an interface specifying a collection of methods, properties, and signals. Examples of DBus interface names are org.freedesktop.DBus.Properties and org.bluez.Device1. A single object can expose multiple interfaces, but the caller will need to specify which interface it wants to call for a given method. These objects are referenced by giving their path. The path is hierarchical and has names like / and /org/bluez/hci0. Only one object can be at each node in the path,

Methods provide functionality. They are like methods you would write in a program, but in DBus the actual method implementation is running in another process, so calling that method is called a Remote Procedure Call.

Properties give information about an object. In the Bluetooth case, properties will say whether a Bluetooth device is paired, if connected, what the address of the radio is, etc.

Signals are initiated by the object which exposes the signals when something happens that another process should know about. For example, a Bluetooth DBus object will raise a signal the first time a new Bluetooth device appears. This is different than a method call, method calls are initiated by a process and go to the process implementing the method, whereas signals are initiated by the process implementing the signal and are sent to everyone who registers to be notified when the signal is sent. The difference is only in who initiates the communication.

Sorting out the BlueZ Dbus API


There are a variety of command line tools for experimenting with DBus. They will allow you to monitor the bus and send messages to DBus objects. These tools are nice, but are usually the most useful if you kinda already know what you are doing. Fortunately, since I had no idea what I was doing, I discovered D-Feet, a tool that gives you a GUI interface for the entire DBus system. You can look at services, click through their entire object hierarchy, find what interfaces and signals they provide. You can also call methods on DBus objects. Using both D-Feet and the dbus-monitor command line program, I was able to gradually piece together how BlueZ was working and how to talk to it to get thing done.

The first thing you should do is make sure you can access DBus and the BlueZ services it exposes without having to be the root user on your machine. The lp Linux group has unfettered access to the BlueZ DBus services, so first I placed myself in the lp group.

sudo usermod -a -G lp keith

Make sure you don't leave off that -a. If you do, you will erase every other group you are in and it will be messy. The -a means add to the groups you already belong to.

For this new group to become effective, you then have to log out and then log back in.

Now install D-Feet. I did it with apt-get.

sudo apt-get install d-feet

Now run it with the command

d-feet

You should see a window like the following.




The BlueZ service sits on the DBus System Bus, so make sure the System Bus tab is selected. The select the org.bluez service. You should now see something like the following. Doubleclicking on the image will make the picture larger.



Here you can see the entire object hierarchy for the Bluez service
  • the root of the object hierarchy at /
  • various managers at /org/bluez
  • a Bluetooth adapter at /org/bluez/hci0
  • and a bluetooth device at /org/bluez/hci0/dev_B0_B4_48_BD_D0_83
Let's go through each of these objects.

The Root Object

The uppermost object in the Bluez object hierarchy implements two interfaces org.freedesktop.DBus.Introspectable and org.freedesktop.DBus.ObjectManager. You can see them by opening the / object in D-Feet.



I have no idea, but I think most DBus objects implement the interfaces org.freedesktop.DBus.Introspectable interface. This interface has a single method Introspect, which allows you to get a string containing a complete an XML description of the object. This description will give all interfaces implemented, their method descriptions, all signals provided by the interfaces, and all properties the object has. You will see examples of properties once we open up some of the later objects.

The most interesting object here is the  org.freedesktop.DBus.ObjectManager object. This object is usually found at the root of a service's object hierarchy and provides the ability to access other objects in the hierarchy. The method GetManagedObjects returns a very complex data structure that gives all the other objects in the hierarchy. If you look at the D-Feet output, you can see it returns a data structure of the type

Dict of {Object Path, Dict of {String, Dict of {String, Variant}}}

The outer dictionary uses object paths for its keys. In the Bluez case here, the keys will be /org/bluez, /org/bluez/hci0, and /org/bluez/hci0/dev_B0_B4_48_BD_D0_83. The value for each key in this outer dictionary is another dictionary. This next dictionary will be keyed by DBus interfaces that each object implements, for example org.freedesktop.DBus.Introspectable or org.bluez.Adapter1. The value for each key will be yet another dictionary, keyed by the names of any properties the interface supports, and their value. Notice the type of the value for this innermost dictionary is Variant. This is a DBus type for dictionaries or methods that can return any of a number of types, such as numbers, strings, etc.

Notice that the org.freedesktop.DBus.ObjectManager object also exposes 2 signals, InterfacesAdded and InterfacesRemoved, which are sent when new objects are added to the hierarchy or are removed.

InterfacesAdded is signaled with 2 arguments. The first is an Object Path and gives the DBus object path to the new object that has been handed to the object hierarchy.  The second argument is a dictionary whose key gives one of the interfaces that the object implements and whose value gives a dictionary of all property/value pairs that the particular interface contains. Once again, we will see examples of those properties later.

You can use the dbus-monitor command to see what an actual InterfacesAdded signal looks like. We want to look at the System Bus, so use the following command line.

dbus-monitor --system

The following output from the monitor shows my computer seeing the TI Sensor Tag for the first time.

signal sender=:1.3 -> dest=(null destination) serial=1252 path=/; interface=org.freedesktop.DBus.ObjectManager; member=InterfacesAdded
   object path "/org/bluez/hci0/dev_B0_B4_48_BD_D0_83"
   array [
      dict entry(
         string "org.freedesktop.DBus.Introspectable"
         array [
         ]
      )
      dict entry(
         string "org.bluez.Device1"
         array [
            dict entry(
               string "Address"
               variant string "B0:B4:48:BD:D0:83"
            )
            dict entry(
               string "Name"
               variant string "CC2650 SensorTag"
            )
            dict entry(
               string "Alias"
               variant string "CC2650 SensorTag"
            )
            dict entry(
               string "Paired"
               variant boolean false
            )
            dict entry(
               string "Trusted"
               variant boolean false
            )
            dict entry(
               string "Blocked"
               variant boolean false
            )
            dict entry(
               string "LegacyPairing"
               variant boolean false
            )
            dict entry(
               string "RSSI"
               variant int16 -72
            )
            dict entry(
               string "Connected"
               variant boolean false
            )
            dict entry(
               string "UUIDs"
               variant array [
                     string "0000aa80-0000-1000-8000-00805f9b34fb"
                  ]
            )
            dict entry(
               string "Adapter"
               variant object path "/org/bluez/hci0"
            )
            dict entry(
               string "ManufacturerData"
               variant array [
                     dict entry(
                        uint16 13
                        variant array of bytes [
                              03 00 00
                           ]
                     )
                  ]
            )
            dict entry(
               string "TxPower"
               variant int16 0
            )
         ]
      )
      dict entry(
         string "org.freedesktop.DBus.Properties"
         array [
         ]
      )
   ]

InterfacesRemoved is signaled with 2 arguments. The first is the Object Path of the object being removed from the object hierarchy. The second argument is an array of the names of DBus interfaces that are being removed along with the object.

The /org/bluez Object


Now let's look at the object at /org/bluez. Click on its line in D-Feet, you will see a window like




Here are interfaces for various Bluez services AgentManager1, Alert1, HealthManager1, and ProfileManager1. I have totally sorted out what these are for yet, for now they are here to show you yet another set of interfaces that an object can expose. Notice this object also implements the org.freedesktop.DBus.Introspectable interface.

The Bluez Bluetooth Adapter at /org/bluez/hci0

The next object down the hierarchy is for the single Bluetooth adapter on my machine. You can have multiple adapters on your machine and each will have object paths like /org/bluez/hci0, /org/bluez/hci1, etc.

There are a lot of methods and properties in an adapter interface, so there are 2 screen shots,


and




The first screenshot shows the org.bluez.Adapter1 interface. This interface exposes 4 methods.

The RemoveDevice method will remove a Bluetooth device from the DBus object hierarchy when it is no longer needed. It takes a single argument, the DBus object path to the device to be removed. An example of such a Bluetooth device's object path is /org/bluez/hci0/dev_B0_B4_48_BD_D0_83. This path includes the name of the adapter and the address of the Bluetooth device in a different format than you usually see Bluetooth addresses.

The StartDiscovery method will tell the adapter to start scanning for new Bluetooth devices. StopDiscovery will tell the adapter to stop scanning. Notice neither of these methods have arguments.

The SetDiscoveryFilter method sets a filter for any devices that the adapter will look for when it is in discovery mode.

This is the first interface we have seen with DBus properties. Let's look at some, but not all of them. The UUIDs property gives the set of UUIDs of Bluetooth services that the adapter supports. Discoverable will have a value of true or false and determines if the adapter will be discoverable by other Bluetooth devices. Discovering will be true if the adapter is scanning, and false otherwise. Notice some of these properties are read only, some of them are read/write.

A very important interface that the adapter implements is the DBus interface org.freedesktop.DBus.Properties. This interface contains 3 methods and 1 signal. The method Get lets you read the value of a property for a particular interface, such as the Discovering property mentioned above in the org.bluez.Adapter1 interface. GetAll will return all properties exposed by a given interface and the current values of those properties. Finally, Set will let you set the value of a property on a given interface.

The Properties signal PropertiesChanged is sent every time any of the properties of the object implementing Properties changes. The first argument of the signal gives the name of the interface that exposes the changed properties. The second argument gives a map of the properties and their values for just the properties that have changed. The final argument gives an array of the properties that are no longer available.

As an example, if the StartDiscovery method is called on the adapter, a PropertiesChanged signal will be raised. The interface in the first argument of the signal will be org.bluez.Adapter1 since it contains the property that will be changing. If the only thing that changes is whether or not the adapter is scanning, the map will contain a single entry showing that Discovering is now true. The last argument would be an empty list in this case. The output shown by dbus-monitor for this signal is shown below.

signal sender=:1.3 -> dest=(null destination) serial=1250 path=/org/bluez/hci0; interface=org.freedesktop.DBus.Properties; member=PropertiesChanged
   string "org.bluez.Adapter1"
   array [
      dict entry(
         string "Discovering"
         variant boolean true
      )
   ]
   array [
   ]



The BlueZ Bluetooth Device Object

The final object to look at is an actual Bluetooth device. In my case I was using a TI Sensor Tag with Bluetooth address B0:B4:48:BD:D0:83. Adapter hci0 is the one who found it, so its DBus object path is /org/bluez/hci0/dev_B0_B4_48_BD_D0_83.

Once again there will be two screenshots since there is a lot of interfaces, methods, signals, and properties.



and



The first interface is org.bluez.Device1. This interface has 6 methods. Pair initiates a paring between the adapter and the remote Bluetooth device. The pairing is cancelled with CancelPairing. Connect will connect to the remote device, Disconnect disconnects from it.
ConnectProfile connects to a profile on the device with the given profile UUID, while DisconnectProfile will disconnect from the profile specified.

The properties for the org.bluez.Device1 interface includes the UUIDs exposed by the device, whether or not it is Connected and/or Paired. For my current usage, it fortunately also exposes RSSI, which gives the signal strength of the Bluetooth device.

Notice that the Bluetooth device object also exposes the org.freedesktop.DBus.Properties interface methods and signals, which will work the same as the description given in the Adapter section.

The Java Library

Now that we have a rudimentary knowledge of the Bluez DBus objects, interfaces, signals, and properties, it is time to get all of this into a Java library.

The dbus-java Library


The dbus-java library supplies a pure Java implementation of the DBus protocol. It allows the user to access remote objects, call methods on them, and receive signals from them. It also allows the user to implement their own objects and expose them on the DBus.

If Java isn't your favorite language, there are DBus libraries for most of the popular languages.

Writing DBus Java Interfaces

The DBus Java library works by having Java interfaces and classes defined that extend specific DBus Java interfaces and classes. The DBus library looks at these interfaces and figures out how to encode and decode the remote procedure calls and signals from and to their Java equivalents. Fortunately you just need to implement the interfaces and classes and not have to worry about the complexities of encoding and decoding, you just use objects that the DBus Java library creates that match your interfaces.

First of all, how is a remote interface defined for the org.freedesktop.DBus.Properties interface? The following is the Java interface that should be written for this DBus interface.

package org.bluez.DBus;

public interface Properties extends DBusInterface {
  <A> Variant<A> Get(String interfaceName, String propertyName);
  Map<String, Variant> GetAll(String interfaceName);
  void Set(String interfaceName, String propertyName, Variant value);
}

How did we know this is what the interface should be? We got this by looking at the interface we got from D-Feet, which said the interface was

Get(String interface, String name) -> (Variant value)
Set(String interface, String name, Variant value) -> ()
GetAll(String interface) -> (Dict of {String, Variant} properties)

and that the interface name was org.freedesktop.DBus.Properties. Notice the package for the Java interface is org.bluez.DBus and the interface name is Properties. The fully qualified name of the interface should be the name of the DBus interface.

Notice that the interface extends DBusInterface, an interface supplied by the DBus Java libraries. All DBus interfaces must extend DBusInterface.

Here we wrote out the Java interface by hand. However, the DBus Java library comes with a program called CreateInterfaces that does all this work for us. However, CreateInterfaces wasn't working for me, something about a bad XML DTD, so I gave up and implemented everything by hand. It didn't take that long.

Now, we can't actually use the Java package org.freedesktop.DBus for our package as there is already a class at that location in the DBus Java libraries. The DBus library allows us to place our classes in any package we want, but only if we tell the DBus library the ultimate name we want the DBus interface to have. Here is the same example as above, but placed in a different Java package. We want the DBus interface to be org.freedesktop.DBus.Properties. However, we placed the class in the package io.smartspaces.support.bluez. The name we want the interface to have can be specified with the annotation DBusInterfaceName. You can see this below.


package io.smartspaces.support.bluez;

@DBusInterfaceName("org.freedesktop.DBus.Properties")
public interface Properties extends DBusInterface {
  <A> Variant<A> Get(String interfaceName, String propertyName);
  Map<String, Variant> GetAll(String interfaceName);
  void Set(String interfaceName, String propertyName, Variant value);
}

Finlly we need to define a class for the signal PropertiesChanged. Looking back at the definition of the signal in D-Feet, we see it needs to have the following signature.


PropertiesChanged(String, 
    Dict of {String, Variant}, Array of [String])


The first argument is the DBus interface whose properties has changed, the second is a dictionary of only the properties whose values have changed and their new values. The final argument is a list of properties that are no longer available for the interface.

The signal classes in the DBus Java library must extend DBusSignal. They also need to call the superclass's constructor with all of the arguments in the signal. Notice the class below has an extra argument, path, that isn't in the definition of the signal we saw in D-Feet. This argument will give the DBus object path for the sender of the signal, for example path will have the value /org/bluez/hci0 when the StartDiscovery method is called on object /org/bluez/hci0 and /org/bluez/hci0 sends the PropertiesChanged signal.

public static class PropertiesChanged extends DBusSignal {
  private final String iface;
  private final Map<String, Variant> propertiesChanged;
  private final List<String> propertiesRemoved;

  public PropertiesChanged(String path, String iface, 
      Map<String, Variant> propertiesChanged,
      List<String> propertiesRemoved) throws DBusException {
    super(path, iface, propertiesChanged, propertiesRemoved);

    this.iface = iface;
    this.propertiesChanged = propertiesChanged;
    this.propertiesRemoved = propertiesRemoved;
  }

  public String getIface() {
    return iface;
  }

  public Map<String, Variant> getPropertiesChanged() {
    return propertiesChanged;
  }

  public List<String> getPropertiesRemoved() {
    return propertiesRemoved;
  }
}

This then needs to be placed inside of an interface that gives the DBus interface that emits the signal. So for the org.freedesktop.DBus.Properties interface and its PropertiesChanged signal, we need the following complete Java interface definition.

package io.smartspaces.support.bluez;

@DBusInterfaceName("org.freedesktop.DBus.Properties")
public interface Properties extends DBusInterface {
  <A> Variant<A> Get(String interfaceName, String propertyName);
  Map<String, Variant> GetAll(String interfaceName);
  void Set(String interfaceName, String propertyName, Variant value);

  public static class PropertiesChanged extends DBusSignal {
    private final String iface;
    private final Map<String, Variant> propertiesChanged;
    private final List<String> propertiesRemoved;

    public PropertiesChanged(String path, String iface, 
        Map<String, Variant> propertiesChanged,
        List<String> propertiesRemoved) throws DBusException {
      super(path, iface, propertiesChanged, propertiesRemoved);

      this.iface = iface;
      this.propertiesChanged = propertiesChanged;
      this.propertiesRemoved = propertiesRemoved;
    }

    public String getIface() {
      return iface;
    }

    public Map<String, Variant> getPropertiesChanged() {
      return propertiesChanged;
    }

    public List<String> getPropertiesRemoved() {
      return propertiesRemoved;
    }
  }

As an aside, it took me quite some time to make signals work. The first argument of the PropertiesChanged signal was String. When I looked at examples of signals in the DBus Java documentation, they all had their first argument as a string, so my signal class had the path, propertiesChanged, and propertiesRemoved arguments only. I never received an instance of the signal. I spent a long time Googling how to register signal handler, particularly the PropertiesChanged signal and never found anything at all. Eventually I noticed the interface argument in the dbus-monitor output and noticed it was a DBus interface name, not an object path that all of the online examples showed. Once I added the interface argument, I started receiving the signals.

The DBus Connection

Once we have our interfaces and signal classes, the next thing needed is a connection to the DBus daemon. You get this by instantiating a DBusConnection object. Look at StandardBluezBluetoothProvider in my Java code and you will see a line

dbusConnection = DBusConnection.getConnection(DBusConnection.SYSTEM);

This gets a connection to the DBus System bus, which is the bus that contains the Bluez service. You will need the connection before you can do anything.

Getting a Remote Object

Now that we have a connection, we can create a local object that looks like the remote object in the other process. We do this with the getRemoteObject() call on the DBus connection.

ObjectManager bluezObjectManager = 
    dbusConnection.getRemoteObject("org.bluez", "/", ObjectManager.class);

This get a connection to the DBus ObjectManager that is found at /, the root of the Bluez object hierarchy. The first argument gives the well-known bus name org.bluez for the Bluez service.

As I said, this Java object now looks like the actual DBus ObjectManager. For instance, it has a method called GetManagedObjects() that calls the GetManagedObjects method on the remote object and returns the results as Java data structures to our Java program.

Map<Path, Map<String, Map<String, Variant>>> values =
    bluezObjectManager.GetManagedObjects();

These calls will block until they return from the remote object. If you don't want to wait for the result you can use an asynchronous response, either by periodically checking a method result object periodically or by getting a callback when the response returns.

Next let's register some signal handlers. For example, let's register one for the InterfacesAdded signal from the ObjectManager.

Unfortunately the version of the DBus Java library does not allow you to use service well known names like org.bluez to register your signals, you must use the unique DBus address, something like :1.15. Unfortunately this can be different on different machines or different when your machine boots up, so we need to use the well-known name. Argh!

Fortunately DBus provides a service that let's you find out what unique bus name the DBus daemon assigned to the org.bluez service.

DBus dbus = dbusConnection.getRemoteObject(
    "org.freedesktop.DBus", "/org/freedesktop/DBus", DBus.class);
bluezDbusBusName = dbus.GetNameOwner("org.bluez");

Once we have the Bluez service bus' unique name, we can register the signal handler for InterfacesAdded.

DBusSigHandler<ObjectManager.InterfacesAdded> interfacesAddedSignalHandler =
     new DBusSigHandler<ObjectManager.InterfacesAdded>() {
  @Override
  public void handle(ObjectManager.InterfacesAdded signal) {
    System.out.println("Interfaces added");
  }
};
dbusConnection.addSigHandler(ObjectManager.InterfacesAdded.class, 
  bluezDbusBusName, bluezObjectManager, interfacesAddedSignalHandler);

The interfacesAddedSignalHandler.handle() method will now be called whenever Bluez raises an InterfacesAdded signal. Here we are just printing at an interface has been added.

Now we can call GetManagedObjects and also get notified about InterfaceAdded signals without having to ask every time a new object or set of interfaces to an existing object are added.

Conclusion

That was a lot!

We covered DBus and its basic concepts. We looked at various objects exposed via DBus from the Bluez API. And we looked at the DBus Java library and how it can be used to access the Bluez objects and put Bluetooth functionality into our Java program.

There is still much to do on this library, I want to be able to register listeners for things like new devices coming into range of the bluetooth radio on the computer, the RSSI of a device as it moves around in a space and other things. But this was a good start. Stay tuned for how to actually use the library, at which point you won't need to think about BlueZ and DBus at all.





Wednesday, February 3, 2016

Announcing the Smart Spaces Project

The fork of the Interactive Spaces project is complete and I spent a very long time removing every use of the word "interactive" and replacing it with the word "smart".

Smart Spaces is now available at https://github.com/smartspaces-io/smartspaces.

Smart Spaces will not be just concerned about interactivity in a physical space, but also smarts. It is time to get interesting learning algorithms and rules based systems into the package. I also want to increase the abstraction level for talking about events happening in a physical space, both in detecting them and also affecting them. I'm not entirely sure what this will all mean, but it will be fun figuring it out.

The initial effort was merely changing the root package name from interactivespaces to io.smartspaces. I imagine I will be removing instances of interactive for some time.The next major project will be removing all deprecated APIs from the Interactive Spaces days and adding the ability to use MQTT for activity to activity communication, routes in Smart Spaces parlance.

Despite the low initial version number, 0.1.0, this is feature complete to Interactive Spaces 1.8.2 (1.8.1 runs in production in the Google Experience Centers) and is ready for deployment. I just numbered low as I want 1.0.0 to have some of the things that were wanted in Interactive Spaces for some time, such as ROS out of master/space controller communications.

The discussion board is found at https://groups.google.com/forum/#!forum/smartspaces

Join us on this adventure.