Edison and RFduino

Edison and RFduino

It’s should be no surprise that I enjoy working with the Edison. It may not be as easy to work with as the Raspberry Pi, but I still like it.

My current project includes getting the Edison to talk Bluetooth Low Energy (BLE) to another device. The RFduino is the device in question, as I should be able to receive data as well as control peripherals attached to the RFduino. The final project will be an addition to the IoT YouTube series that I am working on (at SparkFun). I’m not spoiling anything!

Turns out, I’m a complete noob at Bluetooth. I know very little about the terminology, protocol, or libraries. The best I could find for Python is IanHarvey’s bluepy package. As far as I could tell, it is still a work in progress, with updates almost every day. I picked a particular revision because it seemed to work the best on the Edison. A lot of this work is also based on Kiruss’ blog post, Getting RFduino working with Linux.

Configure the RFduino

  • I used the RFduino Dev Kit for this, but you can program the RFduino any way you want
  • Install Arduino 1.6.3 (this is the only one that works with RFduino when I wrote this)
  • Follow the directions here to install RFduino in the Arduino software
  • Upload the Temperature example (from RFduino_BLE examples)

Configure the Edison

  • I used an Edison and Base Block
  • Install Ubilinux on the Edison (you can use this guide)
  • Log in and ‘su’ to get root access
  • Connect to WiFi (also found in the Ubilinux installation guide)

Start the bluetoothctl interactive prompt

bluetoothctl

In bluetoothctl, type:

scan on

Wait until you see the RFduino pop up. Copy down its MAC address. Then, type:

scan off

You will need to pair with the RFduino (where xx:xx:xx:xx:xx:xx is the MAC address of the RFduino):

pair xx:xx:xx:xx:xx:xx

You can also attempt to connect with the RFduino:

connect xx:xx:xx:xx:xx:xx

Once you are done playing in the bluetoothctl interface, go ahead and exit:

exit

Using Python to Control BLE

You can use Linux commands to connect and communicate via Bluetooth, but the real fun comes from doing it programmatically (Bash scripting excepted, of course). To start, update apt-get and install some libraries:

apt-get update
apt-get install build-essential libdbus-1-dev

Clone and compile bluepy (there is a helper file written in C). Notice that we are checking out a specific revision of bluepy. At the time of this writing, the newest version did not work for me.

git clone https://github.com/IanHarvey/bluepy.git
cd bluepy
git checkout 7d2864686f8b3daad021ea042adc322276e75045 .
cd bluepy
make

There is a good chance that we will need to restart our Bluetooth interface:

hciconfig hci0 down
hciconfig hci0 up

Now, try the btle.py example. We specify the address as “random” (very brief explanation of random address).

python btle.py xx:xx:xx:xx:xx:xx random

You should see an output like:

Service <uuid=Generic Attribute handleStart=8 handleEnd=11> :
    Characteristic <Service Changed>, supports INDICATE
Service <uuid=Generic Access handleStart=1 handleEnd=7> :
    Characteristic <Device Name>, supports READ WRITE
    -> 'RFduino'
    Characteristic <Appearance>, supports READ
    -> '4\x12'
    Characteristic <Peripheral Preferred Connection Parameters>, supports READ
    -> '\x10\x00\x18\x00\x00\x00d\x00'
Service <uuid=2220 handleStart=12 handleEnd=65535> :
    Characteristic <2221>, supports NOTIFY READ
    -> '\x00\x00\xd8A'
    Characteristic <2222>, supports WRITE NO RESPONSE WRITE
    Characteristic <2223>, supports WRITE NO RESPONSE WRITE

This means that you were able to connect to the RFduino with Python! Rejoice, and then take a look at the output. The important part here is the third Service, which contains a non-standard UUID. The first Characteristic is marked as “NOTIFY READ” and contains the identifier 0x2221, which is short for the UUID 00002221-0000-1000-8000-00805f9b34fb. We can use that information to create a short Python script that continuously reads the temperature value (labeled with the UUID 0x2221) being sent by the RFduino.

cd ../..
nano ble_test.py

In our new Python script, paste in the following code. Also, you will need to change the “xx:xx:xx:xx:xx:xx” to your RFduino’s MAC address (keep the quotation marks).

import binascii
import struct
import time
from bluepy.bluepy.btle import UUID, Peripheral

temp_uuid = UUID(0x2221)

p = Peripheral("xx:xx:xx:xx:xx:xx", "random")

try:
    ch = p.getCharacteristics(uuid=temp_uuid)[0]
    if (ch.supportsRead()):
        while 1:
            val = binascii.b2a_hex(ch.read())
            val = binascii.unhexlify(val)
            val = struct.unpack('f', val)[0]
            print str(val) + " deg C"
            time.sleep(1)

finally:
    p.disconnect()

Save and exit (ctrl+x and ‘y’). Run the script with:

python ble_test.py

And you should see a nice stream of temperature data flowing:

BLE data from an RFduino

As far as I can tell, the RFduino is reading its own internal temperature, so that reading may not mean much. However, it is a start to being able to read any sensor or control any device across a BLE link!

