Skip to content

Node-RED Setup

Overview

The Node-RED programming tool provides configurable HTTP and MQTT nodes capable of secure communication with Exosite's Device APIs, enabling you to quickly start gaining insight into the health of your Asset using ExoSense.

General Setup

If it is not already, start Node-RED and launch the GUI - e.g. by opening http://127.0.0.1:1880/ in your browser.

Default Starting View

By default Node-RED may launch with an initial blank flow ("Flow 1"), for example: Default Node-RED page

Import Flows

To enable use of pre-defined flows Node-RED supports the exporting and importing of flow definitions in JSON format. The example below - Example Flows - includes boilerplate flows for both HTTP and MQTT communication with Exosite's Device APIs.

Example Flows

[{"id":"437a9d6d.95ecc4","type":"tab","label":"HTTP","disabled":true,"info":""},{"id":"1c17e3fe.19f42c","type":"tab","label":"MQTT","disabled":true,"info":""},{"id":"5e91c58.8bc983c","type":"subflow","name":"HTTP Provision","info":"","category":"","in":[{"x":20,"y":160,"wires":[{"id":"4711cd79.823434"}]}],"out":[{"x":1720,"y":160,"wires":[{"id":"69de45a3.3aaf7c","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"5303e7d4.f58bc8","type":"subflow","name":"HTTP Post Config","info":"","category":"","in":[{"x":20,"y":160,"wires":[{"id":"1490875e.8483b9"}]}],"out":[{"x":1080,"y":160,"wires":[{"id":"2e7b6d53.fcc182","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"fcf4ba66.688748","type":"subflow","name":"HTTP Post Data","info":"","category":"","in":[{"x":20,"y":160,"wires":[{"id":"751d9da2.6c0d74"}]}],"out":[{"x":1060,"y":160,"wires":[{"id":"4b234547.15115c","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"65302557.9e299c","type":"subflow","name":"HTTP Device Definition","info":"","category":"","in":[{"x":40,"y":100,"wires":[{"id":"c9b10a78.1700a8"}]}],"out":[{"x":880,"y":100,"wires":[{"id":"32ee44f1.57f53c","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"cc6d5451.fb9658","type":"tls-config","name":"HTTP IoT Connector (TLS)","cert":"","key":"","ca":"<TODO>","certname":"","keyname":"","caname":"","servername":"<TODO>","verifyservercert":true},{"id":"92c145b5.b08c08","type":"tls-config","name":"MQTT IoT Connector (TLS)","cert":"","key":"","ca":"<TODO>","certname":"","keyname":"","caname":"","servername":"<TODO>","verifyservercert":true},{"id":"fcea92a9.f9317","type":"mqtt-broker","name":"MQTT Connector","broker":"<TODO>","port":"8883","tls":"92c145b5.b08c08","clientid":"<TODO>","usetls":true,"compatmode":false,"protocolVersion":"4","keepalive":"60","cleansession":false,"birthTopic":"$resource/config_io","birthQos":"0","birthPayload":"{\"channels\":{\"temp\":{\"display_name\":\"Temperature\",\"properties\":{\"data_type\":\"TEMPERATURE\",\"data_unit\":\"DEG_FAHRENHEIT\"}}}}","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""},{"id":"78263cde.91d2f4","type":"debug","z":"5303e7d4.f58bc8","name":"Config Request","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":160,"y":100,"wires":[]},{"id":"c97717ca.c01cc8","type":"inject","z":"437a9d6d.95ecc4","name":"Start","props":[{"p":"schema","v":"{\"type\":\"object\",\"properties\":{\"url\":{\"type\":\"string\",\"description\":\"IoT Connector host url\"},\"identity\":{\"type\":\"string\",\"description\":\"Identity under which to provision\"},\"token\":{\"type\":\"string\",\"description\":\"Authentication token\"},\"config\":{\"type\":\"object\",\"description\":\"ExoSense channel configuration object\"},\"data\":{\"type\":\"object\",\"description\":\"ExoSense channel data object\"}},\"required\":[\"url\",\"identity\"]}","vt":"json"},{"p":"filename","v":"device.json","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":90,"y":160,"wires":[["403b58d8.41a0b8"]]},{"id":"732b4785.813cc8","type":"http request","z":"5303e7d4.f58bc8","name":"POST Config","method":"POST","ret":"txt","paytoqs":"ignore","url":"","tls":"cc6d5451.fb9658","persist":false,"proxy":"","authType":"","x":430,"y":160,"wires":[["b17dddad.dadf7","cb899967.51c098"]]},{"id":"1490875e.8483b9","type":"function","z":"5303e7d4.f58bc8","name":"Config Payload & Headers","func":"// Reference: https://docs.exosite.io/account/iot-connectors/connected-products/device-http-api#provision\nmsg.url = `${msg.device.url}/onep:v1/stack/alias`;\n\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';\nmsg.headers['X-Exosite-CIK'] = msg.device.token;\n\nlet config = JSON.stringify(msg.device.config);\n\nmsg.payload = `config_io=${config}`;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":200,"y":160,"wires":[["78263cde.91d2f4","732b4785.813cc8"]]},{"id":"b17dddad.dadf7","type":"debug","z":"5303e7d4.f58bc8","name":"Config Response","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":450,"y":100,"wires":[]},{"id":"751d9da2.6c0d74","type":"function","z":"fcf4ba66.688748","name":"Data Payload & Headers","func":"// Reference: https://docs.exosite.io/account/iot-connectors/connected-products/device-http-api#provision\nmsg.url = `${msg.device.url}/onep:v1/stack/alias`;\n\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';\nmsg.headers['X-Exosite-CIK'] = msg.device.token;\n\nlet data = JSON.stringify(msg.device.data);\n\nmsg.payload = `data_in=${data}`;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":190,"y":160,"wires":[["38eefff0.b9df2","ba0a62fd.1a775"]]},{"id":"ba0a62fd.1a775","type":"http request","z":"fcf4ba66.688748","name":"POST Data","method":"POST","ret":"txt","paytoqs":"ignore","url":"","tls":"cc6d5451.fb9658","persist":false,"proxy":"","authType":"","x":410,"y":160,"wires":[["40e9ff84.d95dd","c671cea6.bf60d"]]},{"id":"38eefff0.b9df2","type":"debug","z":"fcf4ba66.688748","name":"Data Request","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":160,"y":100,"wires":[]},{"id":"40e9ff84.d95dd","type":"debug","z":"fcf4ba66.688748","name":"Data Response","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":420,"y":100,"wires":[]},{"id":"cb899967.51c098","type":"switch","z":"5303e7d4.f58bc8","name":"Config Response Handler","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"204","vt":"num"},{"t":"neq","v":"204","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":650,"y":160,"wires":[["2e7b6d53.fcc182"],["e96ccec4.306e7"]],"inputLabels":["POST Config Response"],"outputLabels":["Success","Failure"]},{"id":"e96ccec4.306e7","type":"debug","z":"5303e7d4.f58bc8","name":"Config Failure","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":620,"y":220,"wires":[]},{"id":"9b811725.ac5968","type":"http request","z":"5e91c58.8bc983c","name":"POST Provision","method":"POST","ret":"txt","paytoqs":"ignore","url":"","tls":"cc6d5451.fb9658","persist":false,"proxy":"","authType":"","x":440,"y":160,"wires":[["abcc02ef.0da1d","c075ebfd.ed6738"]]},{"id":"4711cd79.823434","type":"function","z":"5e91c58.8bc983c","name":"Provision Payload & Headers","func":"// Reference: https://docs.exosite.io/account/iot-connectors/connected-products/device-http-api#provision\nmsg.url = `${msg.device.url}/provision/activate`;\n\nmsg.headers = {};\nmsg.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=utf-8';\n\nmsg.payload = `id=${msg.device.identity}`;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":200,"y":160,"wires":[["956f18f3.cfd328","9b811725.ac5968"]]},{"id":"abcc02ef.0da1d","type":"debug","z":"5e91c58.8bc983c","name":"Provision Response","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":460,"y":100,"wires":[]},{"id":"956f18f3.cfd328","type":"debug","z":"5e91c58.8bc983c","name":"Provision Request","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":170,"y":100,"wires":[]},{"id":"c075ebfd.ed6738","type":"switch","z":"5e91c58.8bc983c","name":"Provision Response Handler","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"200","vt":"str"},{"t":"neq","v":"200","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":680,"y":160,"wires":[["3ca6b0c5.0640e"],["9ef20798.32ca38"]],"outputLabels":["Success","Failure"]},{"id":"9ef20798.32ca38","type":"debug","z":"5e91c58.8bc983c","name":"Provision Failure","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":650,"y":220,"wires":[]},{"id":"3ca6b0c5.0640e","type":"function","z":"5e91c58.8bc983c","name":"Clear Request Properties","func":"delete msg.redirectList;\ndelete msg.responseUrl;\ndelete msg.statusCode;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":950,"y":160,"wires":[["26998da4.901fc2"]]},{"id":"bb480032.7e848","type":"subflow:5e91c58.8bc983c","z":"437a9d6d.95ecc4","name":"","env":[],"x":760,"y":120,"wires":[["403b58d8.41a0b8"]]},{"id":"2e7b6d53.fcc182","type":"function","z":"5303e7d4.f58bc8","name":"Clear Request Properties","func":"delete msg.redirectList;\ndelete msg.responseUrl;\ndelete msg.statusCode;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":910,"y":160,"wires":[[]]},{"id":"c671cea6.bf60d","type":"switch","z":"fcf4ba66.688748","name":"Data Response Handler","property":"statusCode","propertyType":"msg","rules":[{"t":"eq","v":"204","vt":"str"},{"t":"neq","v":"204","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":630,"y":160,"wires":[["4b234547.15115c"],["b542425d.100de"]],"outputLabels":["Sucess","Failure"]},{"id":"5d51696b.5a2be8","type":"delay","z":"437a9d6d.95ecc4","name":"Data Interval","pauseType":"delay","timeout":"30","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":1550,"y":160,"wires":[["3c23bf18.9398"]]},{"id":"b542425d.100de","type":"debug","z":"fcf4ba66.688748","name":"Data Failure","active":true,"tosidebar":true,"console":true,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":600,"y":220,"wires":[]},{"id":"4b234547.15115c","type":"function","z":"fcf4ba66.688748","name":"Clear Request Properties","func":"delete msg.redirectList;\ndelete msg.responseUrl;\ndelete msg.statusCode;\n\n// Clear device data object for next run\nmsg.device.data = {};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":890,"y":160,"wires":[[]]},{"id":"8dc76ce7.be624","type":"subflow:5303e7d4.f58bc8","z":"437a9d6d.95ecc4","x":970,"y":200,"wires":[["3c23bf18.9398"]]},{"id":"3a0355fa.943aba","type":"subflow:fcf4ba66.688748","z":"437a9d6d.95ecc4","name":"","env":[],"x":1360,"y":160,"wires":[["5d51696b.5a2be8"]]},{"id":"3c23bf18.9398","type":"function","z":"437a9d6d.95ecc4","name":"Device Data","func":"\nfunction getRandomArbitrary(min, max) {\n  return Math.random() * (max - min) + min;\n}\n\nlet number = 13\n\nif (JSON.stringify(msg.device.data) === '{}'){\n    msg.device.data = {\n        \"temp\": Number(getRandomArbitrary(-20, 40).toFixed(2))\n    };\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1170,"y":160,"wires":[["3a0355fa.943aba"]]},{"id":"5675e0a1.539cc","type":"function","z":"437a9d6d.95ecc4","name":"Device Config","func":"\nif (JSON.stringify(msg.device.config) === '{}') {\n    msg.device.config = {\n        \"channels\": {\n            \"temp\": {\n                \"display_name\": \"Temperature\",\n                \"properties\": {\n                    \"data_type\": \"TEMPERATURE\",\n                    \"data_unit\": \"DEG_FAHRENHEIT\",\n                    \"precision\": 2\n                },\n                \"protocol_config\": {\n                    \"report_rate\": 30000,\n                    \"timeout\": 60000\n                }\n            }\n        }\n    };\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":760,"y":200,"wires":[["8dc76ce7.be624"]]},{"id":"471d605b.4ef84","type":"file in","z":"65302557.9e299c","name":"Device File","filename":"device.json","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":330,"y":100,"wires":[["db6703a.b03a5"]]},{"id":"db6703a.b03a5","type":"json","z":"65302557.9e299c","name":"Device Parser","property":"payload","action":"","pretty":false,"x":520,"y":100,"wires":[["32ee44f1.57f53c"]]},{"id":"32ee44f1.57f53c","type":"function","z":"65302557.9e299c","name":"Device Definition","func":"msg.device = {};\n\nif (msg.payload.url.endsWith('/')) {\n    msg.device.url = msg.payload.url.substring(0, msg.payload.url.length - 1);\n} else {\n    msg.device.url = msg.payload.url;\n}\n\nmsg.device.identity = msg.payload.identity;\nmsg.device.token = msg.payload.token || '';\nmsg.device.config = msg.payload.config || {};\nmsg.device.data = msg.payload.data || {};\n\nmsg.payload = msg.device.token;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":730,"y":100,"wires":[["2610b033.6b26"]]},{"id":"2610b033.6b26","type":"debug","z":"65302557.9e299c","name":"Device Definition","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":730,"y":160,"wires":[]},{"id":"9e9cef15.25865","type":"switch","z":"437a9d6d.95ecc4","name":"Provision State Switch","property":"device.token","propertyType":"msg","rules":[{"t":"eq","v":"","vt":"str"},{"t":"neq","v":"","vt":"str"}],"checkall":"false","repair":false,"outputs":2,"x":540,"y":160,"wires":[["bb480032.7e848"],["5675e0a1.539cc"]],"outputLabels":["Not Provisioned","Provisioned"]},{"id":"69de45a3.3aaf7c","type":"file","z":"5e91c58.8bc983c","name":"Device File","filename":"device.json","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":1590,"y":160,"wires":[[]]},{"id":"26998da4.901fc2","type":"function","z":"5e91c58.8bc983c","name":"Update Device File","func":"msg.device.token = msg.payload;\n\nmsg.payload = msg.device;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1190,"y":160,"wires":[["d622e85.3e20218"]]},{"id":"d622e85.3e20218","type":"json","z":"5e91c58.8bc983c","name":"JSON Formatter","property":"payload","action":"str","pretty":true,"x":1400,"y":160,"wires":[["69de45a3.3aaf7c"]]},{"id":"403b58d8.41a0b8","type":"subflow:65302557.9e299c","z":"437a9d6d.95ecc4","name":"","env":[],"x":290,"y":160,"wires":[["9e9cef15.25865"]]},{"id":"49b4217a.1eb6a","type":"mqtt out","z":"1c17e3fe.19f42c","name":"Data Publish","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"fcea92a9.f9317","x":290,"y":160,"wires":[]},{"id":"83f3bb34.e8d8f8","type":"inject","z":"1c17e3fe.19f42c","name":"Example Data","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"$resource/data_in","payload":"{\"temp\":13.21}","payloadType":"json","x":110,"y":160,"wires":[["49b4217a.1eb6a"]]},{"id":"9fbb0ddd.aa338","type":"mqtt in","z":"1c17e3fe.19f42c","name":"Subscriber","topic":"$resource/#","qos":"1","datatype":"auto","broker":"fcea92a9.f9317","x":100,"y":240,"wires":[["a9d2b19.62d595"]]},{"id":"f7c859aa.f28368","type":"debug","z":"1c17e3fe.19f42c","name":"Subscribe Logger","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":290,"y":300,"wires":[]},{"id":"a9d2b19.62d595","type":"function","z":"1c17e3fe.19f42c","name":"Message Parser","func":"delete msg.qos\ndelete msg.retain\n\nlet topicArray = msg.topic.split('/');\n\nmsg.topic = `${topicArray[0]}/${topicArray[1]}`;\nmsg.timestamp = topicArray[2]\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":280,"y":240,"wires":[["54deb72e.017688","f7c859aa.f28368"]]},{"id":"54deb72e.017688","type":"switch","z":"1c17e3fe.19f42c","name":"Config Reflector","property":"topic","propertyType":"msg","rules":[{"t":"eq","v":"$resource/config_io","vt":"str"}],"checkall":"false","repair":false,"outputs":1,"x":480,"y":240,"wires":[["49b4217a.1eb6a"]]},{"id":"25f78485.2eb20c","type":"catch","z":"65302557.9e299c","name":"Catch: File DNE","scope":["471d605b.4ef84"],"uncaught":false,"x":100,"y":240,"wires":[["46e7a516.8edb8c"]]},{"id":"46e7a516.8edb8c","type":"function","z":"65302557.9e299c","name":"Device Init","func":"msg.device = {};\n\n// - - - - - - - - - - - - - - - - -\n// - - - - - -  Required  - - - - -\n// - - - - - - - - - - - - - - - - -\n\n// Set IoT Connector Host\nmsg.device.url = '';\n\n// Set Device ID\nmsg.device.identity = '';\n\n\n// - - - - - - - - - - - - - - - - -\n// - - - - - -  Optional  - - - - -\n// - - - - - - - - - - - - - - - - -\n\n// Set Token if Device ID is already provisioned\nmsg.device.token = '';\n\n// Set a config_io value (ref: https://docs.exosite.io/schema/channel-signal_io_schema#device-gateway-channel-configuration-schema)\nmsg.device.config = {};\n\n// Set an initial data_in payload\nmsg.device.data = {};\n\n\n// Remove trailing '/' from IoT Connector Host if it is present\nif (msg.device.url.endsWith('/')) {\n    msg.device.url = msg.device.url.substring(0, msg.device.url.length - 1);\n}\n\nmsg.payload = msg.device;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":290,"y":240,"wires":[["7bc4b054.be71d"]]},{"id":"c9b10a78.1700a8","type":"function","z":"65302557.9e299c","name":"Schema","func":"msg.schema = {\n  \"type\": \"object\",\n  \"properties\": {\n    \"url\": {\n      \"type\": \"string\",\n      \"description\": \"IoT Connector host url\"\n    },\n    \"identity\": {\n      \"type\": \"string\",\n      \"description\": \"Identity under which to provision\"\n    },\n    \"token\": {\n      \"type\": \"string\",\n      \"description\": \"Authentication token\"\n    },\n    \"config\": {\n      \"type\": \"object\",\n      \"description\": \"ExoSense channel configuration object\"\n    },\n    \"data\": {\n      \"type\": \"object\",\n      \"description\": \"ExoSense channel data object\"\n    }\n  },\n  \"required\": [\n    \"url\",\n    \"identity\"\n  ]\n};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":160,"y":100,"wires":[["471d605b.4ef84"]]},{"id":"7bc4b054.be71d","type":"json","z":"65302557.9e299c","name":"JSON Formatter","property":"payload","action":"str","pretty":true,"x":480,"y":240,"wires":[["9936e449.7bcb08"]]},{"id":"9936e449.7bcb08","type":"file","z":"65302557.9e299c","name":"Device File","filename":"device.json","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":670,"y":240,"wires":[["471d605b.4ef84"]]}]

In the top-right corner of the page, click the hamburger menu and select import. You can copy and paste the example above into the text field, or save it to a file and select it for import.

Post Import

Once imported you should find two new Flows have been created - "HTTP" and "MQTT" - as well as four new Subflows each working to support dynamic functionality of the HTTP flow.

HTTP

Update TLS Configuration

To securely communicate your data to the cloud, HTTP Request Nodes can reference a Global Configuration Node to manage their connection and TLS details.

HTTP TLS Config

  1. Open the Info tab on the right-hand menu
  2. Double-click the gear icon to edit the HTTP IoT Connector (TLS) configuration
  3. Update the CA Certificate definition (see hint below)
  4. Update the Server Name definition to match your IoT Connector (see hint below)
CA Certificate
  • The DigiCert Global Root CA (.cer) can be downloaded from our Device API Encryption Requirements documentation.
  • A path to a locally stored file can be defined.
  • The file can be uploaded directly by deselecting the "Use key and certificates from local files" option.
Server Name
  • Ensure the "Verify server certificate" option is selected.
  • Replace <TODO> with the unique subdomain of your IoT Connector.
  • This is defined as your Solution ID, which can be copied from the IoT Connector UI by clicking the ID shield near the top-left corner of the page:

SolutionID

Once both of the <TODO> sections have been updated, click on the red Update button and then Done to apply your changes.

HTTP Device Definition

There are several properties of a Device that are required to be pre-defined and others optionally:

  • URL (required): IoT Connector Host
  • Identity (required): Identity of the Device
  • Token (optional): Authentication Token
    • Required if identity is already provisioned
  • Config (optional): Data channel definitions
  • Data (optional): Initial data payload

The HTTP flow leverages a local JSON file (example below) to manage and persist these properties. The file can be pre-created with the required definition, or the definition can be set within a node to be written to a file on runtime.

Example Device Definition
{
    "url": "", 
    "identity": "",
    "token": "",
    "config": {},
    "data": {}
}

Device Definition - File

Tip

Follow this section for any of the following:

  • Pre-create the file
    • If the file does exist on runtime it must meet the schema requirements noted above
  • Update the filename
  • Update the file path

Device Definition File

Still working from the Info tab:

  1. Double-click the "Device File" node under the HTTP Device Definition subflow
  2. Update (or note) the configured filename that will be used

Device Definition - Node

Attention

The following will only apply if a local Device Definition file is not found.

Device Definition Node

Still working from the Info tab:

  1. Double-click the "Device Init" node under the HTTP Device Definition subflow
  2. Set values for the required properties
  3. Optionally set values for the remaining properties

Key Nodes

Note

This section will highlight a few additional key nodes.

Device Config Node

Responsible for passing-through a Channel config for reporting, or defining one if not separately defined.

While it should not be necessary if the preceding steps have been completed, this node can be edited.

Device Config Node

Left unchanged, where no Channel config is separately defined this node will create a "temp" Channel:

SolutionID

Device Data Node

Responsible for generating and formatting a data payload.

The contents of this node should be edited, or possibly even replaced with a custom subflow. Without a more extensive refactor, however, it is important to maintain the overall structure of the msg and msg.device objects*.*

Device Data Node

Left unchanged this node will generate random numeric data for a "temp" channel:

SolutionID

Data Interval Node

Responsible for managing the data sample/report rate.

This node can optionally be edited.

Data Interval Node

Left unchanged this node will create a 30s delay in the data generation/reporting loop:

SolutionID

Enable and Deploy

You are now ready to:

  • Enable the HTTP Flow
  • Deploy your changes
Enable and Deploy

By default the HTTP Flow is disabled.

Enable and Deploy

Start

Execution of this example HTTP Flow begins with a manual trigger:

  1. Consider opening the Debug tab on the right-hand menu
  2. Click the "Start" trigger node to begin execution

Note

To provide insight into the runtime object structures, numerous debug nodes have been enabled within the supporting subflows. They can be disabled from the Info tab under each respective subflow.

MQTT

Update TLS Configuration

To securely communicate your data to the cloud, MQTT Nodes can reference a Global Configuration Node to manage their connection and TLS details.

MQTT TLS Config

  1. Open the Info tab on the right-hand menu
  2. Double-click the gear icon to edit the MQTT IoT Connector (TLS) configuration
  3. Update the CA Certificate definition (see hint below)
  4. Update the Server Name definition to match your IoT Connector (see hint below)
CA Certificate
  • The DigiCert Global Root CA (.cer) can be downloaded from our Device API Encryption Requirements documentation.
  • A path to a locally stored file can be defined.
  • The file can be uploaded directly by deselecting the "Use key and certificates from local files" option.
Server Name
  • Ensure the "Verify server certificate" option is selected.
  • Replace <TODO> with the unique subdomain of your IoT Connector.
  • This is defined as your Solution ID, which can be copied from the IoT Connector UI by clicking the ID shield near the top-left corner of the page:

SolutionID

Once both of the <TODO> sections have been updated, click on the red Update button and then Done to apply your changes.

Pre-Provision Device

Today, Node-RED MQTT device clients must be pre-provisioned within the IoT Connector UI.

IoT Connector Provisioning

  • Navigate to your IoT Connector UI (reference: Exosite Cloud Management UI)
  • Click "+ New Device(s)" to add a new Device identity
  • Use the right-hand 3-dot menu to "Manually set device credentials"
    • This will generate an Authentication Token for your Device
Attention

The generated Token is only presented upon generation so copy it locally for use in the next steps. Note that a new Token can be generated at any time by repeating the last step above.

Update MQTT Connector Configuration

Update Connection Details

MQTT Connection Details

Still working from the Info tab:

  1. Double-click the gear icon to edit the MQTT Connector broker configuration
  2. Update the Server definition to match your IoT Connector (see TLS configuration above)
  3. If changed within the IoT Connector itself, update the Port (default is 8883)
  4. Update the Client ID with the Device Identity pre-provisioned in the prior section

Update Security Details

MQTT Security Details

Still working from the Info tab:

  1. Update the Username with the Device Identity pre-provisioned in the prior section (matching Client ID)
  2. Update the Password with the Device Token generated in the prior section (reference: Pre-Provision Device)

Update Initial Message

MQTT Initial Message

Still working from the Info tab:

  1. Update the Payload to ensure the Device Channel Configuration is published when the client initially connects

Update Publish Data

MQTT Example Data

Still working from the Info tab:

  1. Double-click the "Example Data" node under the MQTT flow
  2. Edit the msg.payload with relevant Channel data
Publishing Data

This node can be edited and used for an initial proof but should be replaced with a different node (or subflow) for more dynamic and realistic data generation and publishing. When replacing this node, note and maintain the general structure of msg.topic and msg.payload unless more drastically refactoring.

Enable and Deploy

You are now ready to:

  • Enable the MQTT Flow
  • Deploy your changes
Enable and Deploy

By default the MQTT Flow is disabled.

Enable and Deploy

Start

Execution of this example MQTT Flow begins with a manual trigger:

  1. Consider opening the Debug tab on the right-hand menu
  2. Click the "Example Data" trigger node to begin execution

Note

The example MQTT flow will receive Channel Configurations defined within the ExoSense Device UI and acknowledge them by reporting them back. The data provided via this subscription can be valuable in longer-term dynamic data generation and reporting.