My colleague Tim Park has developed a project called Nitrogen.io which is designed to provide a messaging layer between devices and applications and leverage JavaScript and the node.js ecosystems. Tim has provided a good set of documents over on the Nitrogen.io page and is certainly worth reading to understand the system in-depth. Exploring the code and the samples will also help you more fully understand the system.

This set of blog posts is to provide another perspective on Nitrogen.io and document the process I have gone through to get a simple example up and going. In this initial post, I will talk a briefly about the concepts of Nitrogen.io specific to the example I have been working with. The post will also walk through the steps to get the first part of the sample Temperature Model device up and going.

It should be noted, that there are likely better ways to organize the project and run the application, but that is for another blog post down the road.

Some Nitrogen Basics

The Nitrogen platform comprises of three components:

  • Nitrogen service
  • Nitrogen command line tools
  • Nitrogen library
  • Nitrogen Reactor

The Nitrogen service is something you can host yourself or you can make use to the service provided at api.nitrogen.io. The provided service is the default and the one we will use in this example.

The Nitrogen command line tools is a set of command tools for managing the whole of the Nitrogen platform. The command line tools are needed to set up your account with the service layer as well as manage devices and applications that are part of your system.

When you write the code for applications and devices, you will likely leverage a pieces of the Nitrogen library. This tutorial will show you how to leverage existing code for creating a sensor device without the need to write a lot of plumbing that other sensors would also likely use.

When you want to run an application, one way to do so is within the Nitrogen Reactor. Tim goes into detail about Reactor here. For purposes of this tutorial, think of Reactor as the container we will run our sensor application in.

Getting Started

Before getting started, please ensure that you have installed Node.js and npm for your chosen platform. Additionally, if you are attempting to run this example on Windows, please consult the Nitrogen docs. The examples below assume you are working on

First thing is to install the Nitrogen CLI tools:

nox: jims$ sudo npm-install -t nitrogen-cli

sudo’ is used because the nitrogen-cli tools are being installed global to the system. To verify that the tools have been installed, try the following:

nox: jims$ n2 help

