In the first post of this series I used Javascript to read a
TMP36GZ temperature sensor and write the current temperature to the
console. In the second post I used the
Restify library with Javascript to create a rest based web service that would
send the current temperature to a remote client upon request. In this post I will access that web service
to display the temperature on my iPhone using the RSNetworking library.
Let begin by reviewing how we wired up the TMP36GZ
temperature sensor to the BeagleBone Black.
Here is the wiring diagram:
Next lets review how we developed the REST Web Service that
will respond to client requests for the current temperature. Note:
I am making one change to the code, from my last post, so the REST
service returns a valid JSON object.
The first thing we need to do is to setup a directory
structure that contains the node.js modules needed to run the service. I used the following steps to get the
structure/modules set up (this is based off of the latest Debian image
2014-05-14):
1.
Start off within our home directory.
In Linux the ~ directory is the users home directory.
cd ~
2.
Create a work directory and change to that directory
mkdir temperature
cd temperature
3.
Install the restify module
npm install restify
4. Copy the bonescript
module to our working structure
mkdir node_modules/bonescript
cp /var/lib/cloud9/static/bonescript.js node_modules/bonescript/
At this point you should still be in the temperature
directory and both the restify and bonescript modules should be located in the ~/temperature/node_modules directory. This will let our application use these two
modules.
From the ~/temperature
directory, create a file called tempServer.js
and put the following code in it.
var b = require('bonescript');
var rest = require('restify');
var ip = '0.0.0.0'
var port = '18080'
var path = 'temperature'
var tempPin = 'P9_38';
var currentTemp = 0.0;
b.analogRead(tempPin, readTemperature);
setInterval(function() {b.analogRead(tempPin,
readTemperature)},30000);
var server = rest.createServer({
name :
"Temperature"
});
server.get({path : path , version : '0.1'},
getTemperature);
server.listen(port,ip, function() {
console.log('%s
listening at %s ',server.name, server.url);
});
function getTemperature(req, res, next) {
var key =
"temperature";
var
tempResponse = '{"temperature":"' + currentTemp + '"}';
res.send(200,
JSON.parse(tempResponse));
}
function readTemperature(aRead) {
console.log("Geting
Temp");
var x = (aRead.value * 1800/1024);
var cel = 100*x -50;
var fah = (cel *9/5)+32;
currentTemp
= fah;
}
This code begins by loading both the bonescript and restify
modules that are needed for this application.
We then set the following variables:
ip: The IP address of the
interface to bind too. By using 0.0.0.0
the server will bind to all available interfaces (this is what we want).
port: The port to bind
too. Typically web servers bind to port
80 but we do not want to take up that privileged port (and it also requires
root access to bind to ports below 1024) so we will use 18080 for our service.
path: The URL path for our
service.
tempPin: The pin that will
be connected to the TMP36GZ temperature sensor.
CurrentTemp: Will contain
the current temperature. This will be
updated every 30 seconds.
After we set the variables, we then read the temperature
using the analogRead function from the bonescript module. This function will read the voltage from the tempPin and then call the readTemperature
function when it has the voltage. The readTemperature
function calculates the current temperature based on the voltage of the pin and
stores that temperature into the currentTemp
variable.
We use the Javascript setInterval function to call the readTemperature
function every 30 seconds to update the currentTemp
variable.
Now that we have the temperature and updating it every 30
seconds, we need to create our web service that will respond to our requests. We start off by creating a server object
using restify’s createServer
function.
Next we define what services we wish to offer though this
server object. In this case we only have
one service. This service will respond
to HTTP GET requests so the get function from our server object
is used to define the service. This
service will listen on the path defined in our path variable and when a request
comes in it will call the getTemperature function.
Finally we till the server to listen on the port and
interface that we defined in the variables earlier.
The getTemperature function simply
creates a JSON object that contains the current temperature and uses the send
function from the res response
object to send the object back to the client that requested it. This is where I made the code change from my
previous post. To create the JSON
object, I first create a string that contains the response that I want to send
back to the client and I then use JSON.parse() function to create a valid JSON
object.
Now lets look at how we would write the iOS client
application to retrieve the temperature from the BeagleBone Black’s web
service. We will be writing the client app
in Swift (Apple’s new development language) and will use the RSNetworking
library. RSNetworking is a network
library written entirely in the Swift programming language. RSNetworking
is built using Apple’s
powerful URL Loading System.
The main design goal of RSNetworking is to make it easy and quick for
developers to add powerful asynchronous networking requests, to their
applications written in Swift. As a disclaimer,
I created and maintain the RSNetworking library.
The first thing we will need to do is to download the
RSNetworking library from Github and include the library in our project.
In the MainStoryboard of our project we will add a UILabel
(to display the temperature) and a UIButton (to get the temperature from the
BeagleBone Black). Here is a screen shot
of how UI is laid out.
Now lets look at the code that will retrieve the temperature
from the BeagleBone Black’s Web Service and display it on the screen when the
button is pressed.
import UIKit
class ViewController: UIViewController {
@IBOutlet var tempDisplay : UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
@IBAction func getTemp(AnyObject) {
var rsRequest : RSURLRequest = RSURLRequest();
var url : NSURL = NSURL.URLWithString("http://10.0.1.30:18080/temperature");
rsRequest.dictionaryFromJsonURL(url,
completionHandler:{(response : NSURLResponse!, responseDictionary: NSDictionary!, error: NSError!) -> Void in
if error == nil {
println(responseDictionary);
var temp: Double! =
responseDictionary["temperature"]?.doubleValue!
let displayStr : NSString = "".stringByAppendingFormat("%.2f", temp!)
self.tempDisplay.text = displayStr
} else {
//If there was an error, log it
println("Error : \(error)")
}
})
}
}
The getTemp() function is tied to the UIButton. When the button is pressed the applications
accesses the Web Service on the BeagleBone Black and retrieves the
temperature. If there were no errors it
displays the temperature in the UILabel.
So lets look at the getTemp() function.
We begin by creating an instance of the RSURLRequest class. We then create an instance of NSURL
using the URL for our Web Service. We
then use the dictionaryFromJsonURL() function from the RSURLRequest
class to send our request to the BeagleBone Black.
We pass a block (of code) to the dictionaryFromJsonURL()
function. This block of code verifies
that we did not receive any errors and if no errors were received it converts
the temperature that was received to a Double values and displays the temperature,
with the precision that we want, in the UILabel.
If there were errors we simply log them.
That is all there is to creating our first IoT service with
the BeagleBone Black.