June 04, 2016
Last year, I had written a rather ponderous article on the Device part of the IoT triad consisting of Device, Mobile and Cloud. This time, I want to focus on the Mobile part. In this article, I’ll go through the construction of a cross platform mobile app that displays heart rate measurement data sent by a Nordic nRF51822 device via BLE. I’ll throw in a bit of cloud as well - by periodically posting this data to thingspeak.
There is no firmware development in this article. I’ll be assuming that you have an nRF51 device, and that you have programmed it with the ble_app_hrs example from Nordic.
If you are unfamiliar with nRF51 development, you might want to look through some of my previous articles on the subject:
- Hacking a Cheap LED Lamp with nRF51822
- nRF51822 Begins - nRF-DK, GCC, ADC, UART/BLE
- External nRF51822 SWD Programming using the nRF51-DK
- nRF51-DK PWM & GPIOTE test with S110 SoftDevice
- Talking to Ultrasonic Distance Sensor HC-SR04 using nRF51822
- Controlling an RGB LED with Nordic nRF51-DK (nRF51822/nRF51422)
- Motor Control over BLE with nRF51822 and TB6612FNG
- BLEBot - nRF51822 based BLE Robot
Now let’s look at the mobile part.
Cross Platform Mobile Apps
Mobile App Development
Now let’s get into the nitty-gritty of developing the mobile app.
Our goal is to create a mobile app that does the following:
- Scan for BLE devices
- Connect to Heart Rate Service on a device
- Enable notifications
- Display current heart rate
- Plot heart rate as a function of time
- Post data periodically to ThingSpeak
Let’s get on with the setup.
I won’t cover cordova here, but the official documentation is quite good, and you can start there. For this project, the most important thing is that you need to get the cordova-plugin-ble-central plugin. Your setup will roughly look like the following:
The above was done on OS X which required sudo on cordova commands. (Fixable, but life is short, and there’s too much to do.) Also, a long term iPhone user, I finally decided to ditch iOS and get an Android (Nexus 5X) using this project as an excuse - the main reason being that I am tired of paying developer fees to the demigods at Infinite Loop just so I can put apps on my own darn device. If you use iOS, you will need to add that platform above.
Next, you’ll need to setup your platform (iOS or Android) for development. That’s beyond the scope of this article, but there are many resources to help you out there. Again, the Cordova official documentation has nice sections on platform setup.
After the setup, here’s what the directory structure looks like:
All our action is in the www directory. Once you are done with setup, you need to replace the contents of the www directory with my code which you can find in the Downloads section below.
Here’s what my www looks like:
index.html contains the layout of your app, which is styled by index.css. The logic for your app resides in index.js. We use jquery in this project, so you need that as well.
Now that you are setup, here’s how you build and upload the code to your mobile device:
I had trouble running this on the emulator, and BLE may not work with the emulator anyway. So I suggest that you just plug in the mobile and work with it right from start.
Having a good debugging tool saves you a lot of time on development. Midway through this project, I was delighted to discover this Chrome trick - with your mobile connected via USB to your computer and running the app, go to chrome://inspect/?#devices on your computer. It will list your app, and you can click on inspect to get a developer console. How cool is that?! Here’s a session:
Now let’s look at the code.
Everything starts at index.html, which starts by setting up some parameters and loading scripts inside <head>.
The layout above is simple - just a heading, <div>s for heart rate and status, a connect button, and an HTML5 canvas for drawing the graph.
Now let’s go to the action part.
index.js is where the action happens. Let’s look at the important snippets within.
Talking to BLE
When you click the connect button, the BLE scan is started here:
In the above code, ble.scan() starts looking for BLE devices, and we’re filtering for the service id 0x180D, which is a predefined bluetooth service for sending heart rate information. Each time a device with this service is found, the onConnect() function is called, which calls ble.startNotification() on the heart rate characteristic with id 0x2A37 - this is the actual heart rate measurement. Setting the notification will make the device send the data periodically to the app. This data will be made available through the onData() function passed in. Here’s what it looks like:
To understand the format of the data sent by the heart rate measurement characteristic, please take a look at the official specification. The Nordic ble_app_hrs firmware sends heart rate in 16-bit format, and the code above handles it by combining data from the two adjacent bytes. Once parsed, the value is set to the text display and then passed on to the app.plot() function.
In addition to the above, the status messages are set based on various conditions, like connect, disconnect, failures, etc.
Now let’s look at plotting a graph using the heart rate data.
Drawing a Graph
For display the heart rate data, we create a “rolling graph” of points (represented as filled circles). As new data comes in, old data moves to the right.
Here’s the app.plot() function where the drawing to the HTML5 canvas happens.
In the above code, new data is added to the dataPoints array as they come in. A splice is done when the count exceeds maxLen to keep the number of points drawn constant. The function drawPoints() does the actual drawing, using the arc() method of the canvas context. x+=10; ensures a certain distance between the points on the horizontal axis.
Now for some cloud mischief.
Posting Data to ThingSpeak
Thingspeak is a great platform for plotting your IoT data. It’s free, and lets you create channels for your data, and provides convenient export options for all your data. You’re allowed to update your channel every 15 seconds only - something to remember. Here’s the code that posts data there, from the $(document).ready() function:
In the above code, we’re using a simple AJAX setup to make a ‘GET’ call into the thingspeak channel to update our channel. jquery makes this job easy. We use the setTimeout() method to call this code every 16 seconds. The data returned from the GET call is displayed in the status text.
You’ll need to setup your own thingspeak channel for testing, as I’ve changed the write API key to mine - no naughty business. :-)
Here’s a sample output:
And thus we have our BLE device not only talking to our own mobile app, but using it as a conduit to post data on to the cloud yonder.
You can get the complete source code for this project here:
Here’s the app in action:
We’ve touched on the Mobile part of the IoT triad by building a cross platform mobile application that talks to a BLE device. I think cordova is a good place to start - especially in an IoT context. The concepts learned here can be leveraged as you move to other platforms like Ionic/Angular.