Probably the best way to understand the Internet of Things is to get some things on the Internet and in this article we're going to do just that.

 

icon_19938.pngWhat we are going to assemble is a greenhouse control system which will be able to monitor temperature and light levels and control the windows on the greenhouse. More importantly, at the end of it, you'll have a development platform built for further exploration. At the core of what we are constructing will be a BeagleBone Black, a powerful, small ARM-based general purpose computer which will play host to a number of Eclipse tools, run an MQTT stack for us and act as the main brain of the operation. It'll be responsible for taking our temperature and light readings and publishing them to the Internet while listening for control messages to set the greenhouse windows.

 

Some would, at this point, attach the sensors and controls directly to the BeagleBone Black (BBB). In real world implementations, it's more common to find micro-controllers in the front-line as it were, connected and controlling the sensors, servos and other hardware as they typically are more resilient to the environment, more compatible with the electrical elements and a lot cheaper. Therefore to be more realistic, we are going to attach an Arduino micro-controller over a Serial-over-USB connector though this could be an actual serial connection or a wireless connection of some description - the advantage of a USB connection for this example is that it also supplies the power to the Arduino.

 

So far, you'll need an Arduino and a BeagleBone Black to follow our build process. There are a whole range of Arduinos with different features but we recommend the ever popular Arduino Uno or the Arduino Leonardo. For the sensors and servos, although you can assemble your own collection of hardware, we are going to recommend the Grove Starter Kit Plus, a shield sporting numerous sockets and a collection of components with de-coupling chips and pre-wired with plugs for the shield sockets. This makes it great for experimentation without breaking out the soldering iron.

 

orion.pngWe're going to use Eclipse Orion on the BeagleBone Black rather than the default Cloud9 IDE as it is a development environment more capable of working with languages other than JavaScript, even if here we are using it entirely with JavaScript. The flexibility of being able to use the same tools with whichever language you decide to work in and the ability to use those tools over the Internet is a huge plus when putting together a prototype or development system.

 

The Eclipse IDE, which many are familiar with, is built as a platform for integrating tools from many different vendors in one coherent framework on the desktop. Eclipse Orion has been developed as a separate project which looks to bring that tool integration philosophy to a web-based browser-native development environment. There's actually two Orion IDE's - the project started with a Java based version with an eye on hosted collaborative development platforms while along side that, Orion Node, a Node.js based version of the system designed for a single user has emerged. The Orion IDE offers a syntax aware editor, with search tools, and a shell environment to support command-line style application building, deployment and running. The Orion Node version is also pretty compact and remarkably easy to install, making it a great way to get working on a small device remotely.

 

Beginning building

 

First though, lets make a start by getting the controller assembled. First, attach the Grove shield to the Arduino. Then, in the components you'll find a temperature sensor, a light and a light sensor  we'll get to the servo later. Plug the temperature sensors into the A0 (analog 0) port, a sideways connector on the lower left side of the Grove shield. This port and its other four siblings are able to read an analogue voltage from an electronic device making them ideal for non-digital sensors. Plug the light sensor into A1, just above A0.

 

And that's the hardware assembled:

 

hackpad.com_VCR1WLsIyOE_p.160075_1402832276223_DSC01899.jpg

 

Note that though the Arduino can be powered over the USB port from the BeagleBone it is better, especially when adding power-drawing devices like servos, to use a 9V power supply (or battery) for the microcontroller.

 

Next we'll need to be configuring the BBB and selecting the operating system. To date, most BBB boards have come with the Angstrom Linux distribution installed on the 2GB of eMMC flash storage; they are identifiable by being labelled revision A or B. Although Angstrom is a functional Linux distribution, it isn't mainstream and the BeagleBone project is in the process of switching its default Linux to an up to date Debian GNU/Linux. There's only one catch... Debian is a bit bigger than Angstrom and although it fits onto the 2GB eMMC flash, if you install the packages we will, you'll find yourself with less than 1% free space. If you have an 2GB BBB, we recommend you get yourself a Micro-SD card and install and boot Debian from that - you may also want to install Debian onto the eMMC for consistency.

Instructions on how to install Debian into the eMMC and the latest images for eMMC and SD are on the BeagleBoard.org site. You will also need to resize the image on the SD card once installed to make full use of the SD cards capacity - a guide to this is also available and, to save time, there's a quick version of the process at the end of the page .

 

As new BeagleBone Blacks labelled Revision C are starting to arrive with 4GB of eMMC and Debian pre-installed so this isn't an issue.

 

Organising Orion

 

The next steps can be carried out locally, if you've plugged your BBB into an HDMI monitor and attached a USB keyboard and mouse or remotely over a SSH connection on a network. If the former, you will still need to connect the BBB to your network. Also remember to use a USB hub as the BBB only has one USB port and we have yet to connect the Arduino we talked about earlier. If over the network, the Debian installation will be advertising itself as beaglebone.local, so all thats needed is to run ssh root@beaglebone.local to log in. (It is possible to connect a BBB to a PC over just a USB cable and ssh in, but this by default doesn't share the PCs internet connection which we'll need to install software).

 

