In this article, we demonstrate and explain how Mongoose OS and AWS IoT implement secure remote device management.
First let me show what is possible, then I'll jump to explanations. I'll start with the meaning of "secure remote device management":

  • Secure: all actions are performed over the authenticated & secure AWS IoT service provided by Amazon.
  • Remote: a managed device could be located anywhere. As soon as it is connected to AWS IoT it can be managed.
  • Device: any hardware architecture supported by Mongoose OS which are currently: ESP32, ESP8266, TI CC3200, STM32 Discovery and STM32 Nucleo boards.
  • Management: pretty much anything: change a file on a filesystem; reboot device; trigger an over-the-air firmware update; read I2C bus; toggle GPIO pin; get device data and more. And do it either through the standard mos utility, or programmatically via API!

Demo part 1. Provision a vanilla new device on AWS IoT. Takes 2 minutes

  • Download Mongoose OS mos utility.
  • Get one of the supported hardware modules (in this example we use Espressif's ESP32 WROOM development board) and connect to your computer via the USB cable.
  • Flash Mongoose OS on the module - this is going to install a default JavaScript-enabled firmware:
mos flash mos-esp32
  • Setup WiFi:
mos wifi YOUR_WIFI_NET YOUR_WIFI_PASS
  • Setup AWS IoT. You need an AWS account for that. This command will provision the device on AWS IoT service. A certificate and a private key file will be created, and placed in the current directory. Change eu-west-1 to another region if you wish. mos-default will create a permissive iot:* policy, use your own pre-created policy if needed:
mos aws-iot-setup --aws-region eu-west-1 --aws-iot-policy mos-default

Demo part 2. Manage a provisioned device.

Start another terminal window in the same directory and make an alias for convenience. Note: we are going to use the certificates generated on provisioning step, in order to connect to AWS IoT. I assume Bash shell is used:

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)"

Now the magic starts! Before all mos commands were using a serial port to communicate with a device. From now on an AWS IoT MQTT will be used instead.

List files on the device:

mos1 ls
api_i2c.js
api_mqtt.js
init.js
...

Get device information:

mos1 call Sys.GetInfo
{
  "app": "mjs_hello",
  "fw_version": "1.0",
  "fw_id": "20170207-110935/???",
  "mac": "240AC400405C",
  "arch": "esp32",
  "uptime": 52,
  "ram_size": 0,
  "ram_free": 145308,
  "ram_min_free": 135516,
  "fs_size": 113201,
  "fs_free": 88101
}

Basically, any command listed by mos --help (except mos flash which uses only serial) works! Anything you can do with the device locally you can now also do via AWS IoT.

How does it all work?

Through the Mongoose OS RPC infrastructure, where RPC means Remote Procedure Call. In Mongoose OS, that is simply a C (or JS) function that:

  • Has a name, for example "GPIO.Toggle",
  • Takes a JSON object with function arguments,
  • Gives back a JSON object with results.

These JSON messages could be carried out by many different channels. Mongoose OS by default supports Serial (UART), HTTP, WebSocket, MQTT channels.

Serial channel is used by the mos tool by default. List files on a device connected via a serial/USB cable:

mos ls

If a device has an IP address, an HTTP channel could be used:

mos --port http://IP/rpc ls

Or, a Websocket channel:

mos --port ws://IP/rpc ls

If a device is connected to MQTT server, an MQTT channels can be used:

mos --port mqtt://MQTT_SERVER:PORT/DEVICE_ID ls

In the demonstration an AWS IoT MQTT channel was used. Since AWS IoT uses mutual TLS authentication, we also specified --cert-file, key-file parameters and mqtts:// as a protocol.

Mongoose OS RPC is cool!

The RPC infrastructure implemented by the Mongoose OS is extremely flexible and extensible. Pretty much any device functionality could be exported as an RPC service, and be called via available channels - using mos utility, or programmatically via the RPC API (which, in essence, just forms a JSON-RPC like messages and sends them over to the device).

Since there are low level hardware RPC services like I2C, it is possible to operate a device from elsewhere. A simple firmware could be written in UNIX shell on your workstation. Or as an AWS Lambda function written in Python or JavaScript or as whatever you want.

You can see all available RPC functions that a device implements by mos call RPC.List. You can add any new RPC service yourself - see https://github.com/cesanta/mongoose-os/tree/master/fw/examples/c_rpc for an example.

That's all. Have a question? Ask on our developer forum or send us a message.