How to Get Started with Bluetooth Low Energy on Linux

Jared Wolff · 2014.4.14 · 6 Minute Read · engineering · bluetooth low energy · best

Main image

Bluetooth Low Energy is awesome. The problem, even in 2019, it’s still can be tough to work with.

In this article, you’ll learn the in’s and outs of Bluez. It’s Linux’s answer to connecting and using Bluetooth devices from the command line. It’s open source and it’s easy to use.

First, lets discuss the most important tools that are included with the Bluez stack.

Sidenote: things have changed a bunch since I first wrote this. It’s becoming much easier to create Bluetooth based hardware. I’ll show you how much in this handy how-to.

Get Acquainted With The Tools

hcitool

hcitool is the swiss army knife for Bluetooth in Linux. It is aptly named hcitool as it communicates via a common HCI (Host Controller Interface) port to your bluetooth devices. You can utilize the utility to scan for devices and send commands/data for standard Bluetooth and Bluetooth Low Energy.

gatttool

gatttool is used to access the “services” running on your bluetooth device. In my case, it was instrumental in accessing the Bluetooth Low Energy services running on my nrf51822. The Bluetooth SIG has already spec’d out several services for general use. More information on these services can be found here.

Install The Tools

In order to use Bluez, I needed to install Linux on a virtual machine. If you need a helping hand installing Debian may I suggest this step-by-step guide?

  1. Get the latest Bluez source:

    wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.18.tar.xz
    

    Note: make sure you uninstall Bluez if it is already installed. (apt-get doesn’t have a very recent version) To check if it’s installed run this command:

    dpkg --get-selections | grep -v deinstall | grep bluez
    
  2. Extract the source

    tar xvf bluez-5.18.tar.xz
    
  3. Install dependencies

    sudo apt-get install libglib2.0-dev libdbus-1-dev libusb-dev libudev-dev libical-dev systemd libreadline-dev
    
  4. Run configure

    .configure --enable-library
    

    Note: –enable-library will enable use of the library so you can create your own applications utilizing the Bluez stack

  5. Compile and install the source

    make -j8 && sudo make install
    
  6. The install script does not copy gatttool to your /usr/local/bin/ directory. You must do it manually:

    sudo cp attrib/gatttool /usr/local/bin/
    

Scan For Bluetooth Low Energy Devices

After installing Bluez (and tools) lets see if we can find a Bluetooth Low Energy device.

Note: because my Mac does not have built in Bluetooth Low Energy I am using a cheap Bluetooth Low Energy dongle. These dongles can usually be picked up for around $8.

  1. Attach your Bluetooth device to your VM.

    Virtualbox Add BLTE Device

    Note: if you get a Failed to attach USB device error, you may need to create a device filter that will autoconnect. More information on creating a device filter here.

  2. Check if hcitool can see your device:

    hcitool dev
    

    My output looked like this:

    Devices:
            hci0    00:15:83:6B:CC:EB
    

    Note: if nothing shows up you may have to reinsert your Bluetooth dongle. (if you’re using one)

  3. Now, run a low energy scan

    sudo hcitool lescan
    

    If you device is advertising it should show up.

    F4:C7:F8:0A:BF:C9 TWI
    

    In my case, the device I’m using is call ‘TWI’ and its address is ‘F4:C7:F8:0A:BF:C9’

    Note: you need to make sure your BTLE device is advertising for it to show up.

Connect To Your Bluetooth Low Energy Device

