A quick and dirty introduction to gatttool for accessing data from Bluetooth Low Energy devices

A quick and dirty introduction to gatttool for accessing data from Bluetooth Low Energy devices

bluetooth, BLE

Introduction #

This guide introduces how to use the command-line utility gatttool to read data from a Bluetooth Low Energy (BLE) device. I wrote this guide as a reference for myself on using gatttool to read some infomation about BLE devices, but hopefully other people will find it useful too. I will be updating this guide as needed.

This guide assumes that you are already familiar with the basics of BLE, in particular the GATT and ATT protocols that are used by BLE to wrap its data. If not, Adafruit has a good introduction to some of these concepts. It also assumes that you have some Bluetooth 4.0 compatible hardware interface and a working copy of both hcitool and gatttool on your computer. As far as I know, these come with the Linux-only BlueZ package.

Please note that if you’re just looking to do some quick service/characteristic discovery and have a smartphone with Bluetooth 4.0 support, you can easily do that with some free apps that give you a nice GUI and some built-in parsing of standard services and characteristics. LightBlue Explorer (iOS) and nRF Master Control Panel (Android) are both excellent for doing this.

Reading data #

I’m going to use gatttool to find the Manufacturer Name of a certain device that I own - a BLE-enabled alert button called the V.ALRT / V.BTTN. I will be connecting to it with my PC via BLE, then reading the information one of the device’s characteristics. In the BLE GATT specifications standard, the Manufacturer Name String characteristic is defined as part of the Device Information Service; this is a service that is present on most BLE devices.

First run hcitool lescan to do a scan of BLE devices and to find the address of your device:

$ hcitool lescan
LE Scan ...

I haven’t listed the specific address of my device here, but it should be a group of 6 hexadecimal values. (This is really just a MAC address; however, as a security feature, some BLE devices may change this address to random values over time.)

Once we have the address, run gatttool to discover the device’s services. You can do this in interactive mode:

$ gatttool -b XX:XX:XX:XX:XX:XX -I

In interactive mode, you should use the connect and primary commands to connect to the device and view its services:

[   ][XX:XX:XX:XX:XX:XX][LE] > connect
[CON][XX:XX:XX:XX:XX:XX][LE] > primary

You should see something like this list:

attr handle: 0x0001, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0010, end grp handle: 0x0022 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x0023, end grp handle: 0x0025 uuid: 00001803-0000-1000-8000-00805f9b34fb
attr handle: 0x0026, end grp handle: 0x0028 uuid: 00001802-0000-1000-8000-00805f9b34fb
attr handle: 0x0029, end grp handle: 0x002c uuid: 00001804-0000-1000-8000-00805f9b34fb
attr handle: 0x002d, end grp handle: 0x0031 uuid: 0000180f-0000-1000-8000-00805f9b34fb      

The Manufacturer Name String should be under the Device Information Service, which has a standard UUID of 0x180A. We see it in the list of services in this line:

attr handle: 0x0010, end grp handle: 0x0022 uuid: 0000**180a**-0000-1000-8000-00805f9b34fb

The rest of that UUID is just the 128-bit BLE base UUID, 0000XXXX-0000-1000-8000-00805f9b34fb. Different manufacturers will usually have their own custom 128-bit base UUIDs for their own custom services, with the XXXX varying for each service.

Looking at the rest of the line where that UUID shows up, we can see that there are two additional fields: attr handle and end grp handle. BLE Handles are different from UUIDs: an UUID defines the properties and metadata of the attribute we’ll be accessing, whereas the handle gives the address of a particular attribute. Here, we used the service’s UUID to find out that this particular service is the Device Information Service; now, in order to access the data associated with it, we need to use the service’s listed handles.

Let’s try accessing the characteristics of this service. To do this, use the characteristics command in gatttool. We’ll need to provide it with two handles: the “attr handle”, 0x0010, and the “end grp handle”, 0x0022, for this service. (These are the start and end handles for this service.)

[CON][XX:XX:XX:XX:XX:XX][LE] > characteristics 0x0010 0x0022

We now have a table of characteristics for the Device Information Service we were trying to access:

handle: 0x0011, char properties: 0x02, char value handle: 0x0012, uuid: 00002a23-0000-1000-8000-00805f9b34fb
handle: 0x0013, char properties: 0x02, char value handle: 0x0014, uuid: 00002a24-0000-1000-8000-00805f9b34fb
handle: 0x0015, char properties: 0x02, char value handle: 0x0016, uuid: 00002a25-0000-1000-8000-00805f9b34fb
handle: 0x0017, char properties: 0x02, char value handle: 0x0018, uuid: 00002a26-0000-1000-8000-00805f9b34fb
handle: 0x0019, char properties: 0x02, char value handle: 0x001a, uuid: 00002a27-0000-1000-8000-00805f9b34fb
handle: 0x001b, char properties: 0x02, char value handle: 0x001c, uuid: 00002a28-0000-1000-8000-00805f9b34fb
handle: 0x001d, char properties: 0x02, char value handle: 0x001e, uuid: 00002a29-0000-1000-8000-00805f9b34fb
handle: 0x001f, char properties: 0x02, char value handle: 0x0020, uuid: 00002a2a-0000-1000-8000-00805f9b34fb
handle: 0x0021, char properties: 0x02, char value handle: 0x0022, uuid: 00002a50-0000-1000-8000-00805f9b34fb

The Manufacturer Name String Characteristic has a standard UUID of 0x2A29. Picking it out from the list above:

handle: 0x001d, char properties: 0x02, char value handle: 0x001e, uuid: 0000**2a29**-0000-1000-8000-00805f9b34fb

We can now access the value of the Manufacturer Name String Characteristic via reading from the listed “char value handle”, 0x001e, using the char-read-hnd command:

[CON][XX:XX:XX:XX:XX:XX][LE]> char-read-hnd 1e
Characteristic value/descriptor: 48 69 2d 50 00

In this case we know from the BLE standard that the value of the Manufacturer Name String Characteristic is a UTF-8 string. Plugging in 48 69 2d 50 00 to a hex -> ASCII converter gives “Hi-P”, the name of the manufacturer of the device I’m working with. (they seem to be this electronics manufacturing company).

Note that you can use gatttool under non-interactive mode as well; here’s a guide.

Further reading #

Reverse Engineering a Bluetooth Low Energy Light Bulb: Control With Bluez. A really good guide from Adafruit that describes how to use gatttool in more detail, (including writing to characteristics) as well as introducing how to automate communication with a BLE device using a Python script that wraps gatttool.

Bluetooth: ATT and GATT. A more detailed description of the protocols that BLE is composed of.

The TI SensorTag’s Attribute Table. This is a nice example of a complete BLE attribute table for a real device with a number of different sensors (barometer, thermometer, accelerometer, etc.) and custom services / characteristics for each.