20 thoughts on “Using Python and BLE to Receive Data from the RFduino

  1. Ryan on June 1, 2015 at 3:27 pm Reply

    I continually get the following error when trying to connect to my RFdunio using your scripts:

    “Failed to connect to peripheral %s, addr type: %s” % (addr, addrType))
    bluepy.bluepy.btle.BTLEException: Failed to connect to peripheral , addr type: random

    Do you have any idea why this is happening?

    1. ShawnHymel on June 27, 2015 at 11:10 pm Reply

      Sorry I didn’t see this until now! For some reason WordPress stopped sending me email notifications.

      What do you you have running on the RFduino? You loaded the Temperature example, right? If so, were you able to connect using bluetoothctl?

  2. Shoaib on January 14, 2016 at 1:14 pm Reply

    It is only receiving the last value sent from RFduino program loop instead of all three. What can be the issue?

    1. ShawnHymel on January 14, 2016 at 4:12 pm Reply

      Which RFduino example are you using? The temperature one I referenced (https://github.com/RFduino/RFduino/blob/master/libraries/RFduinoBLE/examples/Temperature/Temperature.ino) should only send one value as a float.

  3. Shoaib on January 14, 2016 at 4:19 pm Reply

    Yes. Just changed the struct unpack command to accommodate int and removed the sleep command. Also tried changing the sleep interval but no success.
    val = struct.unpack(‘i’, val)[0]

    The values I am sending from RFduino are three different values one by one during a single program loop.
    RFduinoBLE.sendInt(aaWorld.x);
    RFduinoBLE.sendInt(aaWorld.y);
    RFduinoBLE.sendInt(aaWorld.z);

    But the program is only receiving last value i.e. the value of aaWorld.z

    1. Shoaib on January 14, 2016 at 4:22 pm Reply

      The three values are being received perfectly on my Android device.

  4. Shoaib on January 15, 2016 at 5:10 pm Reply

    Can you figure out the reason?

    1. ShawnHymel on January 17, 2016 at 5:30 pm Reply

      Try printing out the results from p.getCharacteristics(uuid=temp_uuid) (without the [0] index) to see if you are receiving all 3 values. Otherwise, you might have to set up 3 different characteristics with their own UUID and read them separately (i.e. calling getCharacteristic() 3 times).

  5. Shoaib on February 3, 2016 at 7:23 pm Reply

    I am receiving only one value from getCharacterisitc function. I have the same UUID for all the three values and android is receiving values perfectly fine using the same UUID.

    1. ShawnHymel on February 4, 2016 at 4:30 pm Reply

      I have not had a chance to test this. You should be able to pack more than one value in a characteristic, so it sounds like a problem with the Python code. If you need to get all 3 now, you could try making 3 different characteristics, each with it’s own UUID.

  6. Mohamed Assem on March 15, 2016 at 11:11 pm Reply

    Thank you so much for ur tutorial , So can i run a python script on the edison that would be able to read/write data from/to an android device ?

    1. ShawnHymel on March 17, 2016 at 3:25 pm Reply

      Yes, you can. This tutorial shows how to do it with JavaScript, but the steps are the same. I recommend a Bluetooth debugging app (such as BLE Scanner) for the Android.

  7. A.Kerdany on March 20, 2016 at 9:02 pm Reply

    It would be very appreciated if you could make a tutorial or explain how to read and write to an android device from Edison using pygattlib (python) https://bitbucket.org/OscarAcena/pygattlib
    It has the functions already defined in the examples folder but I can’t make them work. Thanks 🙂

    1. ShawnHymel on March 21, 2016 at 3:44 pm Reply

      Sorry, but this is not something I can do right now, as I am booked working on Node.JS examples and tutorials. I recommend using something like BLE Scanner to scan for and read BLE characteristics.

  8. carlos on June 10, 2016 at 5:42 pm Reply

    hi, there is a way to do this with raspberry pi? i’m new using BLE and need this for a school project. Thanks

    1. ShawnHymel on June 10, 2016 at 7:20 pm Reply

      Yes, bluepy should work on the Raspberry Pi as well. You will need to make sure that you either have a Raspberry Pi 3 or a Bluetooth dongle capable of BLE.

  9. Achim on January 2, 2017 at 4:55 pm Reply

    Hello Shawn,

    I followed your tutorial to the Point where I start the Test-script. I get the error:
    Import Error: No module named bluepy.btle
    This module I didn’t find anywhere. ( Python 2.7X on Raspberry 3 )
    The Connection test before with the btle.py program is running fine.

    1. ShawnHymel on January 4, 2017 at 3:05 am Reply

      If you are using a Raspberry Pi, I recommend trying the Nuimo SDK as per this discussion.

      Edit – nevermind, that’s a wrapper SDK. Let me dig a bit more and get back to you.

    2. ShawnHymel on January 4, 2017 at 3:11 am Reply

      I wonder if my code has an error. It’s been so long since I last tried it. However, the import looks like

      from bluepy.bluepy.btle import UUID, Peripheral
      

      When I think it should be like this:

      from bluepy.btle import UUID, Peripheral
      

      Did you try that?

      1. Achim on January 4, 2017 at 7:39 am Reply

        Hello Shawn,

        thanks for your Response, You are right, without the double bluepy it is running.
        What you do in the example is getting data from the rfduino. Have you an example where i send and receive data? ( LED button on/off ) and get a state Response?

        Kind regards,
        Achim

Leave a Comment Cancel Comment

Your email address will not be published. Marked fields are required.