The Debian GNU/Linux image already has an up-to-date node.js installed so what we initially need to do is install Eclipse Orion, the web-based IDE. We can do this like so:

 

root@beaglebone:~# mkdir greenhouse
root@beaglebone:~# cd greenhouse/
root@beaglebone:~/greenhouse# mkdir workspace
root@beaglebone:~/greenhouse# npm install orion









 

We'll be keeping all our work in the greenhouse directory which is why we also created a workspace directory in there. Once installed you can use npm to start Orion too, but before that, there's a small tweak to be made. We need to edit node_modules/orion/orion.conf and change the fourth line, a commented out line for setting npm_path to:

 

npm_path=/usr/share/npm/bin/npm-cli.js









 

And the last line, a commented out line setting the location of the workspace. In this case it should be replaced by...

 

workspace=/root/greenhouse/workspace

 

... though this could of course be any directory.

 

Save the file and we're ready to start Eclipse Orion:

 

root@beaglebone:~/greenhouse# npm start orion

 

Go to your browser and browse to "http://beaglebone.local:8081/" if accessing remotely (localhost:8081 if local) and you should be greeted by the Orion user interface.

hackpad.com_VCR1WLsIyOE_p.189956_1403513024589_orion-ui.png

The icons at the left hand side set the view in the Orion IDE, the pencil shows the workspace and other directory/file views, the magnifying glass takes you to a search centric view and the rectangular icon, representing a console session, gives access to the Orion shell.

Getting Firmata onboard

 

We now have the hardware for the sensors assembled and an IDE installed on our BBB. The next step is to bring connect them and for this we are going to use Firmata, firmware which implements a generic protocol for talking between host computers and micro-controllers. In many ways, it's the software equivalent of the Grove kit we are using as it makes it easy to work with controllers.

 

You can install the Firmata firmware using the Arduino IDE. At this point you have a choice - you can install the Arduino IDE on a PC, Mac or Linux box and use that or you can install it on the BeagleBone Black. The latter course of action will require you to have a screen or a remote X Windows session configured as the IDE is a GUI application. Install the IDE with sudo apt-get install arduino

 

The former approach, installing the Arduino IDE on a PC, Mac or Linux system, is often quicker as you'll only be doing this once in a while. You can download the software from the Arduino downloads page  we recommend the Arduino 1.5.6-r2 beta or later  and follow the installation instructions.

Whichever route you take, once the Arduino IDE is running, select File » Examples » Firmata » StandardFirmata, select the Arduino board and USB/serial port it is connected to the IDE host machine with in the Tools menu and then click the compile and upload button (the tick and the right arrow in the Firmata sketch window). When this is complete, your Arduino board will understand the Firmata protocol and you can plug the USB cable back into to the BeagleBone Black and we can take control of our Arduino board.

 

Back to Orion

 

We can now return to Orion in the browser and start creating some code. Over on the left hand side of the browser are a pencil, magnifying glass and a terminal window. The pencil lets you view, create and edit projects, the magnifying glass lets you search in various ways and the terminal gives you access to a shell. It's this shell we want to go to next because we have Firmata support on the Arduino and need software to communicate with it.

Johnny-Five is such software, developed for Node.js to enable robotics development. Its big feature is that it allows a programmer to work in terms of LEDs, Buttons , Sensors and Servos rather than high/low pins and it simplifies the process of managing them.

To install it, we use npm as we did earlier to install Orion, but now we can run it from within the shell. Go to the text field at the bottom of the Orion shell view and type:

npm install johnny-five

It'll look like this when it's done installing:

 

hackpad.com_VCR1WLsIyOE_p.100400_1404211483449_Screenshot 2014-06-28 11.37.40.png

 

Click on the pencil to get the file view back and select from the Orion menu File » New » Project » Basic and enter greenhouse as our new project's name. This will move us into the directory for the new project in the viewer. Now select File » New » File and create a file called greenhouse.js.

 

hackpad.com_VCR1WLsIyOE_p.100400_1404215568626_Screenshot 2014-06-28 11.38.52 (1).png

 

We can now start entering some code. First of all, we need to tell Orion's IDE that we're writing Node.js code and not to warn about common Node.js commands and classes. This is done through a jslint directive in a comment:

 

/* jslint node:true */









 

Now we need to bring in the Johnny-Five library. At the core of Johnny-Five is the Board abstraction in that we talk to a Board. We'll create that at the same time as bringing in the library:


var five = require("johnny-five"),
board = new five.Board();









 

