Saturday, April 06, 2013

Raspberry Pi and TI CC2541 SensorTag

Texas Instruments have yet another low cost development kit.  The SensorTag is a Bluetooth Low Energy (BLE) key fob filled with the sorts of sensors that you'll find in the latest smartphone - pressure, temperature, humidity, accelerometer, gyroscope and magnetometer. See the SensorTag User Guide for full details.

If you're interested in experimenting with the SensorTag and you've got one of the latest iPhones, or iPads, then there's no need for you to be reading this,  pop over to Texas Instruments SensorTag page and the ByteWorks blog.  For Raspberry Pi and other Linux users I'll describe what I've figured out so far.

What you'll need

The hardware is really simple, in addition to the SensorTag which can be bought direct from TI post free, you'll need a BLE (aka Bluetooth 4.0) capable dongle.  I'm using a Plugable USB-BT4LE which can be bought on Amazon.  A PC running Linux - Ubuntu 12.10 seems to have everything needed as standard, and it was by testing on a laptop with the Plugable dongle I was able to prove to myself that the dongle and SensorTag both worked and would communicate.   However,  the rest of this post will be about using the RaspberryPi, because that's what I set out to make work.


This is my first RaspberryPi project so I started with a standard Raspbian "wheezy" image.


Finding the SensorTag
$ sudo hcitool lescan

LE Scan ...
90:59:AF:0A:A8:4E (unknown)
90:59:AF:0A:A8:4E SensorTag
ctrl c

Connect to the discovered tag
$ sudo hcitool lecc 90:59:AF:0A:A8:4E

Switch on a sensor and read its value
$ gatttool -b 90:59:AF:0A:A8:4E --interactive

[   ][90:59:AF:0A:A8:4E][LE]> connect
[CON][90:59:AF:0A:A8:4E][LE]> char-read-hnd 0x25
Characteristic value/descriptor: 00 00 00 00
[CON][90:59:AF:0A:A8:4E][LE]> char-write-cmd 0x29 01
[CON][90:59:AF:0A:A8:4E][LE]> char-read-hnd 0x25
Characteristic value/descriptor: a3 ff 7c 06
[   ][90:59:AF:0A:A8:4E][LE]>

The values 0x25 and 0x29 are "handles" that we either read from (0x25 holds the thermometer reading) or write to (0x29 must be set to a value of 01 to turn on the thermometer)

See for details of the sensor handles.  We can also ask the sensors to send a continuous stream of readings.  To do this enter "char-write-cmd 0x26 0100", a value of 0000 will turn the stream off.

A working program

Having figured that out I wrote a simple python script that uses pexpect to drive gatttool.  Grab a copy from github if you're interested.

Building gatttool

I had to build my own copy of gatttool as the version included in wheezy wasn't able to write values to the sensor. To build bluez-5.2 you need to "apt-get install" the following - libglib2.0-dev libdbus-1-dev libusb-dev libudev-dev libical-dev systemd libreadline-dev

See comment from Klaus Seiler on how to build.


Klaus Seiler said...

Thanks for this very valuable info

For other people I want to add how to build bluez to get to the right gatttool version:

A kernel version higher then 3.5
So check with
# uname -r

get a recent bluez version from
# wget
# tar xvf bluez-5.4.tar.xz

get the necessary libs
# apt-get install libusb-dev libdbus-1-dev libglib2.0-dev automake libudev-dev libical-dev libreadline-dev

systemd is not needed, see later

configure and build SW:
# cd bluez-5.4
# ./configure --disable-systemd
# make
# make install

The I even had to copy gatttool manually into the /usr/local/bin dir

# cp attrib/gatttool /usr/local/bin/

dh labs said...

does the tag work out of the box with the plugable dongle? over on the TI forum, they mentioned loading a hex file to make it work with non-TI dongles...


Michael Saunby said...

It worked fine for me without loading anything extra. Can't promise it will work for others.

David said...

After building the latest gatttool from the bluez package, the walkthrough above worked.

I was able to use a BT 4.0 USB dongle (labelled "CSR 4.0", came from Seeedstudio) to talk to a SensorTag from my Raspberry Pi.

Thank you for this great tutorial!

Alex Jonsson said...

Excellent tutorial, had my PI up and running with the TI Sensor Tag in 15 min, much of which was the "make" step for the Bluez ver5.6 (just released). Now off to write some scripts :-)

Christoph Zimmermann said...

I followed the tutorial with the Plugable USB-BT4LE and a fresh raspberry pi image (, upgraded all libs to the current ones (apt-get update , upgrade), installed the dongle, installed blue-z 5.7 according to Klaus Seilers tutorial, but I only get an error message for hcitool lescan:

Set scan parameters failed: File descriptor in bad state

hcitool dev shows no device and "/etc/init.d/bluetooth status" isn't able to find the bluetooth file. Lsusb output:
Bus 001 Device 004: ID 0a5c:21e8 Broadcom Corp.

Can anyone please help me or point me in the right direction?


Christoph Zimmermann said...

problem solved, forgot to power up ble dongle
just run:
hciconfig hci0 up
before hcitool lescan

Anir_n said...

I am using the sensor tags just to find the presence of it.. was able to do the things you told but the hcitool lescan unlike the hcitool scan goes on and on untill i press ctrl c. So how to read the no. of devices available to be paired and get their baddr. Please help its urgent.

RichardN said...

Thanks - that was really helpful. You may also find this useful:

sudo stdbuf -oL hcitool -i hci0 lescan | while read; do beep -l 20 -f 1000; done

which causes the computer to beep every time it receives an advertising packet (turn on and off with the side-button on the sensor-tag).

It's useful for checking range and interference.

Short beeps are needed so that the beep is finished in less time than there is between advertising packets. stdbuf is used to prevent the pipeline queueing up 4k of data at a time.

Albis said...

Thanks for the tutorial and info on installation of bluez stack. I could install the stack and run the example with raspberry + TI-cc2541 tag. Altough it may sound trivial, I could not find a way to get the link's rssi value. hcitool's rssi option is obviously not working in case of BLTE and gatttool does not seem to have a proper command to get the link rssi.

Is there someone who managed to get rssi values for LE using raspberry and bluez?

Thanks in advance.

FozzyFoster said...

Hi guys, has anyone managed to get an RSSI value from the sensortag or any other Bluetooth LE device on the Pi?


Michael Saunby said...

Getting RSSI sounds more like a Bluez question. Have you tried searching on Is it working on another Linux machine but not Raspberry Pi? In which case please share your code and I'll try it out.

Bill said...

Emphasizing what Klaus wrote. IF you get 'A valid handle is required' when you try to enable the sensor, you need to update your gatttool by building bluez from scratch.

On my pi make install of bluex5-7 DOES NOT INSTALL gatttool, you have to copy it by hand.

Bill said...

Sorry about the multiple comments.

Regarding RSSI, you can get it by parsing the output of hcidump during a lescan operation. FWIW, lescan hangs forever. I ended up hacking the bluez hci code to return after it found what I was looking for.

Thomas Kubitza said...

Thanks for the nice tutorial. Here a hint for your python scripts. In the recent bluez version (5.10) gatttools' feedback has changed. The scripts break. Just change all "[CON" through "[LE" to fix this.

Mike Vartanian said...


I am able to see the sensortag using hcitool lescan but am having difficulty connecting to the tag using hcitool lecc or using gatttool -b --interactive and then initiating connect.

Any thoughts or suggestions..? I have downloaded BlueZ5.9 using the instructions shown and copied over gatttool to the usr directory

Thanks for your help,

SFCounterfeiter said...


nice information... thx

But the LE Connection issn't really Low Energy. Because the gatttool tells the Sensortag: Send me every 65ms a connection available message...

That sucks, because I tried to get sensor data every minute only.
My measures tells me that 65 ms connection interval will work for just 20 days...

hcitool has a option to change the interval (lecup), but didn't work for me. (connection breaks)

In IRC the bluez guys told me that this option is soon available at the mgmt-api...

Any experience with that?

Bye Basti

SFCounterfeiter said...

I played around a bit and I got it!

Two possible ways...

The ugly one:

1. read out the connection handle from "sudo hcidump -t" output when you connect with gatttool

2. reset the connection interval with "sudo hcitool lecup --handle 71 --min 100 --max 130" of about 1,25 sec (or tune it more ;) )

The better way:

1. connect to the sensortag over hcitool: "sudo hcitool lecc BC:6A:29:C3:4C:16".

2. connect normally with the gatttool or the "python over tool" and use automatically the same connection

Now it's really low energy and battery will work over months (depends on sensor polling)


Marc Willwacher said...

Many thanks for the great tutorial.
But I got a question on the sensortag. Everytime I want to reconnect, I have to push the button to make the tag accept the connection. Is there a way to read the sensor data, without accepting on tags side.
E.g.: To use it as outdoor thermometer. I dont like to go outside to push the button to start reading the temp. ;-)

Michael Saunby said...

