The Technology Stack Blocks


Web User Interface comes with a built-in web server providing different web apps for device management, testing and getting started with JavaScript development. These can be modified or replaced with a device-specific interface and apps. In any case, the web server is just another plug-in, so it can even be removed entirely if not needed.



Sensors and other devices are presented as services that can be searched for based on various properties. In the following sample, we look for an ambient light (luminance) and a temperature sensor. The code that looks for sensors is implemented as a module and can be imported using the familiar require() function.

var sensors = {};

var ambientLightRefs = serviceRegistry.find('io.macchina.physicalQuantity == "luminance"');
if (ambientLightRefs.length > 0)
    sensors.ambientLight = ambientLightRefs[0].instance();
    logger.information('Ambient Light: ' + sensors.ambientLight.getPropertyString('name'));

var temperatureRefs = serviceRegistry.find('io.macchina.physicalQuantity == "temperature"');
if (temperatureRefs.length > 0)
    sensors.temperature = temperatureRefs[0].instance();
    logger.information('Temperature: ' + sensors.temperature.getPropertyString('name'));

module.exports = sensors;


Once we have a sensor object, we can get a callback whenever the measured value changes. In the following example, we write the current sensor value into a SQLite database, together with a timestamp.

var data = require('data');
var sensors = require("sensors.js");

var dbPath = application.config.getString('datalogger.database');
var dbSession = new data.DBSession('SQLite', dbPath);

    function (event)
        dbSession.execute('INSERT INTO datalog VALUES (?, ?)',

Serial Port

Many devices provide a serial (UART) interface and support a simple text-based protocol. It's easy to process data received from such devices.

var serial = null;
var serialRef = serviceRegistry.findByName('io.macchina.serialport#0');
if (serialRef)
    serial = serialRef.instance();
    logger.notice("SerialDevice found: " + serial.getPropertyString("device"));

serial.setFeature("events", true);
serial.setPropertyString("delimiters", "\n");
serial.setPropertyDouble("timeout", 0.1);
        logger.notice("Received: " +;

Cloud Services

The following example shows how to send data to a cloud service providing a REST interface. We periodically obtain temperature and ambient light measurements and send them to the AirVantage M2M Cloud service.

var net = require('net');
var sensors = require('sensors.js');

var username = application.config.getString("airvantage.username");
var password = application.config.getString("airvantage.password");

        var httpRequest = new net.HTTPRequest('POST', '');
        var epoch = 1000*DateTime().epoch; // seconds to milliseconds
        httpRequest.timeout = 10.0;
        httpRequest.authenticate(username, password);
        httpRequest.content = JSON.stringify(
                                "timestamp": epoch,
                                "value": sensors.temperature.value()
                                "timestamp": epoch,
                                "value": sensors.ambientLight.value()
        var httpResponse = httpRequest.send();
        if (httpResponse.status != 200)
            logger.error("Failed sending data to AirVantage: " + httpResponse.reason);

The above sample blocks in send() until the HTTP request has been completed. HTTP requests can also be sent asynchronously. In this case, a callback function will be called when the request has completed.

        // ...
            function (result)
                if (result.error)
                else if (result.response.status != 200)
                    logger.error("HTTP request failed: " + result.response.reason);
        // ...


The following example shows how to implement a servlet in JavaScript that reads sensor data from the SQLite database and formats it as JSON.

var data = require('data');

var dbPath = application.config.getString('logger.database');
var dbSession = new data.DBSession('SQLite', dbPath);
dbSession.pageSize = 20;

var recordSet = dbSession.execute('SELECT timestamp, temperature FROM datalog ORDER BY timestamp DESC');
response.contentType = 'application/json';

Frequently Asked Questions

What sensors and devices are supported? currently supports the following sensors and devices:

  • Tinkerforge bricklets: Ambient Light, Barometer, Dual Button, GPS, Humidity, IO-4, Motion Detector, Rotary Encoder, Temperature.
  • XBee® ZB Sensors (combined temperature, humidity and light).
  • GPS/GNSS receivers via serial port NMEA 0183 protocol.
  • Devices connected via UART/RS-232 ports.
  • GPIO ports (via Linux sysfs interface).
  • Temperature, humidity, light and other environmental sensors.
  • 3-Axis accelerometers, magnetometers, gyroscopes.
  • Multi-sensor devices like Bosch XDK (via Bluetooth LE) and CISS (via USB), as well as TI SensorTag (via Bluetooth LE).

Support for additional devices is added on an ongoing basis.

What OS platforms are supported? currently supports Linux (ARM and Intel) and macOS. Most of the code is platform independent and compiles on all platforms supported by the POCO C++ Libraries (including Windows and Windows Embedded Compact). However, the build system currently only supports Linux and OS X, specifically when it comes to building the V8 engine. Android should work as well, but is currently untested.

What features require a commercial license?

The following features are not part of the open source version and require a commercial license:

  • REST, SOAP and JSON-RPC web services (client and server).
  • UPnP™ support.
  • Cryptographically signed bundles for secure software updates and implementation of device specific app stores.
  • App/Bundle Sandboxing with entitlements for securely running third-party applications within
  • Advanced, database-based user authentication and authorization with optional LDAP integration.
  • An extensible command line interface framework.

How is different from node.js?

While both and node.js/io.js use the same underlying JavaScript engine (V8), there are significant differences:

  • supports multiple concurrent, but independent scripts, each one running in its own thread.
  • The JavaScript programming model is not strictly asynchronous. To keep things simple (and avoid callback spaghetti), many calls are blocking, although for lengthier I/O operations callback/event-based interfaces are also available. IoT devices don't have to deal with thousands of concurrent requests, so the focus has been on easy of use rather than ultimate scalability.
  • is entirely implemented in C++.
  • has a generic C++-to-JavaScript bridging mechanism (based on a code generator) that makes it very easy to make C++ objects available to JavaScript.
  • has module system (somewhat inspired by OSGi) that can be used for both C++ and JavaScript code.

What does stand for?

Macchina is the italian word for machine (it's pronounced 'makkina). therefore means machines that input/output information, or machines/devices that communicate.