node-red-contrib-boolean-logic-ultimate 1.0.50 → 1.0.53
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 +17 -0
- package/README.md +47 -11
- package/boolean-logic-ultimate/BlinkerUltimate.js +6 -6
- package/boolean-logic-ultimate/BooleanLogicUltimate.html +0 -1
- package/boolean-logic-ultimate/BooleanLogicUltimate.js +5 -6
- package/boolean-logic-ultimate/FilterUltimate.js +4 -5
- package/boolean-logic-ultimate/ImpulseUltimate.js +1 -1
- package/boolean-logic-ultimate/InjectUltimate.js +4 -4
- package/boolean-logic-ultimate/InterruptFlowUltimate.js +5 -6
- package/boolean-logic-ultimate/InvertUltimate.js +4 -5
- package/boolean-logic-ultimate/RailwaySwitchUltimate.html +92 -0
- package/boolean-logic-ultimate/RailwaySwitchUltimate.js +103 -0
- package/boolean-logic-ultimate/SimpleOutputUltimate.js +1 -1
- package/boolean-logic-ultimate/StatusUltimate.js +1 -1
- package/boolean-logic-ultimate/SumUltimate.html +17 -7
- package/boolean-logic-ultimate/SumUltimate.js +25 -9
- package/boolean-logic-ultimate/toggleUltimate.js +5 -6
- package/img/railroadSwitchScambio.png +0 -0
- package/img/railwaySwitch.png +0 -0
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# node-red-contrib-boolean-logic-ultimate
|
|
2
2
|
[](https://www.paypal.me/techtoday)
|
|
3
3
|
|
|
4
|
+
# CHANGELOG
|
|
5
|
+
|
|
6
|
+
<p>
|
|
7
|
+
<b>Version 1.0.53</b> June 2022<br/>
|
|
8
|
+
- NEW: Math Ultimate. The old "Sum" node, now has become a math node, you can peform multipication other than sum.</br>
|
|
9
|
+
- Updated README with samples of Math node.
|
|
10
|
+
</p>
|
|
11
|
+
<p>
|
|
12
|
+
<b>Version 1.0.52</b> Mai 2022<br/>
|
|
13
|
+
- NEW: Railway Switcher Ultimate: new node to switch the input message to an output pin (https://youtu.be/1SjYE7d04u4).</br>
|
|
14
|
+
- Updated README with samples of Railway Switch node.
|
|
15
|
+
</p>
|
|
16
|
+
<p>
|
|
17
|
+
<b>Version 1.0.51</b> February 2022<br/>
|
|
18
|
+
- Blinker Ultimate: fixed minor problem with an orphan timer.</br>
|
|
19
|
+
- Better scoping of some vars, to leave the memory garbace collector to get rid of unused references.</br>
|
|
20
|
+
</p>
|
|
4
21
|
<p>
|
|
5
22
|
<b>Version 1.0.50</b> February 2022<br/>
|
|
6
23
|
- NEW: Added Youtube example for each node. You can find the link in the config window of each one and hede the playlist https://youtube.com/playlist?list=PL9Yh1bjbLAYoRH4IyQB7EL5srHAihiKpy.</br>
|
package/README.md
CHANGED
|
@@ -10,10 +10,7 @@
|
|
|
10
10
|
[](https://www.paypal.me/techtoday)
|
|
11
11
|
[![youtube][youtube-image]][youtube-url]
|
|
12
12
|
|
|
13
|
-
A set of Node-RED enhanced boolean logic, with
|
|
14
|
-
|
|
15
|
-
> Welcome! First of all thank you for your interest in my nodes. This is a set of logic nodes, to overcome the simplicity of the default node-red boolean logic nodes.
|
|
16
|
-
Hope you enjoy that and if you're in trouble, please ask!
|
|
13
|
+
A set of Node-RED enhanced boolean logic and utility nodes, with persistent values after reboot. Compatible also with Homeassistant ON and OFF values.
|
|
17
14
|
|
|
18
15
|
<br/>
|
|
19
16
|
<br/>
|
|
@@ -116,6 +113,8 @@ Resets all inputs to undefined.
|
|
|
116
113
|
|
|
117
114
|
# INTERRUPT FLOWS ULTIMATE
|
|
118
115
|
|
|
116
|
+
The interrupt flows is able to stop the input messages to exiting the node.
|
|
117
|
+
|
|
119
118
|
**Trigger by topic**
|
|
120
119
|
|
|
121
120
|
Whenever the node receives a payload = false from this topic,it stops output messages to the flow.<br/>
|
|
@@ -128,7 +127,7 @@ The node tries to convert any arbitrary input value to a valid boolean value. It
|
|
|
128
127
|
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.</br>
|
|
129
128
|
</br>
|
|
130
129
|
|
|
131
|
-
**INPUT MSG
|
|
130
|
+
**INPUT MSG WITH "TRIGGER" TOPIC**
|
|
132
131
|
|
|
133
132
|
Pass <code>msg.payload = true</code> to allow messages to pass through</br>
|
|
134
133
|
Pass <code>msg.payload = false</code> to prevent messages from passing through</br>
|
|
@@ -329,14 +328,14 @@ Pass <code>msg.payload = false</code> to the node to stop the running sequence</
|
|
|
329
328
|
<br/>
|
|
330
329
|
<br/>
|
|
331
330
|
|
|
332
|
-
#
|
|
331
|
+
# MATH ULTIMATE
|
|
333
332
|
|
|
334
|
-
The pourpose of this node is to
|
|
333
|
+
The pourpose of this node is to do maths on the incoming values. Each incoming message MUST HAVE OWN TOPIC.<br />
|
|
335
334
|
|
|
336
335
|
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/sum.png' width='60%'>
|
|
337
336
|
<details><summary>CLICK HERE, copy and paste it into your flow</summary>
|
|
338
337
|
<code>
|
|
339
|
-
[{"id":"05b6ce0cb476abd5","type":"SumUltimate","z":"
|
|
338
|
+
[{"id":"05b6ce0cb476abd5","type":"SumUltimate","z":"2bf641f4b8742755","name":"Multiply","property":"payload","math":"multiply","x":400,"y":180,"wires":[["567aa6a9719e463e"]]},{"id":"6744e01b88d820b9","type":"inject","z":"2bf641f4b8742755","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Wh Washing machine","payload":"10","payloadType":"num","x":190,"y":180,"wires":[["05b6ce0cb476abd5"]]},{"id":"75823dbc7db78c3c","type":"inject","z":"2bf641f4b8742755","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"Cost per KWh","payload":"20","payloadType":"num","x":160,"y":220,"wires":[["05b6ce0cb476abd5"]]},{"id":"567aa6a9719e463e","type":"debug","z":"2bf641f4b8742755","name":"Result","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":530,"y":180,"wires":[]},{"id":"1793931ba218bc1d","type":"inject","z":"2bf641f4b8742755","name":"Reset","props":[{"p":"reset","v":"","vt":"date"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":130,"y":260,"wires":[["05b6ce0cb476abd5"]]},{"id":"0b3277af03f546d4","type":"comment","z":"2bf641f4b8742755","name":"Getting results, (Sum, Multiply etc...) from the MATH node.","info":"","x":270,"y":140,"wires":[]}]
|
|
340
339
|
</code>
|
|
341
340
|
</details>
|
|
342
341
|
|
|
@@ -351,9 +350,9 @@ resets the values to zero.
|
|
|
351
350
|
|
|
352
351
|
<pre>
|
|
353
352
|
{
|
|
354
|
-
"payload": 30, // This is the
|
|
355
|
-
"topic": "
|
|
356
|
-
"average": 15, // This is the
|
|
353
|
+
"payload": 30, // This is the math result
|
|
354
|
+
"topic": "MyMath", // Node Topic
|
|
355
|
+
"average": 15, // This is the AVERAGE, in case of SUM
|
|
357
356
|
"measurements": 2 // This is the number of topics that have been evaluated
|
|
358
357
|
}
|
|
359
358
|
</pre>
|
|
@@ -373,6 +372,43 @@ The pourpose of this node is to toggle between true/false the payload of every i
|
|
|
373
372
|
|
|
374
373
|
Any message that arrives on input, will be passwd through to the output with the payload toggled between true and false.
|
|
375
374
|
|
|
375
|
+
<br/>
|
|
376
|
+
<br/>
|
|
377
|
+
<br/>
|
|
378
|
+
<br/>
|
|
379
|
+
<br/>
|
|
380
|
+
|
|
381
|
+
# RAILWAY SWITCH ULTIMATE
|
|
382
|
+
|
|
383
|
+
The railway switcher, switches the input msg flow to one ot the two output pins (upper or lower).
|
|
384
|
+
|
|
385
|
+
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/railroadSwitchScambio.png' width='80%'>
|
|
386
|
+
|
|
387
|
+
**Switcher topic**
|
|
388
|
+
|
|
389
|
+
Whenever the node receives a payload from this **topic**, it switches the input messages to an output PIN.<br/>
|
|
390
|
+
|
|
391
|
+
**Then**
|
|
392
|
+
This property, allow you to auto toggle the selected start state after some time.</br>
|
|
393
|
+
</br>
|
|
394
|
+
|
|
395
|
+
**INPUT MSG WITH "TRIGGER" TOPIC**
|
|
396
|
+
|
|
397
|
+
Pass <code>msg.payload = false</code> switches the msg input to the UPPER PIN</br>
|
|
398
|
+
Pass <code>msg.payload = true</code> switches the msg input to the LOWER PIN</br>
|
|
399
|
+
|
|
400
|
+
</br>
|
|
401
|
+
|
|
402
|
+
See the example below.<br/>
|
|
403
|
+
|
|
404
|
+
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/railwaySwitch.png' width='60%'>
|
|
405
|
+
|
|
406
|
+
Copy and paste it into your flow
|
|
407
|
+
```javascript
|
|
408
|
+
[{"id":"a6993d5187f05c0a","type":"RailwaySwitchUltimate","z":"e5b506b72b42922e","name":"Railway Switch","triggertopic":"trigger","initializewith":"0","autoToggle":"0","x":490,"y":180,"wires":[["51e7df8da0bd8d67"],["7f33b14e12c91744"]]},{"id":"2e3014226290f678","type":"InjectUltimate","z":"e5b506b72b42922e","name":"Sample message","topic":"Train","curVal":true,"x":180,"y":140,"wires":[["a6993d5187f05c0a"],[],[]]},{"id":"f6f80cd77a65073e","type":"InjectUltimate","z":"e5b506b72b42922e","name":"Railway switcher","topic":"trigger","curVal":true,"x":180,"y":220,"wires":[[],[],["a6993d5187f05c0a"]]},{"id":"51e7df8da0bd8d67","type":"debug","z":"e5b506b72b42922e","name":"Upper railway","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"topic","statusType":"msg","x":720,"y":140,"wires":[]},{"id":"7f33b14e12c91744","type":"debug","z":"e5b506b72b42922e","name":"Lower railway","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"topic","statusType":"msg","x":720,"y":220,"wires":[]},{"id":"8716120e94a7b6ee","type":"comment","z":"e5b506b72b42922e","name":"Switch between railways","info":"","x":190,"y":80,"wires":[]}]
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
|
|
376
412
|
|
|
377
413
|
|
|
378
414
|
[license-image]: https://img.shields.io/badge/license-MIT-blue.svg
|
|
@@ -12,12 +12,13 @@ module.exports = function (RED) {
|
|
|
12
12
|
node.stopbehaviorPIN2 = node.stopbehaviorPIN2 == "0" ? false : true;
|
|
13
13
|
|
|
14
14
|
function setNodeStatus({ fill, shape, text }) {
|
|
15
|
-
|
|
15
|
+
let dDate = new Date();
|
|
16
16
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// 12/04/2021 Autostart blinker?
|
|
20
20
|
if (config.initializewith !== undefined && config.initializewith === "1") {
|
|
21
|
+
if (node.tBlinker !== null) clearInterval(node.tBlinker);
|
|
21
22
|
node.tBlinker = setInterval(handleTimer, node.blinkfrequency); // Start the timer that handles the queue of telegrams
|
|
22
23
|
node.isBlinking = true;
|
|
23
24
|
setNodeStatus({ fill: "green", shape: "dot", text: "-> Autostarted" });
|
|
@@ -68,9 +69,9 @@ module.exports = function (RED) {
|
|
|
68
69
|
|
|
69
70
|
|
|
70
71
|
function ToBoolean(value) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
let res = false;
|
|
73
|
+
let decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
|
|
74
|
+
|
|
74
75
|
if (typeof value === 'boolean') {
|
|
75
76
|
res = value;
|
|
76
77
|
}
|
|
@@ -82,8 +83,7 @@ module.exports = function (RED) {
|
|
|
82
83
|
|
|
83
84
|
// Is it formated as a decimal number?
|
|
84
85
|
if (decimal.test(value)) {
|
|
85
|
-
|
|
86
|
-
res = v != 0;
|
|
86
|
+
res = parseFloat(value) != 0;
|
|
87
87
|
}
|
|
88
88
|
else {
|
|
89
89
|
res = value.toLowerCase() === "true";
|
|
@@ -17,7 +17,7 @@ module.exports = function (RED) {
|
|
|
17
17
|
node.inputMessage = {}; // 26/01/2022 input message is stored here.
|
|
18
18
|
|
|
19
19
|
function setNodeStatus({ fill, shape, text }) {
|
|
20
|
-
|
|
20
|
+
let dDate = new Date();
|
|
21
21
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -221,7 +221,7 @@ module.exports = function (RED) {
|
|
|
221
221
|
for (let index = 0; index < nTotalDummyToCreate; index++) {
|
|
222
222
|
node.jSonStates["dummy" + index] = node.sInitializeWith === "false" ? false : true;
|
|
223
223
|
}
|
|
224
|
-
setTimeout(() => { setNodeStatus({ fill: "green", shape: "ring", text: "Initialized " + nTotalDummyToCreate + " undefined inputs with " + node.sInitializeWith }); }, 4000)
|
|
224
|
+
let t = setTimeout(() => { setNodeStatus({ fill: "green", shape: "ring", text: "Initialized " + nTotalDummyToCreate + " undefined inputs with " + node.sInitializeWith }); }, 4000)
|
|
225
225
|
}
|
|
226
226
|
}
|
|
227
227
|
}
|
|
@@ -278,8 +278,8 @@ module.exports = function (RED) {
|
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
function ToBoolean(value) {
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
let res = false;
|
|
282
|
+
let decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
|
|
283
283
|
|
|
284
284
|
if (typeof value === 'boolean') {
|
|
285
285
|
res = value;
|
|
@@ -291,8 +291,7 @@ module.exports = function (RED) {
|
|
|
291
291
|
|
|
292
292
|
// Is it formated as a decimal number?
|
|
293
293
|
if (decimal.test(value)) {
|
|
294
|
-
|
|
295
|
-
res = v != 0;
|
|
294
|
+
res = parseFloat(value) != 0;
|
|
296
295
|
}
|
|
297
296
|
else {
|
|
298
297
|
res = value.toLowerCase() === "true";
|
|
@@ -5,7 +5,7 @@ module.exports = function (RED) {
|
|
|
5
5
|
var node = this;
|
|
6
6
|
|
|
7
7
|
function setNodeStatus({ fill, shape, text }) {
|
|
8
|
-
|
|
8
|
+
let dDate = new Date();
|
|
9
9
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -47,8 +47,8 @@ module.exports = function (RED) {
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
function ToBoolean(value) {
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
let res = false;
|
|
51
|
+
let decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
|
|
52
52
|
|
|
53
53
|
if (typeof value === 'boolean') {
|
|
54
54
|
res = value;
|
|
@@ -60,8 +60,7 @@ module.exports = function (RED) {
|
|
|
60
60
|
|
|
61
61
|
// Is it formated as a decimal number?
|
|
62
62
|
if (decimal.test(value)) {
|
|
63
|
-
|
|
64
|
-
res = v != 0;
|
|
63
|
+
res = parseFloat(value) != 0;
|
|
65
64
|
}
|
|
66
65
|
else {
|
|
67
66
|
res = value.toLowerCase() === "true";
|
|
@@ -12,7 +12,7 @@ module.exports = function (RED) {
|
|
|
12
12
|
node.isPlaying = false;
|
|
13
13
|
|
|
14
14
|
node.setNodeStatus = ({ fill, shape, text }) => {
|
|
15
|
-
|
|
15
|
+
let dDate = new Date();
|
|
16
16
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
17
17
|
}
|
|
18
18
|
async function delay(ms) {
|
|
@@ -26,15 +26,15 @@ module.exports = function (RED) {
|
|
|
26
26
|
// 29/08/2020 triggered by button press
|
|
27
27
|
node.buttonpressed = () => {
|
|
28
28
|
setNodeStatus({ fill: "green", shape: "dot", text: "Pin1:true, Pin2:false, Pin3:" + node.curVal.toString() + " (next " + (!node.curVal).toString() + ")" });
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
let msgTrue = { payload: true, topic: node.topic };
|
|
30
|
+
let msgFalse = { payload: false, topic: node.topic };
|
|
31
|
+
let msgToggled = { payload: node.curVal, topic: node.topic };
|
|
32
32
|
node.curVal = !node.curVal;
|
|
33
33
|
node.send([msgTrue, msgFalse, msgToggled]);
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
function setNodeStatus({ fill, shape, text }) {
|
|
37
|
-
|
|
37
|
+
let dDate = new Date();
|
|
38
38
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -10,7 +10,7 @@ module.exports = function (RED) {
|
|
|
10
10
|
node.timerAutoToggle = null;
|
|
11
11
|
|
|
12
12
|
function setNodeStatus({ fill, shape, text }) {
|
|
13
|
-
|
|
13
|
+
let dDate = new Date();
|
|
14
14
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
15
15
|
}
|
|
16
16
|
setNodeStatus({ fill: "green", shape: "ring", text: "-> pass" });
|
|
@@ -59,7 +59,7 @@ module.exports = function (RED) {
|
|
|
59
59
|
node.currentMsg.isReplay = true;
|
|
60
60
|
setNodeStatus({ fill: "yellow", shape: "dot", text: "-> replay" });
|
|
61
61
|
// Restore previous status
|
|
62
|
-
setTimeout(() => {
|
|
62
|
+
let t = setTimeout(() => {
|
|
63
63
|
if (node.bInviaMessaggio) {
|
|
64
64
|
setNodeStatus({ fill: "green", shape: "dot", text: "-> pass" });
|
|
65
65
|
} else {
|
|
@@ -96,8 +96,8 @@ module.exports = function (RED) {
|
|
|
96
96
|
|
|
97
97
|
|
|
98
98
|
function ToBoolean(value) {
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
let res = false;
|
|
100
|
+
let decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
|
|
101
101
|
|
|
102
102
|
if (typeof value === 'boolean') {
|
|
103
103
|
res = value;
|
|
@@ -109,8 +109,7 @@ module.exports = function (RED) {
|
|
|
109
109
|
|
|
110
110
|
// Is it formated as a decimal number?
|
|
111
111
|
if (decimal.test(value)) {
|
|
112
|
-
|
|
113
|
-
res = v != 0;
|
|
112
|
+
res = parseFloat(value) != 0;
|
|
114
113
|
}
|
|
115
114
|
else {
|
|
116
115
|
res = value.toLowerCase() === "true";
|
|
@@ -6,7 +6,7 @@ module.exports = function (RED) {
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
function setNodeStatus({ fill, shape, text }) {
|
|
9
|
-
|
|
9
|
+
let dDate = new Date();
|
|
10
10
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -47,8 +47,8 @@ module.exports = function (RED) {
|
|
|
47
47
|
|
|
48
48
|
|
|
49
49
|
function ToBoolean(value) {
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
let res = false;
|
|
51
|
+
let decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
|
|
52
52
|
|
|
53
53
|
if (typeof value === 'boolean') {
|
|
54
54
|
res = value;
|
|
@@ -60,8 +60,7 @@ module.exports = function (RED) {
|
|
|
60
60
|
|
|
61
61
|
// Is it formated as a decimal number?
|
|
62
62
|
if (decimal.test(value)) {
|
|
63
|
-
|
|
64
|
-
res = v != 0;
|
|
63
|
+
res = parseFloat(value) != 0;
|
|
65
64
|
}
|
|
66
65
|
else {
|
|
67
66
|
res = value.toLowerCase() === "true";
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('RailwaySwitchUltimate', {
|
|
3
|
+
category: 'boolean logic ultimate',
|
|
4
|
+
color: '#ff8080',
|
|
5
|
+
defaults: {
|
|
6
|
+
name: { value: "Railway Switch" },
|
|
7
|
+
triggertopic: { value: "trigger" },
|
|
8
|
+
initializewith: { value: "0" },
|
|
9
|
+
autoToggle: { value: "0" }
|
|
10
|
+
},
|
|
11
|
+
inputs: 1,
|
|
12
|
+
outputs: 2,
|
|
13
|
+
outputLabels: function (i) {
|
|
14
|
+
var ret = "";
|
|
15
|
+
switch (i) {
|
|
16
|
+
case 0:
|
|
17
|
+
return "Upper PIN";
|
|
18
|
+
break;
|
|
19
|
+
case 1:
|
|
20
|
+
return "Lower PIN";
|
|
21
|
+
break;
|
|
22
|
+
default:
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
icon: "font-awesome/fa-train",
|
|
27
|
+
label:
|
|
28
|
+
function () {
|
|
29
|
+
return (this.name || "Switch") + " (" + this.triggertopic + ")";
|
|
30
|
+
},
|
|
31
|
+
paletteLabel: function () {
|
|
32
|
+
return "RailwaySwitchUltimate";
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<script type="text/x-red" data-template-name="RailwaySwitchUltimate">
|
|
38
|
+
<div class="form-row">
|
|
39
|
+
<b>Railway Switch 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>
|
|
40
|
+
   <span style="color:red"><i class="fa fa-youtube-play"></i> <a target="_blank" href="https://youtu.be/1SjYE7d04u4"><u>Youtube Sample</u></a></span>
|
|
41
|
+
<br/>
|
|
42
|
+
<br/>
|
|
43
|
+
</div>
|
|
44
|
+
<div class="form-row">
|
|
45
|
+
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
46
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
47
|
+
</div>
|
|
48
|
+
|
|
49
|
+
<div class="form-row">
|
|
50
|
+
<label for="node-input-triggertopic"><i class="icon-tag"></i> Switcher topic</label>
|
|
51
|
+
<input type="text" id="node-input-triggertopic" placeholder="Name">
|
|
52
|
+
<div><i>An input msg having this topic and payload true or false<br/>will trigger the railway switch between the two output PINs<br/>
|
|
53
|
+
msg.payload = false switches to the upper PIN<br/>
|
|
54
|
+
msg.payload = true switches to the lower PIN<br/>
|
|
55
|
+
</i></div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<div class="form-row">
|
|
59
|
+
<label style="width:160px" for="node-input-initializewith"><i class="fa fa-home"></i> At node-red start</label>
|
|
60
|
+
<select type="text" id="node-input-initializewith" placeholder="" style="width:250px">
|
|
61
|
+
<option value="0">Flow messages to the upper PIN</option>
|
|
62
|
+
<option value="1">Flow messages to the lower PIN</option>
|
|
63
|
+
</select>
|
|
64
|
+
</div>
|
|
65
|
+
<div class="form-row">
|
|
66
|
+
<label style="width:160px" for="node-input-autoToggle"><i class="fa fa-hourglass-o"></i> Then</label>
|
|
67
|
+
<select type="text" id="node-input-autoToggle" placeholder="" style="width:250px">
|
|
68
|
+
<option value="0">Nothing</option>
|
|
69
|
+
<option value="10">Toggle above option after 10 seconds</option>
|
|
70
|
+
<option value="20">Toggle above option after 20 seconds</option>
|
|
71
|
+
<option value="30">Toggle above option after 30 seconds</option>
|
|
72
|
+
<option value="40">Toggle above option after 40 seconds</option>
|
|
73
|
+
<option value="50">Toggle above option after 50 seconds</option>
|
|
74
|
+
<option value="60">Toggle above option after 60 seconds</option>
|
|
75
|
+
<option value="90">Toggle above option after 90 seconds</option>
|
|
76
|
+
<option value="120">Toggle above option after 120 seconds</option>
|
|
77
|
+
</select>
|
|
78
|
+
</div>
|
|
79
|
+
</script>
|
|
80
|
+
|
|
81
|
+
<script type="text/x-red" data-help-name="RailwaySwitchUltimate">
|
|
82
|
+
<p>
|
|
83
|
+
SEE THE README FOR HELP CONFIGURING THE NODE
|
|
84
|
+
</p>
|
|
85
|
+
|
|
86
|
+
<p>
|
|
87
|
+
<a href="https://github.com/Supergiovane/node-red-contrib-boolean-logic-ultimate" target="_blank">Click here to learn how to configure the node.</a>
|
|
88
|
+
</p>
|
|
89
|
+
|
|
90
|
+
<a href="https://www.paypal.me/techtoday" target="_blank"><img src='https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square' width='30%'></a>
|
|
91
|
+
|
|
92
|
+
</script>
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
module.exports = function (RED) {
|
|
2
|
+
function RailwaySwitchUltimate(config) {
|
|
3
|
+
RED.nodes.createNode(this, config);
|
|
4
|
+
this.config = config;
|
|
5
|
+
var node = this;
|
|
6
|
+
node.currentMsg = {}; // Stores current payload
|
|
7
|
+
node.sTriggerTopic = node.config.triggertopic.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '') || "trigger"; // Topic controlling the iRailway
|
|
8
|
+
node.iRailway = Number(node.config.initializewith); // Railway selector
|
|
9
|
+
node.autoToggle = config.autoToggle === undefined ? 0 : parseInt(config.autoToggle); // Auto toggle the selected "initializewith" after a while (useful for homekit bridged, that sends junk after start)
|
|
10
|
+
node.timerAutoToggle = null;
|
|
11
|
+
|
|
12
|
+
function setNodeStatus({ fill, shape, text }) {
|
|
13
|
+
let dDate = new Date();
|
|
14
|
+
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
node.alignStatus = () => {
|
|
18
|
+
let sAutoToggle = node.autoToggle > 0 ? " (Autotoggle in " + node.autoToggle + "s)" : "";
|
|
19
|
+
if (node.iRailway === 0) {
|
|
20
|
+
setNodeStatus({ fill: "green", shape: "dot", text: "-> UPPER PIN" + sAutoToggle });
|
|
21
|
+
} else {
|
|
22
|
+
setNodeStatus({ fill: "blue", shape: "dot", text: "-> LOWER PIN" + sAutoToggle });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (node.autoToggle > 0) {
|
|
27
|
+
node.timerAutoToggle = setTimeout(() => {
|
|
28
|
+
node.autoToggle = 0;
|
|
29
|
+
node.iRailway === 0 ? node.iRailway = 1 : node.iRailway = 0;
|
|
30
|
+
node.alignStatus();
|
|
31
|
+
}, node.autoToggle * 1000);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
node.alignStatus();
|
|
35
|
+
|
|
36
|
+
this.on('input', function (msg) {
|
|
37
|
+
var sIncomingTopic = "";
|
|
38
|
+
if (msg.hasOwnProperty("topic")) {
|
|
39
|
+
// 06/11/2019
|
|
40
|
+
if (!msg.hasOwnProperty("topic") || msg.topic === undefined) msg.topic = "NoTopicReceived";
|
|
41
|
+
sIncomingTopic = msg.topic.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, ''); // Cut unwanted Characters
|
|
42
|
+
if (sIncomingTopic === node.sTriggerTopic) {
|
|
43
|
+
|
|
44
|
+
// 15/11/2021 inform user about undefined topic or payload
|
|
45
|
+
if (!msg.hasOwnProperty("payload") || msg.payload === undefined || msg.payload === null) {
|
|
46
|
+
setNodeStatus({ fill: "red", shape: "dot", text: "Received invalid payload from " + msg.topic || "" });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
msg.payload = ToBoolean(msg.payload); // 15/11/2021 Convert input to boolean.
|
|
51
|
+
|
|
52
|
+
// 28/01/2022 Stop autotoggle
|
|
53
|
+
if (node.timerAutoToggle !== null) clearInterval(node.timerAutoToggle);
|
|
54
|
+
|
|
55
|
+
if (msg.payload === false) node.iRailway = 0;
|
|
56
|
+
if (msg.payload === true) node.iRailway = 1;
|
|
57
|
+
if (node.iRailway === 0) {
|
|
58
|
+
setNodeStatus({ fill: "green", shape: "dot", text: "-> UPPER PIN" });
|
|
59
|
+
} else {
|
|
60
|
+
setNodeStatus({ fill: "blue", shape: "dot", text: "-> LOWER PIN" });
|
|
61
|
+
}
|
|
62
|
+
return; // DONT'S SEND THIS MESSAGE
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
node.currentMsg = RED.util.cloneMessage(msg);
|
|
66
|
+
if (node.iRailway === 0) {
|
|
67
|
+
node.send([msg, null]);
|
|
68
|
+
} else {
|
|
69
|
+
node.send([null, msg]);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
function ToBoolean(value) {
|
|
77
|
+
let res = false;
|
|
78
|
+
let decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
|
|
79
|
+
|
|
80
|
+
if (typeof value === 'boolean') {
|
|
81
|
+
res = value;
|
|
82
|
+
}
|
|
83
|
+
else if (typeof value === 'number' || typeof value === 'string') {
|
|
84
|
+
|
|
85
|
+
if (typeof value === "string" && value.toLowerCase() === "on") return true;
|
|
86
|
+
if (typeof value === "string" && value.toLowerCase() === "off") return false;
|
|
87
|
+
|
|
88
|
+
// Is it formated as a decimal number?
|
|
89
|
+
if (decimal.test(value)) {
|
|
90
|
+
res = parseFloat(value) != 0;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
res = value.toLowerCase() === "true";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return res;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
RED.nodes.registerType("RailwaySwitchUltimate", RailwaySwitchUltimate);
|
|
103
|
+
}
|
|
@@ -18,7 +18,7 @@ module.exports = function(RED) {
|
|
|
18
18
|
|
|
19
19
|
function setNodeStatus({fill, shape, text})
|
|
20
20
|
{
|
|
21
|
-
|
|
21
|
+
let dDate = new Date();
|
|
22
22
|
node.status({fill: fill,shape: shape,text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")"})
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -5,7 +5,7 @@ module.exports = function (RED) {
|
|
|
5
5
|
var node = this;
|
|
6
6
|
|
|
7
7
|
function setNodeStatus({ fill, shape, text }) {
|
|
8
|
-
|
|
8
|
+
let dDate = new Date();
|
|
9
9
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
color: '#ff8080',
|
|
5
5
|
defaults: {
|
|
6
6
|
name: {
|
|
7
|
-
value: "
|
|
7
|
+
value: "Math"
|
|
8
8
|
},
|
|
9
9
|
property: {
|
|
10
10
|
value: "payload"
|
|
11
|
+
},
|
|
12
|
+
math: {
|
|
13
|
+
value: "sum"
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
},
|
|
@@ -16,29 +19,36 @@
|
|
|
16
19
|
icon: "font-awesome/fa-plus",
|
|
17
20
|
label:
|
|
18
21
|
function () {
|
|
19
|
-
return this.name || "
|
|
22
|
+
return this.name || "Math";
|
|
20
23
|
},
|
|
21
24
|
paletteLabel: function () {
|
|
22
|
-
return "
|
|
25
|
+
return "MathUltimate";
|
|
23
26
|
}
|
|
24
27
|
});
|
|
25
28
|
</script>
|
|
26
29
|
|
|
27
30
|
<script type="text/x-red" data-template-name="SumUltimate">
|
|
28
31
|
<div class="form-row">
|
|
29
|
-
<b>
|
|
32
|
+
<b>Math 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>
|
|
30
33
|
   <span style="color:red"><i class="fa fa-youtube-play"></i> <a target="_blank" href="https://youtu.be/jLIbQgmRzuc"><u>Youtube Sample</u></a></span>
|
|
31
34
|
<br/>
|
|
32
35
|
<br/>
|
|
33
36
|
</div>
|
|
34
37
|
<div class="form-row">
|
|
35
|
-
<label for="node-input-name"><i class="icon-tag"></i>
|
|
36
|
-
<input type="text" id="node-input-name" placeholder="
|
|
38
|
+
<label for="node-input-name"><i class="icon-tag"></i> Topic</label>
|
|
39
|
+
<input type="text" id="node-input-name" placeholder="Topic">
|
|
37
40
|
</div>
|
|
38
41
|
<div class="form-row">
|
|
39
|
-
<label for="node-input-property"><i class="icon-tag"></i>
|
|
42
|
+
<label for="node-input-property"><i class="icon-tag"></i> Use msg.</label>
|
|
40
43
|
<input type="text" id="node-input-property" placeholder="payload">
|
|
41
44
|
</div>
|
|
45
|
+
<div class="form-row">
|
|
46
|
+
<label for="node-input-math"><i class="icon-tag"></i> Operation</label>
|
|
47
|
+
<select type="text" id="node-input-math" placeholder="">
|
|
48
|
+
<option value="sum">Sum</option>
|
|
49
|
+
<option value="multiply">Multiply</option>
|
|
50
|
+
</select>
|
|
51
|
+
</div>
|
|
42
52
|
</script>
|
|
43
53
|
|
|
44
54
|
<script type="text/x-red" data-help-name="SumUltimate">
|
|
@@ -3,10 +3,11 @@ module.exports = function (RED) {
|
|
|
3
3
|
RED.nodes.createNode(this, config);
|
|
4
4
|
this.config = config;
|
|
5
5
|
var node = this;
|
|
6
|
+
node.math = config.math === undefined ? "sum" : config.math;
|
|
6
7
|
this.topics = {};
|
|
7
8
|
|
|
8
9
|
function setNodeStatus({ fill, shape, text }) {
|
|
9
|
-
|
|
10
|
+
let dDate = new Date();
|
|
10
11
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -52,14 +53,29 @@ module.exports = function (RED) {
|
|
|
52
53
|
node.topics[msg.topic.toString()] = ret;
|
|
53
54
|
|
|
54
55
|
var quantita = 0;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
56
|
+
|
|
57
|
+
if (node.math === "sum") {
|
|
58
|
+
let somma = Object.keys(node.topics).reduce(function (a, b) {
|
|
59
|
+
++quantita;
|
|
60
|
+
return a + node.topics[b];
|
|
61
|
+
}, 0);
|
|
62
|
+
msg.payload = somma; // Sum
|
|
63
|
+
msg.average = somma / quantita; // Average
|
|
64
|
+
msg.measurements = quantita; // Topics
|
|
65
|
+
} else if (node.math === "multiply") {
|
|
66
|
+
let moltiplicazione = Object.keys(node.topics).reduce(function (a, b) {
|
|
67
|
+
try {
|
|
68
|
+
++quantita;
|
|
69
|
+
return (a > 0 ? a : 1) * node.topics[b]; // Avoid returning zero everytime
|
|
70
|
+
} catch (error) {
|
|
71
|
+
setNodeStatus({ fill: "red", shape: "ring", text: "Error " + error.message });
|
|
72
|
+
return 0;
|
|
73
|
+
}
|
|
74
|
+
}, 0);
|
|
75
|
+
msg.payload = moltiplicazione; // Sum
|
|
76
|
+
msg.average = undefined; // Average
|
|
77
|
+
msg.measurements = quantita; // Topics
|
|
78
|
+
}
|
|
63
79
|
|
|
64
80
|
// overwrite topic if configured
|
|
65
81
|
if (config.name) {
|
|
@@ -6,7 +6,7 @@ module.exports = function (RED) {
|
|
|
6
6
|
node.valueToToggle = config.valueToToggle === undefined ? true : ToBoolean(config.valueToToggle);
|
|
7
7
|
|
|
8
8
|
function setNodeStatus({ fill, shape, text }) {
|
|
9
|
-
|
|
9
|
+
let dDate = new Date();
|
|
10
10
|
node.status({ fill: fill, shape: shape, text: text + " (" + dDate.getDate() + ", " + dDate.toLocaleTimeString() + ")" })
|
|
11
11
|
}
|
|
12
12
|
|
|
@@ -23,7 +23,7 @@ module.exports = function (RED) {
|
|
|
23
23
|
|
|
24
24
|
node.valueToToggle = !node.valueToToggle;
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
let msgOUT = RED.util.cloneMessage(msg);
|
|
27
27
|
try {
|
|
28
28
|
msgOUT.payload = node.valueToToggle;
|
|
29
29
|
setNodeStatus({ fill: "green", shape: "dot", text: "(Send) " + msgOUT.payload });
|
|
@@ -37,8 +37,8 @@ module.exports = function (RED) {
|
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
function ToBoolean(value) {
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
let res = false;
|
|
41
|
+
let decimal = /^\s*[+-]{0,1}\s*([\d]+(\.[\d]*)*)\s*$/
|
|
42
42
|
|
|
43
43
|
if (typeof value === 'boolean') {
|
|
44
44
|
res = value;
|
|
@@ -50,8 +50,7 @@ module.exports = function (RED) {
|
|
|
50
50
|
|
|
51
51
|
// Is it formated as a decimal number?
|
|
52
52
|
if (decimal.test(value)) {
|
|
53
|
-
|
|
54
|
-
res = v != 0;
|
|
53
|
+
res = parseFloat(value) != 0;
|
|
55
54
|
}
|
|
56
55
|
else {
|
|
57
56
|
res = value.toLowerCase() === "true";
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-boolean-logic-ultimate",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "A set of Node-RED enhanced boolean logic
|
|
3
|
+
"version": "1.0.53",
|
|
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 ON and OFF values.",
|
|
5
5
|
"author": "Supergiovane (https://github.com/Supergiovane)",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"fs": "0.0.1-security",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"StatusUltimate": "boolean-logic-ultimate/StatusUltimate.js",
|
|
32
32
|
"ImpulseUltimate": "boolean-logic-ultimate/ImpulseUltimate.js",
|
|
33
33
|
"SumUltimate": "boolean-logic-ultimate/SumUltimate.js",
|
|
34
|
-
"toggleUltimate": "boolean-logic-ultimate/toggleUltimate.js"
|
|
34
|
+
"toggleUltimate": "boolean-logic-ultimate/toggleUltimate.js",
|
|
35
|
+
"RailwaySwitchUltimate": "boolean-logic-ultimate/RailwaySwitchUltimate.js"
|
|
35
36
|
}
|
|
36
37
|
}
|
|
37
|
-
}
|
|
38
|
+
}
|