Mobile
Article

Bluetooth Beacon Enabled Apps with BlueCats and PhoneGap

By Patrick Catanzariti

BLE beacons are the sort of technology that makes me excited to be a developer today. Not only are there so many possibilities, it is available for any developer to start developing for right now. Not a pre-order, not a still-in-development product, not a Kickstarter… Bluetooth beacons are already out there being used! In this article, we’ll explore how you can get started with BLE Beacons pairing the BlueCats beacon Cloud Platform and API with PhoneGap.

What are BLE Beacons?

BLE stands for Bluetooth Low Energy and refers to the Bluetooth wireless network technology that has been designed to work with a much lower power consumption and much lower cost. These two factors alone have made it perfect for a range of new connected devices, including wearables, smart home automation and of most interest to us in this article – beacons.

Beacons are Bluetooth devices that can be placed almost anywhere to provide tracking of a user’s location in that space. They can be throughout a building, on a billboard, inside a vehicle… almost anywhere that could benefit from knowing where your users are. Examples of the potential use in a smartphone app include:

  • A museum tour mobile app that can tell where each user is within the museum and provide them relevant content.
  • Interactive billboards that change or move around when users with an app are nearby!
  • A smart phone automation system that knows which room you are in and runs certain things accordingly.

How do BlueCats Beacons fit in?

BlueCats beacons are BLE Beacons that come with an easily accessible API (available on Android, iOS and PhoneGap) and a cloud platform to manage them. A few weeks ago, I had the pleasure of meeting a few of the guys working on BlueCats beacons and the conversation with them had me itching to try it out! I honestly couldn’t believe how ready the technology was to be implemented.

The Demo

I gave the BlueCats beacons a go, putting together a simple PhoneGap prototype that used their API to inject some location based functionality. I built a prototype countdown timer designed to remind computer addicted souls such as myself to get up every 30 minutes from the computer and move around.

Unlike regular countdown timers, this one uses the power of BlueCats beacons to know whether you’ve actually gotten up and moved to another room. Once the timer goes off, the user must get up and walk to another room with a specific beacon in order to reset the timer. As an added bonus, once they return to their computer a USB beacon recognises that they’ve returned and automatically restarts the timer for them.

Preparing Our PhoneGap App

To get started, lets prepare our demo PhoneGap app using the usual PhoneGap commands. If you don’t already have PhoneGap, install it via this npm command:

sudo npm install -g phonegap

Then we’ll create our baseline app for this demo. I’ve called it “BreakEnforcer” but you can call it whatever you desire. When we run the below command, PhoneGap will set up all our basics.

phonegap create BreakEnforcer

Prepare Our BlueCats App

If you’re new to BlueCats and are looking for a good way to get started, this demo uses BlueCats beacons from the BlueCats StarterPack.

To get started with the BlueCats platform, you’ll have to set up a BlueCats account. You can register the StarterPack at the BlueCats StarterPack Setup page.

Once your account is set up, go to the BlueCats Dashboard and log in.

From here, you’ll see a dashboard that looks a bit like this:

BlueCats Dashboard

Click the “Apps” link on the left hand side to go to the Apps dashboard and then click “Create New App”.

Here, we can enter in our app’s details. I named my app “Break Enforcer”.

Choose the platform you’ll be testing your app on. I chose Android as that’s what I’ll be testing everything on. However, because we are using Phonegap it should be simple enough to recreate the app for the others later on with ease. Then click “Create App”.

BlueCats App Creation Form

Adding Our BlueCats App Into PhoneGap

BlueCats have a PhoneGap plugin we’ll be using to bring in all our BlueCats beacon functionality. To include it in our PhoneGap application, run the following command within the BreakEnforcer directory (or whatever you called your app):

phonegap plugin add https://github.com/bluecats/bluecats-phonegap.git

If you go to the plugins folder of your PhoneGap app, you’ll find a com.bluecats.beacons folder with our BlueCats functionality.

Our Code

All code for this demo is available on GitHub for you to view and adapt to your own beacon creations! I’ll explain the main areas of the code and how they work.