Marc, my workaround for this is to use an MSP430 to periodically hit the connect line (solder a wire to the button). You can be even smarter, as sensing the voltage on the connect line shows whether the device is connected or not - there's a regular pulse if connected. Of course doing this will drain the coin cell very quickly.

benjamin said...

Marc, Michael, I've come here with exactly the same problem. I bought two SensorTags (one inside and one outside) and wanted to create a system that tells me when to open the windows (for minimum moisture).

Does all of this end before it started, because the SensorTag shuts down after 500 seconds with no connection?

I haven't really understood BLE nor the SensorTag. Isn't there something I can do?

Assuming the tag's firmware could be changed to prevent shutting down after 500 seconds without a connection, how long would the battery last then?


Klinenator said...

Does anyone know how to check the distance? On the iPhone app it shows as decibels.

Marc Willwacher said...

Benjamin, Michael:
Ok, you got the same problems.
I asked the question on the TI-Forum , but didn't get an answer.

I think, we have to change the firmware of the tag to work as we expect. To become a broadcaster. But I don't know how to do this.

SFCounterfeiter said...

My last answer is maybe lost...

I have no problems with Bluez 5.10 and sensortag firmware 1.3 and 1.4... I stay connected over weeks and read every minute data to a webgraph....

To use the senortag with the internal battery more then 26 days, you have to do a special low energy "trick".

Try my modified (quick and dirty) python progamm from this URL:

Keep track for the connection handles at the first time... on my raspbian it was every time 70 or 71 on an raspbmc it was always handle 44...
You have to change this in the firmware to get a battery life more then a year...


Marc Willwacher said...

Hi SFCounterfeiter

thanks for the post. I will try your script the next days.

Did explain it somewhere?

> You have to change this in the
> firmware to get a battery life
> more then a year...

What do you mean I have to change in the firmware? The handles? Could you please explain, what is the best way to update the firmware?

benjamin said...

Please see my blog at for info on how to update firmware. It seems to work.

SFCounterfeiter said...

@benjamin Your solution is very unsecure... every 10 secondes another BLE Device could connect faster then yours and read out the Data and also can block your device...

One the other hand, our solution is worse if we lost connection, because the pi is for example rebooting. After a minute you have to press all sensortags in your house again :D

@Marc Willwacher sorry, i would say: change the handles in the python script... leave the ti firmware untouched!

Thomas Ackermann said...

Many thanks for the great tutorial!
I used it as a starting point to connect two SensorTags
and an Arduino equipped with a RedBearLab BLEmini bluetooth
radio to a RaspberryPi.

I recently lifted the versions used to SensorTag v1.5, BlueZ v5.14
and pexpect v3.1 and noticed that SensorTag v1.5 added some new
characteristics and so most of the handles used in the scripts
had to be changed. To ease this a litte bit I wrote a script
"" which does a complete discovery of a BLE device
(but of course a correct script should do a discover-handle-by-uuid
instead of hard-coded handles). Code can be found at


yozh said...


Does the script here work with 5.17 Bluez ? on a RPI running 3.10.34+ Kernel ? It seems that it just spits out write commands and not the values needed. Can some one point me in to a right direction ? Also any tools for web graphing this values such as RRD

Michael Saunby said...

I've just returned to this project and tested with Bluez 5.17. A small change was required, which is now on github - just grab the latest.

As for graphing on the web you could try

yozh said...

Thank you I will try your script again and take a look at that site.

yozh said...

