Sunday, August 31, 2014

IoT: Displaying the temperature from the BeagleBone Black on my iPhone

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. 
                                                                                               

Sunday, August 24, 2014

Creating REST based Web Service using Javascript on the BeagleBone Black

Right after I published the Taking the Temperature with theBeagleBone Black and Javascript, I started thinking about creating a REST based Web Service using Javascript that I could use to read the temperature from a remote device.  For this project I will be using the node.js restify module to create the REST service. 

The TMP36GZ temperature sensor is wired to the Beaglebone Black as show in this diagram.



I always hate running services from within an IDE so I will not use Cloud 9 for this project and instead I will be running the service from the command line using node.js.  So 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_40';
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 tempResponse = {"temperature":currentTemp};
     res.send(200, 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. 

You can run this application using the following command:

Node tempServer.js

Once it is running you can test it from the Beaglebone black command line using curl like this:

curl localhost:18080/temperature

You can also access the service from a remote machine by using the external IP address of your Beaglebone Black like this (remember to change the IP address to the IP address of your Beaglebone Black):




Taking the Temperature with the BeagleBone Black and Javascript

Where I live the temperature this weekend is into the triple digits so there is no way we are going outside to do anything which means we had time for another project with the BeagleBone.  With the temperatures being so high, we decided to figure out how to take the temperature with the BeagleboneBlack.  To take the temperature we will use a TMP36GZ temperature sensor and will develop the application to read the sensor in Javascript.

The first thing we need to do is to wire the temperature sensor. Here is the wiring diagram for this project:



You will notice that we connected the center pin of the TMP36GZ sensor to pin P9_40, which is an analog pin that can be used with the analogRead and analogWrite functions.

Once we had the sensor wired, we needed to developed an application to read the sensor and print out the temperature.  Here is the code that I wrote:

var b = require('bonescript');

console.log("Started");
var tempPin = 'P9_40';

b.analogRead(tempPin, printTemp);

function printTemp(aRead) {
    console.log("Geting temp");
    var x = (aRead.value * 1800/1024);
    console.log("value " + aRead.value);
    console.log("x:  " + x);

    var cel = 100*x -50;
    var fah = (cel *9/5)+32;
    console.log("Fah:  " + fah);
    console.log("Cel:  " + cel);
}

We begin by loading in the bonescript module using node.js require function.  Next we set the tempPin variable to the pin connected to the TMP36GZ temperature sensor.  In our case, we connected the sensor to pin 40 of the P9 expansion header.

We set the pin mode of the tempPin to ANALOG_OUTPUT so we can read the pin and then called the analogRead function to read the pin.  In the printTemp function we converted the voltage to a Celsius temperature and then the Celsius temperature to Fahrenheit and printed the temperature to the console.


If you recall from my earlier post (http://myroboticadventure.blogspot.com/2014/06/using-javascript-with-bonescript-to.html) that I was not really a fan of the Cloud 9 IDE that came with the Angstrom image however I had not tried the latest version that came with the Debian image.  Since I have the latest Debian image on my test Beaglebone Black, I decided to give the new Cloud 9 IDE a try.  I do like the latest version a lot more and I think I will with hold my judgment on it until I use it a bit more.  I would recommend that if you did not like Cloud 9 before that you should give it a second chance. 

Saturday, August 16, 2014

Logic Supply’s Compact USB Wi-Fi Adapter for the Beaglebone Black

I wanted to put my Beaglebone Black onto my Wi-Fi network rather than running a network cable to it so I purchased Logic Supply’s USBWi-Fi adapter for the Beaglebone Black.   The only drawback I have found with the Wi-Fi adapter is the lack of instructions. This post will document how I setup the Wi-Fi adapter on my Beaglebone Black to hopefully assist others.

The package says that the latest release of the Beaglebone Black, with a Debian image, includes the drivers for the Wi-Fi module. I have been using the Angstrom distribution, mainly because the Bluetooth adapters work much better with it however if I have Wi-Fi I would not need the Bluetooth adapter.  So I decided to give the new Debian distribution another try with the Wi-Fi adapter.

Once I flashed the Debian image onto my Beaglebone Black (see instructions on how flashing the Beaglebone on the getting started page (http://beagleboard.org/getting-started)) I plugged the USB Wi-Fi adapter into the Belkin 7-Port USB Powered Hub that is connected to my BeagleBone Black.  Logic Supply strongly recommends that due to the Wi-Fi adapter’s power consumption, you use a 5 Volt AC adapter, rather than powering the Beaglebone Black from USB, when using this adapter.  I would say that is true with any USB Wi-Fi adapter, which is why connected the Wi-Fi adapter to the powered USB hub.

When I plugged the Wi-Fi adapter into the hub, I was hoping that the OS would detect the adapter and configure it then all I would have to do is to connect it to my Wi-Fi network.  Well I was a bit disappointed but that is OK because I like a good challenge and since there were no instructions (who actually reads instructions anyway) it was up to me to figure out how to get it working.

The first thing I did was to unplug the Wi-Fi adapter from the USB hub.  I then ran the following command to monitor any changes to the system log file and plugged the Wi-Fi adapter back in:

            tail –f /var/log/syslog

After plugging the Wi-Fi adapter back in, the log revealed that the OS setup the adapter with the device name ra0.  Once I had the device name, I open up the WICD Network Manager and went to the preferences to add the ra0 device name as the wireless interface.



I then clicked OK to go back to the main screen.  On the main screen I waited a couple of seconds and then clicked Refresh to refresh the list of networks.



I found my network and clicked Properties to set the network properties



And then I was on my Wi-Fi network.  I hope these instructions are able to assist others in configuring Logic Supply’s USB Wi-Fi adapter for the Beaglebone Black.