Bluetooth LE

I am sorry. I am so, so sorry.

Every so often, I decide "Gosh, I'd really like to write code for some Bluetooth LE devices, but I don't really do much on mobile. Maybe things have gotten better on desktop!" So far, I have been disappointed every time. Now is no exception, but I've decided to actually write down that disappointment as a form of therapy.

This post will go over how different desktop OSes, libraries, and hardware deal with Bluetooth LE. I'm sticking to desktop here because product manufacturers assume BTLE devices will usually be used with phones. Mobile certainly isn't a solved problem either, but it's better than desktop right now.

This article isn't an introduction to BTLE itself. I'm going to assume readers know the basic terms and differences between, say, pairing and connection. If you're not familiar, I recommend checking out Adafruit's BTLE Intro. Apple's CoreBluetooth Overview has some nice explanation also, though the examples are obviously platform specific.

Operating System Support

OS X

Starting off easy. OS X has had support as a BTLE Central Node since 10.6, and as a peripheral node since 10.9. Done!

Linux

tl;dr: Bluez < 5.38 or so, use gattlib. Bluez >= 5.38 or so, use dbus.

And then right on up the difficulty curve to Linux, where we have bluez. I've yet to ever hear anyone say "yay bluez!"

Bluez got BTLE support in 4.93 or so. As of this writing (November 2016), we're at 5.43. That's a full major version and a ton of minor versions difference.

Between bluez 4 and 5, APIs moved from direct access to dbus. Then, within DBUS 5, the methods have changed multiple times. I spent part of last weekend trying to write some dbus code for accessing BTLE devices with no luck, as I couldn't seem to identify services on the device. It turns out that I'm on debian Jessie, which comes with dbus 5.23 (released September 2014) . After looking around a bit, it seems most current bluez supporting libraries expect users to have at least 5.38 or higher, and sure enough, those expose different methods.

I was pretty confused by this, as I'd been using pygattlib with no problems on the same linux box to write some BTLE test scripts. Turns out, pygattlib is similar to the C-based gattlib. Both of these use the GATT functions from gatttool in the bluez 4 line to talk to BTLE devices without having to go through dbus, to let older machines/kernels talk BTLE. That's why things worked, because it was just bypassing the dbus interface.

Windows

tl;dr: Either hope your device requires pairing, or your code can deal with WinRT APIs and will only run on updated Windows 10. Otherwise, do something crazy.

Windows started supporting communicating with BTLE as of Windows 8. However, this didn't mean you could just go talking willy-nilly to any device you pleased. You actually had to pair with devices before they were available to functions.

The problem is that device manufacturers are lazy and cheap, and pairing is an optional part of the BTLE handshake process. It's also the part that's vaguely secure, but a lot of products don't really care about that. For many devices, you just connect, query for services, and off you go. This is possible on both OS X and Linux, but on windows, it was a no-go up until a set of Windows 10 updates.

As of updates leading up to and including the Anniversary update in August 2016 (thanks @kraln, WinRT started providing functions to connect without pairing, which is how some of the platforms listed in the next section are going to tackle this. Microsoft has apparently stated that there will never be connection APIs for Win32 (thanks to @vincent_scheib for info).

There is one other workaround for BTLE on windows, even for pre-windows 10 platforms, but it's not pretty. Check out the section below on Noble for more information.

Cross-Platform ways to access BTLE currently

Given those warnings, if you still want to access bluetooth in a pre-written, cross-platform way, here's a few choices. This is by no means an even partially complete list of bluetooth wrappers/libraries, it's just what I looked up while figuring all this out..

Qt (C++)

Qt was actually one of the first places I went to check for this, as they're usually pretty good about supporting as much functionality as possible across platforms.

Qt has had support for BTLE on OS X, Linux, Android, and iOS since 5.7. Notice the lack of Windows there? Looks like they'll get WinRT in 5.8, "platform" support "later".

Web Bluetooth

There is currently a proposed spec being implemented by Google in Blink (the browser engine that backs both Chrome and Opera) that will allow webpages to interact with BTLE devices. This is slated to ship in Chrome 56. It will support Linux, OS X, Android, and ChromeOS. Windows is apparently coming with WinRT later.

Currently, Edge has no stated plans to implement Web Bluetooth but it is "Under Consideration". Mozilla is pushing back on spec implementation in Firefox due to privacy concerns,, though work is happening in Servo.

So while this API may show up in Chrome, it may also ONLY show up in Chrome. This situation certainly hasn't stopped anyone from using APIs before, though.

And for anyone that is saying "Wait, Kyle, didn't you implement one of the Bluetooth stacks for FirefoxOS? What about that?", my reply is "DON'T MENTION THE WAR." (Translation: That was an early version of a non-standardized API that has since been removed from Gecko, Mozilla's browser engine)

Noble (Node.js)

Noble is a node.js BTLE library that supports OS X, Linux, and Windows.

Yes, Windows. Without WinRT. Crazy, right?

Well, yes. It actually is crazy. To use Noble on windows (which many IoT/Maker programs do), you have to install WinUSB drivers over the standard Bluetooth Dongle drivers. Noble then handles the full bluetooth stack for you, bypassing the connection/scanning APIs missing from regular old windows. While a clever way to do that, it's not exactly something you'd want to ship to non-savvy end-users.

BGAPI

Some people aren't happy to just bitbang bluetooth to a dongle though. Instead, they go all the way and implement a specialized API specifically for their dongle. The BlueGiga BLED112 BTLE Dongle comes with a special, proprietary API that allows users to connect to BTLE devices on Windows (and other platforms), also routing around the lack of OS API functionality. So, as long as your platform can talk USB, it can also talk BTLE.

(Found this dongle via an article on the PyGATT library, which supports both Linux dbus and BGAPI for cross platform python bluetooth support).

Conclusion

Well, that's the state of things for the moment. Those are some of the reasons there's no libusb-equivilent for bluetooth yet. Hopefully we'll see Microsoft fill out the Windows API surface soon and make this article a little less sad, 'cause the WinRT stuff is kinda painful. Until then, though, this is what we get to deal with.

Thanks to Sandeep Mistry for filling in some of the details on the Windows situation.

PS Oh, yeah, almost forgot FreeBSD