@metz-connect/node-red-ewio2
Version:
Provides nodes to access EWIO2 interfaces like IOs and metering - from Node-RED
346 lines (336 loc) • 18.8 kB
HTML
<script type="text/javascript">
/**
* Stores counter information of connected EWIO2, that the current value is available if counter in config menu is changed.
* Object is deleted when EWIO2 is changed (changed by selecting another element in dropdown or opening configuration menu).
* @memberof counterNode
*/
var counters = {};
/**
* Stores datapoint information of connected EWIO2, that the current value is available if datapoint in config menu is changed.
* Object is deleted when EWIO2 is changed (changed by selecting another element in dropdown or opening configuration menu).
* @memberof counterNode
*/
var datapoints = {};
/**
* Receives an object with all values of an counter. If it is the currently selected counter, the settings in counter configuration menu are updated.
* @memberof counterNode
*/
RED.comms.subscribe("publish/ewio2/config/counter/#", function (topic, msg) {
const recvPrevIoPort = topic.split("/")[5];
const recvNodeId = topic.split("/")[4];
const ioType = 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 == recvNodeId) {
// only add options for the choosen type
if(msg.ioType == ioType) {
// the msg must contain 5 or 6 (with "updatedInput") elements
if(Object.keys(msg).length === 5 || Object.keys(msg).length === 6) {
const dropdownValue = JSON.stringify({"nodeId": recvNodeId, "host": msg.host, "addr": msg.id});
if(!optionExists(dropdownValue, "#node-input-counter")) {
$("#node-input-counter").append($('<option>', {
value: dropdownValue,
text: msg.name + " @ " + msg.bus
}));
}
// temporarilly store received msgs (only for this EWIO2), to have the current value
counters[dropdownValue] = msg;
// set value of the choosen and received IO port
let selectedIoPort = $('#node-input-counter').val();
log("selected: " + selectedIoPort + "; recvPrevIoPort: " + recvPrevIoPort);
// get an array of all received counters (which are stored in dropdown)
const allCntr = [...$("#node-input-counter")[0].options].map(o => o.value);
// check if the received previous io port (counter) is also available in array
const cntrFound = allCntr.find(function(cntr){return cntr === recvPrevIoPort});
// set received previous io port as currently selected, if valid and if available in array
if(recvPrevIoPort != "undefined" && cntrFound) {
selectedIoPort = recvPrevIoPort;
}
// set "last" value as selected value in dropdown
$('#node-input-counter').val(selectedIoPort);
}
}
}
});
/**
* Receives an object with all values of an counter. If it is the currently selected counter, the settings in counter configuration menu are updated.
* @memberof counterNode
*/
RED.comms.subscribe("publish/ewio2/config/datapoints/#", function (topic, msg) {
const recvPrevIoPort = topic.split("/")[5];
const recvNodeId = topic.split("/")[4];
const ioType = topic.split("/")[3];
// get ewio2 id of disabled select
var ewio2Id =$("#node-input-ewio2 option").eq($("#node-input-ewio2").prop("selectedIndex")).val();
// get counter id of disabled select
var cntrId =$("#node-input-counter option").eq($("#node-input-counter").prop("selectedIndex")).val();
// message was received for the currently selected EWIO2
if(ewio2Id == recvNodeId) {
// only add options for the choosen type
if(msg.ioType == ioType) {
// message was received for the currently selected counter
if (cntrId && JSON.parse(cntrId).addr === msg.counterId) {
// the msg must contain at least 10 elements (11 with additional error reason)
if(Object.keys(msg).length >= 10) {
const dropdownValue = JSON.stringify({"nodeId": recvNodeId, "host": msg.host, "dp": msg.id, "cntr": msg.counterId});
if(!optionExists(dropdownValue, "#node-input-datapoint")) {
$("#node-input-datapoint").append($('<option>', {
value: dropdownValue,
text: msg.name
}));
}
// temporarilly store received msgs (only for this EWIO2), to have the current value
datapoints[dropdownValue] = msg;
// set value of the choosen and received IO port
let selectedIoPort = $('#node-input-datapoint').val();
log("selected dp: " + selectedIoPort + "; recvPrevIoPort: " + recvPrevIoPort);
// get an array of all received datapoints (which are stored in dropdown)
const allDp = [...$("#node-input-datapoint")[0].options].map(o => o.value);
// check if the received previous io port (datapoint) is also available in array
const dpFound = allDp.find(function(dp){return dp === recvPrevIoPort});
// set received previous io port as currently selected, if valid and if available in array
if(recvPrevIoPort != "undefined" && dpFound) {
selectedIoPort = recvPrevIoPort;
}
// when livedata are received --> do not reset datapoint
if(msg.source === "requested") {
// set "last" value as selected value in dropdown
$('#node-input-datapoint').val(selectedIoPort);
}
// trigger datapoint change, to set correct prevIoPort
$('#node-input-datapoint').trigger("change");
// enable all html elements on valid datapoint values
enableHtmlElements(true, "counter");
enableHtmlElements(true, "datapoint");
// enable counter specific html elements
enableCounterSpecificElements(true);
// enable topic html element
enableTopicElement(true);
}
}
}
}
});
/**
* Receives a message, that all counters have been sent.
* @memberof counterNode
*/
RED.comms.subscribe("publish/ewio2/config/done", function (topic, msg) {
if (msg === "counter") {
// trigger ioport change, to set correct prevIoPort (counter)
$('#node-input-counter').trigger("change", [true]);
}
else if (msg === "datapoints") {
// trigger ioport change, to set correct prevIoPort (datapoint)
$('#node-input-datapoint').trigger("change");
}
});
RED.nodes.registerType("EWIO2 - Metering",{
category: "METZ CONNECT",
color: "#4682B4",
defaults: {
ewio2: { value: "", type: "EWIO2" },
name: { value:"" },
counter: { value: "" },
datapoint: { value: "" },
range: { value: "" },
value: { value: "" },
timestamp: { value: "" },
flags: { value: "" },
outputTimestamp: { value: "" },
outputFlags: { value: "" },
outputTopic: { value: "" },
quantity: { value: "" }
},
inputs:1,
outputs:1,
icon: "ewio2-metering.svg",
label: function() {
return this.name||"EWIO2 - Metering";
},
oneditprepare: function() {
let prevCounter = this.counter;
let prevDatapoint = this.datapoint;
initDatapointRanges(this);
const nodeId = this.id;
let prevEwio2Data = getConfigNodeDataStructure(this.ewio2, nodeId);
// save the current selected EWIO2, when configuration menu item "ewio2" gets focus. Forward to Node-RED runtime, to be able to publish value again to Node-RED editor.
$("#node-input-ewio2").focus(function () {
prevEwio2Data = getConfigNodeDataStructure(this.value, nodeId);
})
// whenever EWIO2 configuration is changed, async function is called (to "await" for connection)
$("#node-input-ewio2").change(async function () {
log("onchange ewio2: prev: " + prevEwio2Data.data.configNodeId + "; current: " + this.value);
// clear counter dropdown and locally stored data
$("#node-input-counter option").remove();
counters = {};
// clear datapoint dropdown and locally stored data
$("#node-input-datapoint option").remove();
datapoints = {};
// clear value, range, timestamp and flags
$("#node-input-value").val("");
$("#node-input-range").val("");
$("#node-input-timestamp").val("");
$("#node-input-flags").val("");
// clear and hide error msg
$('#label-error-status').text("");
$('#section-error-status').hide();
// disable counter and datapoint for every selected EWIO2 configuration node
enableIoPortElement("counter", false);
enableIoPortElement("datapoint", false);
// disable counter specific html elements
enableCounterSpecificElements(false);
// disable topic html element
enableTopicElement(false);
let configNodeId = this.value;
if (!configNodeId || configNodeId == "_ADD_") {
return;
}
// disable all html elements only when a valid EWIO2 configuration node is available
enableHtmlElements(false, "counter");
enableHtmlElements(false, "datapoint");
try {
// one EWIO2 is selected in configuration menu and customer changes to another EWIO2 > close websocket connection of "unselected" EWIO2
if (prevEwio2Data.data.configNodeId != "" && prevEwio2Data.data.configNodeId != "_ADD_") {
const selectedEwio2Data = getConfigNodeDataStructure(this.value, nodeId);
if (JSON.stringify(prevEwio2Data.data) !== JSON.stringify(selectedEwio2Data.data)) {
log(prevEwio2Data.data.configNodeId + " deselected -> close websocket connection");
await closeDeleteWebsocket(prevEwio2Data.data, nodeId);
log("close websocket done");
}
}
// reset prevCounter, if another EWIO2 is choosen
log(prevCounter + " typeof: " + typeof prevCounter);
if (prevCounter) {
log("prevCounter-nodeId: " + JSON.parse(prevCounter).nodeId + "; current EWIO2 id: " + this.value);
if (JSON.parse(prevCounter).nodeId != this.value) {
prevCounter = "";
log("reset prevCounter to ''");
}
}
log("prevCounter to send: " + prevCounter);
await getEwio2ConfigData(getConfigNodeDataStructure(configNodeId, nodeId), "counter", prevCounter, nodeId, undefined);
prevEwio2Data = getConfigNodeDataStructure(this.value, nodeId);
}
catch (error) {
log("counter onchange EWIO2 error");
log(error);
}
});
$("#node-input-counter").change(async function (event, paramWsMsgRcvd) {
prevCounter = this.value;
log("onchange counter: " + prevCounter);
// only save value, if a value is choosen. Nothing choosen not possible, due to dropdown
if(this.value != "") {
// reset prevCounter when counter was changed via dropdown
if (!paramWsMsgRcvd) {
prevDatapoint = "";
}
$("#node-input-datapoint option:selected").prop("selected", false)
$("#node-input-datapoint option").remove();
// clear value, range, timestamp and flags
$("#node-input-value").val("");
$("#node-input-range").val("");
$("#node-input-timestamp").val("");
$("#node-input-flags").val("");
await getEwio2ConfigData(getConfigNodeDataStructure(JSON.parse($('#node-input-counter').val()).nodeId, nodeId), "datapoints", prevDatapoint, nodeId, JSON.parse(prevCounter). addr);
}
});
$("#node-input-datapoint").change(async function () {
// only save value, if a value is choosen. Nothing choosen not possible, due to dropdown
if(this.value != "") {
prevDatapoint = this.value;
// set value, range, timestamp and flags of the newly choosen datapoint
const receivedValue = datapoints[this.value].value;
$("#node-input-value").val(receivedValue);
const receivedRange = datapoints[this.value].range;
if (receivedRange) {
$("#node-input-range").val(dpRanges.get(receivedRange));
}
const receivedTimestamp = datapoints[this.value].timestamp;
$("#node-input-timestamp").val(receivedTimestamp);
let receivedFlags = datapoints[this.value].flags;
$("#node-input-flags").val(receivedFlags);
}
});
},
oneditsave: async function() {
log("counter: oneditsave");
let configNodeId = $("#node-input-ewio2").val() || this.ewio2;
await prepareCloseWebsocket(configNodeId, this.id);
},
oneditcancel: async function() {
log("counter: oneditcancel");
let configNodeId = $("#node-input-ewio2").val() || this.ewio2;
await prepareCloseWebsocket(configNodeId, this.id);
},
oneditdelete: async function() {
log("counter: oneditdelete; node-ID: " + this.id);
let configNodeId = $("#node-input-ewio2").val() || this.ewio2;
await prepareCloseWebsocket(configNodeId, this.id);
}
});
</script>
<script type="text/html" data-template-name="EWIO2 - Metering">
<div id="section-error-status" class="form-row" hidden>
<label id="label-error-status" style="color:red; width:inherit"><i class="fa fa-warning"></i> Error</label>
</div>
<div class="form-row">
<label for="node-input-ewio2"><i class="fa fa-microchip"></i> EWIO2</label>
<input type="text" id="node-input-ewio2">
</div>
<div class="form-row">
<label for="node-input-counter"><i class="fa fa-tachometer"></i> <span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.counter"></label>
<select id="node-input-counter" style="width:70%"></select>
</div>
<div class="form-row">
<label for="node-input-datapoint"><i class="fa fa-database"></i> <span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.datapoint"></label>
<select id="node-input-datapoint" style="width:70%"></select>
</div>
<div class="form-row">
<label for="node-input-value"><i class="fa fa-bullseye"></i> <span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.value"></label>
<input type="text" id="node-input-value" disabled>
</div>
<div class="form-row">
<label for="node-input-range"><i class="fa fa-arrows-h"></i> <span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.range"></label>
<input type="text" id="node-input-range" disabled>
</div>
<div class="form-row">
<label for="node-input-timestamp"><i class="fa fa-clock-o"></i> <span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.timestamp"></label>
<input type="text" id="node-input-timestamp" disabled>
</div>
<div class="form-row">
<label for="node-input-flags"><i class="fa fa-flag"></i> Flags</label>
<input type="text" id="node-input-flags" disabled>
</div>
<hr>
<div class="form-row">
<h4><span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.nodeOutput"></h4>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-outputTimestamp" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-outputTimestamp" style="width: auto" data-i18n="@metz-connect/node-red-ewio2/ewio2:label.timestamp"></label>
</div>
<div class="form-row">
<input type="checkbox" id="node-input-outputFlags" style="display: inline-block; width: auto; vertical-align: top;">
<label for="node-input-outputFlags" style="width: auto">Flags</label>
</div>
<div class="form-row">
<label for="node-input-outputTopic"><i class="fa fa-map-signs"></i> Topic</label>
<input type="text" id="node-input-outputTopic">
</div>
<hr>
<div class="form-row">
<h4><span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.loadMeasurements"></h4>
</div>
<div class="form-row">
<label for="node-input-quantity"><i class="fa fa-sort-amount-asc"></i> <span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.quantity"></label>
<input type="number" id="node-input-quantity">
</div>
<hr>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="@metz-connect/node-red-ewio2/ewio2:label.name"></label>
<input type="text" id="node-input-name"/>
</div>
</script>