Fork me on GitHub

AWS IoT support for Mongoose OS

This Mongoose OS library allows your device to talk to Amazon AWS IoT service. It implements device shadow API in both C/C++ and JavaScript, allowing a developer to quickly prototype the device logic in JS before jumping to the C/C++ implementation.

mos tool provides mos aws-iot-setup command for quick AWS IoT provisioning. Take a look at the example video that shows how to implement Internet button functionality in less than 2 minutes:

mos aws-iot-setup command performs the certificate management for you, and onboard your device on AWS IoT cloud. If your device has an Atmel ECC508A secure element attached, then Mongoose Firmware will use ECC508A chip for TLS handshake and keep your credentials secure.

How to use this library

In your Mongoose OS app, edit mos.yml file and add a reference to this library. See an example app that does that.

Remote management via AWS IoT

If you're using Bash shell, you can use this alias to talk to your device interactively via AWS IoT:

alias mos1="mos --cert-file $(mos config-get mqtt.ssl_cert) --key-file $(mos config-get mqtt.ssl_key) --port mqtts://$(mos config-get mqtt.server)/$(mos config-get device.id)"
mos1 ls -l
init.js 330
index.html 250
...

For more in-depth explanation, see Secure remote device management with Mongoose OS blog post.

Device configuration

This library adds an aws configuration section to the device:

"aws": {
  "shadow": {
    "thing_name": ""
  }
}

If aws.shadow.thing_name is left empty, then the provisioned device will use a device.id, which is by default <architecture>_<mac_address>. For example, a newly provisioned ESP32 board might have esp32_C513DA thing name.

Other examples

AWS device shadow tutorial

C API Reference mgos_aws_shadow.h

#include "mgos_aws_shadow.h"

View this file on GitHub: mgos_aws_shadow.h


enum mgos_aws_shadow_event {
  MGOS_AWS_SHADOW_CONNECTED = 0,
  MGOS_AWS_SHADOW_GET_ACCEPTED = 1,
  MGOS_AWS_SHADOW_GET_REJECTED = 2,
  MGOS_AWS_SHADOW_UPDATE_ACCEPTED = 3,
  MGOS_AWS_SHADOW_UPDATE_REJECTED = 4,
  MGOS_AWS_SHADOW_UPDATE_DELTA = 5,
};

typedef void (*mgos_aws_shadow_state_handler)(
    void *arg, enum mgos_aws_shadow_event ev, uint64_t version,
    const struct mg_str reported, const struct mg_str desired,
    const struct mg_str reported_md, const struct mg_str desired_md);

Main AWS Device Shadow state callback handler.

Will get invoked when connection is established or when new versions of the state arrive via one of the topics.

CONNECTED event comes with no state.

For DELTA events, state is passed as "desired", reported is not set.

typedef void (*mgos_aws_shadow_error_handler)(void *arg,
                                              enum mgos_aws_shadow_event ev,
                                              int code, const char *message);

void mgos_aws_shadow_set_state_handler(mgos_aws_shadow_state_handler state_cb,
                                       void *arg);

void mgos_aws_shadow_set_error_handler(mgos_aws_shadow_error_handler error_cb,
                                       void *arg);

const char *mgos_aws_shadow_event_name(enum mgos_aws_shadow_event ev);

Returns ascii name of the event: "CONNECTED", "GET_REJECTED", ...

typedef bool (*mgos_aws_shadow_state_handler_simple)(
    void *arg, enum mgos_aws_shadow_event ev, const char *reported,
    const char *desired, const char *reported_md, const char *desired_md);

void mgos_aws_shadow_set_state_handler_simple(
    mgos_aws_shadow_state_handler_simple state_cb_simple, void *arg);

"Simple" version of mgos_aws_shadow_set_state_handler, primarily for FFI.

bool mgos_aws_shadow_get(void);

Request shadow state. Response will arrive via GET_ACCEPTED topic. Note that MGOS automatically does this on every (re)connect if aws.shadow.get_on_connect is true (default).

bool mgos_aws_shadow_updatef(uint64_t version, const char *state_jsonf, ...);

Send an update. Format string should define the value of the "state" key, i.e. it should be an object with "reported" and/or "desired" keys, e.g.: mgos_aws_shadow_updatef("{reported:{foo: %d, bar: %d}}", foo, bar). Response will arrive via UPDATE_ACCEPTED or REJECTED topic. If you want the update to be aplied only if a particular version is current, specify the version. Otherwise set it to 0 to apply to any version.

bool mgos_aws_shadow_update_simple(double version, const char *state_json);

"Simple" version of mgos_aws_shadow_updatef, primarily for FFI.

JAVASCRIPT API Reference api_aws.js

load("api_aws.js");


AWS.Shadow.setStateHandler(callback, userdata)

Set AWS shadow state handler callback.

When AWS shadow state changes, the callback is called with the following arguments: (userdata, event, reported, desired), where userdata is the userdata given to setStateHandler, event is one of the following: AWS.Shadow.CONNECTED, AWS.Shadow.GET_ACCEPTED, AWS.Shadow.GET_REJECTED, AWS.Shadow.UPDATE_ACCEPTED, AWS.Shadow.UPDATE_REJECTED, AWS.Shadow.UPDATE_DELTA. reported is previously reported state object (if any), and desired is the desired state (if present).

Example:

let state = { on: false, counter: 0 };  // device state: shadow metadata

// Upon startup, report current actual state, "reported"
// When cloud sends us a command to update state ("desired"), do it
AWS.Shadow.setStateHandler(function(data, event, reported, desired) {
  if (event === AWS.Shadow.CONNECTED) {
    AWS.Shadow.update(0, {reported: state});  // Report device state
  } else if (event === AWS.Shadow.UPDATE_DELTA) {
    for (let key in state) {
      if (desired[key] !== undefined) state[key] = desired[key];
    }
    AWS.Shadow.update(0, {reported: state});  // Report device state
  }
  print(JSON.stringify(reported), JSON.stringify(desired));
}, null);

AWS.Shadow.get()

Request shadow state. The event handler will receive a GET_ACCEPTED event.

AWS.Shadow.getVersion();

Return last shadow state version.

AWS.Shadow.update(version, state);

Update AWS shadow state.

State should be an object with "reported" and/or "desired" keys.

Response will arrive via UPDATE_ACCEPTED or UPDATE_REJECTED events. If you want the update to be aplied only if a particular version is current, specify the version. Otherwise set it to 0 to apply to any version.

Example:

// On a button press, update press counter via the shadow
let buttonPin = 0;
GPIO.set_button_handler(buttonPin, GPIO.PULL_UP, GPIO.INT_EDGE_NEG, 200, function() {
  AWS.Shadow.update(0, {desired: {on: state.on, counter: state.counter + 1}});
}, null);