After writing the Spark Core iOS library I started thinking more about being able to control the BeagleBone Black from
my iOS devices. The BeagleBone Black
does not have built in Wi-Fi but I normally have my spare BeagleBone Black
(non-robot one) connected to my Wi-Fi router with a network cable. So I started asking myself; how could I
control my spare BeagleBone Black from my iOS device with it connected directly
to my router? The answer came in the
form of socket.io and bonescript.
Lets look at how we can use socket.io with bonescript to
control one of the user LEDs on the BeagleBone Black. I used the Cloud9 IDE to write this
application so the first thing that I needed to do was to install socket.io
where Cloud9 can use it. To install
socket.io run the following commands (Note: I am using Agnstrom Linux, you may
need to adjust the paths depending our you flavor of Linux):
cd /var/lib/cloud9
npm install socket.io
Once socket.io is installed, we can open the Cloud9 IDE in our
favorite web browser by going to port 3000 of our BeagleBone. You can do this by opening your favorite
browser and entering the IP Address of your BeagleBone followed by colon and
3000 IE: 10.0.1.18:3000.
Now that we have everything setup, lets write the application
to control one of the user LEDs on the BeagleBone black. In the Cloud9 IDE, create a folder called
“RemoteLED”. We will be creating two
files within this folder called toggleled.js and index.html. Lets look at the toggleled.js file first:
var app = require('http').createServer(handler);
var io = require('socket.io').listen(app);
var fs = require('fs');
var b = require('bonescript');
//Set socket.io to listen on port 2080
app.listen(3080);
//my constants
var ledPin = "USR3";
var STATEON = b.HIGH;
var STATEOFF = b.LOW;
//called to initilize the device
setup = function() {
b.pinMode(ledPin,
b.OUTPUT);
b.digitalWrite(ledPin,
STATEOFF);
};
//function called to setup our page
function handler (req, res) {
//load our index.html page
fs.readFile('RemoteLED/index.html',
function (err, data) {
if (err) {
res.writeHead(500);
return res.end('Error
loading page');
}
res.writeHead(200);
res.end(data);
});
}
//on method listener
io.sockets.on('connection', function (socket) {
socket.on('led', function (command)
{
console.log(command);
if (command == 'on'){
b.digitalWrite(ledPin, STATEON);
socket.emit('ledstatus', 'LED is on');
}else{
b.digitalWrite(ledPin, STATEOFF);
socket.emit('ledstatus', 'LED is off');
}
});
});
We begin by adding the external modules needed using the require
function that comes with node.js. Next
we set socket.io to listen for requests on port 3080 and define three
constants.
The setup function is called when the
application starts up. It initializes
the LED pin and also turns the LED off so the LED will begin in the OFF state. The handler function is called when a HTTP
request comes in and sends the index.html page, which we will look at shortly,
to the client.
Finally we add an “on” method listener that listens for
incoming actions. In this example, we
listen for the ‘led’ action and when a ‘led’ action is received it runs the
inner function. This inner function will
turn the LED on if it receives the “on” command otherwise it will turn the LED
off. It also uses the emit
function to send a ‘ledstatus’ action back to the client with the current status
of the LED.
Now lets look at the index.html file.
<html>
<head>
<style>
.button
{height:100px;width:140px;font-size:34px;margin-left:30px;margin-top:50px;}
.status
{font-size:34px;margin-top:50px;margin-left:30px;}
</style>
<script src =
"/socket.io/socket.io.js" > </script>
<script>
var socket =
io.connect();
socket.on('ledstatus',
function (data) {
console.log(data);
var statusDiv
= document.getElementById("status");
statusDiv.innerHTML = data;
});
</script>
<script>
function ledOn(){
socket.emit('led', 'on');
}
function ledOff(){
socket.emit('led', 'off');
}
</script>
</head>
<body>
<input
type="button" name="on" id="onButton"
class="button" value="ON" onClick="ledOn();">
<input
type="button" name="off" id="offButton"
class="button" value="OFF"
onClick="ledOff();">
<div
id="status" class="status">LED is off</div>
</body>
</html>
The interesting parts of this page are between the two
“script” tags. In the first “script” tag
we set up a listener that listens for an ‘ledstatus’ action and when it is
received it will call the inner function that sets the status label to the
message that was received. This action is
sent from the toggleled.js script with the following command: socket.emit('ledstatus',
'LED is on');
The second ”script” tag contains two functions. These functions are called when the on and
off buttons are pressed and uses the emit function to send a ‘led’ action back
to the listener in the toggleled.js script that turns the LED on or off.
If you run this code within the Cloud9 IDE you should be
able to control User LED from any computer or mobile device that can connect to
the BeagleBone Black. The web page
should look like this:
Now lets look at how we would control the User LED on the
Spark Core. I will use Spark’s standard tools and then write an iOS app using
my Spark Core – iOS Library that
will control the User LED on the Spark Core.
If you do not know how to use Spark’s IDE or flash the Spark Core,
please refer to Spark’s getting started page.
Lets begin by looking at the code that we will flash to the
Spark Core:
int userLed = D7;
int ledStatus = 0;
void setup()
{
Spark.function("led",
ledController);
pinMode(userLed,
OUTPUT);
Spark.variable("ledStatus",
&ledStatus, INT);
}
void loop()
{
//doing
nothing
}
int ledController(String param)
{
if (param
== "on")
{
digitalWrite(userLed,
HIGH);
ledStatus
= 1;
return
1;
}
if (param
== "off")
{
digitalWrite(userLed, LOW);
ledStatus = 0;
return
1;
}
return -1;
}
In the setup function we begin by making the ledController
function available through the Spark cloud by using the Spark.function. We can send information to the ledController
function using a POST request from our client. We also define a variable that
can be read using the Spark.variable function using a GET request. We will turn the LED On or Off with the ledController
function and read the LED status from the ledStatus variable.
The ledController function looks at the
parameter that was sent in the POST request.
If the parameter is “on”, the function turns the LED on and sets the ledStatus
variable to 1. If the parameter is “off”,
the function turns the LED off and sets the ledStatus variable to 0. If something besides “on” or “off” was sent,
the function returns -1. Once you have
the code in Spark’s IDE, you should flash it to your Spark Core.
Now lets look at the iOS application to see how it
works. If you are not familiar with my
iOS library for the Spark Core, you can read my blog post about it. You can download the code from the GitHub repository. The full source for the iOS application is in
the Spark Core GitHub repository under the “SparkComparisonApp” directory.
I do not want to go over the full ViewController class here
but I do want to highlight two methods.
-(void)getStatus {
SparkTransactionGet *getTransaction = [[SparkTransactionGet alloc] initWithAccessToken:ACCESS_TOKEN deviceId:DEVICE_ID andProperty:STATUS_VAR];
[SparkCoreConnector connectToSparkAPIWithTransaction:getTransaction andHandler:^(NSURLResponse *response, NSDictionary
*responseDictionary, NSError *error){
if(error == nil) {
NSLog(@"Response: %@",responseDictionary);
int status = [[responseDictionary objectForKey:@"result"] intValue];
NSString *statusStr = @"off";
if (status == 1)
statusStr = @"on";
_statusLabel.text = [NSString stringWithFormat:@"LED
is %@", statusStr];
} else {
NSLog(@"Error: %@",error);
_statusLabel.text = @"Error
Getting Status";
}
}];
}
The getStatus method makes a GET request to
Sparks Cloud API and retrieves the current status of the LED. When the status is returned it sets the statusLabel
UILabel with the status of the LED. If
an error is returned it sets the statusLabel UILabel to an error message.
-(void)sendRequestWithParameter:(NSString *)parameter {
NSLog(@"Params: %@",parameter);
SparkTransactionPost *postTransaction = [[SparkTransactionPost alloc] initWithAccessToken:ACCESS_TOKEN deviceId:DEVICE_ID functionName:FUNCTION andParameters:parameter];
[SparkCoreConnector connectToSparkAPIWithTransaction:postTransaction andHandler:^(NSURLResponse *response, NSDictionary
*responseDictionary, NSError *error){
if(error == nil) {
NSLog(@"Response: %@",responseDictionary);
} else {
NSLog(@"Error: %@",error);
}
[self getStatus];
}];
NSLog(@"Continueing with app");
}
@end
The sendRequestWithParameter: method sends a
POST request to Sparks Cloud API telling it to turn the LED either on or off
depending on what the parameter is. The
parameter should be either “on” or “off” to match the commands on the Spark. When the response comes back from Spark’s
API, acknowledging that the on/off command was received, we then call the getStatus
function to retrieve the current state of the LED.
One thing I did notice with the Spark Core is there is a
noticeable delay from the time I pressed the on or off button to when the
status label was updated. The delay was
less then a second but it was pretty obvious.
I would imagine this delay would not be a problem for most applications
but you would just need to account for it.
The response from the BeagleBone Black was all but instantaneous which
is what I expected from socket.io.
Spark’s IDE is all right.
I would definitely rate the Cloud9 IDE above Spark’s mainly because the
error messages from Spark’s IDE are really unhelpful. I wasted a lot of time trying to track down a
simple typo.
The architecture of the BeagleBone Black’s application is a
lot nicer because the client and server components are contained in one
application making it easier to update.
However if you plan on making a commercial product, being able to upload
the client application to Apple’s app store would be really nice.
The big advantage that the Spark Core has over the
BeagleBone Black is the built in Wi-Fi and it was designed/built to communicate
with remote devices. Spark’s Cloud API
is also very easy to use with the REST based API. Both the BeagleBone Black and the Spark Core
have advantages and disadvantages; you will need to see which one fits best with your project. I will say that I
wish the BeagleBone Black had built in Wi-Fi but it does not.