node-red-contrib-bool-gate
Version:
Node RED node to include boolean logic gates
186 lines (175 loc) • 6.74 kB
JavaScript
var RED = null;
var operators = {
'eq': function (a, b) { return a == b; },
'neq': function (a, b) { return a != b; },
'lt': function (a, b) { return a < b; },
'lte': function (a, b) { return a <= b; },
'gt': function (a, b) { return a > b; },
'gte': function (a, b) { return a >= b; },
'btwn': function (a, b, c) { return a >= b && a <= c; },
'cont': function (a, b) { return (a + "").indexOf(b) != -1; },
'regex': function (a, b, c, d) { return (a + "").match(new RegExp(b, d ? 'i' : '')); },
'true': function (a) { return a === true; },
'false': function (a) { return a === false; },
'null': function (a) { return (typeof a == "undefined" || a === null); },
'nnull': function (a) { return (typeof a != "undefined" && a !== null); }
};
var gates = {
'and': function (data) {
return data.every(function (element) {
if (element.hasOwnProperty("validated")) return element.validated; else return false;
})
},
'or': function (data) {
return data.some(function (element) {
if (element.hasOwnProperty("validated")) return element.validated; else return false;
})
},
'nand': function (data) {
return !data.every(function (element) {
if (element.hasOwnProperty("validated")) return element.validated; else return false;
})
},
'nor': function (data) {
return !data.some(function (element) {
if (element.hasOwnProperty("validated")) return element.validated; else return false;
});
},
'xor': function (data) {
return data.filter(function (element) {
if (element.hasOwnProperty("validated")) return element.validated; else return false;
}).length === 1;
},
'xnor': function (data) {
return data.filter(function (element) {
if (element.hasOwnProperty("validated")) return element.validated; else return false;
}).length !== 1;
}
}
class RuleManager {
constructor(red, node, gate) {
this.data = [];
RED = red;
this.node = node;
this.gate = gate;
}
storeRule(rules) {
return new Promise((resolve, reject) => {
// Store all rules
for (let i = 0; i < rules.length; i++) {
let rule = rules[i];
//Mandatory check
if (!rule.vt) {
if (!isNaN(Number(rule.v))) {
rule.vt = 'num';
} else {
rule.vt = 'str';
}
}
if (rule.vt === 'num') {
if (!isNaN(Number(rule.v))) {
rule.v = Number(rule.v);
}
}
if (typeof rule.v2 !== 'undefined') {
if (!rule.v2t) {
if (!isNaN(Number(rule.v2))) {
rule.v2t = 'num';
} else {
rule.v2t = 'str';
}
}
if (rule.v2t === 'num') {
rule.v2 = Number(rule.v2);
}
}
this.data.push(rule);
}
this.updateState().then(resolve)
});
}
getRules() {
return this.data;
}
getRulesLength() {
return this.data.length;
}
updateState(msg) {
return new Promise((resolve, reject) => {
for (let i = 0; i < this.data.length; i++) {
let rule = this.data[i];
let test = RED.util.evaluateNodeProperty(rule.property, rule.propertyType, this.node, msg);
let v1 = undefined, v2 = undefined;
switch (rule.vt) {
case 'prev': {
v1 = rule.previousValue;
break;
}
case 'msg':
case 'flow':
case 'global':
case 're':
case 'bool': {
v1 = RED.util.evaluateNodeProperty(rule.v, rule.vt, this.node, msg);
break;
}
default: {
if (rule.hasOwnProperty("v")) { // if the user set the value, take it
v1 = rule.v;
}
break;
}
}
v2 = rule.v2;
switch (rule.v2t) {
case 'prev': {
v2 = rule.previousValue;
break;
}
case 'msg':
case 'flow':
case 'global':
case 're':
case 'bool': {
if (typeof v2 !== undefined) {
v2 = RED.util.evaluateNodeProperty(rule.v2, rule.v2t, this.node, msg);
}
break;
}
default: {
if (typeof v2 !== undefined) {
v2 = RED.util.evaluateNodeProperty(rule.v2, rule.v2t, this.node, msg);
}
if (rule.hasOwnProperty("v")) { // if the user set the value, take it
v2 = rule.v2;
}
break;
}
}
//Check if the rule is ok
if (msg) { // if there is a msg
if ((rule.propertyType === 'msg' && msg.topic === rule.topic) || rule.propertyType !== 'msg') { // if the rule match with the message got
if (operators[rule.t](test, v1, v2, rule.case)) {
rule.validated = true;
} else {
rule.validated = false
}
rule.previousValue = test;
}
} else { //if not
if (rule.propertyType !== 'msg') { // if the rule isn't about a message
if (operators[rule.t](test, v1, v2, rule.case)) {
rule.validated = true;
} else {
rule.validated = false
}
rule.previousValue = test;
}
}
}
resolve(gates[this.gate](this.data))
})
}
}
module.exports = RuleManager;