UNPKG

@metz-connect/node-red-ewio2

Version:

Provides nodes to access EWIO2 interfaces like IOs and metering - from Node-RED

355 lines (348 loc) 17.7 kB
<!-- load static data from backend to frontend --> <script type="text/javascript"> $.getScript('get/ewio2/scripts/inits.js') .fail(function (jqxhr, settings, exception) { console.error('Loading inits.js failed.', exception); }); $.getScript('get/ewio2/scripts/backendConnection.js') .fail(function (jqxhr, settings, exception) { console.error('Loading backendConnection.js failed.', exception); }); </script> <script type="text/javascript"> let notAvailableMsg = ""; let notRunningMsg = ""; let ewio2Model; /** * Receives an object with all discovered EWIO2 from Node-RED backend. All EWIO2 are shown in dropdown menu, the ones with Node-RED support are selectable. * @memberof ewio2ConfigNode */ RED.comms.subscribe("publish/ewio2/discovered", function (topic, msg) { var jsonData = JSON.parse(msg); let ewio2Counter = 0; let discoveredEwio2 = []; jsonData.data.forEach(device => { let hostnameLocation = device.hostname; hostnameLocation += " - " + device.address; // add "this EWIO2" (english) or "dieser EWIO2" (deutsch) to localhost address (127.0.0.1) if (device.address === "127.0.0.1") { hostnameLocation += " (" + jsonData.infoStrings.thisStr + ")"; } if (device.location != "") { hostnameLocation += " @ " + device.location; } let nodeRedTooltip = ""; let nodeRedDisabled = false; // Node-RED not available --> show tooltip and disable option in dropdown if (!device.nrAvailable) { nodeRedTooltip = notAvailableMsg; nodeRedDisabled = true; } // Node-RED not running --> show tooltip and disable option in dropdown else if (!device.nrRunning) { nodeRedTooltip = notRunningMsg; nodeRedDisabled = true; } // add host with relevant settings to discoveredEwio2 array const deviceStr = JSON.stringify(device); discoveredEwio2.push({ label: hostnameLocation, value: device.address, temp: deviceStr, nrDisabled: nodeRedDisabled, nrTooltip: nodeRedTooltip }); ewio2Counter++; }); let ewio2HostLookup = $('#node-config-lookup-host'); let ewio2HostInput = $('#node-config-input-host'); let ewio2HostInputTemp = $('#node-config-input-hostTemp'); /** * Starts autocomplete function which creates a dropdown list of all discovered EWIO2. * Only EWIO2 with Node-RED support are selectable, EWIO2 without Node-RED support are shown but inactive and not selectable. * @memberof ewio2ConfigNode * @param {string} searchValue - Autocomplete filters ans shows only discovered EWIO2 which fit to this search string. */ function handleClick(searchValue) { ewio2HostInput.autocomplete({ // list all discovered EWIO2 which are stored in discoveredEWIO2 array source: discoveredEwio2, minLength: 0, // if an item has focus, show the tooltip (Node-RED not available or Node-RED not running or an empty string) focus: function (event, ui) { $(".ui-autocomplete > li").attr("title", ui.item.nrTooltip); }, // only EWIO2 with Node-RED support are selectable select: function (event, ui) { if (!ui.item.nrDisabled) { ewio2HostInput.val(ui.item.value); ewio2HostInputTemp.val(ui.item.temp); } return false; }, // stop the autocomplete functionality close: function (event, ui) { ewio2HostInput.autocomplete("destroy") } }).autocomplete("instance")._renderItem = function(ul, item) { // show EWIO2 without Node-RED support in disabled / "greyed-out" style return $("<li>") .append("<div class='"+(item.nrDisabled ? 'ui-state-disabled' : '')+"'>" + item.label + "</div>") .appendTo(ul); }; // show dropdown with all EWIO2 which fit to curent hostname in html field ewio2HostInput.autocomplete("search", searchValue); } ewio2HostLookup.click(function() { handleClick(""); }); ewio2HostInput.click(function() { handleClick(ewio2HostInput.val()); }); // automatically show autocomplete dropdown when discovery results are received handleClick(); endDiscovery(); if (ewio2Counter === 0) { // disable info button if no EWIO2 were discovered $("#btn-info-ewios").prop("disabled", true); // and show for 3s tooltip that no EWIO2 was discovered $("#btn-info-ewios").tooltip({ items: "#btn-info-ewios", content: jsonData.infoStrings.noEWIO2} ); $("#btn-info-ewios").tooltip("open"); setTimeout(function() { $("#btn-info-ewios").tooltip("close"); }, 3000); } }); /** * Received error messages from Node-RED backend. Shows error message in an html label, which is hidden if no error available. * @memberof ewio2ConfigNode */ RED.comms.subscribe("publish/ewio2/error/#", function (topic, msg) { const recvConfigNodeId = topic.split("/")[3]; // get ewio2 id of disabled select var ewio2Id =$("#node-input-ewio2 option").eq($("#node-input-ewio2").prop("selectedIndex")).val(); // message was received for the currently selected EWIO2 if(ewio2Id == recvConfigNodeId) { // enable all html elements, except IO ports (nothing is selectable on error) enableHtmlElements(true); if (msg.code === "ok") { // hide error label $('#label-error-status').text(""); $('#section-error-status').hide(); } else { let errorString = ""; let errorToCheckOld = ""; let errorToCheckNew = ""; // if a config node is available, load the error from internationalisation framework if (recvConfigNodeId) { const selectedConfigNode = RED.nodes.node(recvConfigNodeId); errorString = selectedConfigNode._(msg.code, { error: msg.message }); errorToCheckOld = selectedConfigNode._("status.no_metering"); errorToCheckNew = selectedConfigNode._("status.noCounter"); } // show error label with error message // do not update new error message, if new error message is "No counter configured at EWIO2!" and old error message was "EWIO2 without metering interface!" // Reason: No metering interface message is received from EWIO2 before number of counters is checked if (($('#label-error-status').text() != errorToCheckOld) || (errorString != errorToCheckNew)) { $('#label-error-status').text(errorString); } $('#section-error-status').show(); $("#node-input-datapoint").prop("disabled", true); } } }); /** * Adds EWIO2 user settings to settings menu of Node-RED * @memberof ewio2ConfigNode */ RED.userSettings.add({ id: "ewio2", title: "EWIO2", // create the settings pane (html) and fill with default values get: function() { var settingsPane = $("<div>",{id: "red-ui-settings-tab-ewio2", class: "red-ui-help"}); // enable / disable log flag (checkbox) var row = $("<div class='red-ui-settings-row'></div>").appendTo(settingsPane); var logEnable = $("<label for='user-settings-ewio2-log-enable'><input id='user-settings-ewio2-log-enable' type='checkbox'> <span data-i18n='@metz-connect/node-red-ewio2/ewio2:settings.logEnabled'></label>").appendTo(row).find("input"); logEnable.prop("checked",false); return settingsPane; }, // store the set values to Node-RED frontend and backend close: function() { const logEnableFlag = $("#user-settings-ewio2-log-enable").is(":checked"); // set enable log flag to Node-RED frontend LOG_DEBUG = logEnableFlag; const logSettings = {enable: $("#user-settings-ewio2-log-enable").is(":checked")}; // set enable log flag to Node-RED backend $.post("put/ewio2/settings", logSettings, function() {} ); }, // load values only from Node-RED backend focus: function() { $.get("get/ewio2/settings", function(data) { // fill html elements with received values $('#user-settings-ewio2-log-enable').prop("checked", data.enable); }); } }); /** * Frontend part of EWIO2 configuration node. * @memberof ewio2ConfigNode */ RED.nodes.registerType('EWIO2',{ category: 'config', defaults: { name: { value: "" }, host: { value: "", validate: function(v) { let host = $('#node-config-input-host').val(); // allow upper-case, lower-case, number and the characters "." and "-". At least one character. if (/^([A-Za-z0-9\.\-]+)$/.test(host)) { return true; } else { return false; } } }, hostTemp: { value: "" }, encryption: { value: "" }, tlsConfig: { value: "", type: "tls-config", required: false } }, credentials: { username: { type: "text" }, password: { type: "password" } }, label: function() { // if no name is available try to use host. If this is also not available use node id return this.name || this.host || this.id; }, oneditprepare: function() { const node = this; // if no user selected, set default to "Administrator" if (!this.credentials.username) { $("#node-config-input-username").val("Administrator"); } // start discovery automatically if EWIO2 settings are opened startDiscovery({thisStr: node._("ewio2Info.thisDevice"), noEWIO2: node._("ewio2Info.noEWIO2")}); // start discovery when button is pressed $('#btn-discover-ewios').click(function (e) { e.preventDefault(); startDiscovery({thisStr: node._("ewio2Info.thisDevice"), noEWIO2: node._("ewio2Info.noEWIO2")}); }); $('#btn-info-ewios').tooltip({ //use 'of' to link the tooltip to your specified input position: { of: '#node-config-input-host', my: 'left top', at: 'left bottom' }, content: "No info!" }); function showEwio2InfoTooltip(ewio2InfoBtn) { const ewioInfo = $("#node-config-input-hostTemp").val(); const ewioHost = $("#node-config-input-host").val(); let infoStr; if (ewioInfo) { const infoObj = JSON.parse(ewioInfo); // only if current host (in html field) is the same as discovered host if (infoObj.address === ewioHost) { infoStr = node._("ewio2Info.host") + ": " + infoObj.hostname; // add "this EWIO2" (english) or "dieser EWIO2" (deutsch) to localhost address (127.0.0.1) infoStr += "<br>"+ node._("ewio2Info.ipAddress") + ": " + infoObj.address + ((infoObj.address === "127.0.0.1") ? " (" + node._("ewio2Info.thisDevice") + ")" :""); infoStr += "<br>"+ node._("ewio2Info.macAddress") + ": " + infoObj.mac; infoStr += "<br>"+ node._("ewio2Info.hwModel") + ": " + infoObj.hwModell; infoStr += "<br>"+ node._("ewio2Info.serial") + ": " + infoObj.serial; infoStr += "<br>"+ node._("ewio2Info.swVersion") + ": " + infoObj.swVersion; if (infoObj.location) { infoStr += "<br>"+ node._("ewio2Info.location") + ": " + infoObj.location; } } // user entered host does not show discovery info else { infoStr = node._("ewio2Info.noInfo"); } } // no discovery info available else { infoStr = node._("ewio2Info.noInfo"); } ewio2InfoBtn.tooltip({ items: "#btn-info-ewios", content: infoStr} ); ewio2InfoBtn.tooltip("open"); } // show EWIO2 info $('#btn-info-ewios').on({ "click": function (e) { e.preventDefault(); showEwio2InfoTooltip($(this)); }, "mouseover": function (e) { e.preventDefault(); showEwio2InfoTooltip($(this)); }, "mouseout": function () { $(this).tooltip("disable"); } }); // temporarilly store values notAvailableMsg = this._("status.nodeRedNotAvailable"); notRunningMsg = this._("status.nodeRedNotRunning"); // check model string of EWIO2 (detect if Node-RED is running on EWIO2 or not) $.post("get/ewio2/model", function(data) { ewio2Model = data; $('#node-config-input-encryption').trigger("change"); }); $("#node-config-input-encryption").change(function () { if (this.checked) { // show tls-config row, only if SSL/TLS checkbox is enabled if (!$("#node-config-input-encryption").is(":disabled")) { $('#node-row-tlsConfig').show(); } } else { $('#node-row-tlsConfig').hide(); } }); }, oneditsave: async function() { log("ewio2: oneditsave"); // close connection when EWIO2 config is saved, to re-establish connection with possibly changed certificate settings await closeDeleteWebsocket(getConfigNodeDataStructure(this.id).data, this.id); log("closeDeleteWebsocket frontend fct done"); }, oneditdelete: async function() { log("ewio2: oneditdelete " + this.id); await closeDeleteWebsocket(getConfigNodeDataStructure(this.id).data, this.id); log("closeDeleteWebsocket frontend fct done"); }, oneditcancel: function() { log("ewio2: oneditcancel"); } }); </script> <script type="text/html" data-template-name="EWIO2"> <div class="form-row" id="div-host-discovery"> <label for="node-config-input-host"><i class="fa fa-microchip"></i> <span data-i18n="label.host"></label> <input type="text" id="node-config-input-host" style="width:50%;"> <a id="node-config-lookup-host" class="btn" data-i18n="[title]label.showEWIO2"><i id="node-config-lookup-topic-icon" class="fa fa-chevron-down"></i></a> <button id="btn-discover-ewios" class="editor-button" data-i18n="[title]label.searchEWIO2"> <i class="fa fa-fw fa-search"></i> </button> <button id="btn-info-ewios" class="editor-button" > <i class="fa fa-fw fa-info"></i> </button> <input type="hidden" id="node-config-input-hostTemp"> </div> <div class="form-row"> <input type="checkbox" id="node-config-input-encryption" style="display: inline-block; width: auto; vertical-align: top;"> <label for="node-config-input-encryption" style="width: auto" data-i18n="label.encryption"></label> <div id="node-row-tlsConfig" > <label style="width: auto; margin-left: 20px; margin-right: 10px;" for="node-config-input-tlsConfig"><span data-i18n="label.tlsConfig"></span></label><input type="text" style="width: 300px" id="node-config-input-tlsConfig"> </div> </div> <div class="form-row"> <label for="node-config-input-username"><i class="fa fa-user"></i> <span data-i18n="label.user"></label> <select id="node-config-input-username" style="width:70%"> <option value="Administrator">Administrator</option> <option value="Operator">Operator</option> <option value="Standard">Standard</option> </select> </div> <div class="form-row"> <label for="node-config-input-password"><i class="fa fa-lock"></i> <span data-i18n="label.password"></label> <input type="password" id="node-config-input-password"> </div> <hr> <div class="form-row"> <label for="node-config-input-name"><i class="fa fa-tag"></i> <span data-i18n="label.name"></label> <input type="text" id="node-config-input-name"> </div> </script>