When the program starts and the Board is created, the library will begin to negotiate with the Firmata enabled Arduino and will reach a point when its ready to start doing some work. We want to capture that "ready" event...


board.on("ready", function() {










The first thing we want to do is monitor the temperature sensor. We want to read the temperature once a second and, if you recall, we attached the sensor to A0. In Johnny-Five, we just have to tell it about that sensor like so:

 

    var tempsensor = new five.Sensor( { pin:"A0", freq:1000 } );


This freq(uency) means that every 1000 millisecond, or second, the sensor will be read and a data event fired. We now want to capture that data event by directing it to our own callback:

 

    tempsensor.on("data", function() {


The event comes complete with a value for the reading (this.value) and we can use that to calculate the temperature by first working out what the resistance of the temperature sensor is and then converting it to a temperature using a formula based on the sensor's data sheet. (See this wiki page on the sensor for more).

 

        var resistance=(1023-this.value)*10000/this.value;
        var temperature=1/(Math.log(resistance/10000)/3975+1/298.15)-273.15;









 

For now, we'll print the result to the console and end the tempsensor callback and the program's code.

 

        console.log("Temp:"+temperature);
    });
});





 

Once we have selected File » Save to write the code to disk, we now have a program ready to run from the Orion shell. If we switch to the shell using the sidebar and click into the command entry panel at the bottom, we can begin typing. The shell will attempt to autocomplete for many things. Type "no" and it will suggest "node". To accept that suggestion, press Tab. We want to start a Node.js program, so type "st" and autocomplete will suggest "start", again press Tab to accept. At this point you can enter a filename but the shell is already anticipating that and will be offering filenames from the current directory; select greenhouse.js from the list and hit return.

The program should start running and, after initializing, start printing readings from the temperature sensor.

 

hackpad.com_VCR1WLsIyOE_p.100400_1404215609798_Screenshot 2014-06-28 14.07.34.png

 

To stop it running, go to the command panel and enter node stop at which point the shell will offer process ids you can stop. There should only be one at this point so select that, hit Return and the process is stopped. We are now reading the sensor, the next step is to get that information out to the world.

Going MQTT

 

