Getting started with Bluetooth Low Energy on Linux
I’m working with BLE on Linux and decided to share here my finding.
First you will need a Bluetooth Low Energy (BLE) compatible host, then if your laptop’s bluetooth is not BLE compatible you will need a bluetooth dongle.
Searching in the Internet I discovered that this low cost CSR V4.0 is compatible.
When plugin it on my laptop I got this info:
#dmesg . [ 8972.648662] usb 3-3: new full-speed USB device number 16 using xhci_hcd [ 8972.870695] usb 3-3: New USB device found, idVendor=0a12, idProduct=0001 [ 8972.870699] usb 3-3: New USB device strings: Mfr=0, Product=2, SerialNumber=0 [ 8972.870702] usb 3-3: Product: CSR8510 A10
Let see the lsusb listing (idVendor=0a12, idProduct=0001):
# lsusb . Bus 003 Device 016: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Ok, but for some strange reason my Debian 8.0 delayed some time (~30s) to get it working, strange but at least:
# hciconfig -a hci0 hci0: Type: BR/EDR Bus: USB BD Address: 00:1A:7D:DA:XX:XX ACL MTU: 310:10 SCO MTU: 64:8 UP RUNNING PSCAN RX bytes:10241 acl:0 sco:0 events:348 errors:0 TX bytes:1738 acl:0 sco:0 commands:47 errors:0 Features: 0xff 0xff 0x8f 0xfe 0xdb 0xff 0x5b 0x87 Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3 Link policy: RSWITCH HOLD SNIFF PARK Link mode: SLAVE ACCEPT Name: 'inspire' Class: 0x00010c Service Classes: Unspecified Device Class: Computer, Laptop HCI Version: 4.0 (0x6) Revision: 0x22bb LMP Version: 4.0 (0x6) Subversion: 0x22bb Manufacturer: Cambridge Silicon Radio (10)
Now let search for a Bluetooth LE device:
# hcitool lescan LE Scan . BC:6A:29:AB:3F:46 (unknown) BC:6A:29:AB:3F:46 SensorTag BC:6A:29:AB:3F:46 (unknown) BC:6A:29:AB:3F:46 SensorTag BC:6A:29:AB:3F:46 (unknown)
You can connect to this device using the gattool
# gatttool -I [ ][LE]> help help Show this help exit Exit interactive mode quit Exit interactive mode connect [address [address type]] Connect to a remote device disconnect Disconnect from a remote device primary [UUID] Primary Service Discovery included [start hnd [end hnd]] Find Included Services characteristics [start hnd [end hnd [UUID]]] Characteristics Discovery char-desc [start hnd] [end hnd] Characteristics Descriptor Discovery char-read-hnd Characteristics Value/Descriptor Read by handle char-read-uuid [start hnd] [end hnd] Characteristics Value/Descriptor Read by UUID char-write-req Characteristic Value Write (Write Request) char-write-cmd Characteristic Value Write (No response) sec-level [low | medium | high] Set security level. Default: low mtu Exchange MTU for GATT/ATT [ ][LE]> connect BC:6A:29:AB:3F:46 Attempting to connect to BC:6A:29:AB:3F:46 Connection successful // Let to list primary Services: [BC:6A:29:AB:3F:46][LE]> primary 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: 0x002a uuid: f000aa00-0451-4000-b000-000000000000 attr handle: 0x002b, end grp handle: 0x0035 uuid: f000aa10-0451-4000-b000-000000000000 attr handle: 0x0036, end grp handle: 0x003d uuid: f000aa20-0451-4000-b000-000000000000 attr handle: 0x003e, end grp handle: 0x0048 uuid: f000aa30-0451-4000-b000-000000000000 attr handle: 0x0049, end grp handle: 0x0054 uuid: f000aa40-0451-4000-b000-000000000000 attr handle: 0x0055, end grp handle: 0x005c uuid: f000aa50-0451-4000-b000-000000000000 attr handle: 0x005d, end grp handle: 0x0061 uuid: 0000ffe0-0000-1000-8000-00805f9b34fb attr handle: 0x0062, end grp handle: 0x0068 uuid: f000aa60-0451-4000-b000-000000000000 attr handle: 0x0069, end grp handle: 0xffff uuid: f000ffc0-0451-4000-b000-000000000000 //Let see the visible characteristics: [BC:6A:29:AB:3F:46][LE]> char-desc 0x0018 0x002A handle: 0x0018, uuid: 00002a26-0000-1000-8000-00805f9b34fb handle: 0x0019, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x001a, uuid: 00002a27-0000-1000-8000-00805f9b34fb handle: 0x001b, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x001c, uuid: 00002a28-0000-1000-8000-00805f9b34fb handle: 0x001d, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x001e, uuid: 00002a29-0000-1000-8000-00805f9b34fb handle: 0x001f, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0020, uuid: 00002a2a-0000-1000-8000-00805f9b34fb handle: 0x0021, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0022, uuid: 00002a50-0000-1000-8000-00805f9b34fb handle: 0x0023, uuid: 00002800-0000-1000-8000-00805f9b34fb handle: 0x0024, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0025, uuid: f000aa01-0451-4000-b000-000000000000 handle: 0x0026, uuid: 00002902-0000-1000-8000-00805f9b34fb handle: 0x0027, uuid: 00002901-0000-1000-8000-00805f9b34fb handle: 0x0028, uuid: 00002803-0000-1000-8000-00805f9b34fb handle: 0x0029, uuid: f000aa02-0451-4000-b000-000000000000 handle: 0x002a, uuid: 00002901-0000-1000-8000-00805f9b34fb [BC:6A:29:AB:3F:46][LE]>
Nice! Everthing is working!
The “gatttool” is deprecated and will be removed soon, then we need to use bluetoothctl instead! This way:
# bluetoothctl //scan for BLE devices: [bluetooth]# scan on Discovery started [CHG] Controller 00:1A:7D:DA:71:10 Discovering: yes [CHG] Device EC:F2:E5:CE:30:5B RSSI: -44 [CHG] Device EC:F2:E5:CE:30:5B RSSI: -52 [CHG] Device EC:F2:E5:CE:30:5B RSSI: -44 //connect to it: [bluetooth]# connect EC:F2:E5:CE:30:5B Attempting to connect to EC:F2:E5:CE:30:5B [CHG] Device EC:F2:E5:CE:30:5B Connected: yes Connection successful //get information from device [Nordic_UART]# info Device EC:F2:E5:CE:30:5B Name: Nordic_UART Alias: Nordic_UART Paired: no Trusted: yes Blocked: no Connected: yes LegacyPairing: no UUID: (1800) UUID: (1801) UUID: Vendor specific (6e400001-b5a3-f393-e0a9-e50e24dcca9e) RSSI: -44 //list the attributes [Nordic_UART]# list-attributes Service /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009 Vendor specific (Primary) Characteristic /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000d Vendor specific Characteristic /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000a Vendor specific Descriptor /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000a/desc000c Client Characteristic Configuration //get information from an attribute: [Nordic_UART]# attribute-info /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009 Service - Vendor specific UUID: 6e400001-b5a3-f393-e0a9-e50e24dcca9e Primary: yes Characteristics: /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000a Characteristics: /org/bluez/hci0/dev_EC_F2_E5_CE_30_5B/service0009/char000d
Bluetooth Low-Energy on Linux API
I have a device with a few custom GATT services, and I would like to write a Linux program to interact with it. After some searching I found out that Linux is using BlueZ to handle the Bluetooth LE protocol. I’m using Ubuntu 15.10 with BlueZ 5.35, but I cannot figure out how use this BlueZ from a user-space program. I cannot find an API documentation anywhere, no tutorials, examples, nothing. Is it even possible to use this BlueZ stack to do anything other than just connecting to Bluetooth devices with default services? And if so, where is the documentation? (Preferably C/C++ API but at this point anything goes)
Yes it’s possible. But there is a learning curve. The bluez APIS are documented in the bluez tree. Those are all DBUS APIs. So to use them you first need to learn a bit about DBUS. There are different bindings to make use of DBUS. They include python, Glib and QT. There are others.
5 Answers 5
- Have a look at attrib/gatttool.c in the bluez sources [1]. Gatttool is a command line utility for connecting to BTLE devices using the C «API». The GATT interface is not exposed in libbluetooth though.
- A newer alternative to gatttool and thus another example to learn from is the btgatt-client, which you can find in tools/btgatt-client.c (to enable compilation configure bluez with —enable-experimental ).
- Besides the C interface bluez integrated a DBUS interface. bluetoothctl is an example tool using the DBUS interface. The code of bluetoothctl can be found in client/ [2].
- Another example program using the C interface of bluez is the Anki Drive SDK [3]. It packaged the bluez GATT C interface in its own library libbzle [4]. When using the C interface you have to connect a socket when establishing a BTLE connection. The gatttool does this via the GATT interface, which in turn uses glib iirc. But you can also do this using syscalls (socket, connect, . ) as explained e.g. here [5]. This document also explains:
Unfortunately, as of now there is no official API reference to refer to, so more curious readers are advised to download and examine the BlueZ source code.
Gilbert Brault also extracted the GATT interface from bluez [6] and links to a rudimentary doxygen documentation of the GATT interface [7] with the following disclaimer:
This is a work in progress with the intent of documenting all important functions and data structures
Also Szymon Janc gave a nice overview in his talk «Bluetooth on Modern Linux» at the Embedded Linux Conference 2016 [8]. Starting at 42:00 he talks about the unexposed C interface. But in general he seems to recommend the DBUS API (see «Tips» slide at 45:30). Some DBUS documentation can be found in doc/gatt-api.txt [9] and Python examples using the DBUS interface can be found in test/ .
I feel your pain. I needed to add user input from a custom BLE peripheral, a simple remote pushbutton, to an embedded program running under Linux (Stretch) on a Raspberry Pi. I was stunned by the needless complexity and Spartan (not a compliment) documentation of the BlueZ API. All the BlueZ “examples” are written from the perspective that Bluetooth is the center of the universe and the user wants to support every Bluetooth device ever invented. In my case I knew exactly the device, service, and GATT characteristics I needed to interact with, and I wanted a minimum overhead task that would do its thing in a low priority thread.
It turns out a BLE central client is pretty straightforward using BlueZ, but it was an arduous road starting with the source for the BlueZ utility bluetoothctl in release 5.49. I accomplished my needs using only three unmodified source files from the BlueZ distribution and excerpts from an additional three source files. Since the BlueZ source is inextricably dependent on D-Bus and the Gnome GLib main loop, I grudgingly included them.
Following OlivierM’s generous lead, and in hopes that my embarrassingly massive investment in time saves someone else a month of their life, I have posted my example Bluetooth BLE client on GitHub: https://github.com/jjjsmit/BluetoothBLEClient
It would arguably be simpler and quicker to write a shell script on Linux to do what you need to do. The BlueZ commands are relatively simple and straightforward, and there are many tutorials and questions on how to use it.
Once you are more familiar with using the commands manually you can then write a minimal shell script so that this is automated for you.