UNPKG

@tulip/node-red-tulip-api

Version:

Node-RED nodes for sending data to the Tulip API

349 lines (325 loc) 12.4 kB
<script type="text/javascript"> RED.nodes.registerType('tulip-machine-attribute', { category: 'Tulip', inputs: 1, outputs: 1, color: '#65CCB8', icon: 'tulip.svg', defaults: { name: { value: 'tulip-machine-attribute' }, apiAuth: { value: '', type: 'tulip-api-auth', required: true, }, keepAlive: { value: true }, keepAliveMsecs: { value: 10000 }, retainMsgProps: { value: true }, singleAttribute: { value: true }, deviceInfo: { value: '{"attributeId":"","deviceId":""}', required: true, }, payloadSource: { value: 'payload', required: true, validate: RED.validators.typedInput('payloadType'), }, payloadType: { value: 'msg' }, }, paletteLabel: 'machine-attr', label: function () { return this.name || 'tulip-machine-attribute'; }, oneditprepare: function () { // Whether or not to show keep-alive msecs option const updateKeepAlive = () => { const keepAlive = $('#node-input-keepAlive').is(':checked'); if (keepAlive) { $('#div-node-input-keepAliveMsecs').show(); } else { $('#div-node-input-keepAliveMsecs').hide(); } }; updateKeepAlive(); $('#node-input-keepAlive').change(() => { updateKeepAlive(); }); const node = this; // Add retainMsgProps as a property to transition legacy nodes. Set to false since // previously msg props were not retained. if (!('retainMsgProps' in node)) { node.retainMsgProps = false; } // Add singleAttribute as a property to transition legacy nodes. Set to true since // previously only single tag was supported. if (node.singleAttribute === undefined || node.singleAttribute === null) { node.singleAttribute = true; } // Set initial state of singleAttribute option & tag selection if (node.singleAttribute) { $('.single-attribute-wrapper').show(); $('#node-input-singleAttribute').prop('checked', true); } else { $('.single-attribute-wrapper').hide(); $('#node-input-singleAttribute').prop('checked', false); } // Show option for selecting tag if singleAttribute is true $('#node-input-singleAttribute').change(() => { let singleAttribute = $('#node-input-singleAttribute').is(':checked'); if (singleAttribute) { $('.single-attribute-wrapper').show(); } else { $('.single-attribute-wrapper').hide(); } }); // Show attribute help text on click $('#attribute-config-info').click(() => { const isHidden = $('#attribute-config-help').is(':hidden'); if (isHidden) { $('#attribute-config-help').show(); } else { $('#attribute-config-help').hide(); } }); // Generate typed input fields $('#node-input-payloadSource').typedInput({ default: 'msg', types: ['msg', 'flow', 'global', 'str', 'num', 'jsonata', 'env'], typeField: $('#node-input-payloadType'), }); $('#node-input-deviceInfo').typedInput({ default: 'json', types: ['json'], }); }, }); </script> <script type="text/html" data-template-name="tulip-machine-attribute"> <div class="form-row"> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <input type="text" id="node-input-name" placeholder="Name" /> </div> <div class="form-row"> <label for="node-input-apiAuth" ><i class="fa fa-user-circle"></i> Tulip API Authentication</label > <input id="node-input-apiAuth" /> </div> <div class="form-row"> <label> Attribute<br>Config <i id="attribute-config-info" class="fa fa-info-circle"></i> </label> <input id="node-input-singleAttribute" type="checkbox" autocomplete="off" style="margin-left:10px; vertical-align:top; width:auto" /> <label for="node-input-singleAttribute" style="width:auto; vertical-align:top"> Single attribute </label> </div> <div id="attribute-config-help" class="form-tips" style="margin:12px" hidden> <p> If checked, specify a single machine attribute to send data to (identified by <code>machineId</code> and <code>attributeId</code>). Write values to that attribute through the configured attribute source. </p> <p> If not checked, you can dynamically pass as <code>msg.payload</code> a list of attributes and values to write. For example, set <code>msg.payload</code> to <pre><code>[ { "machineId": "{machineId}", "attributeId": "{attributeId}", "value": {value} } ]</code></pre> to write the string <code>"val1"</code> to the string-type attribute with id <code>attributeId</code> for machine with id <code>machineId</code>. </p> </div> <div class="form-row single-attribute-wrapper"> <label for="node-input-deviceInfo"><i class="fa fa-clipboard"></i> Device Info</label> <input type="text" id="node-input-deviceInfo" style="width:70%"/> </div> <div class="form-tips single-attribute-wrapper"> <b>Tip:</b> This field can be copy-pasted from your Tulip factory instance. Navigate to Shop Floor > Machines, select your machine from the Machine Library, and click the clipboard icon next to the target Machine Attribute to copy-paste its device info. </div> <hr /> <div class="form-row"> <h4>Advanced</h4> </div> <br> <div class="form-row"> <label for="node-input-keepAlive"> HTTP Options</label> <input type="checkbox" id="node-input-keepAlive" autocomplete="off" style="margin-left:10px; vertical-align:top; width:auto" /> <label for="node-input-keepAlive" style="width:auto"> Enable Connection Keep-Alive </label> </div> <div class="form-row" id="div-node-input-keepAliveMsecs" hidden> <label for="node-input-keepAliveMsecs">&nbsp;</label> <span style="width:auto">Keep-Alive Initial Delay (ms)</span> <input type="number" min="0" step="1" id="node-input-keepAliveMsecs" value="10000" style="width:auto" /> </div> <br> <div class="form-row"> <label for="node-input-retainMsgProps"> Output</label> <input type="checkbox" id="node-input-retainMsgProps" autocomplete="off" style="margin-left:10px; vertical-align:top; width:auto" /> <label for="node-input-retainMsgProps" style="width:auto">Retain Input Message Properties</label> </div> <br> <div class="form-row single-attribute-wrapper"> <label for="node-input-payloadSource"> Attribute Source</label> <input type="text" id="node-input-payloadSource" style="width:70%" /> <input type="hidden" id="node-input-payloadType" /> </div> </script> <script type="text/html" data-help-name="tulip-machine-attribute"> <p>Sends data to machine attribute endpoints using the Tulip Machine API.</p> <h3>Inputs (single attribute)</h3> <dl class="message-properties"> <dt> payload <span class="property-type">string | boolean | integer | float</span> </dt> <dd> The value of the attribute to send. Should match the type of the machine attribute endpoint. </dd> <dt class="optional"> machineId <span class="property-type">string</span> </dt> <dd> Value to override the <code>machineId</code> set in "Device Info". </dd> <dt class="optional"> attributeId <span class="property-type">string</span> </dt> <dd> Value to override the <code>attributeId</code> set in "Device Info". </dd> <dt class="optional"> headers <span class="property-type">JSON</span> </dt> <dd> HTTP headers to include in the request. If a POST or PUT request, the header "Content-Type" will be set to "application/json" and will override <code>msg.headers["Content-Type"]</code>. </dd> </dl> <h3>Inputs (not single attribute)</h3> <dl class="message-properties"> <dt> payload <span class="property-type">Object[]</span> </dt> <dd> A list of { machineId, attributeId, value } objects to write in one batched Machine API request. </dd> <dt class="optional"> headers <span class="property-type">JSON</span> </dt> <dd> HTTP headers to include in the request. If a POST or PUT request, the header "Content-Type" will be set to "application/json" and will override <code>msg.headers["Content-Type"]</code>. </dd> </dl> <h3>Outputs</h3> <ol class="node-ports"> <dl class="message-properties"> <dt>response <span class="property-type">JSON</span></dt> <dd>The HTTP response object from the API request.</dd> <dt>payload</dt> <dd>The parsed response body.</dd> </dl> </ol> <h3>Overview</h3> <p> Each <code>tulip-machine-attribute</code> node is configured to send data to the Tulip Machine API. If "Single attribute" is checked, then the node will send data to a a single machine attribute for a single machine on your Tulip factory instance. If not checked, then the node can send data to a dynamically-selected attribute or list of attributes. This authentication node can be shared between <code>tulip-machine-attribute</code> nodes. </p> <h3>Details</h3> <p> For every <code>msg</code>, the node will by default send an POST request to <a>https://[your-factory-url]/api/v3/attributes/report</a> with request body: <pre><code>{ "attributes": [ { "machineId": deviceInfo.machineId, "attributeId": deviceInfo.attributeId, "value": msg.payload } ] }</code></pre> </p> <p> For basic operation, only <code>msg.payload</code> needs to be passed into the node, and the <code>deviceInfo</code> can be copy-pasted into "Device Info" from the Machine page on your factory instance. </p> <h3>Advanced Operation</h3> <p> For more advanced operation, you can specify the attribute value to come from a source other than <code>msg.payload</code>. Supported sources are: properties of <code>msg</code>, <code>flow</code>, or <code>global</code>; strings; numbers; JSONata expressions; environment variables. </p> <p> Select "Retain Input Message Properties" to keep all properties of the input message in the output message, otherwise they will be cleared. If an input message property conflicts with a property set by this node (ex: <code>msg.response</code>) then the input message property will be overwritten. </p> <p> You can also override the properties in the "Device Info" field with <code>msg</code> properties to configure the node to send to different endpoints. Specifically, <code>msg.attributeId</code> will override <code>deviceInfo.attributeId</code>, and <code>msg.machineId</code> will override <code>deviceInfo.machineId</code>. If you override either property with every <code>msg</code>, it is not needed in the "Device Info" field. For example, if every <code>msg</code> has both <code>machineId</code> and <code>attribute</code> set, you can leave "Device Info" as <code>{}</code>. </p> <p> If "Single attribute" is unchecked, then you can instead performed batched writes setting <code>msg.payload</code> to a list of attributes, each in the format <code>{attributeId, machineId, value}</code>. </p> <p> Lastly, you can configure the HTTP agent to use keep-alive by checking "Enable Connection Keep-Alive" (default=<code>true</code>), and set the agent keepAliveMsecs (default=<code>10000ms</code>). Note that this sets the keep-alive behaviour of the HTTP agent, which is different than setting the "Connection": "Keep-Alive" HTTP header (which can be set through <code>msg.headers</code>). </p> <h3>References</h3> <ul> <li> <a href=https://support.tulip.co/en/articles/4896233-using-node-red-with-edge-mc><b>Using Node-RED with Edge MC</b></a> </li> <li> <b>Tulip API Documentation:</b> available at <a>https://[your-factory-url]/apiDocs</a>, see <code>/attributes/report</code> endpoint. </li> </ul> </script>