Bluetooth Low Energy Peripherals with JavaScript

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:

Next, modify the base-feeds.conf file:

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

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

You can verify that the Bluetooth radio has started with:

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

Testing Edison Bluetooth

The Code

First, install bleno:

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

Run the program with:

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

20 Responses

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

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

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

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

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

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

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

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

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

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

Leave a Reply