Now that we can see the intended Bluetooth device let’s connect to it.

  1. Open gatttool

    sudo gatttool -b <BLE ADDRESS> -I
    

    Where <BLE ADDRESS> is the address you obtained in the earlier steps.

    -I indicates you want to open up an interactive session

  2. Once open, type connect to connect.

    Gatttool Connect

    Note: As long as your BTLE device is still advertising you should the address change to a purple color in the command prompt.

    If you get a connect: No route to host (113), that means the device is not advertising, you’ve used the wrong address or you haven’t run sudo hcitool lescan before opening gatttool.

  3. Get the primary UUIDs

    primary
    

    The command above will generate a list of all the available “services” running on the low energy device. This could give you an idea of what type of functionality the device has (if you have no idea how it works).

    An example output is:

    attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
    attr handle: 0x0008, end grp handle: 0x000b uuid: 00001801-0000-1000-8000-00805f9b34fb
    attr handle: 0x000c, end grp handle: 0xffff uuid: 0000180f-0000-1000-8000-00805f9b34fb
    
  4. Get all the available handles

    char-desc
    

    This command generates a list of all the available handles. Handles are the “connection points” where you can read and write access data. For instance, my device has a handle to access battery level data and another to enable automatic reporting of the battery level data.

    An example output is:

    handle: 0x0001, uuid: 2800
    handle: 0x0002, uuid: 2803
    handle: 0x0003, uuid: 2a00
    handle: 0x0004, uuid: 2803
    handle: 0x0005, uuid: 2a01
    handle: 0x0006, uuid: 2803
    handle: 0x0007, uuid: 2a04
    handle: 0x0008, uuid: 2800
    handle: 0x0009, uuid: 2803
    handle: 0x000a, uuid: 2a05
    handle: 0x000b, uuid: 2902
    handle: 0x000c, uuid: 2800
    handle: 0x000d, uuid: 2803
    handle: 0x000e, uuid: 2a19
    handle: 0x000f, uuid: 2902
    Discover descriptors finished: No attribute found within the given range
    

    Remember, a handle is a sequential number generated by Bluez which is tied to a specific characteristic. You can use the output of char-desc to relate the characteristic UUID to each open handle.

  5. Read from a handle

    In my case, I know that the handle for reading the battery level is 0x000e. The command to read a handle is as follows:

    char-read-hnd <handle>
    

    So, when I run char-read-hnd 0x0001 I get a response of:

    Characteristic value/descriptor: 64
    

    The result returned is a hexadecimal number which, when converted to decimal, is equal to 100. In this case, this number is the percent battery power left on the device according to the Battery Service definition.

  6. Write to a handle

    Now, for giggles, I want to enable notifications for my battery level. I know that, in my case, the handle to enable notifications is 0x000f. The command to write to a handle is as follows:

    char-write-req <handle> <data>
    

    So, when I run char-write-req 0x000f 0100 I start receiving battery level messages (if the level has changed) like the following:

    Characteristic value was written successfully
    Notification handle = 0x000e value: 64
    Notification handle = 0x000e value: 64
    Notification handle = 0x000e value: 64
    

    To disable, I simply run the following:

    char-write-req 0x000f 0000
    

More resources

As you can imagine, there’s more to learn when it comes to BLE. Here are some links:

  1. How to use Particle’s New Bluetooth Low Energy Api to make connected hardware easy
  2. How to use Protobuf to Enhance Your Bluetooth Enabled Device (A 3 part series)
  3. How to Optimize Bluetooth Device battery life using a few simple tools.

Moving forward

We have only reached the tip of the iceberg in terms of information regarding Bluetooth (and Bluetooth Low Energy). Stay tuned for more Bluetooth Low Energy related posts in the future!

In the meantime subscribe below to my list if you haven’t already and i’ll see you on the next one!

👇👇👇👇

Last Modified: 2021.5.18

Subscribe here!

You may also like

How to Connect the nRF9160 Feather to Mosquitto

One thing that’s always tripped me up as an IoT developer is figuring the best way to transmit data. There are many different kinds of radios and mediums. On top of that, there are…

The nRF9160 Feather Launch

I was a complete failure. My prototype wasn’t working. I spent at least an hour trying to rework a frustratingly large LTE module on an impossibly small circuit board. It wasn’t…

The nRF9160 Feather with Bluetooth

One of the cool things about Zephyr is its modularity. It’s also one of things that makes development on the platform difficult. This is especially true if you’re not use to the…