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.

Software

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

Testing

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
[CON][90:59:AF:0A:A8:4E][LE]>
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
[CON][90:59:AF:0A:A8:4E][LE]>
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 http://processors.wiki.ti.com/index.php/SensorTag_User_Guide#Gatt_Server 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.





55 comments:

  1. 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 http://www.bluez.org/
    # wget https://www.kernel.org/pub/linux/bluetooth/bluez-5.4.tar.xz
    extract
    # 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/

    ReplyDelete
  2. 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... http://e2e.ti.com/support/low_power_rf/f/538/p/259955/909139.aspx

    thanks

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

    ReplyDelete
  4. 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!

    ReplyDelete
  5. Anonymous11:15 pm

    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 :-)

    ReplyDelete
  6. I followed the tutorial with the Plugable USB-BT4LE and a fresh raspberry pi image (2013-05-25-wheezy-raspbian.zip), 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?

    Thanks

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

    ReplyDelete
  8. 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.

    ReplyDelete
  9. 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.

    ReplyDelete
  10. 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.

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

    Cheers

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

    ReplyDelete
  13. 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.

    ReplyDelete
  14. 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.

    ReplyDelete
  15. 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.

    ReplyDelete
  16. Hi,

    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,
    Mike

    ReplyDelete
  17. Hello,

    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

    ReplyDelete
  18. 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)

    -Basti

    ReplyDelete
  19. 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. ;-)

    ReplyDelete
  20. 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.

    ReplyDelete
  21. 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?

    thanks!

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

    ReplyDelete
  23. 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.

    ReplyDelete
  24. 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:
    http://home.arcor.de/delta-2000/sensortag.py

    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...

    -Basti

    ReplyDelete
  25. 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?

    ReplyDelete
  26. Please see my blog at bensotech.blogspot.de for info on how to update firmware. It seems to work.

    ReplyDelete
  27. @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!

    ReplyDelete
  28. Hello,

    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

    ReplyDelete
  29. 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 d3js.org

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

    ReplyDelete
  31. 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 sensortag.py BC:6A:29:AE:D9:76
    [re]starting..
    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
    [re]starting..
    Preparing to connect. You might need to press the side button...
    [

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

    ReplyDelete
  33. 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
    [BC:6A:29:AE:D9:76][LE]>

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

    ReplyDelete
  35. not sure what else to do anything I try I keep just getting:
    re]starting..
    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
    [re]starting..
    Preparing to connect. You might need to press the side button...

    While using the tool directly it works just fine.

    ReplyDelete
  36. Michael,

    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.

    ReplyDelete
  37. This comment has been removed by a blog administrator.

    ReplyDelete
  38. 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 https://github.com/msaunby/ble-sensor-pi/blob/master/sensortag/sensortag_xively.py

    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.

    ReplyDelete
  39. 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

    ReplyDelete
  40. 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 sensortag.py 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?

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

    ReplyDelete
  42. 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

    connect
    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

    ReplyDelete
  43. I see you are using pexpect to "shell out" & use the command line...is 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 sensortag.py [ADDRESS]

    ReplyDelete
  44. 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

    ReplyDelete
  45. 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.

    ReplyDelete
  46. Hi,
    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 :-)

    Marco

    ReplyDelete
  47. Hi,
    thanks for this tutorial.
    I followed all the steps but when i start:" python sensortag.py " i get Preparing to connect.....
    I pushed the side-button but nothing happens. I was able to read values from the sensortag with the gatttool. What could be the reason, why it does not work?
    Thanks.

    ReplyDelete
  48. If you want to talk to the devices with Python, you can just use dbus to ask bluetoothd to perform all those operations on your behalf. Some guys from Google just contributed a bunch of new code to BlueZ, including some Python code in BlueZ 5.30 in test/example-gatt-client that shouw you how to talk directly to bluetoothd.

    You don't have to spawn gatttool in a subprocess, which is sort of iffy with the way it uses readline() to do terminal updates.

    ReplyDelete
  49. Hi all,

    Thanks for the informative post. I was going through but I kept getting "Connection refused (111)" after the connect command in gatttool.

    Any advice is much appreciated.

    ReplyDelete
  50. Is it possible to make Sensortag directly work with a Linux terminal rather trough a raspberry pi ?

    ReplyDelete
  51. Other Linux systems should work fine. I've used a laptop running Ubuntu with SensorTag. Just ensure your Bluetooth adaptor handles BLE.

    ReplyDelete
  52. Hello all,

    I am trying to connect my sensor tag cc2541 to raspberry pi2. I have installed Bluez5.7 and have trying to start a connection for three days but all in vain
    I keep getting the same error message:
    Error: connect: connection refused (111)

    Could you please help? any Idea or advice is much appreciated

    ReplyDelete
  53. Hello all,

    I am trying to connect a sensortag cc2541 to a raspberry pi 2. I installed bluez5.7 and am trying to start a connection using the gatttool, but I keep getting the same error message:
    Error: connect: connection refused (111)
    It's been like this for three days. Please help!

    Any idea or advice is much appreciated

    ReplyDelete
  54. Hello all,

    I am trying to connect the raspberry pi to BLE device for getting data and write data.

    I am facing problem while connecting device in non-interactive mode via shell script on ubuntu. When I send "sudo gatttool -b DB:8B:9B:DA:E8:CB -I" then its entered in interactive shell. And now I want to send connect command inside the script but nothing is happening. I am sending the connect command like this -
    sudo gatttool -i hci0 -b EA:74:48:D5:52:6B --interactive <<< connect

    but after that it is leaving the interactive shell and return back to the state where I place command to run the script.

    I make sh file like connect.sh and place script inside this. and then execute the sh file via bash connect.sh

    Can anyone help me out with this.

    Thanks,

    ReplyDelete