Edison with wires!

Edison with wires!

Previously, I’ve shown how to enable Bluetooth Low Energy (BLE) connections using Python. In the past few months, I have been furiously learning JavaScript for an upcoming set of tutorials dealing with the Intel® Edison. Along the way, I needed to make a demo using BLE and JavaScript, which invariably led me to the bleno module.

Bleno is a great tool, but I found some of the examples a little confusing to follow (I get easily lost when a program is split into more than 2 files without a well-documented API). As a result, I constructed a simple echo server demo program that illustrates how characteristics work in BLE. This demo should work on anything that can run JavaScript and has a Bluetooth transceiver.

For this demo, our device (e.g. Edison or Raspberry Pi) is the “peripheral” and a smartphone will be the “central”. See here for more BLE terminology.

Edison Users

If you are planning to use the Edison as the peripheral, you will need to enable the Bluetooth Low Energy device through Linux. Create a serial connection or SSH to your Edison and enter:

rfkill unblock bluetooth
hciconfig hci0 up

Next, modify the base-feeds.conf file:

vi /etc/opkg/base-feeds.conf

Press ‘i’ to insert text, and add the following lines (locations of repositories):

src/gz all http://repo.opkg.net/edison/repo/all
src/gz edison http://repo.opkg.net/edison/repo/edison
src/gz core2-32 http://repo.opkg.net/edison/repo/core2-32

Save and exit by pressing ‘esc’ and enter ‘:wq’. Start the Bluetooth radio with:

rfkill unblock bluetooth
killall bluetoothd
hciconfig hci0 up

You can verify that the Bluetooth radio has started with:

hcitool dev

That should give you the Bluetooth MAC address of the Edison.

Testing Edison Bluetooth

The Code

First, install bleno:

npm install bleno

In a new file (e.g. “ble_echo.js”), enter:

/**
 * Simple bleno echo server
 * Author: Shawn Hymel
 * Date: November 22, 2015
 *
 * Creates a Bluetooth Low Energy device using bleno and offers one service
 * with one characteristic. Users can use a BLE test app to read, write, and
 * subscribe to that characteristic. Writing changes the characteristic's
 * value, reading returns that value, and subscribing results in a string
 * message every 1 second.
 *
 * This example is Beerware (https://en.wikipedia.org/wiki/Beerware).
 */

// Using the bleno module
var bleno = require('bleno');

// Once bleno starts, begin advertising our BLE address
bleno.on('stateChange', function(state) {
    console.log('State change: ' + state);
    if (state === 'poweredOn') {
        bleno.startAdvertising('MyDevice',['12ab']);
    } else {
        bleno.stopAdvertising();
    }
});

// Notify the console that we've accepted a connection
bleno.on('accept', function(clientAddress) {
    console.log("Accepted connection from address: " + clientAddress);
});

// Notify the console that we have disconnected from a client
bleno.on('disconnect', function(clientAddress) {
    console.log("Disconnected from address: " + clientAddress);
});

// When we begin advertising, create a new service and characteristic
bleno.on('advertisingStart', function(error) {
    if (error) {
        console.log("Advertising start error:" + error);
    } else {
        console.log("Advertising start success");
        bleno.setServices([
            
            // Define a new service
            new bleno.PrimaryService({
                uuid : '12ab',
                characteristics : [
                    
                    // Define a new characteristic within that service
                    new bleno.Characteristic({
                        value : null,
                        uuid : '34cd',
                        properties : ['notify', 'read', 'write'],
                        
                        // If the client subscribes, we send out a message every 1 second
                        onSubscribe : function(maxValueSize, updateValueCallback) {
                            console.log("Device subscribed");
                            this.intervalId = setInterval(function() {
                                console.log("Sending: Hi!");
                                updateValueCallback(new Buffer("Hi!"));
                            }, 1000);
                        },
                        
                        // If the client unsubscribes, we stop broadcasting the message
                        onUnsubscribe : function() {
                            console.log("Device unsubscribed");
                            clearInterval(this.intervalId);
                        },
                        
                        // Send a message back to the client with the characteristic's value
                        onReadRequest : function(offset, callback) {
                            console.log("Read request received");
                            callback(this.RESULT_SUCCESS, new Buffer("Echo: " + 
                                    (this.value ? this.value.toString("utf-8") : "")));
                        },
                        
                        // Accept a new value for the characterstic's value
                        onWriteRequest : function(data, offset, withoutResponse, callback) {
                            this.value = data;
                            console.log('Write request: value = ' + this.value.toString("utf-8"));
                            callback(this.RESULT_SUCCESS);
                        }

                    })
                    
                ]
            })
        ]);
    }
});

Run the program with:

node ble_echo.js

And you should see output in the console stating that the BLE service is running. Use a BLE test app on your phone (for example, BLE Scanner on Android) to connect to the device.