Note: all of our code here is enclosed neatly within the app namespace, so when calling functions and such, you’ll need to keep this in mind.

All of our code begins with an initialize() function. It runs two functions, bindEvents() and initCountdownTimer(). bindEvents() sets in motion our beacon functionality, whilst initCountdownTimer() focuses on our timer functions.

initialize: function() {
    this.bindEvents();
    this.initCountdownTimer();
  },

I’ve kept these relatively separate, so if you’re using this as a baseline for a totally different app it shouldn’t be too hard to swap out the timer bits for your own.

Our Beacon Functions

For the beacon functionality, we’ll be using a very similar structure to the sample plugins/com.bluecats.beacons/Samples/HelloBeacons/index.js file you’ll find in your BlueCats plugin folder. Their set up is quite clean and I thought it best to remain consistent! Our example is a little bit more streamlined as we won’t be using all of the features in the sample app. We will be focused on keeping track of when we reach beacons. It is also possible to track when we move away from them or determine which beacon is closest to us – our app won’t be worrying about these.

Back to the code! Within bindEvents(), we set up our event listener that listens for when our phone/tablet device is ready. We track this via the deviceready event.

document.addEventListener('deviceready', this.onDeviceReady, false);

On deviceready, we run two beacon related functions. We’ll explore each below.

onDeviceReady: function() {
    app.receivedEvent('received');
    app.watchBeacons();
  },

The receivedEvent() function is one that responds to three different beacon related events. It looks like so:

receivedEvent: function(event) {
    var parentElement = document.getElementById('deviceready'),
        listeningElement = parentElement.querySelector('.listening'),
        receivedElement = parentElement.querySelector('.received');

    listeningElement.setAttribute('style', 'display:none;');
    receivedElement.setAttribute('style', 'display:block;');

    if (event == 'apptokenrequired') {
      receivedElement.innerHTML = 'App token not set'
    } else if (event == 'bluecatspurring') {
      // We are on the look out for beacons
      receivedElement.setAttribute('style', 'display:none;');
    };

    console.log('Received Event: ' + event);
  },

Initially, it picks up our two message elements, .listening and .received. Then it hides the .listening element and our three event types come into play:

  • 'received' – Whilst our receivedEvent() code doesn’t directly refer to this event string, when we send it through initially it makes our .received element in our app visible. This is the element which says “Device is ready” by default.
  • 'apptokenrequired' – This switches our .received element to say “App token not set”.
  • 'bluecatspurring' – This is passed in when our app is readily looking for beacons. When it does this, we clear the message so our beacon watching is done subtly.

If we look back at our onDeviceReady(), the other function that runs for our beacons is the watchBeacons() function. This sets up our app to watch for BlueCats beacons via the SDK.

We start by declaring a variable called watchIdForEnterBeacon which we’ll use to assign the “watch ID” which references our beacon watcher. This gives us a variable to clear if we want to stop watching beacons via the SDK call named com.bluecats.beacons.clearWatch.

var watchIdForEnterBeacon = null;

Next, we have a test to ensure that you have added in an app token. If you haven’t it will run receivedEvent() and display an error. In a production environment, you could remove this check as you’re unlikely to have missed this step by then. It was a clever check added into the sample by the BlueCats team which I liked and kept in there!

if (blueCatsAppToken == 'BLUECATS-APP-TOKEN') {
    //BlueCats app token hasn't been configured
    app.receivedEvent('apptokenrequired');
    return;
  }

Next we have two sets of options which we can use to adjust how our beacon watching runs. Firstly, sdkOptions are the options we can pass into the com.bluecats.beacons.startPurringWithAppToken() API call. This is what starts the BlueCats SDK and starts looking around for bluetooth devices, so these options relate to that. The one in my example looks like so:

var sdkOptions = {
    useLocalStorage: true
  };

