node-red-contrib-boolean-logic-ultimate 1.1.24 → 1.1.26
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 +16 -0
- package/README.md +48 -5
- package/boolean-logic-ultimate/InterruptFlowUltimate.js +79 -78
- package/boolean-logic-ultimate/utils.js +11 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,22 @@
|
|
|
3
3
|
|
|
4
4
|
# CHANGELOG
|
|
5
5
|
|
|
6
|
+
<p>
|
|
7
|
+
<b>Version 1.1.26</b> July 2025<br/>
|
|
8
|
+
- Interruptflow node: fixed non functional msg.play. </br>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p>
|
|
12
|
+
<b>Version 1.1.25</b> January 2025<br/>
|
|
13
|
+
- BREAKING CHANGE<br/>
|
|
14
|
+
- BREAKING CHANGE<br/>
|
|
15
|
+
- BREAKING CHANGE<br/>
|
|
16
|
+
- Numerical values are now evaluated as string values and translated like any other word in translation table. That means, 1 and numbers major than 1 are not equal to true anymore, and 0 is not equal to false anymore. If you input numerical values as boolean (bad attitude), please fix your flows by change it to boolean.</br>
|
|
17
|
+
- BREAKING CHANGE<br/>
|
|
18
|
+
- BREAKING CHANGE<br/>
|
|
19
|
+
- BREAKING CHANGE<br/>
|
|
20
|
+
|
|
21
|
+
</p>
|
|
6
22
|
<p>
|
|
7
23
|
<b>Version 1.1.24</b> January 2025<br/>
|
|
8
24
|
- Translator node. added js evaluation of the values. For example "{{value>=50}}:true".</br>
|
package/README.md
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|