BLE Scanner on Android

Try writing to the characteristic, reading from it, and subscribing to it. The console on the device should let you know about incoming requests from the central device (i.e. the smartphone).

JavaScript BLE on the Edison

23 thoughts on “Bluetooth Low Energy Peripherals with JavaScript

  1. Rex St. John on December 9, 2015 at 7:54 pm Reply

    Epic.

    1. ShawnHymel on December 9, 2015 at 10:05 pm Reply

      Thanks, Rex 🙂 After playing with BLE some more, it seems that you don’t really need to put the unofficial repositories into base-feeds.conf (despite what the tutorial on Intel’s site says). From what I can tell, you did it on your tutorial to install bluez. Is that right?

  2. Pangea on March 13, 2016 at 4:54 pm Reply

    Hi:

    When I pair I get this:
    home/pi/node_modules/bleno/lib/hci-socket/crypto.js:60
    var output = new Buffer(input.length);
    ^
    TypeError: Cannot read property ‘length’ of undefined
    at swap (/home/pi/node_modules/bleno/lib/hci-socket/crypto.js:60:32)
    at e (/home/pi/node_modules/bleno/lib/hci-socket/crypto.js:37:9)
    at Object.c1 (/home/pi/node_modules/bleno/lib/hci-socket/crypto.js:22:9)
    at Smp.handlePairingRandom (/home/pi/node_modules/bleno/lib/hci-socket/smp.js:130:12)
    at Smp.onAclStreamData (/home/pi/node_modules/bleno/lib/hci-socket/smp.js:58:10)
    at EventEmitter.emit (events.js:117:20)
    at AclStream.push (/home/pi/node_modules/bleno/lib/hci-socket/acl-stream.js:26:10)
    at BlenoBindings.onAclDataPkt (/home/pi/node_modules/bleno/lib/hci-socket/bindings.js:198:21)
    at EventEmitter.emit (events.js:106:17)
    at Hci.onSocketData (/home/pi/node_modules/bleno/lib/hci-socket/hci.js:455:14)

    When I scan I see only 2 primary services, no characteristics, thoug I get connect/disconnect.

    1. ShawnHymel on March 15, 2016 at 3:24 pm Reply

      You should not see a connect/disconnect Bluetooth option. If you are using an Android phone/tablet, this is a bug. Try rebooting the phone to see if that allows you to connect via BLE.

      Edit – I’m assuming that’s what you mean by connect/disconnect option. Otherwise, this seems to be an issue with bleno itself. I recommend taking a look through the issues on their GitHub repo.

  3. Aly El-Kerdany on March 31, 2016 at 1:30 pm Reply

    Your tutorial helped me a lot, now I can now read/wrtie between my edison & android phone, but I want to edit onReadRequest function to be able to send a string (“Hi”) each sec, but when I use the following code
    // Send a message back to the client with the characteristic’s value
    onReadRequest : function(offset, callback) {
    console.log(“Read request received”);
    this.intervalId = setInterval(function() {
    callback(new Buffer(“Hi!”));
    }, 1000);
    },

    I get an error, I don’t want to use the onSubscribe function. I’m I missing something ?

    1. ShawnHymel on April 5, 2016 at 4:56 pm Reply

      What error do you get, and why don’t you want to use onSubscribe? Here is an example of some Edison code that reads a characteristic whenever it changes (using onWriteRequest()): https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments/blob/master/11-Accelerometer/XDK_11_Edison/main.js. Also, here is another example that sends out a notification over BLE whenever a value changes: https://github.com/sparkfun/Inventors_Kit_For_Edison_Experiments/blob/master/12-BLEController/XDK_12_Edison/main.js. Maybe one of those will help?

  4. Aly El-Kerdany on April 6, 2016 at 11:59 am Reply

    The Android side i use does not support the notification method, It only has the read and write characteristics linked with the code written in javascript.
    So i want to modify the onReadRequest Method on the Edison to be able to write to the android each second…
    The error i get is :
    TypeError: value is out of bounds
    at TypeError ()
    at checkInt (buffer.js:705:11)
    at Buffer.writeUInt8 (buffer.js:715:5)
    at Gatt.errorResponse (/home/root/node_modules/bleno/lib/hci-socket/gatt.js:293:7)
    at null. (/home/root/node_modules/bleno/lib/hci-socket/gatt.js:730:35)
    at null. (/home/root/Echo10.js:82:30)
    at wrapper [as _onTimeout] (timers.js:261:14)
    at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

    If u can help with this it would be greatly appreciated.
    Thanks in advance.

    1. ShawnHymel on April 6, 2016 at 1:54 pm Reply

      The Android should support notify, as that is part of the BLE spec. Perhaps this issue will help: https://github.com/sandeepmistry/bleno/issues/86. Are you using a Buffer() in the callback in send your message?

  5. Aly El-Kerdany on April 6, 2016 at 2:54 pm Reply

    I can trigger “onReadRequest” successfully on the edison sending only once to the android , The problem i have is in sending a reply to the android each sec using the interval () function, is it possible to do it in the onReadRequest?

    onReadRequest : function(offset, callback) {
    console.log(“Read request received”);
    this.intervalId = setInterval(function() {
    callback(new Buffer(“Hi!”));
    }, 1000);
    },

    1. ShawnHymel on April 6, 2016 at 5:21 pm Reply

      onReadRequest is only called whenever a device (your Android device, in this case) performs a read on the characteristic. You could have your Android device read the characteristic once per second, which forces the onReadRequest function to be called in the Edison.

      I believe that what you want is the onSubscribe function (see the example code in this tutorial), where the callback starts an interval to update the characterstic’s value every second.

  6. KellyH on April 6, 2016 at 7:58 pm Reply

    Thanks! This is the only tutorial that I’ve been successful with on my edison. I started off with the blePeripheral template from Intel’s XDK IoT edition but that kept failing due to errors on the binding.node. I’ve tried numerous other tutorials with no success. After finding this, I created a new project, copied your source into the main.js and then added “bleno” : “latest” to the package and it finally worked. Thanks again!

    1. ShawnHymel on April 6, 2016 at 8:55 pm Reply

      Awesome! Glad to hear it worked out for you.

  7. Aly El-Kerdany on April 6, 2016 at 9:38 pm Reply

    I thought of sending read requests from my android but it is better for me the other way around.
    I know onSubscribe/onUnsubscribe are great, I’m using the following android code to read/write successfully after changing service UUID , it also has the notify part I think, but I can’t make it work so I will try to search more on this issue.

  8. Aly El-Kerdany on April 6, 2016 at 9:38 pm Reply
  9. Marcio on April 11, 2016 at 10:18 pm Reply

    I tried that android code but it fails. I was able to connect to the module but when I click on either button I get this error in the logcat and nothing in the terminal or the android device screen: com.example.android.bluetoothlegatt W/BluetoothLeService: Custom BLE Service not found. Prior to this I DO get Connected to GATT server, the right device is listed, services discovered and characteristics as well.

  10. Amr Emara on November 20, 2016 at 8:51 pm Reply

    Hi, its my first time to use intel Edison and ive been following this tutorial to create a BLE peripheral of my device and i know this might be a stupid question but i reached the step where i should install bleno and add the code the a new file and i don’t know how to do so ! am i supposed to install bleno on the board after i create a serial connection with it or globally on my machine ? and how do i create a new file on the board and add the code to it ? i’m using OSX 10.11.6

    1. ShawnHymel on November 24, 2016 at 3:02 am Reply

      Correct, you need to connect to your Edison throught an SSH or Serial connection in order to create files and install bleno on the Edison. Here is a guide that might be helpful.

      1. ajithparma on December 28, 2016 at 9:50 am Reply

        Hi ! i have recently find your blog and its just awesome.Got a lot of unique and informative stuff here .
        thanks a lot and keep sharing up.Good Luck!

  11. Milan Alvarado on January 7, 2017 at 3:46 am Reply

    Great article. I am in the process of using a raspi 3 as the peripheral. I can get read and write of the characteristic working. Essentially, it is the echo example with light blue android central client reading, writing, and notifying correctly. What I would like to do is write bytes from my console to the characteristic to display content on my ble central. What is the easiest way to do this?

    1. ShawnHymel on January 22, 2017 at 4:42 pm Reply

      It depends on how you want to display that information on your central, which I’m assuming is the Android phone. My first thought is to create an app that uses a BLE central library to show the characteristic’s data. I did something similar here. Specifically, look at the “Phone App” section under “The Code” to see how I used a BLE central Cordova plugin. Hope that helps!

  12. Dany on March 25, 2018 at 8:53 am Reply

    Helloo, Thanks for the great article, just a small question , from my phone i can see the connection but i can’t connect.

    I’ve seen things related to using blueZ > 5.14 and disabling bluetoothd, but they’re either outdated or didn’t work for me.

    Did you have any issue from this kind ?

    1. ShawnHymel on March 26, 2018 at 4:21 pm Reply

      I vaguely remember running into issues with trying to connect on my Android a few years ago. I needed to restart my phone to get it to work, if I recall.

      1. Dany on March 27, 2018 at 7:17 am Reply

        Thank you, it actually worked with me, what I had to do was always start it this way

        hciconfig hci0 down
        sudo HCI_CHANNEL_USER=1 node ble_echo.js

        for some reason sometimes the service is not visible, but this is something i’ll dig up.. Thanks for the blog!

Leave a Comment Cancel Comment

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