"Boost Your Digital Presence: Partner with a Leading SEO Agency"
Programming IoT Gateways in JavaScript with macchina.io
1. Programming IoT Gateways
in JavaScript with macchina.io
Günter Obiltschnig
Applied Informatics Software Engineering GmbH
guenter@appinf.com
@obiltschnig, @macchina_io
2. About Me
hard-core C++ developer (20+ years), who also likes JavaScript
“full stack++”, embedded, hardware to web frontend + cloud
POCO C++ Libraries (2004)
Applied Informatics GmbH (2006)
my-devices.net (2010)
AIS Radar for iOS (2011)
macchina.io (2013)
3. m .ioacchina
A modular open source toolkit for building embedded IoT
applications that connect sensors, devices and cloud services.
6. > open source (Apache 2.0 License)
> built in C++ for best performance and efficiency
(JavaScript for parts of web interface)
> modular and extensible
> mature, proven codebase:
POCO C++ Libraries, Google V8, Eclipse Paho, SQLite
AngularJS, jQuery, OpenLayers, Ace (text editor),
+ Applied Informatics OSP and Remoting frameworks
> C++-to-JavaScript bridge
> Raspberry Pi, Beaglebone, Edison, RED, MangOH, etc.
> prototype on Linux or OS X host, easily deploy to device
> web interface with JavaScript editor
7. Sensors & Devices Protocols Cloud Services
Temperature, Ambient Light,
Humidity, Air Pressure, etc.
HTTP AirVantage
I/O, Trigger, Rotary Encoder MQTT Bluemix
Accelerometer CoAP* Twitter
GNSS/GPS WebEvent Twilio (SMS)
Barcode Reader, RFID* WebTunnel my-devices.net
XBee (ZigBee, IEEE 802.15.4) XBee API any with HTTP/REST APIs
Serial Port Modbus*, CANopen*
* planned
8. Pro Users and Device Manufacturers
> add device specific APIs
> make devices programmable in JavaScript for partners or end users
> device specific app store (sell additional software features)
> additional frameworks (UPnP, Remoting SOAP and JSON-RPC)
> customizable web user interface
> improved user authentication and authorization
> signed bundles
> pro support
12. POCO C++ Libraries
> Started 2004
> ~300.000 LOC
> 1000+ classes
> on GitHub since 2012
1000+ stars
400+ forks
30-50 clones/day
> ~100 contributors
> Boost License
> http://pocoproject.org
POSIX, WIN32, other (RT)OS API
Foundation
C++ and C Standard LibrariesApplication
Zip
Net
Crypto
Data
SQLite
ODBC
MySQL
NetSSL
Util
Tools, Utilities and
additional Libraries
XML JSON
13. V8
> Google’s JavaScript Engine
> Used by Chrome/Chromium and node.js
> C++ library, (reasonably) easy to integrate and to extend
> Compiles JavaScript to native code (x86, ARM, MIPS)
> Great performance
> BSD License
14. Remoting
> Similar to .NET Remoting or Java RMI, but for C++
> Code generator parses annotated C++ header files and generates code
(serialization/deserialization, method dispatching, helpers)
> Supports different transports (binary TCP, SOAP, JSON-RPC)
> Used for automatic C++-to-JavaScript bridging
> Will also be used to implement sandbox mechanism
15. Open Service Platform (OSP)
> Inspired by OSGi, but for C++ (also JavaScript, Python, etc.)
> Dynamic module system based on bundles
(Zip files with metadata,
shared libs, other files)
> Dependency and
lifecycle management
> Services and service registry
> Web Server
POCO Core Libraries
(Foundation,XML,Util,Net)
Operating
System
API
Std.C/C++
Libraries
Service
Registry
Portable Runtime
Environment
Life
C
ycle
M
anagem
ent
Bundle
M
anagem
ent
Standard
Services
Bundles
install,resolve,start,stop
and uninstall bundles
provide services to other
bundles and find services
provided by other bundles
manage bundle versions
and dependencies
web server,
web- and console-
based management,
user authentication
and authorization,
preferences,etc.
application-specific
functionality and services
16. Combining POCO C++ Libraries and V8
> JavaScript is single-threaded and garbage-collected
> POCO is multithreaded (specifically web server)
> Make C++ object available to JavaScript
easy for static objects, just provide Wrapper
> Allow JavaScript code to create C++ objects
easy if you don’t care about memory/resource leaks
> Register a callback function called by GC when object is deleted
allows you to properly delete underlying c++ object
> However, V8 does not do callbacks when script ends
wrapped C++ objects won’t be deleted, leaks resulting
> Need to track every C++ object a script creates and clean up afterwards :-(
20. Service
<<generatedFrom>>
IService
ServiceProxy
Service
RemoteObject
The interface class has
all @remote methods
from the service class.
Service
Skeleton
<<invokes>>
<<generated>>
<<generated>><<generated>>
<<generated>>
Service
ServerHelper
<<generated>>
Registers
Skeleton, RemoteObject
and EventDispatcher (if
needed) with the Object
Request Broker.
Service
ProxyFactory
<<creates>>
<<generated>>
Service
ClientHelper
<<generated>>
Registers ProxyFactory
with the Object Request
Broker.
<<registers>><<registers>>
<<registers>>
Service
EventSubscriber
<<generated>>
Service
EventDispatcher
<<generated>>
<<registers>>
21. var tempSensor = ...;
tempSensor.on(‘valueChanged', function(ev) {
var temp = ev.data;
// ...
});
if (tempSensor.ready())
{
var temp = tempSensor.value();
// ...
}
28. // history.jss
var db = require(‘../database.js');
var validItems = ['temperature', 'humidity', 'illuminance'];
var data = [];
db.session.pageSize = form.maxItems ? parseInt(form.maxItems) : 20;
var item = form.item;
if (validItems.indexOf(item) > -1)
{
var recordSet = db.session.execute(
'SELECT timestamp, ' + item + ' FROM datalog ORDER BY timestamp DESC');
29. // history.jss (continued)
for (var row = 0; row < recordSet.rowCount; row++)
{
var time = recordSet.getValue('timestamp');
var value = recordSet.getValue(item);
var date = LocalDateTime('1970-01-01');
date.addSeconds(time);
data[recordSet.rowCount - row - 1] =
{
timestamp: date.format('%H:%M:%S'),
value: value
};
recordSet.moveNext();
}
recordSet.close();
}
response.contentType = 'application/json';
response.write(JSON.stringify(data));
response.send();
30. // MQTT to AirVantage
var sensors = require('sensors.js');
var mqttClientRefs = serviceRegistry.find(
'io.macchina.mqtt.serverURI == "tcp://na.airvantage.net:1883"');
if (mqttClientRefs.length > 0)
{
logger.information("MQTT Client found!");
var mqttClient = mqttClientRefs[0].instance();
setInterval(function() {
var epoch = "" + 1000*DateTime().epoch; // seconds to milliseconds
var payload = {};
payload[epoch] = {
"sensors.temperature": sensors.temperature.value(),
"sensors.humidity": sensors.humidity.value()
"sensors.illuminance": sensors.illuminance.value()
};
mqttClient.publish('JA347400060803/messages/json',
JSON.stringify(payload), 0);
}, 10000);
}
31. // Send SMS via Twilio
function sendSMS(to, message)
{
var accountSID = application.config.getString("twilio.accountSID");
var authToken = application.config.getString("twilio.authToken");
var from = application.config.getString(“twilio.from");
var twilioHttpRequest = new HTTPRequest(
"POST",
"https://api.twilio.com/2010-04-01/Accounts/"
+ accountSID
+ "/SMS/Messages"
);
twilioHttpRequest.authenticate(accountSID, authToken);
twilioHttpRequest.contentType = "application/x-www-form-urlencoded";
twilioHttpRequest.content =
"From=" + encodeURIComponent(from) +
"&To=" + encodeURIComponent(to) +
"&Body=" + encodeURIComponent(message);
twilioHttpRequest.send(function(result) {
logger.information("Twilio SMS Response: ",
result.response.status,
result.response.content);
});
}
32. var sensors = require('sensors.js');
var enableSMS = true;
sensors.illuminance.on('valueChanged', function(ev) {
logger.notice("valueChanged: " + ev.data);
if (ev.data < 10)
{
logger.warning("Lights out!");
if (enableSMS)
{
sendSMS("+436765166737", "Lights out!");
enableSMS = false;
}
}
else if (ev.data > 50)
{
enableSMS = true;
}
});