The aws-iot-device-sdk.js package allows developers to write JavaScript applications which access the AWS IoT Platform; it is intended for use in embedded devices which support Node.js, but it can be used in other Node.js environments as well.
This document provides instructions on how to install and configure the AWS IoT device SDK for Node.js and includes examples demonstrating use of the SDK APIs.
This package is built on top of mqtt.js and provides two classes: 'device' and 'thingShadow'. The 'device' class loosely wraps mqtt.js to provide a secure connection to the AWS IoT platform and expose the mqtt.js interfaces upward via an instance of the mqtt client.
The 'thingShadow' class implements additional functionality for accessing Thing Shadows via the AWS IoT API; the thingShadow class allows devices to update, be notified of changes to, get the current state of, or delete Thing Shadows from AWS IoT. Thing Shadows allow applications and devices to synchronize their state on the AWS IoT platform. For example, a remote device can update its Thing Shadow in AWS IoT, allowing a user to view the device's last reported state via a mobile app. The user can also update the device's Thing Shadow in AWS IoT and the remote device will synchronize with the new state. The 'thingShadow' class supports multiple Thing Shadows per mqtt connection and allows pass-through of non-Thing-Shadow topics and mqtt events.
Installing with npm:
npm install aws-iot-device-sdk
Installing from github:
git clone https://github.com/aws/aws-iot-device-sdk-js.git
cd aws-iot-device-sdk-js
npm install mqtt
npm install blessed
npm install blessed-contrib
Note that the dependencies on 'blessed' and 'blessed-contrib' are required only for the temperature-control.js example program and will not be necessary in most application environments.
var awsIot = require('aws-iot-device-sdk');
var device = awsIot.device({
keyPath: '~/awsCerts/private.pem.key',
certPath: '~/awsCerts/certificate.pem.crt',
caPath: '~/awsCerts/root-CA.crt',
clientId: 'myAwsClientId',
region: 'us-east-1'
});
//
// Device is an instance returned by mqtt.Client(), see mqtt.js for full
// documentation.
//
device
.on('connect', function() {
console.log('connect');
device.subscribe('topic_1');
device.publish('topic_2', JSON.stringify({ test_data: 1}));
});
device
.on('message', function(topic, payload) {
console.log('message', topic, payload.toString());
});
var awsIot = require('aws-iot-device-sdk');
var thingShadows = awsIot.thingShadow({
keyPath: '~/awsCerts/private.pem.key',
certPath: '~/awsCerts/certificate.pem.crt',
caPath: '~/awsCerts/root-CA.crt',
clientId: 'myAwsClientId',
region: 'us-east-1'
});
//
// Thing shadow state
//
var rgbLedLampState = {"state":{"desired":{"red":187,"green":114,"blue":222}}};
//
// Client token value returned from thingShadows.update() operation
//
var clientTokenUpdate;
thingShadows.on('connect', function() {
//
// After connecting to the AWS IoT platform, register interest in the
// Thing Shadow named 'RGBLedLamp'.
//
thingShadows.register( 'RGBLedLamp' );
//
// 2 seconds after registering, update the Thing Shadow named
// 'RGBLedLamp' with the latest device state and save the clientToken
// so that we can correlate it with status or timeout events.
//
// Note that the delay is not required for subsequent updates; only
// the first update after a Thing Shadow registration using default
// parameters requires a delay. See API documentation for the update
// method for more details.
//
setTimeout( function() {
clientTokenUpdate = thingShadows.update('RGBLedLamp', rgbLedLampState );
}, 2000 );
});
thingShadows.on('status',
function(thingName, stat, clientToken, stateObject) {
console.log('received '+stat+' on '+thingName+': '+
JSON.stringify(stateObject));
});
thingShadows.on('delta',
function(thingName, stateObject) {
console.log('received delta '+' on '+thingName+': '+
JSON.stringify(stateObject));
});
thingShadows.on('timeout',
function(thingName, clientToken) {
console.log('received timeout '+' on '+operation+': '+
clientToken);
});
awsIot.device()
awsIot.thingShadow()
awsIot.thingShadow#register()
awsIot.thingShadow#unregister()
awsIot.thingShadow#update()
awsIot.thingShadow#get()
awsIot.thingShadow#delete()
awsIot.thingShadow#publish()
awsIot.thingShadow#subscribe()
awsIot.thingShadow#unsubscribe()
Returns an instance of the mqtt.Client()
class, configured for a TLS connection with the AWS IoT platform and with
arguments as specified in options
. The awsIot-specific arguments are as
follows:
region
: the AWS IoT region you will operate in (default 'us-east-1')clientId
: the client ID you will use to connect to AWS IoTcertPath
: path of the client certificate associated with your AWS accountkeyPath
: path of the private key file for your client certificatecaPath
: path of your CA certificate
options
also contains arguments specific to mqtt. See [the mqtt client documentation]
(https://github.com/mqttjs/MQTT.js/blob/master/README.md#client) for details
of these arguments.
Supports all events emitted by the mqtt.Client() class.
The thingShadow
class wraps an instance of the device
class with additional
functionality to operate on Thing Shadows via the AWS IoT API. The
arguments in options
include all those in the device class, with
the addition of the following arguments specific to the thingShadow
class:
operationTimeout
: the timeout for thing operations (default 30 seconds)postSubscribeTimeout
: the time to wait after subscribing to an operation's sub-topics prior to publishing on the operation's topic (default 2.2 seconds)
Supports all events emitted by the mqtt.Client() class; however, the semantics for the
message
event are slightly different and additional events are available
as described below:
function(topic, message) {}
Emitted when a message is received on a topic not related to any Thing Shadows:
topic
topic of the received packetmessage
payload of the received packet
function(thingName, stat, clientToken, stateObject) {}
Emitted when an operation update|get|delete
completes.
thingName
name of the Thing Shadow for which the operation has completedstat
status of the operationaccepted|rejected
clientToken
the operation's clientTokenstateObject
the stateObject returned for the operation
Applications can use clientToken values to correlate status events with the operations that they are associated with by saving the clientTokens returned from each operation.
function(thingName, stateObject) {}
Emitted when a delta has been received for a registered Thing Shadow.
thingName
name of the Thing Shadow that has received a deltastateObject
the stateObject returned for the operation
function(thingName, clientToken) {}
Emitted when an operation update|get|delete
has timed out.
thingName
name of the Thing Shadow that has received a timeoutclientToken
the operation's clientToken
Applications can use clientToken values to correlate timeout events with the operations that they are associated with by saving the clientTokens returned from each operation.
Register interest in the Thing Shadow named thingName
. The thingShadow class will
subscribe to any applicable topics, and will fire events for the Thing Shadow
until awsIot.thingShadow#unregister() is called with thingName
. options
can contain the following arguments to modify how this Thing Shadow is processed:
ignoreDeltas
: set totrue
to not subscribe to thedelta
sub-topic for this Thing Shadow; used in cases where the application is not interested in changes (e.g. update only.) (defaultfalse
)persistentSubscribe
: set tofalse
to unsubscribe from all operation sub-topics while not performing an operation (defaulttrue
)discardStale
: set tofalse
to allow receiving messages with old version numbers (defaulttrue
)
The persistentSubscribe
argument allows an application to get faster operation
responses at the expense of potentially receiving more irrelevant response
traffic (i.e., response traffic for other clients who have registered interest
in the same Thing Shadow). When persistentSubscribe
is set to true
(the default),
postSubscribeTimeout
is forced to 0 and the thingShadow
class will publish
immediately on any update, get, or delete operation for this registered Thing Shadow.
When set to false
, operation sub-topics are only subscribed to during the scope
of that operation; note that in this mode, update, get, and delete operations will
be much slower; however, the application will be less likely to receive irrelevant
response traffic.
Note that when persistentSubscribe
is set to true
(the default), you must wait the postSubscribeTimeout
(default 2.2 seconds) between registering interest in the Thing Shadow and performing the first update to it. After this time interval has expired, you can update the Thing Shadow without waiting.
The discardStale
argument allows applications to receive messages which have
obsolete version numbers. This can happen when messages are received out-of-order;
applications which set this argument to false
should use other methods to
determine how to treat the data (e.g. use a time stamp property to know how old/stale
it is).
Unregister interest in the Thing Shadow named thingName
. The thingShadow class
will unsubscribe from all applicable topics and no more events will be fired
for thingName
.
Update the Thing Shadow named thingName
with the state specified in the
JavaScript object stateObject
. thingName
must have been previously
registered
using awsIot.thingShadow#register(). The thingShadow class will subscribe
to all applicable topics and publish stateObject
on the update sub-topic.
This function returns a clientToken
, which is a unique value associated with
the update operation. When a 'status' or 'timeout' event is emitted,
the clientToken
will be supplied as one of the parameters, allowing the
application to keep track of the status of each operation. The caller may
create their own clientToken
value; if stateObject
contains a clientToken
property, that will be used rather than the internally generated value. Note
that it should be of atomic type (i.e. numeric or string).
Get the current state of the Thing Shadow named thingName
, which must have
been previously registered using awsIot.thingShadow#register(). The
thingShadow class will subscribe to all applicable topics and publish on the
get sub-topic.
This function returns a clientToken
, which is a unique value associated with
the get operation. When a 'status or 'timeout' event is emitted,
the clientToken
will be supplied as one of the parameters, allowing the
application to keep track of the status of each operation. The caller may
supply their own clientToken
value (optional); if supplied, the value of
clientToken
will be used rather than the internally generated value. Note
that this value should be of atomic type (i.e. numeric or string).
Delete the Thing Shadow named thingName
, which must have been previously
registered using awsIot.thingShadow#register(). The thingShadow class
will subscribe to all applicable topics and publish on the delete
sub-topic.
This function returns a clientToken
, which is a unique value associated with
the delete operation. When a 'status' or 'timeout' event is emitted,
the clientToken
will be supplied as one of the parameters, allowing the
application to keep track of the status of each operation. The caller may
supply their own clientToken
value (optional); if supplied, the value of
clientToken
will be used rather than the internally generated value. Note
that this value should be of atomic type (i.e. numeric or string).
Identical to the mqtt.Client#publish() method, with the restriction that the topic may not represent a Thing Shadow. This method allows the user to publish messages to topics on the same connection used to access Thing Shadows.
Identical to the mqtt.Client#subscribe() method, with the restriction that the topic may not represent a Thing Shadow. This method allows the user to subscribe to messages from topics on the same connection used to access Thing Shadows.
Identical to the mqtt.Client#unsubscribe() method, with the restriction that the topic may not represent a Thing Shadow. This method allows the user to unsubscribe from topics on the same used to access Thing Shadows.
The 'examples' directory contains several programs which demonstrate usage of the AWS IoT APIs:
-
device-example.js: demonstrate simple MQTT publish and subscribe operations.
-
echo-example.js: test Thing Shadow operation by echoing all delta state updates to the update topic; used in conjunction with the AWS IoT Console to verify connectivity with the AWS IoT platform.
-
thing-example.js: use a Thing Shadow to automatically synchronize state between a simulated device and a control application.
-
thing-passthrough-example.js: demonstrate use of a Thing Shadow with pasthrough of standard MQTT publish and subscribe messages.
-
temperature-control.js: an interactive device simulation which uses Thing Shadows.
The example programs use command line parameters to set options. To see the available options, run the program and specify the '-h' option as follows:
node examples/<EXAMPLE-PROGRAM> -h
The example programs require certificates (created using either the AWS IoT Console or the AWS IoT CLI) in order to authenticate with AWS IoT. Each example program uses command line options to specify the names and/or locations of certificates as follows:
-f, --certificate-dir=DIR look in DIR for certificates
The --certificate-dir (-f) option will read all certificates from the directory specified. Default certificate names are as follows:
- certificate.pem.crt: your AWS IoT certificate
- private.pem.key: the private key associated with your AWS IoT certificate
- root-CA.crt: the root CA certificate (available from Symantec here)
-k, --private-key=FILE use FILE as private key
-c, --client-certificate=FILE use FILE as client certificate
-a, --ca-certificate=FILE use FILE as CA certificate
The '-f' (certificate directory) option can be combined with these so that you don't have to specify absolute pathnames for each file.
The AWS IoT Console can generate JSON configuration data specifying the parameters required to connect a device to the AWS IoT Platform. The JSON configuration data includes pathnames to certificates, the hostname and port number, etc... The command line option '--configuration-file (-F)' is used when reading parameters from a configuration file.
-F, --configuration-file=FILE use FILE (JSON format) for configuration
The configuration file is in JSON format, and may contain the following properties:
- host - the host name to connect to
- port - the port number to use when connecting to the host (8883 for AWS IoT)
- clientId - the client ID to use when connecting
- privateKey - file containing the private key
- clientCert - file containing the client certificate
- caCert - file containing the CA certificate
- thingName - thing name to use
The '-f' (certificate directory) and '-F' (configuration file) options can be combined so that you don't have to use absolute pathnames in the configuration file.
device-example.js is run as two processes which communicate with one another via the AWS IoT platform using MQTT publish and subscribe. The command line option '--test-mode (-t)' is used to set which role each process performs. It's easiest to run each process in its own terminal window so that you can see the output generated by each. Note that in the following examples, all certificates are located in the ~/certs directory and have the default names as specified in the Certificates section.
node examples/device-example.js -f ~/certs --test-mode=1
node examples/device-example.js -f ~/certs --test-mode=2
Similar to device-example.js, thing-example.js is also run as two processes which communicate with one another via the AWS IoT platform. thing-example.js uses a Thing Shadow to synchronize state between the two processes, and the command line option '--test-mode (-t)' is used to set which role each process performs. As with device-example.js, it's best to run each process in its own terminal window. Note that in the following examples, all certificates are located in the ~/certs directory and have the default names as specified in the Certificates section.
node examples/thing-example.js -f ~/certs --test-mode=1
node examples/thing-example.js -f ~/certs --test-mode=2
Similar to thing-example.js, thing-passthrough-example.js is also run as two processes which communicate with one another via the AWS IoT platform. thing-passthrough-example.js uses a Thing Shadow to synchronize state from one process to another, and uses MQTT publish/subscribe to send information in the other direction. The command line option '--test-mode (-t)' is used to set which role each process performs. As with thing-example.js, it's best to run each process in its own terminal window. Note that in the following examples, all certificates are located in the ~/certs directory and have the default names as specified in the Certificates section.
node examples/thing-passthrough-example.js -f ~/certs --test-mode=1
node examples/thing-passthrough-example.js -f ~/certs --test-mode=2
echo-example.js is used in conjunction with the AWS Iot Console to verify connectivity with the AWS IoT platform and to perform interactive observation of Thing Shadow operation. In the following example, the program is run using the configuration file '../config.json', and the certificates are located in the '~/certs' directory. Here, the '-f' (certificate directory) and '-F' (configuration file) options are combined so that the configuration file doesn't need to contain absolute pathnames.
node examples/echo-example.js -F ../config.json -f ~/certs --thing-name testThing1
temperature-control.js is an interactive simulation which demonstrates how Thing Shadows can be used to easily synchronize applications and internet-connected devices.
Like thing-example.js, temperature-control.js runs in two separate terminal windows and is configured via command-line options; in the following example, all certificates are located in the ~/certs directory and have the default names as specified in the Certificates section. The process running with '--test-mode=2' simulates an internet-connected temperature control device, and the process running with '--test-mode=1' simulates a mobile application which is monitoring/controlling it. The processes may be run on different hosts if desired.
temperature-control.js uses the blessed.js and blessed-contrib.js libraries to provide an interactive terminal interface; it looks best on an 80x25 terminal with a black background and white or green text and requires UTF-8 character encoding.
node examples/temperature-control.js -f ~/certs --test-mode=1
node examples/temperature-control.js -f ~/certs --test-mode=2
The simulated temperature control device has two controls; Setpoint and Status. Status controls whether or not the device is active, and Setpoint controls the interior temperature the device will attempt to achieve. In addition, the device reports the current interior and exterior temperatures as well as its operating state (heating, cooling, or stopped).
Two Thing Shadows are used to connect the simulated device and mobile application; one contains the controls and the other contains the measured temperatures and operating state. Both processes can update the controls, but only the device can update the measured temperatures and the operating state.
Controlling the simulation is done using the up, down, left, right, and Enter keys as follows:
- up increase the Setpoint
- down decrease the Setpoint
- left move left on the menu bar
- right move right on the menu bar
- Enter select the current menu option
The operating state of the device is indicated by the color of the Interior temperature field as follows:
- Red: heating
- Cyan: cooling
- White: stopped
The following example shows the temperature control simulation in 'device' mode while the operating state is 'heating'.
The log window displays events of interest, e.g. network connectivity, Status toggles, re-synchronization with the Thing Shadow, etc...
- Mode: Toggle the device Status. Status can be controlled from both the simulated device and the mobile application.
- Network: Toggle the network connectivity of the device or mobile application; this can be used to observe how both sides re-synchronize when connectivity is restored.
In this example, the mobile application is disconnected from the network. Although it has requested that the Setpoint be lowered to 58 degrees, the command can't be sent to the device as there is no network connectivity, so the operating state still shows as 'stopped'. When the mobile application is reconnected to the network, it will attempt to update the Thing Shadow for the device's controls; if no control changes have been made on the device side during the disconnection period, the device will synchronize to the mobile application's requested state; otherwise, the mobile application will re- synchronize to the device's current state.
The simulation can be exited at any time by pressing q, Ctrl+c, or by selecting 'exit' on the menu bar.
This SDK is distributed under the Apache License, Version 2.0, see LICENSE.txt and NOTICE.txt for more information.
If you have technical questions about AWS IoT Device SDK, use the AWS IoT Forum. For any other questions on AWS IoT, contact AWS Support.