Introduction: Bluetooth Low Energy: Read-Write to Sensor Network From Raspberry Pi

Originally published in this blog.

The goal of this tutorial is to demonstrate how you can read and write from a Bluetooth Low Energy (BLE) device. For example, if you want to read the 'number of steps' data from your fitbit and make interesting apps with it, this tutorial might help you.

In this tutorial, I am using a RedBearLab Bluetooth Low Energy (BLE) shield connected to an Arduino UNO. This BLE+Arduino combo essentially represents a BLE device. We will use a Raspberry Pi to read from & write to this BLE device.

Step 1: Components Used

Arduino UNO R3

Redbear Lab BLE Shield

Raspberry Pi

BLE CSR Dongle

Some wires etc.

Step 2: Initial Setup

Install hard-float Raspberryian OS using this link.

Install Bluez using step 1, 2, 3 of this link.

I used CSR 4.0 dongle in the Raspberry Pi for BLE connection.

Make sure you have gatttool in the path using

$which gatttool 

If it is not in the path, copy it from bluez/bluez-5.11/attrib

$cp bluez/bluez-5.11/attrib/gatttool /usr/local/bin/

Step 3: Bluetooth Dongle Setup, Scan and Connect

Check if the Bluetooth dongle is up and running

~/bluez/bluez-5.11 $ tools/hciconfig 

If not (you will see DOWN written in the result), use below command to get it up

~/bluez/bluez-5.11 $ tools/hciconfig hci0 up

Now scan for BLE devices. The command below might continue scanning forever, so type CTRL+C when you have the device address

$ sudo hcitool lescan 

Lets assume that you get the BLE device address xx:xx:xx:xx:xx:xx. Now connect with the device using gatttool

$ sudo gatttool -b xx:xx:xx:xx:xx:xx -t random --interactive 

You might not need to use -t random. Also if you get device busy error, remove the dongle and reconnect it. You will see an interactive prompt. Type connect like below

[xx:xx:xx:xx:xx:xx][LE]> connect 

Attempting to connect to xx:xx:xx:xx:xx:xx

Connection successful

Step 4: Preparing to Read & Write

Once it is connected, we want to write to a LED to turn in ON/OFF, and read the sensor data. We are using FSR as the sensor in this example. We will use gatttool to do the read & write.

Before we begin, we need to understand how this works fundamentally. You can go ahead and read this book or any other good tutorial that I am not aware of. But basically, you need to have some code on your Arduino that sets up a profile in the nRF8001 component on your RedBearLab shield that defines "pipes" which is the link between a characteristic exposed by the radio and a function from which you can read data or to which you can send data.

I am using SimpleControl sketch from RedBearLab as the code that runs on Arduino. To do read-write, we need to know which address to write and what value to write.

Step 5: Find the Address to Read and Write

I look at RedBearLab's Android source code to figure out the TX, RX address. In the RBLGattAttribute.java, you will see

public static String BLE_SHIELD_TX = "713d0003-503e-4c75-ba94-3148f18d941e"; 
public static String BLE_SHIELD_RX = "713d0002-503e-4c75-ba94-3148f18d941e"; 

Now, if you type below in the gatttool interactive prompt, you can figure our the address (handle) of those TX, RX

[xx:xx:xx:xx:xx:xx][LE]> char-desc 
handle: 0x000b, uuid: 713d0003-503e-4c75-ba94-3148f18d941e 
handle: 0x000c, uuid: 2803
handle: 0x000d, uuid: 713d0002-503e-4c75-ba94-3148f18d941e
handle: 0x000e, uuid: 2902

So you basically see that the handle of TX, RX are 0x000b and 0x000d respectively.

Step 6: Write to a LED: Turn ON/OFF

From the SimpleControl.java, you can see that you need to write 010100 to the TX handle to turn the LED ON and 010000 to turn it OFF.

digitalOutBtn.setOnCheckedChangeListener(new OnCheckedChangeListener() { 
@Override
public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
byte buf[] = new byte[] { (byte) 0x01, (byte) 0x00, (byte) 0x00 };
if (isChecked == true)
buf[1] = 0x01;
else
buf[1] = 0x00;
................................
}
});

Now type below to turn the LED ON

[xx:xx:xx:xx:xx:xx][LE]>char-write-cmd 0x000b 010100

Step 7: Read Analog Data

Similarly from the SimpleControl.java, you can see that you need to write A00100 to the handle 0x000b to enable the analog reading capability through the RedBearLab shield. You also need to enable listening to the 0x000e handle. The 0x000e is the handle of the Client Characteristic Configuration (CCC) uuid 2902. You can find this 0x000e handle by typing char-read-uuid 2902 in the gatttool interactive prompt.

[xx:xx:xx:xx:xx:xx][LE]>char-write-cmd 0x000b A00100 
[xx:xx:xx:xx:xx:xx][LE]>char-write-req 0x000e 0100 --listen

You will see sensor values in coming the the RX handle (0x000d)

Notification handle = 0x000d value: 0b 00 c0 
Notification handle = 0x000d value: 0b 00 d0 
Notification handle = 0x000d value: 0b 00 e4 
Notification handle = 0x000d value: 0b 00 f0 
...................
Microcontroller Contest

Participated in the
Microcontroller Contest