You should see something like:

    _   ___ __
   / | / (_) /__________  ____ ____  ____
  /  |/ / / __/ ___/ __ \/ __ `/ _ \/ __ \
 / /|  / / /_/ /  / /_/ / /_/ /  __/ / / /
/_/ |_/_/\__/_/   \____/\__, /\___/_/ /_/
                       /____/
Commands:

apikeys    Manage api keys.
app        Manage app installation and execution.
device     Manage devices (alias for principal)
message    Send and show messages
permission Manage permissions between principals.
principal  Manage principals (devices, users, ...)
reactor    Manage reactor instances (alias for app)
service    Manage the Nitrogen service you are working with.
user       Manage users (alias for principal)

The next step is to create your account. This account will be created on the service previously mentioned which is running at api.nitrogen.com. To create the account:

jims@nox:~$ n2 user create
Name: testuser
Email: testuser@outlook.com
Choose a password:
Repeat password:

You should then see something like:

ID                        TYPE    NAME          LAST IP          LAST CONNECTION
61232eea018cecc2049f3b26  user    testuser      10.211.55.7      2014-09-21T20:02:50.301Z

What this process has done has created a user named “testuser” with the service on api.nitrogen.io. A user is one type of principal within the Nitrogen framework. You can think of a principal as an entity to which you can tie specific permissions to, for instance what kind of messages can they read in the Nitrogen service. For purposes of this series of blog posts, you really only need to think of the user you just created as the entity all the interactions will take place under.

One piece of data we will need to retain for later, and it also illustrates something about the Nitrogen framework, is the API_KEY that was generated for your user account. To retrive the API_KEY associated with your account, do the following:

jims@nox:~$ n2 apikeys ls

You will see:

KEY                               NAME           OWNER
ce7e9baa5b326165e2c170d495c169bc  User           61232eea018cecc2049f3b26

That this is showing you is the id **for the **key associated with the id of the user. Looking above, note that the id 61232eea018cecc2049f3b26 is the same as that of the account you previously created. The value “ce7e9baa5b326165e2c170d495c169bc” references the API_KEY for your account.

At this point, we have the basics of the principal user setup in order to move on to actually writing some code.

Getting Ready To Write Some Code — Let’s Talk Structure

One approach to implementing a device for Nitrogen is to break it down into a couple of components. For a device you basically have three components:

  • Device specifics
  • Device manager
  • Device application

The device specifics are encompassed by the component that talks to the actual physical device and implements the API specified by the device manager. The device manager is a component that manages the interactions between the system as a whole and the device itself, it also encapsulates communication with the service as well as manages messages and commands relevant to the device. Finally, the device application is the glue that ties the device and the the manager together and encapsulates the relevant infrastructure for deploying the device to the Reactor.

Since Nitrogen is based upon Node.js and relies heavily on the Node infrastructure, including npm you can think of a device being three different npm modules that are tied together. Once they are tied together, only then can they be deployed into the Reactor.

To do this, we will create each of the three pieces as npm packages that will be published and each subsequent step will build off the previous through the use of these npm packages.

For purposes of the device we are implementing, we should note that since we are building a sensor device, we will actually be leveraging existing infrastructure for the Device manager, specifically the package nitrogen-sensor which implements the SensorManager object within the Nitrogen platform.

About SensorManager and Sensors in General

In the Nitrogen framework, Managers are responsible for defining the APIs for the devices as well as the types of messages (and commands) that are listened for. The SensorManager, as mentioned, expects sensors to implement certain APIs and sends certain messages and subscribes to certain commands. The skeleton for a sensor device would resemble:

var nitrogen = require('nitrogen');

function <DEVICE_NAME>Device(config) {
  nitrogen.Device.apply(this, arguments);
  ... handle config ...

  this.tags = [... messages / commands the sensor sends/receives ...];
}

<DEVICE_NAME>Device.prototype = Object.create(nitrogen.Device.prototype);
<DEVICE_NAME>Device.prototype.constructor = <DEVICE_NAME>Device;

<DEVICE_NAME>Device.prototype.measure = function(callback) {
  ... perform measurements ...

  var messages = [
  ... generate measurement result messages ...
  ];
  return callback(null, messages);
};

<DEVICE_NAME>Device.prototype.status = function(callback) {
    var statusMessage = {
      ... generate status ...
    }
    callback(false, statusMessage);
};

module.exports = <DEVICE_NAME>Device;

The messages and commands that a sensor device might send/receive are defined within the SensorManager schema which can be found here. The available messages a sensor might send include:

  • humidity
  • pressure
  • temperature

Generating A Temperature Model Sensor and Publishing it to NPM

For the simplicity of this posting, rather than show a temperature model, we will return a static temperature value — let’s say 98.6 degrees. This means that the device example above for a device we want to name TemperatureModel, then the above skeleton becomes:

var nitrogen = require('nitrogen');

function TemperatureModelDevice(config) {
  nitrogen.Device.apply(this, arguments);
  this.config = config;

  if(!this.config) {
    this.config = {};
  }

  this.tags = ['sends:temperature'];
}

TemperatureModelDevice.prototype = Object.create(nitrogen.Device.prototype);
TemperatureModelDevice.prototype.constructor = TemperatureModelDevice;

TemperatureModelDevice.prototype.measure = function(callback) {
  var self = this;
  var messages = [
    new nitrogen.Message({
      type: 'temperature',
      body: {
          temperature: 98.6
      }
    })
  ];
  return callback(null, messages);
};

TemperatureModelDevice.prototype.status = function(callback) {
    callback(false, {});
};

module.exports = TemperatureModelDevice;

However, code alone is not sufficient. As mentioned, we plan on publishing this as an npm module, so the total package would require the following over all structure:

tempModel/
  package.json
  lib/
    index.js

The contents of index.js is the code above. The complete steps to publish a package as an npm module are beyond the scope of this blog, but the package.json file also needs to be populated, so as an example, for this sensor it would resemble:

{
  "name": "my-tempmodel",
  "homepage": "https://github.com/<github username>/devices",
  "main": "./lib",
  "version": "0.1.0",
  "dependencies": {
      "nitrogen": "~0.2"
  }
}

The package.json file defines the name for the temperature model, sets a version, and notes that we depend upon version 0.2 of nitrogen.

Assuming your system is set up for executing “npm publish” from the “tempModel” directory, the package “my-tempmodel” will be available to pull from there once you execute “npm publish”..

Creating A Temperature Model Sensor Application and Publishing it to NPM

The process for creating the application is very similar to creating the sensor device. We need a directory structure that includes the application as well as the package.json which tells us how to publish the component as well as the dependencies it relies upon.

So, like above, we need to create the following directory structure:

tempModel/
  package.json
  app/
    index.js

The contents of package.json would resemble:

{
  "name": "my-tempmodelapp",
  "homepage": "https://github.com/<github username>/apps",
  "repository": {
    "type": "git",
    "url": "https://github.com/<github username>/apps"
  },
  "version": "0.1.0",
  "main": "./app",
  "dependencies": {
    "nitrogen": "~0.2.0",
    "my-tempmodel": "~0.1.0",
    "nitrogen-sensor": "~0.1.4"
  }
}

This package.json is has a few more dependencies. First off, it depends upon the device we previously defined and published “my-tempmodel”. Additionally, it pulls in the dependency “nitrogen-sensor” which is where the implementation of SensorManager lives.

So, we have our skeleton set up, the file “index.js” is where we actually define our application. As mentioned previously, most of the magic in connecting the device to the service running at api.nitrogen.io is handled by the SensorManager Nitrogen library. The code is placed within the index.js file and resembles the following:

var TemperatureModelDevice = require('my-tempmodel')
  , SensorManager = require('nitrogen-sensor');

function TemperatureModel(session, params) {
    this.session = session;
    this.params = params;
}

TemperatureModel.prototype.start = function() {
    this.device = new TemperatureModelDevice(this.session.principal);
    this.manager = new SensorManager(this.device).start(this.session);
};

TemperatureModel.prototype.stop = function() {
};

module.exports = TemperatureModel;

You will notice as you implement similar sensor devices, that the above is really fairly cookie cutter. You include a reference to your device, hook it up, and done.

All that remains for the above is to “npm publish” again, and now you have two packages published as npm modules.

Getting things Running Under Reactor

As mentioned, once we write some code, we need a container to run it in. Nitrogen Reactor provides that container. However, in order to use the reactor, it is simpler for purposes of this blog to clone the repository, make necessary changes, and run the Reactor from the source code checked out. There may be a better way to do this down the road, but that is for another day and another time.

So, to start, issue the following command:

nox: jims$ git clone https://github.com/nitrogenjs/reactor.git

This will clone the Reactor code into the directory you are in. Next enter the following set of commands:

cd reactor
export API_KEY=<API_KEY defined above>
export DEVICE_NAME=tempmodel1
npm install

What this does is sets a couple of critical values that we need for launching the reactor. “export API_KEY” sets the value to our API_KEY which we showed back in setting up our user. “npm install” tells Node.js to install any dependencies that Reactor may have. The process should be relatively quick.

Once the above is complete, you should execute and see the following:

jims@nox:~/n2/reactor$ node server.js
9/15/2014 23:17:14: tempmodel1: info: no reactorState messages found. starting clean.
9/15/2014 23:17:14: tempmodel1: info: commandManager: started.

What this is telling us is that we have started a Reactor instance with the name “tempmodel1” on our system. If you log into https://admin.nitrogen.io with the account you created earlier, select “Messages” in the top bar, you should see an entry resembling:

TIMESTAMP                                FROM          TO  TYPE  BODY
September 21, 2014 at 6:00:26 PM PDT.34  tempmodel69        ip    {"ip_address":"63.249.94.5"}

What this message indicates is that Reactor we have deployed is talking to the service a api.nitrogen.com. If you do not see this entry, you should try:

  • make sure your API_KEY exported is correct
  • make sure you have logged into http://admin.nitrogen.io with the correct account
  • make sure your nitrogen-cli setup is set to the defaults (if you installed from scratch and did not change anything, this should not be an issue)
  • throw up hands and curse (well, investigate other means of troubleshooting)

Next step is to deploy our application to the reactor. This is done through the nitrogen-cli. The process takes part in two phases:

  • install an app instance into the Reactor
  • start the app instance within the Reactor

To install the application within the Reactor, the syntax for the command is:

n2 reactor install <reactor id> <instance id> <module name>

In this case:

  • <reactor id> refers to the name of the Reactor instance above, in this case “tempmodel1”
  • <instance id> is a name given to the instance of the application we will be installing into the reactor
  • <module name> is the npm module name of our application, in this case “my-tempmodelapp”

It should be noted that if you have started multiple Reactor instances with the same name (say in different directories), you might run into problems. The reason for multiple <instance id>s is that some modules take arguments and when you start the particular instance id you can pass arguments to it (our application does not take such).

So to install our specific application within the reactor, the command line and output will resemble:

jims@nox:~/n2$ n2 reactor install tempmodel1 test1 my-tempmodelapp
sending install command for module: model-temperature to instance: test1

On the console for Reactor, you should see something resembling:

9/15/2014 23:56:56: tempmodel1: info: ReactorManager: executing install of instance: test1: my-tempmodelapp@undefined

You will also likely see several lines of output similar to an npm install.

If you look at the messages on https://admin.nitrogen.io, you should see messages similar to the following (though formatting is hard):

9/15/2014 23:57:13.11  tempmodel1              reactorState
                  INSTANCE  STATE        MODULE            EXECUTE AS
                  test1      stopped      my-tempmodelapp   61232eea018cecc2049f3b26
9/15/2014 23:56:56.10  tempmodel1              reactorState
                  INSTANCE  STATE        MODULE            EXECUTE AS
                  test1      installing  my-tempmodelapp   61232eea018cecc2049f3b26
9/15/2014 23:56:55.60  testuser   tempmodel70  reactorCommand
                  {"command":"install","execute_as":"61232eea018cecc2049f3b26","instance_id":"test1","module":"my-tempmodelapp"}

If you see the above (both in terms of the Reactor console window and the messages in the admin GUI), then the our sensor application was successfully installed. If it was not, make sure your API_KEY is correct, you can talk to/reach api.nitrogen.io, etc.

Finally, all that remains is to start our application. Once again, this is just another Nitrogen cli command. The syntax is as follows:

n2 reactor start <reactor id> <instance id> [params]

Since our application does not take any parameters, it can simply be started with:

jims@nox:~/n2$ n2 reactor install tempmodel1 test1

Which should result in output on the Reactor console resembling:

9/16/2014 00:13:24: tempmodel1: info: ReactorManager: executing start of instance: test1
9/16/2014 00:13:25: tempmodel1: info: reactor: starting test1
9/16/2014 00:13:25: tempmodel1: info: reactor: forking test1
9/16/2014 00:13:25: tempmodel1: info: reactor: sending message to container: test1
9/16/2014 00:13:25: testuser: debug: session: created.
9/16/2014 00:13:25: testuser: warn: reactor: executing application without switching users from root.
9/16/2014 00:13:26: tempmodel1: info: instance test1 sent state: running
9/16/2014 00:13:26: testuser: debug: CommandManager::execute: empty command queue.
9/16/2014 00:13:26: testuser: debug: starting heartbeat interval
9/16/2014 00:13:26: testuser: info: commandManager: started.
9/16/2014 00:13:27: testuser: debug: session: socket.io connected
9/16/2014 00:13:59: jims: debug: received heartbeat

Looking again at the messages again on https://admin.nitrogen.io, you should see messages similar to the following:

9/16/2014 00:13:26.63  testuser                temperature  {"temperature":98.6}
9/16/2014 00:13:26.12  tempmodel1              reactorState
                  INSTANCE  STATE        MODULE                EXECUTE AS
                  test1     running      my-tempmodelapp       61232eea018cecc2049f3b26
9/16/2014 00:13:24.42  tempmodel1              reactorState
                  INSTANCE  STATE        MODULE                EXECUTE AS
                  test1      starting    my-tempmodelapp        61232eea018cecc2049f3b26

If you look at the first entry there, you see a “temperature” message with a reading of 98.6 which is exactly what we wrote our device to do.

Success! (for now)

Conclusions and Where to Go From Here

Nitrogen.io is a framework that we only glossed the surface of. In fact, this example leveraged much of the platform to do as little coding as possible. However, what this example does do is show you how you can go from setting up a device to publishing messages. The next segment in the tutorial (Part 2) will first make the temperature readings more interesting/dynamic. Also, it will actually write something to react to those messages. Creating data is like a tree falling in the forest, unless someone notices it, no one cares.

In creating this tutorial, I basically started with an idea and the Nitrogen website. I browsed the documentation and dove head first in. What you are getting is the streamlined “this worked” version.

If you run into problems, feel free to drop me a note. The actual examples that I implemented can be found as follows:

  • the device here in particular “temperatureModel”
  • the application here in particular “device/temperatureModel”

The next blog posting will update the device to actually implement the daily temperature flux noted within the README. It will also cover implementing an application that will subscribe to and respond to triggers within the temperature messages.