element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Pi IoT
  • Challenges & Projects
  • Design Challenges
  • Pi IoT
  • More
  • Cancel
Pi IoT
Blog [PiIoT#05]: Presence Monitoring with BTLE Beacons
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Events
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: vish
  • Date Created: 23 Jul 2016 10:21 AM Date Created
  • Views 876 views
  • Likes 2 likes
  • Comments 2 comments
  • raspberry pi 3 bluetooth
  • mqtt
  • nrf24l01+
  • raspberry pi 3 projects
  • vish_piiot
  • freeboard
  • piiot
  • nodejs
  • raspberry pi projects
  • arduino_platform
  • piiot challenge
  • arduino
Related
Recommended

[PiIoT#05]: Presence Monitoring with BTLE Beacons

vish
vish
23 Jul 2016

In one of my previous posts, [PiIoT#03]: Cheap BLE Beacons with nRF24L01+, I discussed how to create cheap BLE beacons with nRF24L01+ modules. In this post, I'm going to use the inbuilt BLE functionality of Pi3 to detect the presence of such BLE tags and update it a UI. This is done is two steps. First part, I uses a nodeJS script to monitor the presence of such BLE tags around Pi and send MQTT messages of specific topics to a connected broker. Next, these messages are subscribed by a freeboard UI running inside a browser and updated to the dashboard.

 

Setting up the beacons

A detailed description of faking a BLE beacon is already discussed previously. All you have to do is to upload it with different MAC address to different beacons. A modified version of example sketch is given below:

// RF24 Beacon  
  
#include <SPI.h>  
  
#include "RF24Beacon.h"  
  
RF24Beacon beacon( 9,10 );  
  
uint8_t customData[] = { 0x01, 0x02, 0x03 };  
      
void setup() {  
      
    beacon.begin();  
    beacon.setMAC( 0x01, 0x02, 0x03, 0x04, 0x05, 0xF6 );   // Change this
       
    uint8_t temp = beacon.setName( "beacon1" );   // Change this
    beacon.setData( customData, 2 );  
  
}  
  
void loop() {  
  
    // beacon.sendData( customData, sizeof(customData) );  
    beacon.beep();  
      
    delay( 1000 );  
} 

The code is very similar to the one discussed in previous post, except you need to take care a few things here:

  1. In line#14, change the MAC id for each of the beacons you create. This is used to uniquely identify the beacon by nodejs script.
  2. At line#16, change the beacon name to some thing more meaningful for your use -  like 'car keys' or 'jimmy' for each beacons.
  3. At line#26, appropriately set the delay for advertising.

Now you can upload the code to you beacons and verify the advertising packets with hcitool as mentioned in previous post.

 

Scanning for beacons with Pi

Next part is a nodejs script to scan for the beacons and publish mqtt messages. For scanning for beacons, I use 'noble' library and for mqtt I use MQTT.js. Both can be installed through npm as below:

$ npm install noble
$ npm install mqtt

Once these packages are installed, we can start writing the script. My script is loosely based on one of the example scripts available with noble package for continuously checking for beacons. Basically the script does this:

  1. Connects to MQTT broker and publish a message on 'helloTopic' which indicates the scanner is online
  2. Switches on the bluetooth and start scanning
  3. Once it founds a valid advertisement, it check whether that tag is new
    1. If new, then add this to the list of online tags 'onlineTags' along with it's uuid and last seen time stamp
    2. If this tag is already in list, update lastSeen time and RSSI value
  4. With a period, run a function
    1. which checks for the lastSeen time of all available beacons and see if anyone went offline
    2. If some tag is missing, publish a message indicating 'offline' status with -100dB rssi
    3. If online, publish a message 'online' status and last known RSSI
  5. Also handle App exits by publishing a disconnect message to broker on 'helloTopic'

The script is given below:

// Scan for BLE beacons and send MQTT messages for each beacon status
var noble = require('noble');
var mqtt  = require( 'mqtt' )
var util  = require('util');

// 
var RSSI_THRESHOLD    = -90;
var EXIT_GRACE_PERIOD = 4000; // milliseconds

var onlineTags = [];

// ---------------- MQTT Connection --------------
var helloTopic      = 'user/vish/devices/jupiter'
var beaconBaseTopic = 'user/vish/devices/ble_tags'

// Configuration of broker
var connectOptions = {
  host: '192.168.1.54',
  port: 1883
}

// -------------- MQTT Event Handling function --------------------
function onConnect() {
  console.log( 'Connected to broker ' + connectOptions.host +':' + connectOptions.port )
  
  // Send a hello message to network
  client.publish(helloTopic, '{"connected":"true"}' )
}

function onMessage( topic, message ) {
  console.log( "    New message: [" + topic + "] > " + message )
}

client = mqtt.connect( connectOptions )
client.on( 'connect', onConnect )
client.on( 'message', onMessage )

// ------------------ BLE Scanner functions ----------------------
function onDiscover( peripheral ) {
  console.log( new Date() + ' ' + peripheral.advertisement.localName + ' ' + peripheral.uuid + ' ' + peripheral.rssi )
  if( peripheral.rssi < RSSI_THRESHOLD ) {
    return;
  }

  var id        = peripheral.id;
  var newTag    = !onlineTags[id];

  if( newTag ) {
    onlineTags[id] = {
      tag: peripheral
    };
    console.log( new Date() + ': "' + peripheral.advertisement.localName + '" ONLINE  (RSSI ' + peripheral.rssi + 'dB) ')
    // publish a message for beacon
    msg = {
      uuid: peripheral.uuid,
      rssi: peripheral.rssi,
      adv : peripheral.advertisement,
      online: true,
      lastSeen: Date.now()
    }
    client.publish( beaconBaseTopic + "/" + peripheral.advertisement.localName, JSON.stringify(msg) )
  }

  // Update rssi & last seen time
  onlineTags[id].rssi       = peripheral.rssi
  onlineTags[id].lastSeen   = Date.now();
}

noble.on('discover', onDiscover );

noble.on('stateChange', function(state) {
  if (state === 'poweredOn') {
    noble.startScanning([], true);
  } else {
    noble.stopScanning();
  }
});


// ------ Timed function to check whether the devices are online and publish MQTT packets accordingly ----
function checkNUpdate() {
    // for each device in range
    for( var tagId in onlineTags ) {
        var tag = onlineTags[tagId].tag
        // prepare message
        var msg = {
            uuid: tag.uuid,
            adv: tag.advertisement,
            lastSeen: onlineTags[tagId].lastSeen
        }
        if( onlineTags[tagId].lastSeen < (Date.now()-EXIT_GRACE_PERIOD) ) {
            // Device went offline
            msg.online  = false
            msg.rssi    = -100
            // delete from the list of visible tags
            delete onlineTags[tagId];
            console.log( new Date() + ': "' + tag.advertisement.localName + '" OFFLINE (RSSI ' + tag.rssi + 'dB) ')
        } else {
            // device in with in range
            msg.online  = true
            msg.rssi    = tag.rssi
        }
        client.publish( beaconBaseTopic + "/" + tag.advertisement.localName, JSON.stringify(msg) )
    }
}



// Function to be called at the end of script
function handleAppExit (options, err) {  
  if( err ){
    console.log(err.stack)
  }

  if( options.cleanup ){
    client.publish( helloTopic, '{"connected":"false"}' )
    client.end( true )
  }

  if( options.exit ){
    process.exit()
  }
}

// Handle the different ways an application can shutdown
process.on('exit', handleAppExit.bind(null, {  
  cleanup: true
}))
process.on('SIGINT', handleAppExit.bind(null, {  
  exit: true
}))
process.on('uncaughtException', handleAppExit.bind(null, {  
  exit: true
}))


// Create the checkNUpdate function to run preiodically
setInterval( checkNUpdate, EXIT_GRACE_PERIOD/2 );

 

You can save this as 'scanner.js' and then use

$ sudo node scanner.js

to start the script.

Here, my 'hello' topic is of the form 'user/vish/devices/<pi_name>' to identify from which Pi the scanner is working. Once you start the script, you can use any MQTT message viewer like MQTT-Spy to monitor the messages. For each BLE tag in the visibility, Pi will publish a MQTT message on topic  'user/vish/devices/ble_tags/<beacon_name>' with the scan info and last seen time stamp.

 

Creating a dashboard

Creating dashboard is almost same as the one I explained in my previous post. But before going to freeboard, make sure that you started the scanner.js script. Then only you will be able to find your beacons in the datasource list in freeboard. The procedure of creating new dashboard is as follows:

  1. In Freeboard, add your MQTT broker as a data source subscribing to 'beaconBaseTopic/#'. In my case, my MQTT datasource is named as 'Mercury' and beaconBaseTopic as 'user/vish/devices/ble_tags'
  2. Create a pane for each of the beacons
  3. Inside pane, create a Text widget with title 'Name' and value selected as the "datasources[\"Mercury\"][\"user/vish/devices/ble_tags/beacon1\"][\"adv\"][\"localName\"]".
  4. Create another text field with title as 'Last Seen'. For selecting the value, click on JS Editor option and enter

    return new Date(datasources[\"Mercury\"][\"user/vish/devices/ble_tags/beacon1\"][\"lastSeen\"]).toTimeString()

  5. Next create a Guage widget with title 'RSSI' and as data source select "datasources[\"Mercury\"][\"user/vish/devices/ble_tags/beacon1\"][\"rssi\"]". Put max value as 0 and min value as -100.
  6. Create an Indicator light widget with title 'Online'. For value,enter "datasources[\"Mercury\"][\"user/vish/devices/ble_tags/beacon1\"][\"online\"]"
  7. Like this you can create as many as panes for beacons. Don't forget to change the mqtt topic names to match with your beacon names.

Result will be some thing like below: Here I put monitoring for 4 beacons.

Since your scanner.js script is running, you can see that the status is updated online.image

 

Test

Now we are ready to test. For testing, I modified the arduino sketch to emit four different beacon advertisements from same tag. A video of the test is given below:

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

In the video, I'm using two raspberry pi's - one serves as my MQTT broker (B+) and Pi3 is where i'm running the freeboard server and tag scanner codes. Both are connected to my Wifi.

 

Happy Hacking,

vish

[PiIot#04]: Freeboarding with MQTT

<< Prev | Index | Next >>

  • Sign in to reply
  • BluetoothBeacon
    BluetoothBeacon over 1 year ago

    Good article!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • element14Dave
    element14Dave over 9 years ago

    Nice work so far vish let us know if there is anything we can do to support your next steps!

     

    Dave

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube