Mobile - - By Patrick Catanzariti

How to Prototype Beacon Apps with Estimote and Evothings

Bluetooth beacons are an incredibly valuable way to set up location based triggers for apps. Estimote have a range of Bluetooth beacons that are quite easy to set up and experiment with.

Estimote Beacons

One of the tough parts of testing out Bluetooth beacons is that device simulators aren’t able to access Bluetooth devices, so you need to use physical smartphones to test. This is where Evothings comes in really handy! Evothings is a neat simple way to prototype mobile web apps using HTML5 and JavaScript. Within Evothings, you can make changes to your code and have them automatically appear on your smartphone ready with access to your Bluetooth beacons.

In this article, we’ll look at combining the power of Evothings with Estimote Beacons to prototype a beacon enabled mobile app. In particular, we’ll be building an app that turns a LIFX light on and off via IFTTT if you get close to a beacon. Don’t have a LIFX light? Not a problem! You could replace this functionality with any other HTTP requests you’d like to toggle when nearby.

What You’ll Need

The Code

All code for this is available on GitHub for you to use as you wish!

Setting Up Your Estimote Beacons

Go to Estimote Cloud and log into your account (or sign up for one if you don’t have any beacons yet!).

From there, your “Beacons” section should already be loaded. If you don’t have any beacons assigned to your account yet, you’ll need to either buy some via the “Buy Beacons” button, transfer them from another account via the “Transfer Beacons” button or activate your dev kit if it came with an activation code:

Estimote without beacons

If you do have beacons, they’ll appear in a list. Choose the one you’d like to use in this demo and click its “Settings” button:

Estimote Beacon list

In here, you will want to take note of the beacon’s MAC address as we will be using it later:

Estimote Beacon settings

That should be all you need in terms of Estimote beacon set up – it is quite easy at a prototyping level.

Getting Evothings Running

To set up your Evothings workflow ready for our coding, head to the Evothings download page and download the Evothings Studio and Evothings Viewer mobile app. This gives us a really easy way to build our app and test the changes on a smartphone instantly.

When you first open Evothings Studio, you’ll be prompted to connect by getting a connect key. Click “Get Key” to generate the key you’ll use to pair up your workbench with your mobile app:

Get Key For Evothings Workbench

Then open up Evothings on your smartphone, you’ll be greeted with a screen that asks for that connect key. Type it in and click “Connect”:

Evothings Viewer

When you are connected and ready to go, you will see this screen:

Evothings Viewer Connected

You are now ready to get into coding the app.

Our HTML

The HTML for this app is mostly from Evothings templates they’ve publically provided, just with the title and headings changed, along with the addition of a <div id="in-room"></div> for some basic status messages to appear on screen.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no
      initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
    <title>Magical room light automation</title>
    <style>
      @import 'ui/css/evothings-app.css';
      @import 'ui/css/patcat.css';
    </style>
    <script>
    // Redirect console.log to Evothings Workbench.
    if (window.hyper && window.hyper.log) { console.log = hyper.log }
    </script>

    <script src="cordova.js"></script>
    <script src="libs/jquery/jquery.js"></script>
    <script src="libs/evothings/evothings.js"></script>
    <script src="libs/evothings/ui/ui.js"></script>
    <script src="app.js"></script>
  </head>
  <body>
    <header>
      <button class="back" onclick="history.back()">
        <img src="ui/images/arrow-left.svg" />
      </button>

      <img class="logotype" src="ui/images/logo.svg" alt="Evothings" />
    </header>
    <h1>Magical room light automation</h1>
    <div id="in-room"></div>
  </body>
</html>

I’ve also put my custom CSS within ui/css/patcat.css:

html,
body,
section,
main footer {
  background: #390066;
  color: #fff;
  text-align: center;
}

header {
  background: #EACFF3;
}

.in-room,
.in-room body,
.in-room section,
.in-room main footer {
  background: #F3EC97;
  color: #333;
}

.in-room h1 {
  color: #333;
}

.in-room header {
  background: #F3EDE6;
}

h1 {
  padding: 0 0 1em;
}

Our JavaScript Code

Our app.js file looks like so:

