UNPKG

node-red-contrib-iiot-opcua

Version:

An Industrial IoT OPC UA toolbox contribution package for Node-RED based on node-opcua.

233 lines (204 loc) 11.4 kB
<!-- The BSD 3-Clause License Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com) Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/) All rights reserved. node-red-contrib-iiot-opcua --> <script type='text/javascript'> RED.nodes.registerType('OPCUA-IIoT-Method-Caller', { category: 'IIoT', color: '#ABCDEF', defaults: { connector: {type: "OPCUA-IIoT-Connector", required: true}, objectId: {value: ""}, methodId: {value: ""}, methodType: {value: "basic", required: true}, value: {value: null}, justValue: {value: true}, name: {value: ""}, showStatusActivities: {value: false}, showErrors: {value: false}, inputArguments: {value: []} }, inputs: 1, outputs: 1, align: "left", icon: "icon.png", label: function () { return this.name || "Method Caller"; }, labelStyle: function () { return this.name ? "node_label_italic" : ""; }, oneditprepare: function () { let node = this let tabs = RED.tabs.create({ id: "node-input-method-tabs", onchange: function (tab) { $("#node-input-method-tabs-content").children().hide() $("#" + tab.id).show() } }) tabs.addTab({ id: "opcuaiiot-method-tab-settings", label: this._("opcua-iiot-contrib.tabs-label.settings") }) tabs.addTab({ id: "opcuaiiot-method-tab-argument", label: this._("opcua-iiot-contrib.tabs-label.argument") }) // Argument Management node.inputArguments.forEach(function (element, index, array) { generateArgumentEntry(element, index); }) function generateArgumentEntry (argument, id) { let container = $('<li/>', { style: "background: #fefefe; margin:0; padding:8px 0px; border-bottom: 1px solid #ccc;" }) let row = $('<div id="row' + id + '"/>').appendTo(container) $('<i style="color: #eee; cursor: move;" class="node-input-method-argument-handle fa fa-bars"></i>').appendTo(row) let nameField = $('<input/>', { id: "node-input-method-argument-name" + id, class: 'methodArgumentName', type: "text", style: "margin-left:5px;width:20%;", placeholder: 'name' }).appendTo(row) let datatypeField = $('<select/>', { id: "node-input-method-argument-dataType" + id, class: 'methodArgumentDatatype', type: "text", style: "margin-left:5px;width:18%;", }).appendTo(row); $.getJSON('/opcuaIIoT/plain/DataTypeIds', function (data) { $(data).each(function () { datatypeField.append($("<option>").attr('value', this).text(this)); }); datatypeField.val(argument.dataType) }) let valueField = $('<input/>', { id: "node-input-method-argument-value" + id, class: 'methodArgumentValue', type: "text", style: "margin: 0 auto;width:43%;min-width:60px;margin-left:5px", placeholder: 'value' }).appendTo(row) nameField.val(argument.name) datatypeField.val(argument.dataType) valueField.val(argument.value) let finalspan = $('<span/>', {style: "float: right;margin-right: 10px;"}).appendTo(row) let removeArgumentButton = $('<a/>', { href: "#", class: "editor-button editor-button-small", style: "margin-top: 7px; margin-left: 5px;" }).appendTo(finalspan) $('<i/>', {class: "fa fa-remove"}).appendTo(removeArgumentButton) removeArgumentButton.click(function () { container.css({"background": "#fee"}) container.fadeOut(300, function () { $(this).remove() }); }); $("#node-input-method-argument-container").append(container) } $("#node-input-method-argument-container").sortable({ axis: "y", handle: ".node-input-method-argument-handle", cursor: "move" }); $("#node-input-method-argument-container .node-input-method-argument-handle").disableSelection() let cacheItemCount = 0 $("#node-input-method-argument-add").click(function () { cacheItemCount++ generateArgumentEntry({name: '', dataType: '', value: ''}, cacheItemCount) // length is every time one more than index $("#node-input-method-argument-container-div").scrollTop($("#node-input-method-argument-container-div").get(0).scrollHeight) }) // dialog handling function switchDialogResize () { let rows = $("#dialog-form>div:not(.node-input-method-argument-container-row)") let height = $("#dialog-form").height() rows.each(function (index, row) { height -= row.outerHeight(true) }) let editorRow = $("#dialog-form>div.node-input-method-argument-container-row") height -= (parseInt(editorRow.css("marginTop")) + parseInt(editorRow.css("marginBottom"))) $("#node-input-method-argument-container-div").css("height", height + "px") } $("#dialog").on("dialogresize", switchDialogResize) $("#dialog").on("dialogopen", function (ev) { let size = $("#dialog").dialog('option', 'sizeCache-switch') if (size) { $("#dialog").dialog('option', 'width', size.width) $("#dialog").dialog('option', 'height', size.height) switchDialogResize() } else { setTimeout(switchDialogResize, 10) } }) $("#dialog").on("dialogclose", function (ev, ui) { $("#dialog").off("dialogresize", switchDialogResize) }) }, oneditsave: function () { let node = this let cacheArguments = $("#node-input-method-argument-container").children() node.inputArguments = [] cacheArguments.each(function () { node.inputArguments.push({ name: $(this).find(".methodArgumentName").val(), dataType: $(this).find(".methodArgumentDatatype").val(), value: $(this).find(".methodArgumentValue").val() }) }) // console.log('well done editsave ...') } }); </script> <script type='text/x-red' data-template-name='OPCUA-IIoT-Method-Caller'> <div class='form-row'> <ul style='background:#fff;min-width:600px;margin-bottom:20px' id='node-input-method-tabs'></ul> </div> <div id='node-input-method-tabs-content' style='min-height:170px'> <div id='opcuaiiot-method-tab-settings' style='display:none'> <div class='form-row' style='min-width:640px'> <label for='node-input-connector'><i class='icon-globe'></i> <span data-i18n='opcua-iiot-contrib.label.connector'></span></label> <input type='text' id='node-input-connector'> </div> <div class='form-row'> <label for='node-input-objectId'><i class='icon-tasks'></i> <span data-i18n='opcua-iiot-contrib.label.objectId'></span></label> <input type='text' id='node-input-objectId' placeholder='ns=0;s=Server or ns=0;i=2253'> </div> <div class='form-row'> <label for='node-input-methodId'><i class='icon-tasks'></i> <span data-i18n='opcua-iiot-contrib.label.methodId'></span></label> <input type='text' id='node-input-methodId' placeholder='ns=1;s=Bark or ns=1;i=VendorName-Bark'> </div> <div class='form-row'> <label for='node-input-methodType'><i class='icon-tasks'></i> <span data-i18n='opcua-iiot-contrib.label.methodType'></span> </label> <select type='text' id='node-input-methodType'> <option value='basic'>Basic</option> <option value='complex'> Complex</option> </select> </div> <div class='form-row'> <label for='node-input-value'><i class='icon-tag'></i> <span data-i18n='opcua-iiot-contrib.label.value'></span></label> <input type='text' id='node-input-value' placeholder=''> </div> <div class='form-row'> <label for='node-input-name'><i class='fa fa-tag'></i> <span data-i18n='node-red:common.label.name'></span></label> <input type='text' id='node-input-name' placeholder=''> </div> <hr> <div class='form-row'> <label style='min-width:160px' for='node-input-justValue'><i class='fa fa-simplybuilt'></i> <span data-i18n='opcua-iiot-contrib.label.justValue'></span></label> <input type='checkbox' id='node-input-justValue' style='max-width:30px'> </div> <hr> <div class='form-row'> <label style='min-width:160px' for='node-input-showStatusActivities'><i class='fa fa-bolt'></i> <span data-i18n='opcua-iiot-contrib.label.showActivities'></span></label> <input type='checkbox' id='node-input-showStatusActivities' style='max-width:30px'> </div> <div class='form-row'> <label style='min-width:160px' for='node-input-showErrors'><i class='fa fa-exclamation-circle'></i> <span data-i18n='opcua-iiot-contrib.label.showErrors'></span></label> <input type='checkbox' id='node-input-showErrors' style='max-width:30px'> </div> </div> <div id='opcuaiiot-method-tab-argument' style='display:none'> <div class='form-row node-input-method-argument-container-row' style='margin-bottom:0'> <div id='node-input-method-argument-container-div' style='box-sizing:border-box;border-radius:5px;height:340px;padding:5px;border:1px solid #ccc;overflow-y:scroll'> <ol id='node-input-method-argument-container' style='list-style-type:none;margin:0'></ol> </div> </div> <div class='form-row'> <a href='#' class='editor-button editor-button-small' id='node-input-method-argument-add' style='margin-top:4px'><i class='fa fa-plus'></i> <span data-i18n='opcua-iiot-contrib.label.addButton'></span></a> </div> </div> </div> </script> <script type='text/x-red' data-help-name='OPCUA-IIoT-Method-Caller'> <h2>OPC UA IIoT Method Caller</h2> <p>The Node is to call a basic or complex method on the OPC UA server.</p> <h3>Input </h3> <p> If the settings of the node are filled, then a simple inject will work, otherwise the incoming has to receive a complex message with all parameters. </p> <p>You need to add your XML definition of types and attributes to the server.</p> <div> <strong> Simple event message payload could be a simple inject if the node parameters are filled or you have to send the parameters via msg object like: </strong> <pre>msg.payload.</pre> <ul> <li>objectId (Object-Id) </li><li>methodId (Method-Id) </li><li> inputArguments (Array) <ul> <li>name (just to name the method parameter - has no effect to later use for now) </li><li> dataType (all node-opcua DataTypes) </li><li>value (value or Variant as expected from node-opcua) </li></ul> </li><li> methodType (basic, complex) </li></ul> </div> <p> The settings in that node will override incoming data if the msg property is empty or undefined.</p> <div> <strong> Complex event message:</strong> <ul> <li>objectId (Object-Id) </li><li>methodId (Method-Id) </li><li> inputArguments (Array) <ul> <li>dataType </li><li>value </li></ul> </li><li>methodType </li><li>nodetype </li></ul> </div> <h3>Output</h3> <div> <strong>Event message:</strong> <ul> <li>payload (Array) <ul> <li>statusCode </li><li> inputArgumentResults (Array) </li><li>inputArgumentDiagnosticInfos (Array) </li><li>outputArguments (Array) </li></ul> </li><li>definitionResults <ul> <li>methodId </li><li>methodDefinition </li></ul> </li><li>nodetype (method) </li><li> methodType </li></ul> </div> <strong>Name</strong> <p>Name in the flow of Node-RED.</p> <p> Set showErrors to get errors from node-opcua on browse.</p> </script>