Massimo 4 anni fa
parent
commit
18cdfb8c22
4 ha cambiato i file con 98 aggiunte e 122 eliminazioni
  1. +4
    -0
      CHANGELOG.md
  2. +91
    -119
      boolean-logic-ultimate/BooleanLogicUltimate.js
  3. +2
    -2
      boolean-logic-ultimate/FilterUltimate.js
  4. +1
    -1
      package.json

+ 4
- 0
CHANGELOG.md Vedi File



<a href="http://eepurl.com/gJm095" target="_blank">Subscribe to my channel.</a> Only news about my nodes, no spam, no ads. I'm a github developer, not a merchant. <a href="http://eepurl.com/gJm095" target="_blank">Subscribe to my channel.</a> Only news about my nodes, no spam, no ads. I'm a github developer, not a merchant.


<p>
<b>Version 1.0.15</b>May 2020<br/>
- Adjusted status of Boolean Logic ultimate. Replaced the text "null", with --- for better understanding.</br>
</p>
<p> <p>
<b>Version 1.0.14</b><br/> <b>Version 1.0.14</b><br/>
- NEW: added blinker node. Thanks to @Marco for the suggestion.</br> - NEW: added blinker node. Thanks to @Marco for the suggestion.</br>

+ 91
- 119
boolean-logic-ultimate/BooleanLogicUltimate.js Vedi File