tried the new script and this is all I`m getting.

root@raspberrypi:~/ble/sensortag# hcitool lecc BC:6A:29:AE:D9:76
Connection handle 69
root@raspberrypi:~/ble/sensortag# python BC:6A:29:AE:D9:76
Preparing to connect. You might need to press the side button...
char-write-cmd 0x29 01
char-write-cmd 0x26 0100
char-write-cmd 0x31 01
char-write-cmd 0x2e 0100
char-write-cmd 0x3c 01
char-write-cmd 0x39 0100
char-write-cmd 0x44 01
char-write-cmd 0x41 0100
char-write-cmd 0x5b 07
char-write-cmd 0x58 0100
char-write-cmd 0x4f 02
Preparing to connect. You might need to press the side button...

Michael Saunby said...

yozh, have you checked that gatttool is working correctly for you? The script just automates the calling of gatttool.

yozh said...

If I do it with the gatttool it works fine see below.

root@raspberrypi:~# hcitool lescan
LE Scan ...
BC:6A:29:AE:D9:76 (unknown)
BC:6A:29:AE:D9:76 SensorTag
^Croot@raspberrypi:~# gatttool -b BC:6A:29:AE:D9:76 --interactive
[BC:6A:29:AE:D9:76][LE]> connect
Attempting to connect to BC:6A:29:AE:D9:76
Connection successful
[BC:6A:29:AE:D9:76][LE]> char-write-cmd 0x29 01
[BC:6A:29:AE:D9:76][LE]> char-read-hnd 0x25
Characteristic value/descriptor: 2d ff 58 0b

yozh said...

Not Sure why my other post didnt go thru. But I pasted that manually this works just fine from the tool.

yozh said...

not sure what else to do anything I try I keep just getting:
Preparing to connect. You might need to press the side button...
char-write-cmd 0x29 01
char-write-cmd 0x26 0100
char-write-cmd 0x31 01
char-write-cmd 0x2e 0100
char-write-cmd 0x3c 01
char-write-cmd 0x39 0100
char-write-cmd 0x44 01
char-write-cmd 0x41 0100
char-write-cmd 0x5b 07
char-write-cmd 0x58 0100
char-write-cmd 0x4f 02
Preparing to connect. You might need to press the side button...

While using the tool directly it works just fine.

yozh said...


Is there anyway you can help with this ? I need to use this for a project Im building and I have been stuck forever on this. Seems that somehow your script is not returning results, and I do see gatttool running in ps aux when I execute the script. I also able to run gattool manually and get results.

yozh said...
This comment has been removed by a blog administrator.
Michael Saunby said...

yozh, you're getting an exception which the script thinks is a timeout, but could be something else - a missing library, a typo. If you've some Python coding skills you'll get there pretty quickly once you dive into the code.

To simplify things have a look at the script

Maybe comment out the xively_init() and xively_write() lines.

If it's not working for you the "restart" stuff isn't helping you, and this script doesn't do that.

uri schatzberg said...

thank you very much for this tutorial.
i am trying to run this on an ubuntu machine. how do i compile bluez-5.4 for linux and amd processor?
the gatttool doesn't work when i just make at the directory.
i would appreciate any help

Dave said...

This info has got me from zero to a long ways, pairing and reading data from the command line etc. Thank you! But I have been stuck for awhile now trying to get working for me. (Apr 2013version) It hangs at from sensor_calcs Import*
Can't find that module. Is that module something you wrote or should it have been part of gatttool or bluez install?

yozh said...

II was never able to get this to work. It always said the same thing as above.

Michael Saunby said...

See SensorTag and Raspberry Pi revisited for an update on this post and for the code.

Kishen Someshwar said...

if i want to make multiple connections simultaneously then how would the procedure be altered? for now i am doing something like this:

gatttool -b 90:45:ER:34:56 - I

char-read-hnd 0x25
char-write-cmd 0x29 01
char-read-hnd 0x25

It shows some values like ae 23 er uk
I am a newbie playing with BLE. I would really appreciate some guidance

Hoyt Clagwell said...

I see you are using pexpect to "shell out" & use the command there a reason the following commands are not included in this shell process (to make the connecting process fully under program control)?

To enable the bluetooth adaptor and find your SensorTag device address do the following -

sudo hciconfig hci0 up
sudo hcitool lescan

python [ADDRESS]

Hoyt Clagwell said...

I see only part of the connection process is done with pexpect...can the entire process be done with pexpect (such as lescan and lecc)...I tried it myself without much luck yet (don't know much about pexpect).

address do the following -
sudo hciconfig hci0 up
sudo hcitool lescan

Press the side button and you should get a couple of lines showing the device is working. Hit Ctrl-C to exit. Now you're ready to g

Mn Nm said...

I found your sample code for reading ambient and object temperature in python. However, i don't completely understand this:

tosigned = lambda n: float(n-0x10000) if n>0x7fff else float(n)

How i read the above piece of code:
if n>0x7fff: n = float(n-0x10000)
else n = float(n)

Basically what is happening is that the two's complement value is converted to float. Why should this only happen when the value of n is greater than 0x7fff? If the value is 0x7fff or smaller, then we just convert i to float. Why? I don't understand this.

Marco Tonoli said...

did anyone has find a definitive solution for 180 sec standby? i wann use this device to put it in a remote location, and sometimes natural event-based check some data but presso side button is not simple.
I tried some test but i have not the raspberry BT so tested with my android S4 but when open the firmware page device sensor-kit reset.
Also, can someone what is A and B firmware? are alternative each other? how i can boot with A or B firmware?

sorry for multiple question :-)