|
|
2
|
+
|
|
2
3
|
[![NPM version][npm-version-image]][npm-url]
|
|
3
4
|
[![NPM downloads per month][npm-downloads-month-image]][npm-url]
|
|
4
5
|
[![NPM downloads total][npm-downloads-total-image]][npm-url]
|
|
@@ -24,13 +25,9 @@ A set of Node-RED enhanced boolean logic and utility nodes, with persistent valu
|
|
|
24
25
|
Other than true/false, all nodes accepts [Homeassistant](https://www.home-assistant.io) output strings.
|
|
25
26
|
|
|
26
27
|
You can **even add your own input translation word list**, thanks to the translator-config node.
|
|
27
|
-
|
|
28
28
|
The translator node can translate an input payload, to a true/false boolean values.<br />
|
|
29
|
-
|
|
30
29
|
Each row in the text box, represents a translation command. <br/>
|
|
31
|
-
|
|
32
30
|
There are some default translation's rows, to make the *boolean-logic-ultimate* nodes compatible with Homeassistant as default. <br/>
|
|
33
|
-
|
|
34
31
|
You can add your own translation row.<br/>
|
|
35
32
|
|
|
36
33
|
| | Description |
|
|
@@ -39,6 +36,48 @@ You can add your own translation row.<br/>
|
|
|
39
36
|
|
|
40
37
|

|
|
41
38
|
|
|
39
|
+
|
|
40
|
+
<br/>
|
|
41
|
+
<br/>
|
|
42
|
+
|
|
43
|
+
# BOOLEAN LOGIC
|
|
44
|
+
|
|
45
|
+
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/bl1.png' width='60%'>
|
|
46
|
+
|
|
47
|
+
<details><summary>CLICK HERE, copy and paste it into your flow</summary>
|
|
48
|
+
<code>
|
|
49
|
+
[{"id":"1a90a718.5c0409","type":"BooleanLogicUltimate","z":"adb2ee5c.0bf6e","name":"","filtertrue":"both","persist":true,"sInitializeWith":"WaitForPayload","triggertopic":"trigger","outputtriggeredby":"all","inputCount":2,"topic":"result","x":380,"y":160,"wires":[["5f9fbfcc.d2c34"],[],[]]},{"id":"81ef6fec.5d413","type":"inject","z":"adb2ee5c.0bf6e","name":"Night","topic":"Dark","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":180,"wires":[["1a90a718.5c0409"]]},{"id":"e0d5d620.966478","type":"inject","z":"adb2ee5c.0bf6e","name":"Daylight","topic":"Dark","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":160,"y":140,"wires":[["1a90a718.5c0409"]]},{"id":"1c2f8e73.2c22ba","type":"inject","z":"adb2ee5c.0bf6e","name":"Motion detect true","topic":"Motion","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":240,"wires":[["1a90a718.5c0409"]]},{"id":"5f9fbfcc.d2c34","type":"debug","z":"adb2ee5c.0bf6e","name":"Garden Light","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":580,"y":160,"wires":[]},{"id":"201baa3d.7c63ae","type":"inject","z":"adb2ee5c.0bf6e","name":"Motion detect false","topic":"Motion","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":280,"wires":[["1a90a718.5c0409"]]},{"id":"b65f4ff4.bfe2c8","type":"comment","z":"adb2ee5c.0bf6e","name":"Motion sensor turns on lights, when it's dark. The light turns off itself at day","info":"","x":290,"y":100,"wires":[]}]
|
|
50
|
+
</code>
|
|
51
|
+
</details>
|
|
52
|
+
|
|
53
|
+
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/bl2.png' width='60%'>
|
|
54
|
+
|
|
55
|
+
<details><summary>CLICK HERE, copy and paste it into your flow</summary>
|
|
56
|
+
<code>
|
|
57
|
+
[{"id":"53a10a7a.cf1894","type":"BooleanLogicUltimate","z":"a76c6a12.37379","name":"","filtertrue":"onlytrue","persist":true,"sInitializeWith":"true","triggertopic":"Pushbutton","outputtriggeredby":"onlyonetopic","inputCount":2,"topic":"result","x":340,"y":220,"wires":[["cd9244ea.471b78"],[],[]]},{"id":"9318320b.670af8","type":"inject","z":"a76c6a12.37379","name":"","topic":"Pushbutton","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":220,"wires":[["53a10a7a.cf1894"]]},{"id":"20a981b9.552b4e","type":"inject","z":"a76c6a12.37379","name":"","topic":"IsNight","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":320,"wires":[["53a10a7a.cf1894"]]},{"id":"da0dff55.d7888","type":"inject","z":"a76c6a12.37379","name":"","topic":"IsNight","payload":"false","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":360,"wires":[["53a10a7a.cf1894"]]},{"id":"7129d101.1fb7d8","type":"comment","z":"a76c6a12.37379","name":"Pushbutton to switch on light stairs, only if it's night.","info":"","x":210,"y":180,"wires":[]},{"id":"cd9244ea.471b78","type":"debug","z":"a76c6a12.37379","name":"Temporized Stairs Lightbulb","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":580,"y":220,"wires":[]},{"id":"ad5a62a1.7ad81","type":"comment","z":"a76c6a12.37379","name":"Brightness sensor","info":"","x":110,"y":280,"wires":[]}]
|
|
58
|
+
</code>
|
|
59
|
+
</details>
|
|
60
|
+
|
|
61
|
+
The node performs Boolean logic on the incoming payloads.<br/>
|
|
62
|
+
|
|
63
|
+
The node expects a fixed number of topics (configured in the settings) on which it will operate. It will only output a value
|
|
64
|
+
|
|
65
|
+
when it has seen the expected number of topics. If it ever sees more than the configured number of topics it will log a message then reset its state and start over.<br/>
|
|
66
|
+
|
|
67
|
+
The input message is preserved and passed to the output, changing only the topic and the payload.
|
|
68
|
+
|
|
69
|
+
The node performs some checks on the incoming boolean payloads and outputs all results at the same time, as follow:<br/>
|
|
70
|
+
|
|
71
|
+
- Output "AND": true or false<br/>
|
|
72
|
+
- Output "OR": true or false<br/>
|
|
73
|
+
- Output "XOR": true or false<br/>
|
|
74
|
+
|
|
75
|
+
If you need ***"NAND"*** or ***"NOR"*** gate, just put an **InvertUltimate** node respectively after the "AND" or "OR" output.
|
|
76
|
+
|
|
77
|
+
The node can have a persistent input: the input values are retained after a node-red reboot. That means, that if you reboot your node-red, you don't need to wait all inputs to arrive and initialize the node, before the node can output a payload.<br/>
|
|
78
|
+
|
|
79
|
+
You can also set the default values of the topic inputs.<br/>
|
|
80
|
+
|
|
42
81
|
The node can convert arbitrary input values to true/false. It supports Homeassistant string to boolean conversion as well. For enabling auto conversion, please be sure to disable **Reject non boolean (true/false) input values** <br/>
|
|
43
82
|
|
|
44
83
|
### NODE CONFIGURATION
|
|
@@ -86,8 +125,11 @@ The interrupt flows is able to stop the input messages to exiting the node.
|
|
|
86
125
|
**INPUT MSG WITH "TRIGGER" TOPIC**
|
|
87
126
|
|
|
88
127
|
Pass <code>msg.payload = true</code> to allow messages to pass through</br>
|
|
128
|
+
|
|
89
129
|
Pass <code>msg.payload = false</code> to prevent messages from passing through</br>
|
|
130
|
+
|
|
90
131
|
Pass <code>msg.play = true</code> from a message having the "trigger" topic, to replay the last stored message</br>
|
|
132
|
+
|
|
91
133
|
Pass <code>msg.reset = true</code> from a message having the "trigger" topic, to clear the last stored message</br>
|
|
92
134
|
|
|
93
135
|
<code>
|
|
@@ -485,6 +527,8 @@ Copy and paste it into your flow
|
|
|
485
527
|
|
|
486
528
|
Please refer to [this](https://github.com/wouterbulten/kalmanjs) link, on how it works.
|
|
487
529
|
|
|
530
|
+
|
|
531
|
+
|
|
488
532
|

|
|
489
533
|
|
|
490
534
|
| Property | Description |
|
|
@@ -498,7 +542,6 @@ Please refer to [this](https://github.com/wouterbulten/kalmanjs) link, on how it
|
|
|
498
542
|
### Inputs
|
|
499
543
|
|
|
500
544
|
: reset (any) : by passing msg.reset, the Kalman filter will be reset.
|
|
501
|
-
|
|
502
545
|
: payload (number) : the payload containing the number. If you've changed the incoming evaluation property in the ***Input*** field, the number to be evaluated must be put in such message's property, instead of the *payload* property.
|
|
503
546
|
|
|
504
547
|
<br/>
|
|
@@ -11,7 +11,7 @@ module.exports = function (RED) {
|
|
|
11
11
|
) || "trigger"; // Topic controlling the bInviaMessaggio
|
|
12
12
|
node.bInviaMessaggio =
|
|
13
13
|
node.config.initializewith === undefined ||
|
|
14
|
-
|
|
14
|
+
node.config.initializewith === "1"
|
|
15
15
|
? true
|
|
16
16
|
: false; // Send the message or not
|
|
17
17
|
node.autoToggle =
|
|
@@ -64,94 +64,95 @@ module.exports = function (RED) {
|
|
|
64
64
|
|
|
65
65
|
this.on("input", function (msg) {
|
|
66
66
|
var sIncomingTopic = "";
|
|
67
|
-
if (msg.hasOwnProperty("topic")) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
67
|
+
//if (msg.hasOwnProperty("topic")) {
|
|
68
|
+
// 06/11/2019
|
|
69
|
+
if (!msg.hasOwnProperty("topic") || msg.topic === undefined)
|
|
70
|
+
msg.topic = "NoTopicReceived";
|
|
71
|
+
sIncomingTopic = msg.topic.replace(
|
|
72
|
+
/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi,
|
|
73
|
+
""
|
|
74
|
+
); // Cut unwanted Characters
|
|
75
|
+
if (sIncomingTopic === node.sTriggerTopic) {
|
|
76
|
+
const utils = require("./utils.js");
|
|
77
|
+
let sPayload = utils.fetchFromObject(
|
|
78
|
+
msg,
|
|
79
|
+
config.payloadPropName || "payload"
|
|
80
|
+
);
|
|
81
|
+
// 15/11/2021 inform user about undefined topic or payload
|
|
82
|
+
if (sPayload === undefined) {
|
|
83
|
+
setNodeStatus({
|
|
84
|
+
fill: "red",
|
|
85
|
+
shape: "dot",
|
|
86
|
+
text: "Received invalid payload from " + msg.topic || "",
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
msg.payload = utils.ToBoolean(
|
|
91
|
+
sPayload,
|
|
92
|
+
RED.nodes.getNode(config.translatorConfig) // Retrieve the config node. It can be null, but it's handled in utils.js; // 15/11/2021 Convert input to boolean.
|
|
93
|
+
);
|
|
94
|
+
//if (msg.payload === undefined) return null;
|
|
95
|
+
if (node.timerAutoToggle !== null) {
|
|
96
|
+
// 28/01/2022 Stop autotoggle
|
|
97
|
+
clearInterval(node.timerAutoToggle);
|
|
98
|
+
}
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
setNodeStatus({
|
|
103
|
-
fill: "yellow",
|
|
104
|
-
shape: "dot",
|
|
105
|
-
text: "-> replay",
|
|
106
|
-
});
|
|
107
|
-
// Restore previous status
|
|
108
|
-
let t = setTimeout(() => {
|
|
109
|
-
if (node.bInviaMessaggio) {
|
|
110
|
-
setNodeStatus({
|
|
111
|
-
fill: "green",
|
|
112
|
-
shape: "dot",
|
|
113
|
-
text: "-> pass",
|
|
114
|
-
});
|
|
115
|
-
} else {
|
|
116
|
-
setNodeStatus({
|
|
117
|
-
fill: "red",
|
|
118
|
-
shape: "dot",
|
|
119
|
-
text: "|| stop (stored last msg)",
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}, 1000);
|
|
123
|
-
node.send(node.currentMsg);
|
|
124
|
-
} else {
|
|
125
|
-
setNodeStatus({
|
|
126
|
-
fill: "grey",
|
|
127
|
-
shape: "dot",
|
|
128
|
-
text: "Nothing to replay",
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
return;
|
|
132
|
-
} else if (msg.hasOwnProperty("reset")) {
|
|
133
|
-
node.currentMsg = {};
|
|
100
|
+
if (msg.hasOwnProperty("play")) {
|
|
101
|
+
if (node.currentMsg.payload !== undefined) {
|
|
102
|
+
node.currentMsg.isReplay = true;
|
|
134
103
|
setNodeStatus({
|
|
135
104
|
fill: "yellow",
|
|
136
105
|
shape: "dot",
|
|
137
|
-
text: "
|
|
106
|
+
text: "-> replay",
|
|
138
107
|
});
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
108
|
+
// Restore previous status
|
|
109
|
+
let t = setTimeout(() => {
|
|
110
|
+
if (node.bInviaMessaggio) {
|
|
111
|
+
setNodeStatus({
|
|
112
|
+
fill: "green",
|
|
113
|
+
shape: "dot",
|
|
114
|
+
text: "-> pass",
|
|
115
|
+
});
|
|
116
|
+
} else {
|
|
117
|
+
setNodeStatus({
|
|
118
|
+
fill: "red",
|
|
119
|
+
shape: "dot",
|
|
120
|
+
text: "|| stop (stored last msg)",
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}, 1000);
|
|
124
|
+
node.send(node.currentMsg);
|
|
125
|
+
} else {
|
|
146
126
|
setNodeStatus({
|
|
147
|
-
fill: "
|
|
127
|
+
fill: "grey",
|
|
148
128
|
shape: "dot",
|
|
149
|
-
text: "
|
|
129
|
+
text: "Nothing to replay",
|
|
150
130
|
});
|
|
151
|
-
return;
|
|
152
131
|
}
|
|
132
|
+
return;
|
|
133
|
+
} else if (msg.hasOwnProperty("reset")) {
|
|
134
|
+
node.currentMsg = {};
|
|
135
|
+
setNodeStatus({
|
|
136
|
+
fill: "yellow",
|
|
137
|
+
shape: "dot",
|
|
138
|
+
text: "Deleted stored msg",
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
} else if (msg.payload === true) {
|
|
142
|
+
node.bInviaMessaggio = true;
|
|
143
|
+
setNodeStatus({ fill: "green", shape: "dot", text: "-> pass" });
|
|
144
|
+
return;
|
|
145
|
+
} else if (msg.payload === false) {
|
|
146
|
+
node.bInviaMessaggio = false;
|
|
147
|
+
setNodeStatus({
|
|
148
|
+
fill: "red",
|
|
149
|
+
shape: "dot",
|
|
150
|
+
text: "|| stop (stored last msg)",
|
|
151
|
+
});
|
|
152
|
+
return;
|
|
153
153
|
}
|
|
154
154
|
}
|
|
155
|
+
//}
|
|
155
156
|
node.currentMsg = RED.util.cloneMessage(msg);
|
|
156
157
|
if (node.bInviaMessaggio) {
|
|
157
158
|
node.send(msg);
|
|
@@ -4,7 +4,8 @@ module.exports.ToBoolean = function ToBoolean(value, _configTranslationNode) {
|
|
|
4
4
|
|
|
5
5
|
if (typeof value === "boolean") {
|
|
6
6
|
return value;
|
|
7
|
-
} else if (typeof value === "string") {
|
|
7
|
+
} else if (typeof value === "string" || typeof value === "number") {
|
|
8
|
+
if (typeof value === "number") value = value.toString(); // We work with strings
|
|
8
9
|
try {
|
|
9
10
|
let translationTable = [];
|
|
10
11
|
value = value.toLowerCase();
|
|
@@ -36,15 +37,16 @@ module.exports.ToBoolean = function ToBoolean(value, _configTranslationNode) {
|
|
|
36
37
|
} catch (error) {
|
|
37
38
|
console.log("Boolean-Logic-Ultimate:utils:toBoolean: " + error.message);
|
|
38
39
|
}
|
|
39
|
-
} else if (typeof value === "number") {
|
|
40
|
-
// Is it formated as a decimal number?
|
|
41
|
-
if (decimal.test(value)) {
|
|
42
|
-
res = parseFloat(value) != 0;
|
|
43
|
-
} else {
|
|
44
|
-
res = value.toLowerCase() === "true";
|
|
45
|
-
}
|
|
46
|
-
return res;
|
|
47
40
|
}
|
|
41
|
+
// else if (typeof value === "number") {
|
|
42
|
+
// // Is it formated as a decimal number?
|
|
43
|
+
// if (decimal.test(value)) {
|
|
44
|
+
// res = parseFloat(value) != 0;
|
|
45
|
+
// } else {
|
|
46
|
+
// res = value.toLowerCase() === "true";
|
|
47
|
+
// }
|
|
48
|
+
// return res;
|
|
49
|
+
// }
|
|
48
50
|
};
|
|
49
51
|
|
|
50
52
|
module.exports.ToAny = function ToAny(value, _configTranslationNode) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-boolean-logic-ultimate",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.26",
|
|
4
4
|
"description": "A set of Node-RED enhanced boolean logic and utility nodes, flow interruption, blinker, invert, filter, toggle etc.., with persistent values after reboot. Compatible also with Homeassistant values.",
|
|
5
5
|
"author": "Supergiovane (https://github.com/Supergiovane)",
|
|
6
6
|
"dependencies": {
|