Earlier this month I had written a tutorial for detecting nearby BLE iBeacon devices using a Raspberry Pi Zero W and an application written with Golang. It was a great example of accomplishing something with Go and very little code.
Scanning for BLE devices is a great use case for Internet of Things (IoT) devices like the Raspberry Pi Zero W, and Golang isn’t the only great language around. I, like many others, do a lot of Node.js development as well.
We’re going to see how to scan for BLE iBeacon devices using Node.js and the popular Node.js BLE (Noble) library.
If you haven’t already done so, you’ll need Node.js installed on your Pi Zero W. If you’re not sure how to install Node.js on an ARMv6l device, check out my previous tutorial titled, Install Node.js on a Raspberry Pi Zero W without NodeSource.
If you’re using Raspbian Linux, the necessary dependencies for working with Bluetooth likely aren’t already available. Instead we have to install them.
Use SSH to connect to the Raspberry Pi Zero W and execute the following command:
sudo apt-get install bluetooth bluez libbluetooth-dev libudev-dev
The libraries are nothing special to the noble library and are common for using Bluetooth on Linux. In fact, the list came from the noble documentation.
Going forward, we’re going to assume that all development will happen via the Raspberry Pi Zero W through SSH or something similar. First we’ll need to create a fresh project.
From the CLI, execute the following command:
npm init -y
The above command will create a package.json file, or in other words, a new Node.js project.
To actually scan for BLE iBeacons, we’ll need to install a few packages for our project. From the CLI execute the following commands:
npm install noble --save
npm install node-beacon-scanner --save
The above commands will install the noble package for scanning for BLE devices and the node-beacon-scanner package which parses BLE packets and only works with those classified as beacons. Beacons include iBeacon and Eddystone, but we’re going to focus on iBeacon.
The node-beacon-scanner library is not a requirement, but it does make life easier since you won’t have to manually parse the advertisement data.
If you’re like me, using a Mac for development, you can actually test your code locally before transfering it to the Raspberry Pi Zero W. The catch is that you need to be using a specific version of noble. Instead of using the primary package that was installed previously, you could execute the following:
npm install https://github.com/jacobrosenthal/noble.git#highsierra --save
You can learn more about High Sierra support in an issue ticket on GitHub. However, it is likely to be merged into the primary package at some point. Again, this is only necessary if you wish to test on Mac, not strictly on the Raspberry Pi.
Now that we have a project created, we can start development. For simplicity, all of our code will exist in a single JavaScript file.
Create a new file in your project called app.js and include the following JavaScript code:
const Noble = require("noble");
const BeaconScanner = require("node-beacon-scanner");
var scanner = new BeaconScanner();
scanner.onadvertisement = (advertisement) => {
var beacon = advertisement["iBeacon"];
beacon.rssi = advertisement["rssi"];
console.log(JSON.stringify(beacon, null, " "))
};
scanner.startScan().then(() => {
console.log("Scanning for BLE devices...") ;
}).catch((error) => {
console.error(error);
});
While short and simple, the above JavaScript code is quite powerful. To give credit where credit is due, most of it came from the node-beacon-scanner documentation.
So what is happening?
We’re including the previously downloaded libraries, the first which does the heavy lifting and the second which wraps the first to do our advertisement parsing. Once we start scanning, we use our onadvertisement
listener to pick up any beacons. Quite a lot of data comes back, but I’ve always found that the RSSI and iBeacon data is what’s useful.
In this example we only plan to print out the iBeacon devices that were discovered. We could easily take the advertisement data and add it to a database like one of my previous examples, or even send push notifications.
When we’re ready to start the application and scan for BLE packets, we can’t just run it like we would any ordinary Node.js application. Instead we have to run it with privilege like the following:
sudo node app.js
We need to use sudo
because only privileged applications can access Bluetooth functionality on Linux.
If everything went smooth and you have iBeacon devices broadcasting nearby, the Raspberry Pi Zero W should pick them up and print them out like in the above image.
You just saw how to scan for Bluetooth Low Energy (BLE) iBeacon devices using a Raspberry Pi Zero W and Node.js. You could easily take this tutorial to the standard size Raspberry Pi if you’d like as well, since it also has BLE support.
If you’re curious to know what kind of iBeacon I’m using, I’m using Gimbal beacons because you can pick them up for $5.00 each and configure them to use the iBeacon specification.
Want to accomplish the same BLE scanning with Go? Check out my previous tutorial.
A video version of this article can be seen below.