UNPKG

node-red-contrib-self-healing

Version:
287 lines (262 loc) 8.85 kB
<script type="text/javascript"> RED.nodes.registerType("readings-watcher", { category: "SHEN", color: "#74b9ff", defaults: { name: { value: "" }, strategyMask: { value: 1 }, valueType: { required: true, validate: RED.validators.regex(/(percentile|fixed)/), value: "percentile", }, minchange: { required: false, validate: RED.validators.number(), value: 0.0, }, maxchange: { required: false, validate: RED.validators.number(), value: 1.0, }, stucklimit: { required: false, validate: RED.validators.number(), value: 2, }, }, inputs: 1, outputs: 2, inputLabels: "number", outputLabels: ["ok", "error"], icon: "status.png", label: function () { return this.name || "readings-watcher"; }, oneditsave: strategy_encode, oneditprepare: strategy_decode, }); function strategy_encode() { this.strategyMask = 0; if (document.getElementById("minchangeStrat").checked) this.strategyMask |= 1; if (document.getElementById("maxchangeStrat").checked) this.strategyMask |= 2; if (document.getElementById("stucklimitStrat").checked) this.strategyMask |= 4; this.valueType = document .getElementById("value-type-btn1") .classList.contains("selected") ? "percentile" : "fixed"; } function strategy_decode() { let min = document.getElementById("minchangeStrat"); let max = document.getElementById("maxchangeStrat"); let stuck = document.getElementById("stucklimitStrat"); document.getElementById("minchangeStrat").checked = (this.strategyMask & 1) == 1; document.getElementById("maxchangeStrat").checked = (this.strategyMask & 2) == 2; document.getElementById("stucklimitStrat").checked = (this.strategyMask & 4) == 4; document.getElementById("minchangeCtrl").style.display = (this.strategyMask & 1) == 1 ? "block" : "none"; document.getElementById("maxchangeCtrl").style.display = (this.strategyMask & 2) == 2 ? "block" : "none"; document.getElementById("stucklimitCtrl").style.display = (this.strategyMask & 4) == 4 ? "block" : "none"; if (this.valueType.localeCompare("fixed") == 0) { document.getElementById("value-type-btn1").classList.remove("selected"); document.getElementById("value-type-btn2").classList.add("selected"); } else { document.getElementById("value-type-btn2").classList.remove("selected"); document.getElementById("value-type-btn1").classList.add("selected"); } } function toggleVisibility(element) { let node = document.getElementById(element); node.style.display = node.style.display === "none" ? "block" : "none"; } function setValueType(element) { [].forEach.call(document.querySelectorAll(".value-type-btns"), (e) => { e.classList.remove("selected"); }); element.classList.add("selected"); } </script> <script type="text/html" data-template-name="readings-watcher"> <div class="form-row"> <br /> <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" data-i18n="[placeholder]node-red:common.label.name" /> </div> <div class="form-row"> <h3>Enable/Disable Strategies:</h3> <label for="minchangeStrat" style="width:55%;">Minimum change</label> <input type="checkbox" id="minchangeStrat" style="width:20%;" onclick="toggleVisibility('minchangeCtrl')" /> <label for="maxchangeStrat" style="width:55%;">Maximum change</label> <input type="checkbox" id="maxchangeStrat" style="width:20%;" onclick="toggleVisibility('maxchangeCtrl')" /> <label for="stucklimitStrat" style="width:55%;"> Stuck at same reading </label> <input type="checkbox" id="stucklimitStrat" style="width:20%;" onclick="toggleVisibility('stucklimitCtrl')" /> </div> <div> <div class="form-row"> <h3>Values:</h3> <span class="button-group" name="valueType"> <button id="value-type-btn1" type="button" class="red-ui-button toggle selected value-type-btns" value="percentile" onclick="setValueType(this)" > Percentile </button> <button id="value-type-btn2" type="button" class="red-ui-button toggle value-type-btns" value="fixed" onclick="setValueType(this)" > Fixed </button> </span> </div> <div class="form-row" id="minchangeCtrl"> <label for="node-input-minchange" style="width:80%;"> <i class="icon-tag"></i> Minimum change between readings: </label> <input type="number" id="node-input-minchange" placeholder="0.0" min="0" step="0.01" /> </div> <div class="form-row" id="maxchangeCtrl"> <label for="node-input-maxchange" style="width:80%;"> <i class="icon-tag"></i> Maximum change between readings: </label> <input type="number" id="node-input-maxchange" placeholder="1.0" min="0" step="0.01" /> </div> <div class="form-row" id="stucklimitCtrl"> <label for="node-input-stucklimit" style="width:80%;"> <i class="icon-tag"></i> Trigger after X repeated readings: </label> <input type="number" id="node-input-stucklimit" placeholder="2" min="2" /> </div> </div> </script> <script type="text/html" data-help-name="readings-watcher"> <p> A node to check if sequencial readings are within expected parameters, using different verification methods. </p> <h3>Properties</h3> <dl class="message-properties"> <dt>name<span class="property-type">string</span></dt> <dd>name of node to be displayed in editor</dd> <dt>toggles<span class="property-type">checkbox</span></dt> <dd>checkboxes to enable/disable the verification methods available</dd> <dt>valueType<span class="property-type">button</span></dt> <dd> Toggleable buttons to choose between percentile or fixed change calculation </dd> <dt>minchange<span class="property-type">number</span></dt> <dd>Minimum change allowed between consecutive readings</dd> <dt>maxchange<span class="property-type">number</span></dt> <dd>Maximum change allowed between consecutive readings</dd> <dt>stucklimit<span class="property-type">number</span></dt> <dd>Number of equal value readings allowed before triggering error</dd> </dl> <h3>Inputs</h3> <dl class="message-properties"> <p> A message containing a <code>payload</code> property with a <code>number</code> is required </p> <p>{ "payload":10 }</p> </dl> <h3>Outputs</h3> <dl class="message-properties"> <p> A <code>timestamp</code> is added to the message (or updated if it exists already) </p> <p> If reading is within expected parameters, message is forwarded to the <code>ok</code> output </p> <p>{ "payload": 10, "timestamp": 1604141914614 }</p> <p> Otherwise, it is sent through <code>error</code> output and a <code>type</code> is added to show which verification failed </p> <p>{ "payload": 10, "timestamp": 1604141914614, "type": "minchange" }</p> </dl> <h3>Details</h3> <p> Different strategies can be enabled to check consecutive readings. When enabled, a corresponding property will appear in the <code>Values</code> section. </p> <p> Values can be interpreted as percentile or fixed. Two consecutive readings of <code>10</code> and <code>15</code> have a <code>0.5 "percentile change</code> or a <code>5 "fixed" change</code> </p> <p> <code>minchange</code> will trigger an error if the difference between two consecutive readings is lower than the specified limit </p> <p><code>maxchange</code> will do the same if the is higher than the limit</p> <p> <code>stucklimit</code> will compare the last <code>X</code> readings and trigger an error if they are all the same value </p> <p> If the <code>payload</code> is not a <code>number</code>, no message is sent and an error is called with <code>done(error)</code>. </p> <p> When the node is finished with a message, <code>done()</code> is called, so any <code>complete</code> nodes can receive a message about it. Likewise for <code>done(err)</code> and any <code>catch</code> nodes if any error happens. </p> </script>