Prevues of Coming Attractions: Macchina.io
Macchina.io is the new name for our IoT Framework which we've announced some time ago. A few weeks ago, at the Sierra Wireless Developer Day in Paris, we presented a demo of the current state of the project. Apart from our existing C++ toolkits — the POCO C++ Libraries at the core, the Open Service Platform, Remoting and Universal Plug and Play, my-devices.net and new toolkits for talking to various sensors and devices, as well as various protocols, the main feature is the integration of a JavaScript runtime environment. This enables rapid creation of applications for smart IoT gateway devices. Need to obtain some measurements from a sensor and periodically write to a database? Just a few lines of JavaScript code. Visualize the data on a web page? Just a few lines of JavaScript as well. Want to send sensor data to a cloud service? You guessed it — a few lines of JavaScript code. Following are some samples for what can be done. For our samples, we're using sensors from TinkerForge, in this case a temperature and an ambient light sensor. Macchina.io runs on an ARM Embedded Linux platform.
The first sample shows how to periodically (once per second) read the current measurements from the temperature and ambient light sensors, and, with a timestamp, write them into a SQLite database table. To prevent the table from growing endlessly, we have a second timer task that periodically removes old entries from the table.
include('sensors.js');
var keepDataSeconds = application.config.getString("logger.keepDataSeconds", 3600);
var dbPath = application.config.getString("logger.database");
var dbSession = new DBSession('SQLite', dbPath);
dbSession.execute('PRAGMA journal_mode=WAL');
dbSession.execute('CREATE TABLE IF NOT EXISTS datalog ( \
timestamp INTEGER, \
temperature FLOAT, \
luminance FLOAT \
)');
setInterval(
function()
{
dbSession.execute('INSERT INTO datalog VALUES (?, ?, ?)',
DateTime().epoch,
sensors.temperature.value(),
sensors.ambientLight.value());
},
1000);
setInterval(
function()
{
var cutoffTime = DateTime().epoch - keepDataSeconds;
dbSession.execute('DELETE FROM datalog WHERE timestamp < ?',
cutoffTime);
},
keepDataSeconds*1000);
This sample shows how to:
- read configuration settings from the application's configuration file,
- create a SQLite database,
- set up periodic timers, and
- execute SQL statements on an SQLite database (including data binding).
The sensors object is created in the sensors.js file, which is shared among multiple scripts and shown below.
var sensors = {};
var ambientLightRef = serviceRegistry.findByName(
'com.iotframework.tf.ambientlight#jk7'
);
if (ambientLightRef)
{
sensors.ambientLight = ambientLightRef.instance();
logger.information(
'Ambient Light: ' + sensors.ambientLight.getPropertyString('name')
);
}
var temperatureRef = serviceRegistry.findByName(
'com.iotframework.tf.temperature#dV3'
);
if (temperatureRef)
{
sensors.temperature = temperatureRef.instance();
logger.information(
'Temperature: ' + sensors.temperature.getPropertyString('name')
);
}
Here we can see how to obtain sensor objects from the framework's service registry, where all sensor and device objects, as well as other service objects are registered. For those familiar with OSP, this is actually the OSP service registry. Through some magic involving the Remoting toolkit, the sensor objects, which are implemented in C++, can be made available to JavaScript without having to manually write any glue code. To keep things simple, we're identifying sensors by their IDs. We could also search for sensors having specific capabilities. Another aspect this sample shows is how the POCO logging framework is also available from JavaScript.
The next sample shows how to make the sensor data from the database available via the web server as a JSON document. This can be used to show nice-looking charts using a client-side JavaScript toolkit such as KendoUI DataViz.
var dbPath = application.config.getString('logger.database');
var dbSession = new DBSession('SQLite', dbPath);
dbSession.pageSize = 20;
var recordSet = dbSession.execute(
'SELECT timestamp, temperature FROM datalog ORDER BY timestamp DESC'
);
var data = [];
for (var row = 0; row < recordSet.rowCount; row++)
{
var time = recordSet.getValue('timestamp');
var temp = recordSet.getValue('temperature');
var date = DateTime('1970-01-01');
date.addSeconds(time);
data[recordSet.rowCount - row - 1] =
{
timestamp: date.format('%H:%M:%S'),
temperature: temp
};
recordSet.moveNext();
}
recordSet.close();
response.contentType = 'application/json';
response.write(JSON.stringify(data));
response.send();
This script is actually registered with the OSP web server and executed whenever the /dataviz/temperature.jss page is requested by a client. We're basically getting data (the 20 most recent values) from the database table, packing them into an array, then serializing the array as JSON and returning it as HTTP response.
Finally, let's see how to send sensor data to a cloud service. In the particular case, we're using the Sierra Wireless AirVantage M2M Cloud service, which offers a nice REST interface for sending sensor values.
include('sensors.js');
var username = application.config.getString("airvantage.username");
var password = application.config.getString("airvantage.password");
setInterval(
function()
{
var httpRequest = new HTTPRequest(
'POST',
'https://na.airvantage.net/device/messages'
);
var epoch = 1000*DateTime().epoch; // seconds to milliseconds
httpRequest.timeout = 10.0;
httpRequest.authenticate(username, password);
httpRequest.content =
'[ \
{ \
"sensor.temperature": [ \
{ \
"timestamp" : ' + epoch + ', \
"value" : ' + sensors.temperature.value() + ' \
} \
], \
"sensor.light": [ \
{ \
"timestamp" : ' + epoch + ', \
"value" : ' + sensors.ambientLight.value() + ' \
} \
] \
} \
]';
var httpResponse = httpRequest.send();
if (httpResponse.status != 200)
{
logger.error(
"Failed sending data to AirVantage: "
+ httpResponse.reason
);
}
},
30000);
Like in the first sample, we're using a timer to send sensor values periodically (every 30 seconds). We create a HTTPRequest object, use HTTP Basic Authentication to authenticate the request (username and password for the cloud service are obtained from the application's configuration file), create a JSON document containing the sensor values as request body and send the data securely using HTTPS.
That's all for now. Stay tuned for more announcements about Macchina.io in the coming weeks!