PebbleSharp, Linux, and BlueZ 4

After my initial pilot of a Javascript/phone application written for the pebble to see how the idea worked, I decided to build a solution which would allow me to keep my (relatively) expensive phone on shore, and go sail with something a bit more modest in price ($20-30), the raspberry pi. The first step was to get the pi connected to the pebble.

Installing bluetooth on Raspbian wheezy is a fairly straightforward ordeal of simply running

sudo apt-get install bluetooth

I then went looking for a way to easily pair my pebble and found the blueman widget, which is installed with

sudo apt-get install blueman

This was going so well! This should be easy!

The next order of business was to get the Pebble to "talk" to my application on the Raspberry Pi. A quick google returned the PebbleSharp project which appeared to do much of what I was looking for, although it appeared to be maybe a little stale. After compiling and running a demo application I was met with a fun exception.
System.PlatformNotSupportedException: No supported Bluetooth protocol stack found.

I should have known it was too good to be true! PebbleSharp uses a bluetooth library called to abstract away the details of the various bluetooth implementations. Even on windows there are multiple bluetooth drivers with varying implementation details. On linux, the bluetooth stack is called bluez. Thankfully, there is a bluez module for the 32feet library.

Getting it to work, however, was going to be more involved than simply hitting run. I have documented the full process here on a fork I am working on for pebblesharp. There were 3 seperate issues, the first was that I was missing a number of packages, critically libbluetooth-dev.

The second issue is documented in this bug report. The issue is that mono was unable to match the bluetooth address family when attempting to open the socket to the device and would throw an exception. In order to get the library working, mono would have to be built from source, after applying the attached patch. This is easier said than done on the pi, it takes roughly 5 hours to compile mono, far more if you also want monodevelop etc to go along with it.

Finally, the structs being returned from the interop calls to bluez were not lining up with what was defined in the 32feet bluez module. Debugging interop is always a joy, especially when the structs contain pointers to other structs, and if any of those pointers are off by a byte or so the whole chain falls apart. After MUCH Console.Writeline (stepping through the monodevelop debugger was broken due to my fiddling with mono) I was able to rectify my struct alignment & padding issue. I'm not a good enough C developer to know exactly why my struct alignment was different than what the original author defined. My suspicion is that it has to do with the compilation options I used with Mono and the fact that it was being done on armhf rather than x86/amd64.

With all this in place, I was able to use PebbleSharp to "ping" the pebble and execute various api type calls (getting the time, sending a text etc). Unfortunately, PebbleSharp didn't have the AppMessage functionality that I would need to communicate with my counterpart app on the pebble, I would be building that myself. I'll go into detail on this in a future post.

This solution worked for me on Raspbian wheezy for the entirety of the 2015 sailing season. Once paired, the pebble remained paired with the pi and would reconnect to it every time it booted up. The only problem I had was if the phone that the pebble was paired to was ALSO in range, the pebble would not connect to the pi and remain connected to the phone. This was easily remedied by simply turning off bluetooth on my phone when I left it in the car to go sail.

There are a few downsides to this solution. First, it only works with BlueZ <5, which was fine for wheezy, but will not work with Jessie (or presumably any newer distros). bluez has moved their API firmly in the direction of dbus, and all bluetooth integration is meant to be done against a new set of dbus interfaces that are intended to be versioned and not change over time (unlike the bluez headers).

Second, it requires the user to pair the pebble using the command line or desktop widget, so the pi must be configured at a monitor and keyboard to get things set up ahead of time.

Third, as explained above it requires running a patched build of mono, which is a fairly painful setup procedure, and is unlikely to go away since the patch as currently implemented is unlikely to be accepted (and for good reasons).

Finally, the version of BlueZ used does not support BLE (bluetooth low energy).

There is good news however, the new dbus api is much easier to work with than native calls via interop, although it could use some documentation and examples. I will go into this in my next post.