module.exports = function(RED) {
function BooleanLogicUltimate(config) {
module.exports = function (RED) {
function BooleanLogicUltimate(config) {
RED.nodes.createNode(this, config); RED.nodes.createNode(this, config);
var node = this; var node = this;
node.config = config; node.config = config;
node.sInitializeWith = typeof node.config.sInitializeWith === "undefined" ? "WaitForPayload" : node.config.sInitializeWith; node.sInitializeWith = typeof node.config.sInitializeWith === "undefined" ? "WaitForPayload" : node.config.sInitializeWith;
var fs = require('fs'); var fs = require('fs');
var decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/ var decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
// Helper for the config html, to be able to delete the peristent states file // Helper for the config html, to be able to delete the peristent states file
RED.httpAdmin.get("/stateoperation_delete", RED.auth.needsPermission('BooleanLogicUltimate.read'), function (req, res) { RED.httpAdmin.get("/stateoperation_delete", RED.auth.needsPermission('BooleanLogicUltimate.read'), function (req, res) {
//node.send({ req: req }); //node.send({ req: req });
var contents = fs.readFileSync("states/" + node.id.toString()).toString(); var contents = fs.readFileSync("states/" + node.id.toString()).toString();
if (typeof contents !== 'undefined') { if (typeof contents !== 'undefined') {
node.jSonStates = JSON.parse(contents); node.jSonStates = JSON.parse(contents);
setNodeStatus({fill: "blue",shape: "ring",text: "Loaded persistent states (" + Object.keys(node.jSonStates).length + " total)."});
setNodeStatus({ fill: "blue", shape: "ring", text: "Loaded persistent states (" + Object.keys(node.jSonStates).length + " total)." });
} }
} catch (error) { } catch (error) {
setNodeStatus({fill: "grey",shape: "ring",text: "No persistent states"});
setNodeStatus({ fill: "grey", shape: "ring", text: "No persistent states" });
} }
} else { } else {
setNodeStatus({fill: "yellow",shape: "dot",text: "Waiting for input states"});
setNodeStatus({ fill: "yellow", shape: "dot", text: "Waiting for input states" });
} }




// 14/08/2019 If some inputs are to be initialized, create a dummy items in the array // 14/08/2019 If some inputs are to be initialized, create a dummy items in the array
initUndefinedInputs(); initUndefinedInputs();


this.on('input', function (msg) { this.on('input', function (msg) {
var topic = msg.topic; var topic = msg.topic;
var payload = msg.payload; var payload = msg.payload;
if (topic !== undefined && payload !== undefined) { if (topic !== undefined && payload !== undefined) {
var value = ToBoolean( payload );
var value = ToBoolean(payload);
// 14/08/2019 if inputs are initialized, remove a "dummy" item from the state's array, as soon as new topic arrives // 14/08/2019 if inputs are initialized, remove a "dummy" item from the state's array, as soon as new topic arrives
if(node.sInitializeWith !== "WaitForPayload")
{
if (node.sInitializeWith !== "WaitForPayload") {
// Search if the current topic is in the state array // Search if the current topic is in the state array
if (typeof node.jSonStates[topic] === "undefined")
{
if (typeof node.jSonStates[topic] === "undefined") {
// Delete one dummy // Delete one dummy
for (let index = 0; index < node.config.inputCount; index++) { for (let index = 0; index < node.config.inputCount; index++) {
if (node.jSonStates.hasOwnProperty("dummy" + index)) { if (node.jSonStates.hasOwnProperty("dummy" + index)) {
delete node.jSonStates["dummy" + index]; delete node.jSonStates["dummy" + index];
//RED.log.info(JSON.stringify(node.jSonStates)) //RED.log.info(JSON.stringify(node.jSonStates))
break; break;
}
}
} }
} }
} }
// Add current attribute // Add current attribute
node.jSonStates[topic] = value; node.jSonStates[topic] = value;
// Save the state array to a perisistent file // Save the state array to a perisistent file
if (node.config.persist == true) {
if (node.config.persist == true) {
try { try {
if (!fs.existsSync("states")) fs.mkdirSync("states"); if (!fs.existsSync("states")) fs.mkdirSync("states");
fs.writeFileSync("states/" + node.id.toString(),JSON.stringify(node.jSonStates));
fs.writeFileSync("states/" + node.id.toString(), JSON.stringify(node.jSonStates));
} catch (error) { } catch (error) {
setNodeStatus({fill: "red",shape: "dot",text: "Node cannot write to filesystem: " + error});
setNodeStatus({ fill: "red", shape: "dot", text: "Node cannot write to filesystem: " + error });
} }
} }
// Do we have as many inputs as we expect? // Do we have as many inputs as we expect?
var keyCount = Object.keys(node.jSonStates).length; var keyCount = Object.keys(node.jSonStates).length;


if( keyCount == node.config.inputCount ) {
if (keyCount == node.config.inputCount) {
var resAND = CalculateResult("AND"); var resAND = CalculateResult("AND");
var resOR = CalculateResult("OR"); var resOR = CalculateResult("OR");
var resXOR = CalculateResult("XOR"); var resXOR = CalculateResult("XOR");
if (node.config.outputtriggeredby == "onlyonetopic") { if (node.config.outputtriggeredby == "onlyonetopic") {
if (typeof node.config.triggertopic !== "undefined" if (typeof node.config.triggertopic !== "undefined"
&& node.config.triggertopic !== "" && node.config.triggertopic !== ""
&& msg.hasOwnProperty("topic") && msg.topic !==""
&& node.config.triggertopic === msg.topic)
{
SetResult(resAND, resOR, resXOR, node.config.topic,msg);
} else
{
setNodeStatus({ fill: "grey", shape: "ring", text: "Saved (" + (msg.hasOwnProperty("topic") ? msg.topic : "empty input topic") + ") " + value});
&& msg.hasOwnProperty("topic") && msg.topic !== ""
&& node.config.triggertopic === msg.topic) {
SetResult(resAND, resOR, resXOR, node.config.topic, msg);
} else {
setNodeStatus({ fill: "grey", shape: "ring", text: "Saved (" + (msg.hasOwnProperty("topic") ? msg.topic : "empty input topic") + ") " + value });
} }
} else
{
SetResult(resAND, resOR, resXOR, node.config.topic,msg);
} else {
SetResult(resAND, resOR, resXOR, node.config.topic, msg);
} }
} }
else if(keyCount > node.config.inputCount ) {
setNodeStatus({ fill: "gray", shape: "ring", text: "Reset due to unexpected new topic"});
else if (keyCount > node.config.inputCount) {
setNodeStatus({ fill: "gray", shape: "ring", text: "Reset due to unexpected new topic" });
DeletePersistFile(); DeletePersistFile();
} else { } else {
setNodeStatus({ fill: "green", shape: "ring", text: "Arrived topic " + keyCount + " of " + node.config.inputCount});
setNodeStatus({ fill: "green", shape: "ring", text: "Arrived topic " + keyCount + " of " + node.config.inputCount });
} }
} }
}); });
this.on('close', function(removed, done) {
this.on('close', function (removed, done) {
if (removed) { if (removed) {
// This node has been deleted // This node has been deleted
// Delete persistent states on change/deploy // Delete persistent states on change/deploy
done(); done();
}); });


function DeletePersistFile (){
function DeletePersistFile() {
// Detele the persist file // Detele the persist file
try { try {
if (fs.existsSync("states/" + node.id.toString())) fs.unlinkSync("states/" + node.id.toString()); if (fs.existsSync("states/" + node.id.toString())) fs.unlinkSync("states/" + node.id.toString());
setNodeStatus({fill: "red",shape: "ring",text: "Persistent states deleted ("+node.id.toString()+")."});
setNodeStatus({ fill: "red", shape: "ring", text: "Persistent states deleted (" + node.id.toString() + ")." });
} catch (error) { } catch (error) {
setNodeStatus({fill: "red",shape: "ring",text: "Error deleting persistent file: " + error.toString()});
setNodeStatus({ fill: "red", shape: "ring", text: "Error deleting persistent file: " + error.toString() });
} }
node.jSonStates = {}; // Resets inputs node.jSonStates = {}; // Resets inputs
// 14/08/2019 If the inputs are to be initialized, create a dummy items in the array // 14/08/2019 If the inputs are to be initialized, create a dummy items in the array
} }


function initUndefinedInputs() { function initUndefinedInputs() {
if (node.sInitializeWith !== "WaitForPayload")
{
if (node.sInitializeWith !== "WaitForPayload") {
var nTotalDummyToCreate = Number(node.config.inputCount) - Object.keys(node.jSonStates).length; var nTotalDummyToCreate = Number(node.config.inputCount) - Object.keys(node.jSonStates).length;
if (nTotalDummyToCreate > 0) { if (nTotalDummyToCreate > 0) {
RED.log.info("BooleanLogicUltimate: Will create " + nTotalDummyToCreate + " dummy (" + node.sInitializeWith + ") values") RED.log.info("BooleanLogicUltimate: Will create " + nTotalDummyToCreate + " dummy (" + node.sInitializeWith + ") values")
for (let index = 0; index < nTotalDummyToCreate; index++) { for (let index = 0; index < nTotalDummyToCreate; index++) {
node.jSonStates["dummy" + index] = node.sInitializeWith === "false" ? false : true; node.jSonStates["dummy" + index] = node.sInitializeWith === "false" ? false : true;
} }
setTimeout(() => { setNodeStatus({fill: "green",shape: "ring",text: "Initialized " + nTotalDummyToCreate + " undefined inputs with " + node.sInitializeWith});}, 4000)
}
setTimeout(() => { setNodeStatus({ fill: "green", shape: "ring", text: "Initialized " + nTotalDummyToCreate + " undefined inputs with " + node.sInitializeWith }); }, 4000)
}
} }
} }


function setNodeStatus({fill, shape, text})
{
function setNodeStatus({ fill, shape, text }) {
var dDate = new Date(); var dDate = new Date();
node.status({fill: fill,shape: shape,text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")"})
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
} }


function CalculateResult(_operation) { function CalculateResult(_operation) {
var res; var res;
if( _operation == "XOR") {
if (_operation == "XOR") {
res = PerformXOR(); res = PerformXOR();
} }
else { else {
// We need a starting value to perform AND and OR operations. // We need a starting value to perform AND and OR operations.
var keys = Object.keys(node.jSonStates); var keys = Object.keys(node.jSonStates);
res = node.jSonStates[keys[0]]; res = node.jSonStates[keys[0]];
for( var i = 1; i < keys.length; ++i ) {
for (var i = 1; i < keys.length; ++i) {
var key = keys[i]; var key = keys[i];
res = PerformSimpleOperation( _operation, res, node.jSonStates[key] );
res = PerformSimpleOperation(_operation, res, node.jSonStates[key]);
} }
} }
return res;
}
function PerformXOR()
{

return res;
}

function PerformXOR() {
// XOR = exclusively one input is true. As such, we just count the number of true values and compare to 1. // XOR = exclusively one input is true. As such, we just count the number of true values and compare to 1.
var trueCount = 0; var trueCount = 0;
for( var key in node.jSonStates ) {
if( node.jSonStates[key] ) {
for (var key in node.jSonStates) {
if (node.jSonStates[key]) {
trueCount++; trueCount++;
} }
} }
return trueCount == 1; return trueCount == 1;
} }
function PerformSimpleOperation( operation, val1, val2 ) {
function PerformSimpleOperation(operation, val1, val2) {
var res; var res;
if( operation === "AND" ) {
if (operation === "AND") {
res = val1 && val2; res = val1 && val2;
} }
else if( operation === "OR" ) {
else if (operation === "OR") {
res = val1 || val2; res = val1 || val2;
} }
else { else {
node.error( "Unknown operation: " + operation );
node.error("Unknown operation: " + operation);
} }
return res; return res;
} }
function ToBoolean( value ) {
function ToBoolean(value) {
var res = false; var res = false;
if (typeof value === 'boolean') { if (typeof value === 'boolean') {
res = value; res = value;
}
else if( typeof value === 'number' || typeof value === 'string' ) {
}
else if (typeof value === 'number' || typeof value === 'string') {
// Is it formated as a decimal number? // Is it formated as a decimal number?
if( decimal.test( value ) ) {
var v = parseFloat( value );
if (decimal.test(value)) {
var v = parseFloat(value);
res = v != 0; res = v != 0;
} }
else { else {
res = value.toLowerCase() === "true"; res = value.toLowerCase() === "true";
} }
} }
return res; return res;
}; };
function SetResult(_valueAND, _valueOR, _valueXOR, optionalTopic,_msg) {
setNodeStatus({fill: "green",shape: "dot",text: "(AND)" + _valueAND + " (OR)" +_valueOR + " (XOR)" +_valueXOR});
// 24/01/2020 Output the entire input msg by duplicating the input and replacing only relevant fields.
function SetResult(_valueAND, _valueOR, _valueXOR, optionalTopic, _msg) {
setNodeStatus({ fill: "green", shape: "dot", text: "(AND)" + (_valueAND !== null ? _valueAND : "---") + " (OR)" + (_valueOR !== null ? _valueOR : "---") + " (XOR)" + (_valueXOR !== null ? _valueXOR : "---") });
var msgAND = null;
if (_valueAND != null) { if (_valueAND != null) {
var msgAND = RED.util.cloneMessage(_msg);
msgAND = RED.util.cloneMessage(_msg);
msgAND.topic = optionalTopic === undefined ? "result" : optionalTopic; msgAND.topic = optionalTopic === undefined ? "result" : optionalTopic;
msgAND.operation = "AND"; msgAND.operation = "AND";
msgAND.payload = _valueAND; msgAND.payload = _valueAND;
} }
if (_valueOR!=null){
var msgOR = RED.util.cloneMessage(_msg);
var msgOR = null;
if (_valueOR != null) {
msgOR = RED.util.cloneMessage(_msg);
msgOR.topic = optionalTopic === undefined ? "result" : optionalTopic; msgOR.topic = optionalTopic === undefined ? "result" : optionalTopic;
msgOR.operation = "OR"; msgOR.operation = "OR";
msgOR.payload= _valueOR;
msgOR.payload = _valueOR;
} }
var msgXOR = null;
if (_valueXOR != null) { if (_valueXOR != null) {
var msgXOR = RED.util.cloneMessage(_msg);
msgXOR = RED.util.cloneMessage(_msg);
msgXOR.topic = optionalTopic === undefined ? "result" : optionalTopic; msgXOR.topic = optionalTopic === undefined ? "result" : optionalTopic;
msgXOR.operation = "XOR"; msgXOR.operation = "XOR";
msgXOR.payload= _valueXOR;
msgXOR.payload = _valueXOR;
} }
node.send([msgAND, msgOR, msgXOR]); node.send([msgAND, msgOR, msgXOR]);
// if (_valueAND!=null){
// var msgAND = {
// topic: optionalTopic === undefined ? "result" : optionalTopic,
// operation:"AND",
// payload: _valueAND
// };
// }
// if (_valueOR!=null){
// var msgOR = {
// topic: optionalTopic === undefined ? "result" : optionalTopic,
// operation:"OR",
// payload: _valueOR
// };
// }
// if (_valueXOR!=null){
// var msgXOR = {
// topic: optionalTopic === undefined ? "result" : optionalTopic,
// operation:"XOR",
// payload: _valueXOR
// };
// }
// node.send([msgAND,msgOR,msgXOR]);

}; };
}
RED.nodes.registerType("BooleanLogicUltimate",BooleanLogicUltimate);
}

RED.nodes.registerType("BooleanLogicUltimate", BooleanLogicUltimate);
} }

+ 2
- 2
boolean-logic-ultimate/FilterUltimate.js Vedi File

msgFalse.payload = false; msgFalse.payload = false;
if (bRes === true) { if (bRes === true) {
setNodeStatus({ fill: "green", shape: "dot", text: "(Send) true,null" });
setNodeStatus({ fill: "green", shape: "dot", text: "(Send) true" });
node.send([msgTrue, null]); node.send([msgTrue, null]);
} else } else
{ {
setNodeStatus( {fill: "green" ,shape: "dot" ,text: "(Send) null,false"});
setNodeStatus( {fill: "green" ,shape: "dot" ,text: "(Send) false"});
node.send([null, msgFalse]); node.send([null, msgFalse]);
} }
return; return;

+ 1
- 1
package.json Vedi File

{ {
"name": "node-red-contrib-boolean-logic-ultimate", "name": "node-red-contrib-boolean-logic-ultimate",
"version": "1.0.14",
"version": "1.0.15",
"description": "A set of Node-RED enhanced boolean logic, with persisten values after reboot and more", "description": "A set of Node-RED enhanced boolean logic, with persisten values after reboot and more",
"author": "Supergiovane (https://github.com/Supergiovane)", "author": "Supergiovane (https://github.com/Supergiovane)",
"dependencies": { "dependencies": {

Loading…
Annulla
Salva