node-red-contrib-boolean-logic-ultimate 1.0.62 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +11 -10
- package/boolean-logic-ultimate/BlinkerUltimate.html +1 -1
- package/boolean-logic-ultimate/BooleanLogicUltimate.html +13 -2
- package/boolean-logic-ultimate/BooleanLogicUltimate.js +488 -338
- package/boolean-logic-ultimate/Comparator.html +102 -0
- package/boolean-logic-ultimate/Comparator.js +99 -0
- package/boolean-logic-ultimate/FilterUltimate.html +16 -4
- package/boolean-logic-ultimate/FilterUltimate.js +67 -46
- package/boolean-logic-ultimate/ImpulseUltimate.html +1 -1
- package/boolean-logic-ultimate/InterruptFlowUltimate.html +15 -3
- package/boolean-logic-ultimate/InterruptFlowUltimate.js +155 -93
- package/boolean-logic-ultimate/InvertUltimate.html +14 -5
- package/boolean-logic-ultimate/InvertUltimate.js +74 -46
- package/boolean-logic-ultimate/RailwaySwitchUltimate.html +13 -2
- package/boolean-logic-ultimate/RailwaySwitchUltimate.js +110 -71
- package/boolean-logic-ultimate/SimpleOutputUltimate.html +1 -1
- package/boolean-logic-ultimate/SumUltimate.html +1 -1
- package/boolean-logic-ultimate/toggleUltimate.html +13 -3
- package/boolean-logic-ultimate/toggleUltimate.js +1 -1
- package/boolean-logic-ultimate/translator-config.html +63 -0
- package/boolean-logic-ultimate/translator-config.js +8 -0
- package/boolean-logic-ultimate/utils.js +52 -43
- package/package.json +4 -2
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('Comparator', {
|
|
3
|
+
category: 'boolean logic ultimate',
|
|
4
|
+
color: '#ff8080',
|
|
5
|
+
defaults: {
|
|
6
|
+
name: {
|
|
7
|
+
value: "Comparator"
|
|
8
|
+
},
|
|
9
|
+
property: {
|
|
10
|
+
value: "payload"
|
|
11
|
+
},
|
|
12
|
+
math: {
|
|
13
|
+
value: "==="
|
|
14
|
+
},
|
|
15
|
+
topic1: {
|
|
16
|
+
value: "", required: true
|
|
17
|
+
},
|
|
18
|
+
topic2: {
|
|
19
|
+
value: "", required: true
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
inputs: 1,
|
|
23
|
+
outputs: 1,
|
|
24
|
+
icon: "font-awesome/fa-arrows-v",
|
|
25
|
+
label:
|
|
26
|
+
function () {
|
|
27
|
+
return this.name || "Comparator";
|
|
28
|
+
},
|
|
29
|
+
paletteLabel: function () {
|
|
30
|
+
return "ComparatorUltimate";
|
|
31
|
+
},
|
|
32
|
+
oneditprepare: function () {
|
|
33
|
+
if ($("#node-input-property").val() === "") $("#node-input-property").val("payload");
|
|
34
|
+
$("#node-input-property").typedInput({ default: 'msg', types: ['msg'] });
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<script type="text/html" data-template-name="Comparator">
|
|
40
|
+
<div class="form-row">
|
|
41
|
+
<b>Comparator</b>    <span style="color:red"><i class="fa fa-youtube-play"></i> <a target="_blank" href="https://youtu.be/fDRsQPu3bG4"><u>Youtube Sample</u></a></span>
|
|
42
|
+
<br/>
|
|
43
|
+
<br/>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="form-row">
|
|
46
|
+
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
47
|
+
<input type="text" id="node-input-name" placeholder="Topic">
|
|
48
|
+
</div>
|
|
49
|
+
<hr/>
|
|
50
|
+
<div class="form-row">
|
|
51
|
+
<label for="node-input-property"><i class="icon-tag"></i> Input</label>
|
|
52
|
+
<input type="text" id="node-input-property" placeholder="payload">
|
|
53
|
+
</div>
|
|
54
|
+
<div class="form-row">
|
|
55
|
+
<label for="node-input-topic1"><i class="icon-tag"></i> Topic 1</label>
|
|
56
|
+
<input type="text" id="node-input-topic1" placeholder="For example, topic 1">
|
|
57
|
+
</div>
|
|
58
|
+
<div class="form-row">
|
|
59
|
+
<label for="node-input-math"><i class="icon-tag"></i> Operation</label>
|
|
60
|
+
<select type="text" id="node-input-math" placeholder="">
|
|
61
|
+
<option value="===">=== (equals)</option>
|
|
62
|
+
<option value="!==">!== (not equals)</option>
|
|
63
|
+
<option value=">=">></option>
|
|
64
|
+
<option value="<="><</option>
|
|
65
|
+
<option value=">=">>=</option>
|
|
66
|
+
<option value="<="><=</option>
|
|
67
|
+
</select>
|
|
68
|
+
</div>
|
|
69
|
+
<div class="form-row">
|
|
70
|
+
<label for="node-input-topic2"><i class="icon-tag"></i> Topic 2</label>
|
|
71
|
+
<input type="text" id="node-input-topic2" placeholder="For example, topic 2">
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
</script>
|
|
75
|
+
|
|
76
|
+
<script type="text/markdown" data-help-name="Comparator">
|
|
77
|
+
<p>The Comparator, compares two msg values and outputs true/false.</p>
|
|
78
|
+
|
|
79
|
+
|Property|Description|
|
|
80
|
+
|--|--|
|
|
81
|
+
| Name | It's the node name. This will be also the output topic. |
|
|
82
|
+
| Input | It's the msg property to be evaluated. *By default, it is *payload*, but you can also specify other properties, for example "payload.value"*. It **must** be a numeric value. The node will try to automatically convert numeric values expressed as strings, to real numbers. |
|
|
83
|
+
| Topic 1 | It's the topic to be evaluated against the second topic. |
|
|
84
|
+
| Comparator | It's the comparator. It compares the Topic 1 against the Topic 2. |
|
|
85
|
+
| Topic 2 | It's the second topic to be evaluated against the first topic. |
|
|
86
|
+
|
|
87
|
+
<br/>
|
|
88
|
+
|
|
89
|
+
### Outputs
|
|
90
|
+
|
|
91
|
+
1. Standard output
|
|
92
|
+
: payload (boolean) : the standard output of the command.
|
|
93
|
+
|
|
94
|
+
### Details
|
|
95
|
+
|
|
96
|
+
`msg.payload` is used as the payload of the published message. I'ts true or false based on the result of the compare operation.
|
|
97
|
+
|
|
98
|
+
<br/>
|
|
99
|
+
|
|
100
|
+
[Find it useful?](https://www.paypal.me/techtoday)
|
|
101
|
+
|
|
102
|
+
</script>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
module.exports = function (RED) {
|
|
2
|
+
function Comparator(config) {
|
|
3
|
+
RED.nodes.createNode(this, config);
|
|
4
|
+
var node = this;
|
|
5
|
+
node.config = config;
|
|
6
|
+
node.math = config.math === undefined ? "===" : config.math;
|
|
7
|
+
node.topic1Value = undefined;
|
|
8
|
+
node.topic2Value = undefined;
|
|
9
|
+
|
|
10
|
+
function setNodeStatus({ fill, shape, text }) {
|
|
11
|
+
let dDate = new Date();
|
|
12
|
+
node.status({
|
|
13
|
+
fill: fill,
|
|
14
|
+
shape: shape,
|
|
15
|
+
text:
|
|
16
|
+
text +
|
|
17
|
+
" (" +
|
|
18
|
+
dDate.getDate() +
|
|
19
|
+
", " +
|
|
20
|
+
dDate.toLocaleTimeString() +
|
|
21
|
+
")",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
setNodeStatus({ fill: "grey", shape: "dot", text: "" });
|
|
26
|
+
|
|
27
|
+
function fetchFromObject(obj, prop) {
|
|
28
|
+
if (obj === undefined) {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var _index = prop.indexOf(".");
|
|
33
|
+
if (_index > -1) {
|
|
34
|
+
return fetchFromObject(
|
|
35
|
+
obj[prop.substring(0, _index)],
|
|
36
|
+
prop.substr(_index + 1)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return obj[prop];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
node.on("input", function (msg) {
|
|
44
|
+
if (!msg.hasOwnProperty("topic")) {
|
|
45
|
+
setNodeStatus({
|
|
46
|
+
fill: "red",
|
|
47
|
+
shape: "ring",
|
|
48
|
+
text: "Incoming msg without topic! Please set the topic.",
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
let props = ([] = node.config.property.split("."));
|
|
55
|
+
let ret = fetchFromObject(msg, node.config.property);
|
|
56
|
+
if (ret !== undefined) {
|
|
57
|
+
ret = Number(ret);
|
|
58
|
+
|
|
59
|
+
// Sum
|
|
60
|
+
if (!isNaN(ret) && isFinite(ret)) {
|
|
61
|
+
if (msg.topic === node.config.topic1) node.topic1Value = ret;
|
|
62
|
+
if (msg.topic === node.config.topic2) node.topic2Value = ret;
|
|
63
|
+
|
|
64
|
+
if (
|
|
65
|
+
node.topic1Value === undefined ||
|
|
66
|
+
node.topic2Value === undefined
|
|
67
|
+
) {
|
|
68
|
+
setNodeStatus({
|
|
69
|
+
fill: "blue",
|
|
70
|
+
shape: "ring",
|
|
71
|
+
text: "Waiting for valid topics.",
|
|
72
|
+
});
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (eval(node.topic1Value + node.math + node.topic2Value)) {
|
|
77
|
+
//msg.inputmsg = RED.util.cloneMessage(msg);
|
|
78
|
+
msg.topic = node.config.name;
|
|
79
|
+
msg.payload = true;
|
|
80
|
+
} else {
|
|
81
|
+
msg.payload = false;
|
|
82
|
+
}
|
|
83
|
+
msg.topic = node.config.name;
|
|
84
|
+
node.send(msg);
|
|
85
|
+
setNodeStatus({
|
|
86
|
+
fill: "green",
|
|
87
|
+
shape: "dot",
|
|
88
|
+
text: "Done " + msg.payload,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
} catch (error) {
|
|
93
|
+
setNodeStatus({ fill: "red", shape: "ring", text: error.message });
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
RED.nodes.registerType("Comparator", Comparator);
|
|
99
|
+
};
|
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
name: {
|
|
7
7
|
value: "Filter"
|
|
8
8
|
},
|
|
9
|
-
payloadPropName: { value: "payload", required: false }
|
|
9
|
+
payloadPropName: { value: "payload", required: false },
|
|
10
|
+
translatorConfig: { type: "translator-config", required: false }
|
|
10
11
|
},
|
|
11
12
|
inputs: 1,
|
|
12
13
|
outputs: 2,
|
|
@@ -31,14 +32,14 @@
|
|
|
31
32
|
paletteLabel: function () {
|
|
32
33
|
return "FilterUltimate";
|
|
33
34
|
},
|
|
34
|
-
oneditprepare: function () {
|
|
35
|
+
oneditprepare: function () {
|
|
35
36
|
if ($("#node-input-payloadPropName").val() === "") $("#node-input-payloadPropName").val("payload");
|
|
36
37
|
$("#node-input-payloadPropName").typedInput({ default: 'msg', types: ['msg'] });
|
|
37
38
|
}
|
|
38
39
|
});
|
|
39
40
|
</script>
|
|
40
41
|
|
|
41
|
-
<script type="text/
|
|
42
|
+
<script type="text/html" data-template-name="FilterUltimate">
|
|
42
43
|
<div class="form-row">
|
|
43
44
|
<b>Filter Ultimate</b>    <span style="color:red"><i class="fa fa-question-circle"></i> <a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-boolean-logic-ultimate"><u>Help online</u></a></span>
|
|
44
45
|
   <span style="color:red"><i class="fa fa-youtube-play"></i> <a target="_blank" href="https://youtu.be/DXfpXRM-LJA"><u>Youtube Sample</u></a></span>
|
|
@@ -53,6 +54,16 @@
|
|
|
53
54
|
<label for="node-input-payloadPropName"><i class="fa fa-ellipsis-h"></i> Input</label>
|
|
54
55
|
<input type="text" id="node-input-payloadPropName">
|
|
55
56
|
</div>
|
|
57
|
+
|
|
58
|
+
<div class="form-row">
|
|
59
|
+
<br />
|
|
60
|
+
<b>Translator</b>
|
|
61
|
+
<br/>
|
|
62
|
+
<label for="node-input-translatorConfig" >
|
|
63
|
+
<font color="green" size="4px"><i class="fa fa-sign-in" aria-hidden="true"></i></font> Input
|
|
64
|
+
</label>
|
|
65
|
+
<input type="text" id="node-input-translatorConfig" />
|
|
66
|
+
</div>
|
|
56
67
|
</script>
|
|
57
68
|
|
|
58
69
|
<script type="text/markdown" data-help-name="FilterUltimate">
|
|
@@ -66,7 +77,8 @@ The input message is preserved and passed to the output, changing only the topic
|
|
|
66
77
|
|
|
67
78
|
|Property|Description|
|
|
68
79
|
|--|--|
|
|
69
|
-
| Input |
|
|
80
|
+
| Input | It's the msg property to be evaluated. *By default, it is "payload", but you can also specify other properties, for example "payload.value"* |
|
|
81
|
+
| Translator Input | Translates the incoming <code>payload</code> value, to true/false. This allows the compatibility with, for example, **HomeAssistant** nodes. |
|
|
70
82
|
|
|
71
83
|
<br/>
|
|
72
84
|
|
|
@@ -1,55 +1,76 @@
|
|
|
1
1
|
module.exports = function (RED) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
function FilterUltimate(config) {
|
|
3
|
+
RED.nodes.createNode(this, config);
|
|
4
|
+
this.config = config;
|
|
5
|
+
var node = this;
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
function setNodeStatus({ fill, shape, text }) {
|
|
8
|
+
let dDate = new Date();
|
|
9
|
+
node.status({
|
|
10
|
+
fill: fill,
|
|
11
|
+
shape: shape,
|
|
12
|
+
text:
|
|
13
|
+
text +
|
|
14
|
+
" (" +
|
|
15
|
+
dDate.getDate() +
|
|
16
|
+
", " +
|
|
17
|
+
dDate.toLocaleTimeString() +
|
|
18
|
+
")",
|
|
19
|
+
});
|
|
20
|
+
}
|
|
11
21
|
|
|
22
|
+
setNodeStatus({ fill: "grey", shape: "dot", text: "Waiting" });
|
|
23
|
+
this.on("input", function (msg) {
|
|
24
|
+
const utils = require("./utils.js");
|
|
25
|
+
let sPayload = utils.fetchFromObject(
|
|
26
|
+
msg,
|
|
27
|
+
config.payloadPropName || "payload"
|
|
28
|
+
);
|
|
12
29
|
|
|
13
|
-
|
|
14
|
-
|
|
30
|
+
// 15/11/2021 inform user about undefined topic or payload
|
|
31
|
+
if (sPayload === undefined) {
|
|
32
|
+
setNodeStatus({
|
|
33
|
+
fill: "red",
|
|
34
|
+
shape: "dot",
|
|
35
|
+
text: "Received invalid payload from " + msg.topic || "",
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
15
39
|
|
|
16
|
-
|
|
17
|
-
|
|
40
|
+
var bRes = null;
|
|
41
|
+
try {
|
|
42
|
+
bRes = utils.ToBoolean(
|
|
43
|
+
sPayload,
|
|
44
|
+
RED.nodes.getNode(config.translatorConfig) // Retrieve the config node. It can be null, but it's handled in utils.js
|
|
45
|
+
);
|
|
46
|
+
} catch (error) {}
|
|
18
47
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
48
|
+
if (bRes === undefined || bRes === null) {
|
|
49
|
+
setNodeStatus({
|
|
50
|
+
fill: "red",
|
|
51
|
+
shape: "dot",
|
|
52
|
+
text:
|
|
53
|
+
"Received non convertible boolean value " +
|
|
54
|
+
sPayload +
|
|
55
|
+
" from " +
|
|
56
|
+
msg.topic,
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
24
60
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
bRes = utils.ToBoolean(sPayload);
|
|
29
|
-
} catch (error) {
|
|
30
|
-
}
|
|
61
|
+
// 24/01/2020 Clone input message and replace only payload
|
|
62
|
+
var msgOut = RED.util.cloneMessage(msg);
|
|
63
|
+
msgOut.payload = bRes;
|
|
31
64
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
65
|
+
if (bRes === true) {
|
|
66
|
+
setNodeStatus({ fill: "green", shape: "dot", text: "(Send) true" });
|
|
67
|
+
node.send([msgOut, null]);
|
|
68
|
+
} else if (bRes === false) {
|
|
69
|
+
setNodeStatus({ fill: "green", shape: "dot", text: "(Send) false" });
|
|
70
|
+
node.send([null, msgOut]);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
36
74
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
msgOut.payload = bRes;
|
|
40
|
-
|
|
41
|
-
if (bRes === true) {
|
|
42
|
-
setNodeStatus({ fill: "green", shape: "dot", text: "(Send) true" });
|
|
43
|
-
node.send([msgOut, null]);
|
|
44
|
-
} else if (bRes === false) {
|
|
45
|
-
setNodeStatus({ fill: "green", shape: "dot", text: "(Send) false" });
|
|
46
|
-
node.send([null, msgOut]);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
RED.nodes.registerType("FilterUltimate", FilterUltimate);
|
|
55
|
-
}
|
|
75
|
+
RED.nodes.registerType("FilterUltimate", FilterUltimate);
|
|
76
|
+
};
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
|
|
89
89
|
|Property|Description|
|
|
90
90
|
|--|--|
|
|
91
|
-
| Input |
|
|
91
|
+
| Input | It's the msg property to be evaluated. *By default, it is "payload", but you can also specify other properties, for example "payload.value"* |
|
|
92
92
|
|
|
93
93
|
* Avaiable Commands
|
|
94
94
|
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
triggertopic: { value: "trigger" },
|
|
8
8
|
initializewith: { value: "1" },
|
|
9
9
|
autoToggle: { value: "0" },
|
|
10
|
-
payloadPropName: { value: "payload", required: false }
|
|
10
|
+
payloadPropName: { value: "payload", required: false },
|
|
11
|
+
translatorConfig: { type: "translator-config", required: false }
|
|
11
12
|
},
|
|
12
13
|
inputs: 1,
|
|
13
14
|
outputs: 1,
|
|
@@ -39,7 +40,7 @@
|
|
|
39
40
|
});
|
|
40
41
|
</script>
|
|
41
42
|
|
|
42
|
-
<script type="text/
|
|
43
|
+
<script type="text/html" data-template-name="InterruptFlowUltimate">
|
|
43
44
|
<div class="form-row">
|
|
44
45
|
<b>Interrupt Flow Ultimate</b>    <span style="color:red"><i class="fa fa-question-circle"></i> <a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-boolean-logic-ultimate"><u>Help online</u></a></span>
|
|
45
46
|
   <span style="color:red"><i class="fa fa-youtube-play"></i> <a target="_blank" href="https://youtu.be/1T1g0HCeYA8"><u>Youtube Sample</u></a></span>
|
|
@@ -84,6 +85,16 @@
|
|
|
84
85
|
<option value="120">Toggle above option after 120 seconds</option>
|
|
85
86
|
</select>
|
|
86
87
|
</div>
|
|
88
|
+
|
|
89
|
+
<div class="form-row">
|
|
90
|
+
<br />
|
|
91
|
+
<b>Translator</b>
|
|
92
|
+
<br/>
|
|
93
|
+
<label for="node-input-translatorConfig" >
|
|
94
|
+
<font color="green" size="4px"><i class="fa fa-sign-in" aria-hidden="true"></i></font> Input
|
|
95
|
+
</label>
|
|
96
|
+
<input type="text" id="node-input-translatorConfig" />
|
|
97
|
+
</div>
|
|
87
98
|
</script>
|
|
88
99
|
|
|
89
100
|
<script type="text/markdown" data-help-name="InterruptFlowUltimate">
|
|
@@ -94,8 +105,9 @@
|
|
|
94
105
|
|Property|Description|
|
|
95
106
|
|--|--|
|
|
96
107
|
| Trigger by topic | Whenever the node receives a payload = false from this topic,it stops output messages to the flow. As soon it receives payload = true from this topic, the output messages start to flow out again. The node will output the current stored message plus an added property "isReplay = true", as soon as it receives a ***msg.play = true*** from this topic. The node will clear the current stored message, as soon as it receives a ***msg.reset = true*** from this topic. |
|
|
97
|
-
| With Input |
|
|
108
|
+
| With Input | It's the msg property to be evaluated. *By default, it is "payload", but you can also specify other properties, for example "payload.value"* |
|
|
98
109
|
| Then | This property, allow you to auto toggle the selected start state (pass or block) after a timer has elapsed. You can choose from some pre-defined delays. If you have, for example, an Homekit-Bridged nodeset with a thermostat node or security system node in your flow, once node-red restarts, these homekit nodes output a default message to the flow. Just put an InterruptFlow node with a "block at start" behaviour and a toggle delay enabled behind homekit nodes, to temporary stop the chained nodes to receive the unwanted startup message.|
|
|
110
|
+
| Translator Input | Translates the incoming <code>payload</code> value, to true/false. This allows the compatibility with, for example, **HomeAssistant** nodes. |
|
|
99
111
|
|
|
100
112
|
<br/>
|
|
101
113
|
|