Introduction: Control Bluetooth LE Devices From a Raspberry Pi
Bluetooth Low Energy (aka BLE/Bluetooth 4.0/Bluetooth Smart) is the most recent incarnation of Bluetooth technology developed by the Bluetooth SIG (the organization that maintains the specification). This communication protocol is designed for applications where data needs to be transferred in small amounts at relatively low speed while consuming low amounts of power (e.g., heart rate monitor, step counter, wireless keyboard). This latest version of the protocol is not compatible with its predecessor (Bluetooth classic), as an upside, long gone are the days where pairing devices was necessary!
The goal of this Instructable is to demonstrate how you can setup your Raspberry Pi to read and write data from Bluetooth Low Energy (BLE) devices nearby. Whether you want to read the number of steps from your fitbit, or your heart rate from your iWatch, or read/write any type of data from/to BLE devices, this guide should help you along the way.
Currently, Bluetooth Low Energy (BLE) is not well supported by the standard Raspberry Pi distributions, thus some additional work is required to get it working. We describe in detail the steps you'll need to get your Raspberry Pi ready to start using Bluetooth LE.
Step 1: List of Materials
In this Instructable we'll be using the following materials:
1 x Raspberry Pi 2 or 3 with a 5V USB Power Supply
1 x 8GB MicroSD Card
Any BLE device (e.g., fitbit, cellphone, smartwatch)
Step 2: Getting the Operating System (Raspbian) on the MicroSD Card
To complete the rest of this tutorial you'll need to have your Raspberry Pi up and running. This process involves roughly 3 steps:
In our "Getting Started with Raspberry Pi" tutorial, we show you how to go from unboxing your Raspberry Pi to running your first applications on it; be sure to check it out.
In addition, we've made a detailed video of the process:
Step 3: Configuring Raspbian to Use Bluetooth LE
By default, the Raspbian distribution comes without a Bluetooth stack. The bluez package is quite old and has patchy support for Low Energy. You can build and install a more modern version as described below.
After the system is up and running open up the Terminal program and a browser window, then start following the commands.
First, do not, I repeat, do NOT use the version available through aptitude. It is a very old version and doesn't work very well.
# Do NOT do this ->sudo apt-get install bluez
In case you have it already installed, go ahead and remove it. If you're not sure if you have it installed, go ahead and do this step anyway:
sudo apt-get --purge remove bluez
Next, we have to determine what's the latest version available. To do this, navigate to the official website https://www.kernel.org/pub/linux/bluetooth/ and look for the package bluez-X.XX.tar.xz where X.XX is the version. At the time of this writing the latest version is 5.34!
Then, go back to the Terminal on the Raspberry Pi and remembering to change X.XX for the latest version we find we enter:
Subsequently, we uncompress the package by:
tar xvf bluez-X.XX.tar.xz
We need at this point to make sure all the necessary libraries for running the bluetooth stack:
sudo apt-get install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev
Are now ready to compile the bluez package:
./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-library -disable-systemd
sudo make install
For a strange reason the standard installation process misses installing one of the files to the correct directory. To solve this:
sudo cp attrib/gatttool /usr/bin/
And that's it! We're now ready to test out our Bluetooth LE USB Adapter on our Raspberry Pi!
Step 4: Connecting the Bluetooth LE USB Adapter
This is very straight-forward as the Raspbian Operating System is capable of detecting when the Bluetooth LED USB Adapter is hotplugged (i.e., plugged in when the system is running). This is great as we need not reboot in order to use the adapter. We can simply plug in the USB adapter to an available USB port.
And then ensure that the system has recognized it by going back to the Terminal and entering:
The output should show the device as one of the entries.
Step 5: Testing the Bluetooth LE USB Adapter
Now that the Bluetooth LE USB Adapter is recognized by the system and we've successfully installed the Bluetooth stack, we're ready to test that we can access it. From the terminal we can first bring up the interface by:
sudo hciconfig hci0 up
And see if the device is up and running:
Should return the status of the BLE interface, in our case hci0. We can then move to the next step where scan for nearby BLE devices!
Step 6: Scanning for Nearby BLE Devices
After installing the Bluetooth stack and successfully added the Bluetooth LE USB adapter to our Raspberry Pi we're ready to scan for nearby BLE devices.
In our case, we've downloaded a Node.js App to a MacBook called Bleno. This very useful app allows us to set our laptop as a Peripheral Device. We've configured the app so that our peripheral device is named "I <3 Instructables" and echoes any message we send to it (for more details look at the examples in the Bleno repository).
Then, going back to the terminal in our Raspberry Pi, we run:
sudo hcitool lescan
Often times this command runs indefinitely, thus we can hit CTRL+C in order to stop it. From the output, we can pick up the MAC addresses of nearby BLE devices.
We can see that before we hit CTRL+C, the device is present in the output of the scan with a MAC address of 28:37:37:1A:D3:CF. We'll need this address in the next step, so make sure you're able to complete this before moving forward.
Step 7: Connecting to a BLE Device
One of our favorite features of Bluetooth 4.x is that, different than in previous versions, we need not go through the obnoxious pairing process to connect to a device. On our Raspberry Pi, we'll be using the program gatttool to connect to our nearby BLE device, and write/read data to/from it.
In the previous step we were able to get the MAC address 28:37:37:1A:D3:CF of the Peripheral Device that we're running through the Bleno app. To connect to this device we're going to use another tool part of the BLE stack we installed called gatttool. We're able to run this tool in an interactive mode so that we step through the process of issuing commands over BLE to our Peripheral Devices!
sudo gatttool -b 28:37:37:1A:D3:CF -I
Note that your MAC address will likely be different :) Also, you might need to add "-t random" to the list of arguments if you have trouble with the next steps. If you get device busy error simply remove the dongle and reconnect it.
Once you see the interactive prompt you can simply type connect and wait for the connection to be established. After getting the "Connection successful" message on the screen, we're now ready to start writing and reading data to and from the BLE Peripheral Device!
Step 8: Writing Data to a BLE Device
Now that we're connected to our BLE Peripheral Device, which in this case is a laptop running the Bleno Node.js app, we can use the commands primary and char-desc to list all the different services and characteristics available on the device.
In our case, our simple device only has 1 characteristic for writing data to it, and retrieving the last data that it received. The handle for this characteristic is 0x0026, thus within the interactive command line interface for gatttoolwe can:
[28:37:37:1A:D3:CF][LE]>char-write-req 0x0026 1234
This command sends the value "1234" to the handle 0x0026. We can verify that the command is received by looking at the debug messages of our Bleno app. In our case, the app prints out the value "1234" after receiving it!
In our final step, we'll proceed in a similar fashion in order to read back the value we've just written to the device.
Step 9: Reading Data From a BLE Device
Now that we've written some data to our BLE Peripheral Device it's time to read it! For this we make use of the same handle 0x0026, and again within the interactive command line interface for gatttool we can
This command reads the value we last sent (which in this case should be "1234") to the handle 0x0026. We can verify that the request is received by looking at the debug messages of our Bleno app. In our case, the app prints out "EchoCharacteristic - onReadRequest: value = 1234" after receiving it!