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:
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.
- Open the Info tab on the right-hand menu
- Double-click the gear icon to edit the HTTP IoT Connector (TLS) configuration
- Update the CA Certificate definition (see hint below)
- 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:
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
- Recommended, see ExoSense Data IO Schema
- 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
Still working from the Info tab:
- Double-click the "Device File" node under the HTTP Device Definition subflow
- 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.
Still working from the Info tab:
- Double-click the "Device Init" node under the HTTP Device Definition subflow
- Set values for the required properties
- 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:
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:
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:
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.
Start¶
Execution of this example HTTP Flow begins with a manual trigger:
- Consider opening the Debug tab on the right-hand menu
- 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.
- Open the Info tab on the right-hand menu
- Double-click the gear icon to edit the MQTT IoT Connector (TLS) configuration
- Update the CA Certificate definition (see hint below)
- 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:
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.
- 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¶
Still working from the Info tab:
- Double-click the gear icon to edit the MQTT Connector broker configuration
- Update the Server definition to match your IoT Connector (see TLS configuration above)
- If changed within the IoT Connector itself, update the Port (default is 8883)
- Update the Client ID with the Device Identity pre-provisioned in the prior section
Update Security Details¶
Still working from the Info tab:
- Update the Username with the Device Identity pre-provisioned in the prior section (matching Client ID)
- Update the Password with the Device Token generated in the prior section (reference: Pre-Provision Device)
Update Initial Message¶
Still working from the Info tab:
- Update the Payload to ensure the Device Channel Configuration is published when the client initially connects
Update Publish Data¶
Still working from the Info tab:
- Double-click the "Example Data" node under the MQTT flow
- 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.
Start¶
Execution of this example MQTT Flow begins with a manual trigger:
- Consider opening the Debug tab on the right-hand menu
- 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.