Basically, we’re requesting it caches the beacons from our BlueCats account locally for when we don’t have internet access. All potential options include:

  • trackBeaconVisits – Should we log each visit to our beacons into the BlueCats API? (True or false)
  • useLocalStorage – Our local beacon caching as used above (boolean value).
  • cacheAllBeaconsForApp – Should we cache all beacons on startup? (True or false)
  • discoverBeaconsNearby – Should we cache beacons as detected by the device? (True or false)
  • cacheRefreshTimeIntervalInSeconds – How often to check for changes from the API in seconds.

Next, we have our beaconWatchOptions which we’ll use within the com.bluecats.beacons.watchEnterBeacon() function within the API. This is what watches and responds to each time we come into range of a beacon, so these options relate to that.

In our code, we’re setting minimumTriggerIntervalInSeconds to 5 to reduce how often callbacks are run. I thought the default of running it each second would be too frequent for this app as we’re not going to be moving too often into new beacons.

We also have an empty filter option. I didn’t have a need to filter which beacons the app would find, however not having this empty JSON caused an error, so I’ve left an empty object here.

var beaconWatchOptions = {
    minimumTriggerIntervalInSeconds: 5,
    filter: {}
  };

All potential options include:

  • minimumTriggerIntervalInSeconds – The minimum seconds between callbacks as used above.
  • repeatCount – How often the trigger should be able to reoccur. We’ll want it to always happen every time we enter into range of a beacon so we don’t set this, however if you wanted to limit this, here’s the place.
  • Within filter, we have the following:
    • minimumProximity and maximumProximity – the minimum and maximum distance we want to trigger these calls. These can be set to a string of either 'BC_PROXIMITY_IMMEDIATE' (~<0.5m), 'BC_PROXIMITY_NEAR' (~<3m), 'BC_PROXIMITY_FAR' (~>3m) and 'BC_PROXIMITY_UNKNOWN'.
    • minimumAccuracy – The minimum distance in metres (default of 0).
    • maximumAccuracy – The maximum distance in metres (defaults to unrestricted).
    • sitesNamed – Pass in an array of sites you’ve got defined in your SDK account which you want to be used in the app (e.g. ['Fortress of Solitude', 'Batcave', 'The Watchtower'].
    • categoriesNamed – Pass in an array of categories you’ve got defined in your SDK account which you want to be used in the app (e.g. ['Memorial Statue', 'Bat-Poles']).

Then, we have our com.bluecats.beacons.startPurringWithAppToken() call from the BlueCats API which starts up our BlueCats SDK as mentioned earlier. We give it our blueCatsAppToken and sdkOptions defined above, along with a purringSuccess() callback function once it is ready to access beacons and a logError() function for if an error occurs.

com.bluecats.beacons.startPurringWithAppToken(
    blueCatsAppToken, purringSuccess, logError, sdkOptions
  );

Our purringSuccess() function triggers the 'bluecatsspurring' event you’ll remember from earlier. It also runs watchBeaconEntry() which we’ll cover next.

function purringSuccess() {
    app.receivedEvent('bluecatspurring');
    watchBeaconEntry();
  }

watchBeaconEntry() performs the most exciting bits of our app – it watches for and reacts to BlueCats beacons. Initially, it checks to see whether we’ve already got a watch ID for watchIdForEnterBeacon. If so, we clear it first.

function watchBeaconEntry() {
    if (watchIdForEnterBeacon != null) {
      com.bluecats.beacons.clearWatch(watchIdForEnterBeacon);
    };

Then, we set up our beacon watch using the com.bluecats.beacons.watchEnterBeacon() from the BlueCats API. This will run when we cross paths with a beacon. Within it, we have a callback function that can access the watchData from the beacon that we’ve found.

watchIdForEnterBeacon = com.bluecats.beacons.watchEnterBeacon(
      function(watchData){
        // Our response will be here

With our watchData we will receive an array of beacons inside watchData.filteredMicroLocation.beacons. Each item in this array has a whole range of information on the beacon. There is a lot of potential info, if you’d like the whole list, see the BlueCats PhoneGap beacon info section on the GitHub page.

In our app, we’re focused on one thing – the beacon’s name. I’ve called my beacon connected via USB “USBeecon” and my beacon in the other room as “BeaconBeta” (I had another two I’ve named “BeaconAlpha” and “BeaconGamma” but I liked the color of “BeaconBeta” for this). You’ll likely have your own names for beacons, change the code below to match those.

We use the Underscore.js library to search through each item in the array of beacons and see whether the beacon has either name. If the beacon has the “BeaconBeta” name, it is the one in our break room that the user needs to get up and move towards. In that case, breakRoomBeacon is set to true. If the beacon has the “USBeecon” name, then computerBeacon is set to true instead.

var breakRoomBeacon = _.find(watchData.filteredMicroLocation.beacons, function(beacon) {
    return beacon.name == 'BeaconBeta';
  });

  var computerBeacon = _.find(watchData.filteredMicroLocation.beacons, function(beacon) {
    return beacon.name == 'USBeecon';
  });

The next bit of code refers to our timer object which has stored info on our timer. I’ll go over it quickly later in this article, but basically – we have a variable within it called state that keeps track of the state of our timer (e.g. is it counting down, has it expired, are we on break… etc).

If it has expired and we are at the beacon in our break room, we run app.runBreakMode() which sets our app into break mode:

// Room was entered, break successful
  if (app.timer.state == 'expired' && breakRoomBeacon) {
    app.runBreakMode();
  }

If we’ve had our break and are back at our computer’s USB beacon, we’ll run app.startCountdownTimer() to start the timer counting down again automatically.

// Back at the computer
  else if (app.timer.state == 'breaksuccess' && computerBeacon) {
    app.startCountdownTimer();
  }

To finish our com.bluecats.beacons.watchEnterBeacon() function, our second and third variables are our logError() function and our beaconWatchOptions we set up earlier.

}, logError, beaconWatchOptions);
  }

Our logError() function is quite simple and just does a basic console log:

function logError() {
    console.log('Error occurred watching beacons');
  }

That is all of our beacon functionality covered! Next, we’ll go over the timer functions quickly. We won’t go into depth with everything on the timer, as the main focus is our beacons. The timer functions are mostly working with (new Date).getTime() and starting/restarting/stopping our timer on that.

Our Timer Functions

The main variable called timer that we used earlier when we encountered a beacon, is our object that knows all about the settings and state of our timer.

timer: {
    targetDuration: (1 * 60 * 1000), // Minutes * 60 * 1000
    initialCount: 0,
    currentCount: 0,
    targetCount: 0,
    timeout: null,
    elem: null,
    toggleButton: null,
    restartButton: null,
    message: null,
    expired: false,
    state: ''
  },

Explaining each of these should give a good overview of how the timer works:

  • targetDuration – This sets up in milliseconds how long we want the timer to countdown for. I’ve got it as (30 * 60 * 1000), which sets it to 30 minutes.
  • initialCount – When we start our countdown timer, we set this to the time it is at that moment.
  • currentCount – Every time we check what the time is for our countdown timer (every half second), we store that time in this variable.
  • targetCount – In this variable, we add our targetDuration to our initialCount to know the time we’re counting down to.
  • timeout – In order to run each tick of our countdown timer, we use a setTimeout(). We run this every half second (in case there’s a bit of a delay and PhoneGap cannot run exactly every second). Each half second, we check the current time against our intended time and update the timer. We store a reference to that timeout so we can clear it within this variable. Note: This can be quite battery draining and definitely could be optimised in a future version (or a native app that can keep track of the time in a background process).
  • elem – Our actual timer which we update with the latest countdown time left each tick.
  • toggleButton and restartButton – These are our two buttons that starts our timer and restarts our timer.
  • message – The element used to show messages underneath the timer.
  • expired – A boolean for whether the timer has expired or not.
  • state – The state of our timer, it can be:
    • 'ready' – Our timer is ready to begin.
    • 'running' – Our timer is running.
    • 'enforcer' – Our timer has count down to thirty minutes and it wants our user to take a break.
    • 'breaksuccess' – Our timer has seen us go into the other room with the beacon and is happy again.

The rest of the timer code should be relatively self explanatory, app.countdown() runs every 500 milliseconds to countdown the timer, if it runs out it sets the state to 'enforcer' and demands our user gets up and goes into the other room.

app.setTimerState() is used frequently and sets up our app depending on the state our timer is at. The functionality of our buttons, whether they appear or not, our app message underneath the timer and the class applied to the overall app to style these different states is all handled here.

Testing Our BLE Beacon Enabled App

PhoneGap have a Developer App which allows for local testing on iOS, Android and Windows Phone. I couldn’t get it to work with BlueCats which I believe is due to the fact the BlueCats require a third party plugin. Testing Bluetooth apps within the Android emulator will not work either as the emulator does not support Bluetooth. So to test our app, we’ll need to use an actual Android device.

We’ll be covering the basics of PhoneGap for Android, however if you’d like more information or are looking to develop on a different platform, see the PhoneGap Platform Guides (the steps in terms of compiling and all should be very similar though).

We add in Android as a platform for our app using this command:

phonegap platform add android

Once that runs successfully, we then run the command for PhoneGap to build our app using Cordova:

phonegap build android

If you receive an error that says uses-sdk:minSdkVersion 7 cannot be smaller than version 10 declared in library, you’ll need to update config.xml. The line:

<preference name="android-minSdkVersion" value="7" />

Should be:

<preference name="android-minSdkVersion" value="10" />

Then, connect up your Android device via USB (ensure that USB Debugging and Developer Options are enabled) and run:

phonegap run android

You should now see your app running wonderfully and be able to test out your beacon app prototype!

Break Enforcer Running App

BlueCats and Break Enforcer in action

BlueCats and Break Enforcer in action

Conclusion

Getting apps connected to Bluetooth beacons was a lot simpler and more ready for big corporate projects than I’d anticipated was possible before uncovering BlueCats beacons! Their SDK makes developing with BLE beacons quite pain free, this simple prototype app was just the tip of the iceberg.

If you’d like to find out more about the capabilities of the BlueCats PhoneGap SDK, see their GitHub page. If you’d prefer to try developing natively, their developer page has all you should need!

I’m always very keen to see and hear about creations people make from the demo code, if you do make something great with BlueCats beacons, let me know! Leave a note in the comments or get in touch with me on Twitter (@thatpatrickguy), I’d love to check it out!

  • http://www.konig.co Chris Speer

    Great article and very informative, I am just starting to Blog as well and wrote a post when Facebook made these available for all businesses to apply for free. Facebook Beacon is designed to create more engagement for businesses. Keep up the good work, here is my article if you get a chance to check it out, This literally just came out this week so I’m one of the first to write about it and I included a link where anyone can apply for a free Bluetooth Beacon from Facebook.

    http://www.konig.co/what-is-facebook-bluetooth-beacon

  • Patrick Catanzariti

    Thanks for the link Chris, lovely to meet you (in comment land at least). Facebook beacons are an interesting idea too! I wonder if it would be possible to set up BlueCats beacons to be a Facebook beacon amongst other things… that way we could have one beacon running for various uses.

  • Vishal Joshi

    Nice article. I am struggling with the accuracy data that my Android App (with BlueCats Beacon SDK for Android) receives from BlueCats BLE Beacons. I have this app running on my Android device with BlueCat beacons placed, say, at a distance of 5 meters. The accuracy data keep displaying different information. I am using SDK’s call beacon.getAccuracy(). The information ranges from 1 meter to 6 meters even when my beacon is kept permanent on a distance of 5 meters from my device.
    My question: Is there a way to improve this? I would like to know if its something in my app codebase thats generating this problem. I am not sure this would be the case because the accuracy data is coming from SDK API and not from any calculation I did in my app. I have also tried changing target speed to run and increasing advertise intervals but no luck.

    Requesting Patrick if you could help with more information on this.

    Thanks.

Recommended

Learn Coding Online
Learn Web Development

Start learning web development and design for free with SitePoint Premium!

Get the latest in Mobile, once a week, for free.