Getting Started with Bluetooth Low Energy (BLE)

Getting Started with Bluetooth Low Energy (BLE) © Apache-2.0

In this tutorial, we'll learn how to set up BLE GATT services to make a thermometer using Intel's Arduino 101

  • 30 respects

Components and supplies

Apps and online services

About this project


This project covers what bluetooth low energy is and how to use it with the Arduino 101. We'll go over services, characteristics, and how to control inputs and outputs on the Arduino via the LightBlue app on our phone.

Fun fact: bluetooth gets its name from a viking king, Harold Bluetooth, and the bluetooth logo is a combination of two runes.

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['1082c12e5a'] = [{ URL: '', caption: '', type: 'image' }];

What is Bluetooth?

A Bluetooth product, like a headset or watch, contains a tiny computer chip with a Bluetooth radio and software that makes it easy to connect to other bluetooth devices. When two Bluetooth devices want to talk to each other, they need to pair. Because bluetooth can't connect at long distances, bluetooth networks are called 'pico-nets' (pico means tiny).

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['88121b7c71'] = [{ URL: '', caption: 'a piconet', type: 'image' }];

As you might have guessed, there are different types of Bluetooth. The kind you use to stream high quality audio or video (for instance, in your wireless headphones) is called BR/EDR (basic rate/enhanced data rate). BR/EDR and Bluetooth Low Energy (BLE) are fundamentally different. Bluetooth with low energy functionality is built on an entirely new development framework using Generic Attributes, or GATT. Today, we're exploring BLE, since that's what Arduino 101 and most IoT devices use.

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['9568b34fb4'] = [{ URL: '', caption: 'The diagram', type: 'image' }];

Control a Button and an LED from your phone via BLE
  • Attach a button and an LED to Arduino pins 4 and 13 respectively (see diagram)
  • Connect the Arduino 101 to your computer
  • Turn bluetooth on on your phone.
  • When you open the app, you'll probably see a device called 'ARDUINO 101-XXXX.' Click on it.
if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['827e95a205'] = [{ URL: '', caption: 'Select your device', type: 'image' },{ URL: '', caption: 'View the GAP', type: 'image' }];

Once you're connected, you can see the advertisement data, including its Local Name (ButtonLED gets cut short to ButtonLE since the General Advertising Profile uses the Shortened Local Name, which only allows 8 characters). You can also see the service UUIDs and characteristic UUIDs (in this case they're the same). UUIDs are the randomly generated 128-bit characters that identify a unique Bluetooth service. All this data together is called the GAP, or General Advertising Profile.

The profile is created within the setup on lines 25-28 of the sketch:

 // set the local name peripheral advertises 
 // set the UUID for the service this peripheral advertises: 

You can think of your Arduino 101, or any BLE Peripheral, as a newspaper publisher, say, the New York Times. The Arduino 101 prints 'news', called a service, every now and then. Readers or Central Devices like your phone can subscribe to the news.

Just as the New York Times prints both the Times and The Boston Globe, the Arduino 101 can have multiple services. Each service, in turn, can have multiple characteristics. These are like the different sections in the newspaper.

Services and characteristics are defined in the sketch here:

BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service 
// create switch characteristic and allow remote device to read and write 
BLECharCharacteristic ledCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite); 
// create button characteristic and allow remote device to get notifications 
BLECharCharacteristic buttonCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify); // allows remote device to get notifications 

In our case, we have an LED characteristic and a button characteristic.

On your phone, you can choose which characteristics you wish to subscribe to via a mechanism called notify. If you're subscribed to a characteristic, then every time the value of that characteristic changes, you get a notification. In this case, the characteristic you can subcribe to is whether or not our button was pressed.

Click on the UUID that has 'Read Notify' properties and try pressing the button a few times


if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['2275d78cc9'] = [{ URL: '', caption: 'The second characteristic, button characteristic, has \'Read Notify\' properties', type: 'image' },{ URL: '', caption: 'Select \'Listen for notifications\' to subscribe to all changes.', type: 'image' },{ URL: '', caption: 'Press the button a few times', type: 'image' },{ URL: '', caption: 'The button was pressed, then released...', type: 'image' }];

Do you see the value changing from 0x00 to 0x01?

There's another property, called 'indicate,' which is the same as notify except that your reader sends back a response to let the peripheral know that they got the notification. We won't be using it in this sketch, but some reader devices require their peripherals to use indicate rather than notify, so it's good to be aware of it.

Characteristics can also be 'write' accessible. To extend the New York Times metaphor, this is kind of like letters to the editor, where the subscriber can send something to the publication. In this case, we're going to write a value to our light to tell it to turn on.

You can turn it to on by sending any value other than zero, and turn it back off by sending zero:

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['7611e66894'] = [{ URL: '', caption: 'Select \'Write new value\'', type: 'image' },{ URL: '', caption: 'Send any non-zero value to turn your light on! Try typing \"1\"', type: 'image' },{ URL: '', caption: 'Even strings of nonsense work! Turn your light off by sending it zeros.', type: 'image' }];

Rad! So now you can receive data from your peripheral (the Arduino 101) on your reader (your phone), as well as turn an LED off and on.

You also learned about read, write, notify and indicate properties, and how to combine them in characteristics to create services.

But guess what? You won't always need to create your own custom services or characteristics, because any service you can imagine has already been defined as a GATT service. Remember that GATT stands for General Attributes? Yeah, I have no idea how they came up with that acronym either. Anyway, GATT is the layer that defines services and characteristics and enables read/write/notify/indicate operations on them. Check out these long lists of predefined services and characteristics.

Let's set up a temperature monitor to test out one of these predefined services.

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['3ff17aee56'] = [{ URL: '', caption: '\"The circuit\"', type: 'image' }];

Setting up the temperature monitor
  • Plug your grove temperature sensor into A0 of your grove shield attached ro your Arduino 101 as shown in "the circuit" above.
  • Note: I used grove parts to simplify this, but you can easily use another temperature sensor - just be sure to include the appropriate library in your code!

I've left some of the values out of this sketch and given them placeholders (written in CAPS).

Each service and each characteristic that is predefined in the General Attributes has an ID. We'll need to find the documentation for the temperature service, choose the characteristics that we need, and find their IDs.

Go to the Gatt specifications page on Find the Health Thermometer Service.

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['9ec84a89b3'] = [{ URL: '', caption: '', type: 'image' },{ URL: '', caption: '', type: 'image' },{ URL: '', caption: '', type: 'image' }];

On the service page, each characteristic is noted as being mandatory or optional. In the Temperature service, the mandatory one is called "Measurement."

Click on the blue text, and you'll be taken to the Temperature Measurement page. Here you can find the ID for the Measurement Characteristic. Add this to your code.

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['adf7241cbf'] = [{ URL: '', caption: 'Characteristics will say if they\'re optional or mandatory on the service description', type: 'image' },{ URL: '', caption: '', type: 'image' },{ URL: '', caption: '', type: 'image' }];

Now your code should look more like the BLE_Thermometer_final sketch. Upload it to your Arduino and run it! Connect your phone to your arduino with the Light Blue app. Hey look, we're getting data! But why does it say 0x0016? It's the temperature in hexadecimal.

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['a19893c3d8'] = [{ URL: '', caption: '', type: 'image' },{ URL: '', caption: '', type: 'image' },{ URL: '', caption: '', type: 'image' }];

In the Light Blue app, there's a list of data types that you can use. Hexadecimal is the default, but you can choose binary, bytes, integers, and signed integers, and you can choose big endian or little endian and how many bytes to include. We could spend all day playing with these, but we'll leave the discussion of data types for another day:

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['c54c5cd497'] = [{ URL: '', caption: '', type: 'image' }];

Unfortunately, the data in the LightBlue app isn't available to me in decimal, so I need to convert it to get the temperature in thei format that I'm used to. I pull out my handy hexadecimal converter and convert 0x0016 to decimal. I get 22. Hey look! The temperature showing in the serial monitor is also 22!

if (typeof(lightBoxImages) == 'undefined') { lightBoxImages = {}; } lightBoxImages['d9a9ca4214'] = [{ URL: '', caption: 'serial monitor output', type: 'image' }];

Nice work! Hopefully you understand slightly better how bluetooth communication is structured. Need an extra challenge? Try converting the temperature from Celcius to Farenheit.

Further reading:

Using Bluetooth Low Energy with the Arduino 101

BLE Services: A beginners tutorial

BLE Characterstics: A beginners tutorial

Examples from the Arduino 101 page

Definitely try these out!


Custom parts and enclosures

BLE Thermometer
This contains two files; BLE_Thermometer_blank has blank values for you to fill out to practice finding BLE Characteristic and Service numbers.


Arduino 101 with Grove Temperature sensor
plug temp sensor into A0
Tempreture sensor connector om6exhmpoe
Button & LED
Use this with the BLE button sketch.
101button bb c9mfwjbqh9


Similar projects you might like

Home Automation With Arduino 101 Using Bluetooth Low Energy

Project tutorial by naveen manwani

  • 8 respects

Arduino101 / tinyTILE BLE: Match-Making Sunglasses

Project tutorial by Kitty Yeung

  • 50 respects

Arduino 101 Bluetooth MIDI

Project showcase by Don Coleman

  • 1 comment
  • 5 respects

A Posture Detector Sending Bluetooth Data to a Cordova App

Project tutorial by Gini76

  • 27 respects

BLE Bot 9000

Project tutorial by 5 developers

  • 79 respects
Add projectSign up / Login