We're going to use the MQTT messaging protocol to send our data out. MQTT is built for this kind of task because it's lightweight and flexible. For this part of the example, suffice to say that with MQTT you can send messages with tags to what looks like (but isn't) a file-system hierarchy on a server. To make life easier, Eclipse runs a sandbox server at iot.eclipse.org so we'll use that as the MQTT server. What we need is MQTT support so go to the shell, make sure you are in the top level "Orion Content" directory (if not enter cd .. till you are) and then enter npm install mqtt to install the Node.js MQTT library.

 

hackpad.com_VCR1WLsIyOE_p.100400_1404215664783_Screenshot 2014-06-28 14.23.04.png

 

After that's installed, return to Edit view and bring up greenhouse.js. After the require for johnny-five we want to add code to bring in MQTT and connect to the Eclipse sandbox...


 

var mqtt = require("mqtt"),
client = mqtt.createClient(1883,"iot.eclipse.org");









 

 

And that's a basic connection set up. Now we need to publish our temperature data. After the console.log we'll add this line...


 

client.publish("greenhouse/mygreenhousename/sensor/temp",temperature.toString(), { retain:true });

 

 

The first parameter is the topic, a file-system-like path - greenhouse/mygreenhousename/sensor/temp but don't make assumptions about it working like a path; it's more of an informal hierarchy of names. This first thing for us though is to change mygreenhousename to something that is unique to you to avoid colliding with other users on the sandbox who are also following this article. Now we have the 'greenhouse' and your own name for that greenhouse. Beneath that we have sensor where, going forward, we'll put all our sensor data and beneath that a temp element where we'll post the temperature data.

 

The next parameter is us converting our temperature to a string before posting to make it more readable; MQTT doesn't have any rules for what is called the payload of a message so it could be binary or an image. We've gone with the good old string because we'll want to read it later when testing.

 

Finally we set an option, "retain" to true to ask the server to hold onto the value for any other client that requests the data. If we don't set retain, the value will be broadcast to any client listening for it at the time but it won't be available for clients that connect after the broadcast leaving them to wait. While we're pushing the temperature out every second, we may want to only do that when it has changed and that may be an indeterminate amount of time.

 

Save this code, return to the Orion shell and start the program again. It should start as it did before, but now, if you open a new browser window and look at http://eclipse.mqttbridge.com/greenhouse/mygreenhousename/sensor/temp you should also see that same temperature reflected on the Eclipse sandbox. The eclipse.mqttbridge.com site also monitors to iot.eclipse.org MQTT server and makes debugging easier by allowing you to browse the various MQTT topics that it sees appearing on the server.

 

Now we know that's working, you may want to go back and delete the console.log line.

Let there be light (sensor)

 

We've only done the temperature sensor, but it should simple to add support for the light sensor and it is. After the temperature sensor handler we can add


var lightsensor = new five.Sensor( { pin:"A1", freq:5000 });









To map the light sensor and get it sampled every five seconds and then send that sampled value to the MQTT server like so...


client.publish("greenhouse/mygreenhousename/sensor/temp",temperature.toString(),
{ retain:true });









 

And with just those few lines, if you re-run the program, you'll be transmitting light and temperature data. The process for adding more sensors follows this basic pattern though you can, for example, cut down on bandwidth by only updating when your code detects a change locally or using some other logic. As before, if you browse to if you browse to http://eclipse.mqttbridge.com/greenhouse/mygreenhousename/sensor/light you should see

Moving on

 

In our virtual greenhouse, we are getting the temperature and light readings, but we aren't able to take any action on then like opening the windows. For that you'll need a servo to attach to the window control. If you look in the Grove kit, you'll find one along with all the basic mounting gear. Don't worry about mounting it to anything yet, just take a Grove cable and plug it into digital port 3 (D3) which on most Arduino's is the first digital port that supports PWM (Pulse Width Modulation, useful for controlling servo motors).

 

With the servo installed we can now add some lines to greenhouse.js to control the servo. We'll add this code immediately after the light sensor code. We start by declaring we have a servo on pin 3.


 

var servo=new five.Servo(3);
servo.center();









 

 

Servo motors typically take a value from 0 to 180 and move to that angle. We are going to get the value for the servo via the same MQTT server we are publishing our temperature and light readings to. We will be listening from someone broadcasting a new setting under the greenhouse/mygreenhousename/commands/servo by using the MQTT library's subscribe command.


 

client.subscribe("greenhouse/mygreenhousename/commands/servo");

 

 

Now, when anything happens in that topic, an event will be triggered. We can capture this by waiting for the "message" event...


client.on('message', function(topic,message) {
    console.log("Got topic "+topic+" with "+message);









 

We get the topic value because you can actually subscribe to multiple different topics and wildcard topic names in subscriptions - getting the topic name lets us make decisions based on what particular topic generated the message. For now though, we're only subscribed to one topic so we'll assume that's a servo control message. We can now process the message and we'll keep it simple and just parse whatever's arrived as an integer.

 

    var val=parseInt(message);
    if(val<10) { val=10; }
    if(val>170) { val=170; }
    servo.to(val);
});









 

We also map it into a tighter range (as servos can be mechanically tetchy at the ends of their ranges) and then we tell the servo to move to that position. And that's it. If we run this version of the code, nothing will happen with the servo until we post a value to the iot.eclipse.org server. Again the eclipse.mqttbridge.com server comes to our aid. We can use curl to send a value over HTTP to it like so:


 

curl -X POST --data-binary "100" http://eclipse.mqttbridge.com/greenhouse/mygreenhousename/commands/servo

 

Beyond the servo

 

Of course you could always write another node.js client (or use other language) to monitor the temperature and light levels by subscribing to those topics and control the airflow by publishing new servo positions.

The combination of Eclipse Orion, Johnny-five, MQTT, the BeagleBone Black and Arduino make for a formidable set of tools when setting out to explore what you can create for the Internet of Things. And you can of course add more sensors and control more devices, or take the BeagleBone out of the equation by adding ethernet or Wi-Fi to the Arduino and porting the JavaScript Node.js code to run on the Arduino itself. Or add a meshed wireless controller and use the BeagleBone to coordinate that mesh of devices... and even run the MQTT server on the BeagleBone and...

 

Just add imagination and the Internet of Things is yours!

Final code

 

/*jslint node:true */

var five = require("johnny-five"),
board = new five.Board();

var mqtt = require("mqtt"),
client = mqtt.createClient(1883,"iot.eclipse.org");

board.on("ready", function() {
    var tempsensor = new five.Sensor( { pin:"A0", freq:1000 } );

    tempsensor.on("data", function() {
        var resistance=(1023-this.value)*10000/this.value;
        var temperature=1/(Math.log(resistance/10000)/3975+1/298.15)-273.15;
        console.log( "Temp:"+temperature.toFixed(2) );
        client.publish("greenhouse/mygreenhousename/sensor/temp",temperature.toString(),
                    { retain:true });
    });

    var lightsensor = new five.Sensor( { pin:"A1", freq:5000 });

    lightsensor.on("data",function() {
        var light=this.value;
        client.publish("greenhouse/mygreenhousename/sensor/light",light.toString(),
                    { retain:true });
    });

    var servo=new five.Servo(3);
    servo.center();

    client.subscribe("greenhouse/mygreenhousename/commands/servo");
    client.on('message', function(topic,message) {
        console.log("Got topic "+topic+" with "+message);
        var val=parseInt(message);
        if(val<10) { val=10; }
        if(val>170) { val=170; }
        servo.to(val);
    });
});