var app = (function() {
  var app = {},
    roomBeacon,
    updateTimer = null,
    inRoom = false;

  app.initialize = function() {
    document.addEventListener("deviceready", function() {
      evothings.scriptsLoaded(onDeviceReady);
    }, false);
  };

  function onDeviceReady() {
    startScan();

    $("#in-room").html("Out of room!");

    updateTimer = setInterval(checkForBeacon, 1000);
  }

  function startScan() {
    function onBeaconsRanged(beaconInfo) {
      for (var i in beaconInfo.beacons) {
        var beacon = beaconInfo.beacons[i];

        if (beacon.rssi = 2 && inRoom) {
        console.log("Exited the room");
        inRoom = false;
        $("html").removeClass("in-room");
        $("#in-room").html("Out of room!");

        turnOffBulb();
        setTimeout(turnOnBulb, 1000);
      }
    }
  }

  function turnOnBulb() {
    $.getJSON("https://maker.ifttt.com/trigger/entered_room/with/key/{YOURKEYHERE}?jsoncallback=?", {
      format: "json"
    }, function() {
      console.log("Entered room and told IFTTT about it!");
    })
    .done(function(data) {
      console.log("Done");
    })
    .fail(function(data) {
      console.log(JSON.stringify(data));
    })
    .always(function(data) {
      console.log("Finished");
    });
    console.log("Turn on bulb");
  }

  function turnOffBulb() {
    $.getJSON("https://maker.ifttt.com/trigger/left_room/with/key/{YOURKEYHERE}?jsoncallback=?", {
      format: "json"
    }, function() {
      console.log("Left room and told IFTTT about it!");
    })
    .done(function(data) {
      console.log("Done");
    })
    .fail(function(data) {
      console.log(JSON.stringify(data));
    })
    .always(function(data) {
      console.log("Finished");
    });
    console.log("Turn off bulb");
  }

  return app;
})();

app.initialize();

Our JavaScript Code Explained

Let’s simplify it down a bit to step through. Our initial skeleton for the code looks like so:

var app = (function() {
  var app = {},
    roomBeacon,
    updateTimer = null,
    inRoom = false;

  app.initialize = function() {
    document.addEventListener("deviceready",
      function() {
        // What we'll want to do when our app is ready!
      }, false);
  };

  // Other code will be here!

  return app;
})();

app.initialize();

In the code above we namespace everything within app. The roomBeacon variable stores our beacon once we have seen it, updateTimer will store our regular JavaScript interval to check for beacons and inRoom will remember whether or not the app believes we are in the room (depending on whether it sees the beacon in range or not).

When our JavaScript runs, we direct it to the app.initialize() function. However, we don’t run any of the functionality until the deviceReady event and the evothings.scriptsLoaded event fires. That way we know the app has loaded and Evothings is ready to watch and reload upon any changes.

function onDeviceReady() {
  startScan();

  $("#in-room").html("Out of room!");

  updateTimer = setInterval(checkForBeacon, 1000);
}

Within onDeviceReady(), we start scanning for beacons (we’ll cover the startScan() function soon). Then we set our #in-room element in our HTML to say “Out of room!” as our default.

We then run checkForBeacon() every second, which assesses how far away our beacon is and decides if we are in the room or not.

Our startScan() function looks like so:

function startScan() {
  function onBeaconsRanged(beaconInfo) {
    // Will explain this soon!
  }

  function onError(errorMessage) {
    console.log("Ranging beacons did fail: " + errorMessage);
  }

  estimote.beacons.requestAlwaysAuthorization();

  estimote.beacons.startRangingBeaconsInRegion(
    {},
    onBeaconsRanged,
    onError);
}

All of the functionality of the startScan() function start with estimote.beacons.startRangingBeaconsInRegion(). This starts our app scanning for Estimote beacons. We pass in three things:

  • A blank object ({}) to represent that we want all beacons. We could instead pass in a region we’ve defined in our Estimote beacon options like so: {identifier:'MyRegion'}.
  • Our success function we want to run when we’ve successfully looked for beacons in range (onBeaconsRanged()).
  • Our failure function if something goes wrong (onError() – a relatively simple function that logs the error).

The inside of our onBeaconsRanged() function looks like so:

function onBeaconsRanged(beaconInfo) {
  for (var i in beaconInfo.beacons) {
    var beacon = beaconInfo.beacons[i];

    if (beacon.rssi < 0 && beacon.macAddress == "CE:95:71:43:C9:DD") {
      console.log("Found room beacon");
      roomBeacon = beacon;
    }
  }
}

This receives an array called beaconInfo with details of all the beacons that are visible to the device. Our beacons are specifically found within beaconInfo.beacons, so we iterate through them all and check their RSSI (Recieved Signal Strength Indication) and MAC address. If their RSSI is a negative value, our app has spotted the beacon. We then check to see whether our beacon’s MAC address is the same as the beacon we are looking for. If so, we log the event into our console and set our roomBeacon variable to this beacon.

For iOS 8, your app is required to ask for permission to use location services (on other platforms, this function will gracefully degrade and do nothing):

estimote.beacons.requestAlwaysAuthorization();

You’ll remember we ran the function checkForBeacon() every second. That function looks like so:

function checkForBeacon() {
  if (roomBeacon) {
    console.log("Checking beacon distance");

    if (roomBeacon.distance < 2 && !inRoom) {
      console.log("Entered the room");
      inRoom = true;
      $("html").addClass("in-room");
      $("#in-room").html("In room!");

      turnOnBulb();

      setTimeout(turnOnBulb, 1000);
    } else if (roomBeacon.distance >= 2 && inRoom) {
      console.log("Exited the room");
      inRoom = false;
      $("html").removeClass("in-room");
      $("#in-room").html("Out of room!");

      turnOffBulb();
      setTimeout(turnOnBulb, 1000);
    }
  }
}

If we have a roomBeacon, then we run our tests on how far away that beacon is. If you are within two meters of the beacon and we haven’t set inRoom to true, then we have just entered the room. We set inRoom to true, log a message to the console, show the message “In room!” on our app and change the class on our <html> tag so we can restyle our app depending on if we’re inside the room or not. We also run turnOnBulb() which will do just that – turn on our LIFX bulb using IFTTT.

If we are further than two meters away from the beacon but the app still thinks we are in the room, we set inRoom to false and set everything to be the opposite of the above. We run turnOffBulb() to turn off the LIFX bulb.

One thing you might be wondering – why do we have a setTimeout() re-running turnOnBulb() and turnoffBulb()? I’ve found sometimes with IFTTT (or possibly the LIFX connectivity in my home), it doesn’t always receive the request the first time. Running it twice seems to fix this nicely!

To actually turn the LIFX bulbs on and off, we make a JSON request to an IFTTT’s action via https://maker.ifttt.com/trigger/entered_room/with/key/{YOURKEYHERE}?jsoncallback=?. Turning them off is the same idea, just with left_room as the trigger name instead of entered_room. If this all sounds like gibberish to you, have a read of my “Connecting the IoT and Node.js to IFTTT” tutorial first!

function turnOnBulb() {
  $.getJSON("https://maker.ifttt.com/trigger/entered_room/with/key/{YOURKEYHERE}?jsoncallback=?", {
    format: "json"
  }, function() {
    console.log("Entered room and told IFTTT about it!");
  })
  .done(function(data) {
    console.log("Done");
  })
  .fail(function(data) {
    console.log(JSON.stringify(data));
  })
  .always(function(data) {
    console.log("Finished");
  });
  console.log("Turn on bulb");
}

Testing On Your Device

To test the app, click the “Projects” tab and drag your index.html into Evothings Studio to add it to the projects to watch. Then click “Run” to run it:

Evothings Code Running

If you’ve got the Evothings Viewer open on your smartphone, you should have the app appear and run as intended! If you enter the room with the beacon, your light should turn on (and the app should visually show you’ve entered the room) and if you exit the room, the light should turn off (and the app should show you have left).

App in action

Conclusion

Prototyping with Estimote beacons and Evothings is just the start, from here you can create a Cordova or Phonegap app, copy over the files from this one and export it into an app you can submit to app stores. You’d just need to add in a way for custom beacons to be added into settings (as you won’t want everyone relying on your beacon unless it is for a public place like a cafe).

If you create a Bluetooth beacon powered prototype with Estimote beacons and Evothings, please share it in the comments or get in touch with me on Twitter (@thatpatrickguy). I’d love to see what you come up with and share it around!

Sponsors