node-red-contrib-boolean-logic-ultimate 1.2.16 → 1.2.17
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
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
# CHANGELOG
|
|
6
6
|
|
|
7
|
+
<p>
|
|
8
|
+
<b>Version 1.2.17</b> July 2026<br/>
|
|
9
|
+
|
|
10
|
+
- HysteresisUltimate: added permanent output control through <code>msg.permanentLockState</code>, supporting <code>lock</code>, <code>lockOn</code>, <code>lockOff</code> and <code>unlock</code>.<br/>
|
|
11
|
+
- HysteresisUltimate: control-topic configuration and diagnostics remain available while state output is locked.<br/>
|
|
12
|
+
- Updated the Hysteresis editor help, README documentation, automated tests and importable example flow.<br/>
|
|
13
|
+
- Reorganized the README with a clearer heading structure, installation instructions and a categorized node index.<br/>
|
|
14
|
+
</p>
|
|
15
|
+
|
|
7
16
|
<p>
|
|
8
17
|
<b>Version 1.2.16</b> July 2026<br/>
|
|
9
18
|
|
package/README.md
CHANGED
|
@@ -2,13 +2,9 @@
|
|
|
2
2
|
<img src="img/logo-supervibe.png" alt="Boolean Logic Ultimate - Max Supervibe" width="380">
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
# Boolean Logic Ultimate
|
|
6
6
|
|
|
7
|
-
A
|
|
8
|
-
|
|
9
|
-
<br/>
|
|
10
|
-
<br/>
|
|
11
|
-
<br/>
|
|
7
|
+
A collection of enhanced logic and utility nodes for Node-RED. It supports persistent values after reboot and conversion of common Home Assistant values.
|
|
12
8
|
|
|
13
9
|
[![NPM version][npm-version-image]][npm-url]
|
|
14
10
|
[![NPM downloads per month][npm-downloads-month-image]][npm-url]
|
|
@@ -22,14 +18,35 @@ A set of Node-RED enhanced boolean logic and utility nodes, with persistent valu
|
|
|
22
18
|
<img src="img/readmemain.png" alt="Boolean Logic Ultimate for Node-RED — Max Supervibe" width="70%">
|
|
23
19
|
</p>
|
|
24
20
|
|
|
25
|
-
##
|
|
21
|
+
## Getting started
|
|
26
22
|
|
|
27
|
-
-
|
|
23
|
+
Install the package from the Node-RED palette manager or run this command in your Node-RED user directory:
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
25
|
+
```shell
|
|
26
|
+
npm install node-red-contrib-boolean-logic-ultimate
|
|
27
|
+
```
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
Importable flows are available from the Node-RED editor under **Menu (☰) → Import → Examples**, or directly in the [`examples/`](examples/) folder. See the [examples overview](examples/README.md) for the complete list.
|
|
30
|
+
|
|
31
|
+
## Documentation
|
|
32
|
+
|
|
33
|
+
| Logic and routing | Timing and flow | Values and simulation |
|
|
34
|
+
| ----------------- | --------------- | --------------------- |
|
|
35
|
+
| [Boolean Logic](#boolean-logic) | [Interrupt Flows Ultimate](#interrupt-flows-ultimate) | [Translator node](#translator-node) |
|
|
36
|
+
| [Invert Ultimate](#invert-ultimate) | [Blinker Ultimate](#blinker-ultimate) | [Simple Output Ultimate](#simple-output-ultimate) |
|
|
37
|
+
| [Filter Ultimate](#filter-ultimate) | [Impulse Ultimate](#impulse-ultimate) | [Inject Ultimate](#inject-ultimate) |
|
|
38
|
+
| [Hysteresis Ultimate](#hysteresis-ultimate) | [Rate Limiter Ultimate](#rate-limiter-ultimate) | [Status Ultimate](#status-ultimate) |
|
|
39
|
+
| [Railway Switch Ultimate](#railway-switch-ultimate) | [Debouncer Ultimate](#debouncer-ultimate) | [Math Ultimate](#math-ultimate) |
|
|
40
|
+
| [Toggle Ultimate](#toggle-ultimate) | [Staircase Light Ultimate](#staircase-light-ultimate) | [Kalman Filter Ultimate](#kalman-filter-ultimate) |
|
|
41
|
+
| | | [Presence Simulator Ultimate](#presence-simulator-ultimate) |
|
|
42
|
+
|
|
43
|
+
Each node section contains its configuration, accepted input messages, outputs and runtime commands where applicable.
|
|
44
|
+
|
|
45
|
+
## Changelog
|
|
46
|
+
|
|
47
|
+
- See the project [changelog](CHANGELOG.md) for release details.
|
|
48
|
+
|
|
49
|
+
## Examples
|
|
33
50
|
|
|
34
51
|
Importable Node-RED example flows are available in the [`examples/`](examples/) folder (one JSON per node). See [`examples/README.md`](examples/README.md) for a quick overview.
|
|
35
52
|
|
|
@@ -37,12 +54,9 @@ Importable Node-RED example flows are available in the [`examples/`](examples/)
|
|
|
37
54
|
|
|
38
55
|
- Node-RED editor → Menu (☰) → **Import** → **Examples** and select an example from `node-red-contrib-boolean-logic-ultimate`
|
|
39
56
|
|
|
40
|
-
|
|
41
|
-
<br/>
|
|
42
|
-
|
|
43
|
-
# TRANSLATOR NODE
|
|
57
|
+
## Translator node
|
|
44
58
|
|
|
45
|
-
|
|
59
|
+
In addition to true/false, the nodes accept common [Home Assistant](https://www.home-assistant.io) state strings.
|
|
46
60
|
|
|
47
61
|
You can **even add your own input translation word list**, thanks to the translator-config node.
|
|
48
62
|
|
|
@@ -50,20 +64,17 @@ The translator node can translate an input payload, to a true/false boolean valu
|
|
|
50
64
|
|
|
51
65
|
Each row in the text box, represents a translation command. <br/>
|
|
52
66
|
|
|
53
|
-
|
|
67
|
+
Default translation rows make the _boolean-logic-ultimate_ nodes compatible with common Home Assistant states. <br/>
|
|
54
68
|
|
|
55
69
|
You can add your own translation row.<br/>
|
|
56
70
|
|
|
57
71
|
| | Description |
|
|
58
72
|
| --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
59
|
-
| Translate | Add, delete or edit
|
|
73
|
+
| Translate | Add, delete or edit a translation command. Each row must use the format **input string:true(or false)**, for example <code>open:true</code> or <code>closed:false</code>. Expressions such as <code>{{value>=50}}:true</code> are also supported; when the expression evaluates to true, the translator returns the selected value. |
|
|
60
74
|
|
|
61
75
|

|
|
62
76
|
|
|
63
|
-
|
|
64
|
-
<br/>
|
|
65
|
-
|
|
66
|
-
# BOOLEAN LOGIC
|
|
77
|
+
## Boolean Logic
|
|
67
78
|
|
|
68
79
|
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/bl1.png' width='60%'>
|
|
69
80
|
|
|
@@ -103,7 +114,7 @@ You can also set the default values of the topic inputs.<br/>
|
|
|
103
114
|
|
|
104
115
|
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/>
|
|
105
116
|
|
|
106
|
-
###
|
|
117
|
+
### Configuration
|
|
107
118
|
|
|
108
119
|
| Property | Description |
|
|
109
120
|
| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -125,17 +136,11 @@ The node can convert arbitrary input values to true/false. It supports Homeassis
|
|
|
125
136
|
| msg.reset = true | Resets all saved input values to undefined |
|
|
126
137
|
| msg.inputcount | Changes the inputs count property. For example, <b>msg.inputcount = 3</b> Whenever you lower the inputcount from a higher number to a lower one, for example from 3 to 2, it's suggested to do a <b>msg.reset=true</b> to reset all stored input values. |
|
|
127
138
|
|
|
128
|
-
|
|
129
|
-
<br/>
|
|
130
|
-
<br/>
|
|
131
|
-
<br/>
|
|
132
|
-
<br/>
|
|
133
|
-
|
|
134
|
-
# INTERRUPT FLOWS ULTIMATE
|
|
139
|
+
## Interrupt Flows Ultimate
|
|
135
140
|
|
|
136
141
|
The interrupt flows is able to stop the input messages to exiting the node.
|
|
137
142
|
|
|
138
|
-
###
|
|
143
|
+
### Configuration
|
|
139
144
|
|
|
140
145
|
| Property | Description |
|
|
141
146
|
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -147,13 +152,13 @@ The interrupt flows is able to stop the input messages to exiting the node.
|
|
|
147
152
|
|
|
148
153
|
**INPUT MSG WITH "TRIGGER" TOPIC**
|
|
149
154
|
|
|
150
|
-
Pass <code>msg.payload = true</code> to allow messages to pass through
|
|
155
|
+
Pass <code>msg.payload = true</code> to allow messages to pass through<br/>
|
|
151
156
|
|
|
152
|
-
Pass <code>msg.payload = false</code> to prevent messages from passing through
|
|
157
|
+
Pass <code>msg.payload = false</code> to prevent messages from passing through<br/>
|
|
153
158
|
|
|
154
|
-
Pass <code>msg.play = true</code> from a message having the "trigger" topic, to replay the last stored message
|
|
159
|
+
Pass <code>msg.play = true</code> from a message having the "trigger" topic, to replay the last stored message<br/>
|
|
155
160
|
|
|
156
|
-
Pass <code>msg.reset = true</code> from a message having the "trigger" topic, to clear the last stored message
|
|
161
|
+
Pass <code>msg.reset = true</code> from a message having the "trigger" topic, to clear the last stored message<br/>
|
|
157
162
|
|
|
158
163
|
<code>
|
|
159
164
|
// Assume you set the "trigger by topic" field to "trigger"
|
|
@@ -169,7 +174,7 @@ msg.topic = "trigger"
|
|
|
169
174
|
msg.reset = true;
|
|
170
175
|
</code>
|
|
171
176
|
|
|
172
|
-
|
|
177
|
+
<br/>
|
|
173
178
|
|
|
174
179
|
See the example below.<br/>
|
|
175
180
|
|
|
@@ -195,19 +200,13 @@ This allow to save the state of a node and then replay it back whenever you want
|
|
|
195
200
|
</code>
|
|
196
201
|
</details>
|
|
197
202
|
|
|
198
|
-
|
|
199
|
-
<br/>
|
|
200
|
-
<br/>
|
|
201
|
-
<br/>
|
|
202
|
-
<br/>
|
|
203
|
-
|
|
204
|
-
# INVERT ULTIMATE
|
|
203
|
+
## Invert Ultimate
|
|
205
204
|
|
|
206
205
|
Outputs the inverted input. For example true -> false<br />
|
|
207
206
|
|
|
208
207
|
The input message is preserved and passed to the output, changing only the topic and the payload. If the input message has it's own topic, it'll be preserved as well.<br/>
|
|
209
208
|
|
|
210
|
-
###
|
|
209
|
+
### Configuration
|
|
211
210
|
|
|
212
211
|
| Property | Description |
|
|
213
212
|
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -215,13 +214,7 @@ The input message is preserved and passed to the output, changing only the topic
|
|
|
215
214
|
|
|
216
215
|
<br/>
|
|
217
216
|
|
|
218
|
-
|
|
219
|
-
<br/>
|
|
220
|
-
<br/>
|
|
221
|
-
<br/>
|
|
222
|
-
<br/>
|
|
223
|
-
|
|
224
|
-
# FILTER ULTIMATE
|
|
217
|
+
## Filter Ultimate
|
|
225
218
|
|
|
226
219
|
This node has 2 outputs.<br />
|
|
227
220
|
|
|
@@ -231,7 +224,7 @@ If the input payload is false, the node will send nothing on output 1 and <code>
|
|
|
231
224
|
|
|
232
225
|
The input message is preserved and passed to the output, changing only the topic and the payload. If the input message has it's own topic, it'll be preserved as well.<br/>
|
|
233
226
|
|
|
234
|
-
###
|
|
227
|
+
### Configuration
|
|
235
228
|
|
|
236
229
|
| Property | Description |
|
|
237
230
|
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -239,15 +232,9 @@ The input message is preserved and passed to the output, changing only the topic
|
|
|
239
232
|
|
|
240
233
|
<br/>
|
|
241
234
|
|
|
242
|
-
|
|
243
|
-
<br/>
|
|
244
|
-
<br/>
|
|
245
|
-
<br/>
|
|
246
|
-
<br/>
|
|
247
|
-
|
|
248
|
-
# BLINKER ULTIMATE
|
|
235
|
+
## Blinker Ultimate
|
|
249
236
|
|
|
250
|
-
|
|
237
|
+
This node blinks an LED or another device.<br />
|
|
251
238
|
|
|
252
239
|
output1 : outputs the value true/false<br/>
|
|
253
240
|
|
|
@@ -255,7 +242,7 @@ output2 : outputs the inverted value false/true<br/>
|
|
|
255
242
|
|
|
256
243
|
<br/>
|
|
257
244
|
|
|
258
|
-
###
|
|
245
|
+
### Configuration
|
|
259
246
|
|
|
260
247
|
| Property | Description |
|
|
261
248
|
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -263,11 +250,11 @@ output2 : outputs the inverted value false/true<br/>
|
|
|
263
250
|
|
|
264
251
|
<br/>
|
|
265
252
|
|
|
266
|
-
Pass <code>msg.payload = true</code> to start blinking
|
|
253
|
+
Pass <code>msg.payload = true</code> to start blinking<br/>
|
|
267
254
|
|
|
268
|
-
Pass <code>msg.payload = false</code> to stop blinking
|
|
255
|
+
Pass <code>msg.payload = false</code> to stop blinking<br/>
|
|
269
256
|
|
|
270
|
-
Pass <code>msg.interval = 2000</code> to change the blinking interval
|
|
257
|
+
Pass <code>msg.interval = 2000</code> to change the blinking interval<br/>
|
|
271
258
|
|
|
272
259
|
- output1 stop behavior : when the blinker receives the stop message, you can select the behavior of the output1<br/>
|
|
273
260
|
- output2 stop behavior : when the blinker receives the stop message, you can select the behavior of the output2<br/>
|
|
@@ -280,19 +267,13 @@ Pass <code>msg.interval = 2000</code> to change the blinking interval</br>
|
|
|
280
267
|
</code>
|
|
281
268
|
</details>
|
|
282
269
|
|
|
283
|
-
|
|
284
|
-
<br/>
|
|
285
|
-
<br/>
|
|
286
|
-
<br/>
|
|
287
|
-
<br/>
|
|
270
|
+
## Simple Output Ultimate
|
|
288
271
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
The pourpose of this node is to send a message with payload TRUE on the first output and FALSE on second output, independently from the msg input.<br />
|
|
272
|
+
This node sends a message with payload TRUE on the first output and FALSE on the second output, independently of the input message.<br />
|
|
292
273
|
|
|
293
274
|
This is useful if you need to simply send a true or false payload.
|
|
294
275
|
|
|
295
|
-
###
|
|
276
|
+
### Configuration
|
|
296
277
|
|
|
297
278
|
| Property | Description |
|
|
298
279
|
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -308,15 +289,9 @@ This is useful if you need to simply send a true or false payload.
|
|
|
308
289
|
</code>
|
|
309
290
|
</details>
|
|
310
291
|
|
|
311
|
-
|
|
312
|
-
<br/>
|
|
313
|
-
<br/>
|
|
314
|
-
<br/>
|
|
315
|
-
<br/>
|
|
292
|
+
## Inject Ultimate
|
|
316
293
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
The pourpose of this node is to send a message with payload TRUE on the first output, FALSE on second output and a TOGGLE (true/false) on the third output, by pressing the pushbutton.<br />
|
|
294
|
+
This node sends TRUE on the first output, FALSE on the second output and a toggled true/false value on the third output when its button is pressed.<br />
|
|
320
295
|
|
|
321
296
|
This is useful if you need to simply test your flow.
|
|
322
297
|
|
|
@@ -328,15 +303,9 @@ This is useful if you need to simply test your flow.
|
|
|
328
303
|
</code>
|
|
329
304
|
</details>
|
|
330
305
|
|
|
331
|
-
|
|
332
|
-
<br/>
|
|
333
|
-
<br/>
|
|
334
|
-
<br/>
|
|
335
|
-
<br/>
|
|
336
|
-
|
|
337
|
-
# STATUS ULTIMATE
|
|
306
|
+
## Status Ultimate
|
|
338
307
|
|
|
339
|
-
|
|
308
|
+
This node displays the value of a passing message as its Node-RED status.<br />
|
|
340
309
|
|
|
341
310
|
**Show msg.**
|
|
342
311
|
|
|
@@ -349,15 +318,9 @@ The pourpose of this node is to show a status of the passingthrough message.<br
|
|
|
349
318
|
[{"id":"8c1648bf.58e6","type":"StatusUltimate","z":"5c2de561.6a0de4","name":"Status","property":"testobject.color","x":90,"y":180,"wires":[["b96cd259.3f8398"]]},{"id":"3beb9c6.90d1e64","type":"function","z":"5c2de561.6a0de4","name":"Dummy msg","func":"msg.payload = \"The payload is \" + msg.payload;\nmsg.myproperty = \"This is my custom property\";\nmsg.testobject = {len : 100, color : \"blue\"};\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":230,"y":100,"wires":[["8c1648bf.58e6"]]},{"id":"84080b79.df3f38","type":"debug","z":"5c2de561.6a0de4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":710,"y":180,"wires":[]},{"id":"b534d2ec.635398","type":"InjectUltimate","z":"5c2de561.6a0de4","name":"Inject","topic":"1","curVal":true,"x":90,"y":100,"wires":[[],[],["3beb9c6.90d1e64"]]},{"id":"9745c77a.0361b","type":"comment","z":"5c2de561.6a0de4","name":"View the status of a message passing through the StatusUltimate node","info":"","x":270,"y":40,"wires":[]},{"id":"b96cd259.3f8398","type":"StatusUltimate","z":"5c2de561.6a0de4","name":"Status","property":"payload","x":230,"y":180,"wires":[["ac2b784b.b44a48"]]},{"id":"ac2b784b.b44a48","type":"StatusUltimate","z":"5c2de561.6a0de4","name":"Status","property":"myproperty","x":450,"y":180,"wires":[["84080b79.df3f38"]]}]
|
|
350
319
|
</code>
|
|
351
320
|
</details>
|
|
352
|
-
|
|
353
|
-
<br/>
|
|
354
|
-
<br/>
|
|
355
|
-
<br/>
|
|
356
|
-
<br/>
|
|
357
|
-
|
|
358
|
-
# IMPULSE ULTIMATE
|
|
321
|
+
## Impulse Ultimate
|
|
359
322
|
|
|
360
|
-
|
|
323
|
+
This node sends a timed sequence of pulsed commands, for example to open a garage door or control an appliance.<br />
|
|
361
324
|
|
|
362
325
|
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/Impulse.png' width='60%'>
|
|
363
326
|
<details><summary>CLICK HERE, copy and paste it into your flow</summary>
|
|
@@ -366,7 +329,7 @@ The pourpose of this node is to send a sequence of pulsed commands to for exampl
|
|
|
366
329
|
</code>
|
|
367
330
|
</details>
|
|
368
331
|
|
|
369
|
-
###
|
|
332
|
+
### Configuration
|
|
370
333
|
|
|
371
334
|
| Property | Description |
|
|
372
335
|
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -388,23 +351,17 @@ Restart the sequence from the beginning. Use **_restart_** alone, without **:**
|
|
|
388
351
|
comment. For example: **_// This opens the garage_**. The comment are ignored, so you can write what you want.<br />
|
|
389
352
|
<br />
|
|
390
353
|
|
|
391
|
-
Pass <code>msg.payload = true</code> to the node to start the sequence
|
|
354
|
+
Pass <code>msg.payload = true</code> to the node to start the sequence<br/>
|
|
392
355
|
|
|
393
|
-
Pass <code>msg.payload = false</code> to the node to stop the running sequence
|
|
356
|
+
Pass <code>msg.payload = false</code> to the node to stop the running sequence<br/>
|
|
394
357
|
|
|
395
358
|
<br />
|
|
396
359
|
|
|
397
360
|
- Output: the node outputs a message you specified in the command textbox<br/>
|
|
398
361
|
|
|
399
|
-
|
|
400
|
-
<br/>
|
|
401
|
-
<br/>
|
|
402
|
-
<br/>
|
|
403
|
-
<br/>
|
|
362
|
+
## Math Ultimate
|
|
404
363
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
The pourpose of this node is to do maths on the incoming values. Each incoming message MUST HAVE OWN TOPIC.<br />
|
|
364
|
+
This node performs calculations on incoming values. Each incoming message must have its own topic.<br />
|
|
408
365
|
|
|
409
366
|
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/sum.png' width='60%'>
|
|
410
367
|
<details><summary>CLICK HERE, copy and paste it into your flow</summary>
|
|
@@ -413,7 +370,7 @@ The pourpose of this node is to do maths on the incoming values. Each incoming m
|
|
|
413
370
|
</code>
|
|
414
371
|
</details>
|
|
415
372
|
|
|
416
|
-
###
|
|
373
|
+
### Configuration
|
|
417
374
|
|
|
418
375
|
| Property | Description |
|
|
419
376
|
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -439,18 +396,11 @@ resets the values to zero.
|
|
|
439
396
|
}
|
|
440
397
|
</pre>
|
|
441
398
|
|
|
442
|
-
|
|
399
|
+
## Toggle Ultimate
|
|
443
400
|
|
|
444
|
-
|
|
445
|
-
<br/>
|
|
446
|
-
<br/>
|
|
447
|
-
<br/>
|
|
448
|
-
|
|
449
|
-
# TOGGLE ULTIMATE
|
|
401
|
+
This node toggles between true and false whenever an inbound message arrives.<br />
|
|
450
402
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
### NODE CONFIGURATION
|
|
403
|
+
### Configuration
|
|
454
404
|
|
|
455
405
|
| Property | Description |
|
|
456
406
|
| -------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -460,21 +410,15 @@ The pourpose of this node is to toggle between true/false, everytime an inboud m
|
|
|
460
410
|
|
|
461
411
|
**INPUT**<br />
|
|
462
412
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
<br/>
|
|
466
|
-
<br/>
|
|
467
|
-
<br/>
|
|
468
|
-
<br/>
|
|
469
|
-
<br/>
|
|
413
|
+
Every input message is passed to the output with its payload toggled between true and false.
|
|
470
414
|
|
|
471
|
-
|
|
415
|
+
## Railway Switch Ultimate
|
|
472
416
|
|
|
473
|
-
The railway
|
|
417
|
+
The railway switch redirects incoming messages to one of the available outputs, like a railway junction.
|
|
474
418
|
|
|
475
419
|
<img src='https://raw.githubusercontent.com/Supergiovane/node-red-contrib-boolean-logic-ultimate/master/img/railroadSwitchScambio.png' width='80%'>
|
|
476
420
|
|
|
477
|
-
###
|
|
421
|
+
### Configuration
|
|
478
422
|
|
|
479
423
|
| Property | Description |
|
|
480
424
|
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -528,7 +472,7 @@ this JSON input message redirects all input messages to the third PIN, and so on
|
|
|
528
472
|
}
|
|
529
473
|
```
|
|
530
474
|
|
|
531
|
-
|
|
475
|
+
<br/>
|
|
532
476
|
|
|
533
477
|
See the example below.<br/>
|
|
534
478
|
|
|
@@ -625,14 +569,9 @@ Copy and paste it into your flow
|
|
|
625
569
|
];
|
|
626
570
|
```
|
|
627
571
|
|
|
628
|
-
|
|
629
|
-
<br/>
|
|
630
|
-
<br/>
|
|
631
|
-
<br/>
|
|
632
|
-
|
|
633
|
-
# KALMAN FILTER ULTIMATE
|
|
572
|
+
## Kalman Filter Ultimate
|
|
634
573
|
|
|
635
|
-
|
|
574
|
+
Outputs the Kalman-filtered input.
|
|
636
575
|
|
|
637
576
|
Please refer to [this](https://github.com/wouterbulten/kalmanjs) link, on how it works.
|
|
638
577
|
|
|
@@ -653,13 +592,11 @@ Please refer to [this](https://github.com/wouterbulten/kalmanjs) link, on how it
|
|
|
653
592
|
|
|
654
593
|
: 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.
|
|
655
594
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
# RATE LIMITER ULTIMATE
|
|
595
|
+
## Rate Limiter Ultimate
|
|
659
596
|
|
|
660
597
|
Gateway per sensori e dispositivi troppo “chiacchieroni”: limita burst e rimbalzi con modalità **Debounce**, **Throttle** e **Window**. Lo stato del nodo riporta sempre modalità corrente, contatori di messaggi inoltrati e bloccati.
|
|
661
598
|
|
|
662
|
-
###
|
|
599
|
+
### Configuration
|
|
663
600
|
|
|
664
601
|
| Property | Description |
|
|
665
602
|
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -678,23 +615,21 @@ Gateway per sensori e dispositivi troppo “chiacchieroni”: limita burst e rim
|
|
|
678
615
|
|
|
679
616
|
<br/>
|
|
680
617
|
|
|
681
|
-
###
|
|
618
|
+
### Outputs
|
|
682
619
|
|
|
683
620
|
- **Output 1**: messaggi inoltrati, invariati.
|
|
684
621
|
- **Output 2**: diagnostica (`{mode, reason, passed, dropped, msg, propertyValue}`) e statistiche periodiche su `controlTopic/stats`.
|
|
685
622
|
|
|
686
623
|
<br/>
|
|
687
624
|
|
|
688
|
-
###
|
|
625
|
+
### Control messages (`msg.topic === controlTopic`)
|
|
689
626
|
|
|
690
627
|
- `msg.reset = true` → azzera contatori, accoda azzerata e timer cancellati.
|
|
691
628
|
- `msg.flush = true` → forza l’emissione immediata del messaggio in attesa.
|
|
692
629
|
- `msg.mode = 'debounce'|'throttle'|'window'` → cambia modalità runtime e resetta lo stato.
|
|
693
630
|
- `msg.interval`, `msg.wait`, `msg.windowSize`, `msg.maxInWindow` → aggiorna i parametri corrispondenti.
|
|
694
631
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
# DEBOUNCER ULTIMATE
|
|
632
|
+
## Debouncer Ultimate
|
|
698
633
|
|
|
699
634
|
Nodo dedicato al solo debounce: utile quando vuoi filtrare rimbalzi o burst rapidi senza portarti dietro le altre modalità del `RateLimiterUltimate`. Può inoltrare il **primo** messaggio, l’**ultimo** oppure **entrambi**, dopo un intervallo di quiete configurabile.
|
|
700
635
|
|
|
@@ -704,7 +639,7 @@ Nell'immagine si vede il comportamento tipico: a sinistra arrivano molti messagg
|
|
|
704
639
|
|
|
705
640
|
Example flow: [`examples/DebouncerUltimate.json`](examples/DebouncerUltimate.json)
|
|
706
641
|
|
|
707
|
-
###
|
|
642
|
+
### Configuration
|
|
708
643
|
|
|
709
644
|
| Property | Description |
|
|
710
645
|
| ------------- | ------------------------------------------------------------------------------------------ |
|
|
@@ -712,24 +647,22 @@ Example flow: [`examples/DebouncerUltimate.json`](examples/DebouncerUltimate.jso
|
|
|
712
647
|
| Emit | Scegli se inviare subito il primo messaggio, solo l’ultimo dopo la pausa, oppure entrambi. |
|
|
713
648
|
| Control topic | Topic dei messaggi di controllo (default `debouncer`). |
|
|
714
649
|
|
|
715
|
-
###
|
|
650
|
+
### Outputs
|
|
716
651
|
|
|
717
652
|
- **Output 1**: messaggi inoltrati dopo il debounce.
|
|
718
653
|
|
|
719
|
-
###
|
|
654
|
+
### Control messages (`msg.topic === controlTopic`)
|
|
720
655
|
|
|
721
656
|
- `msg.reset = true` → cancella timer e messaggio pendente.
|
|
722
657
|
- `msg.flush = true` → inoltra subito l’ultimo messaggio in attesa.
|
|
723
658
|
- `msg.wait` → aggiorna il ritardo di debounce a runtime.
|
|
724
659
|
- `msg.emitOn = 'leading'|'trailing'|'both'` → cambia la modalità di emissione.
|
|
725
660
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
# PRESENCE SIMULATOR ULTIMATE
|
|
661
|
+
## Presence Simulator Ultimate
|
|
729
662
|
|
|
730
663
|
The purpose of this node is to replay a programmable sequence of messages in order to simulate occupancy when you are away.
|
|
731
664
|
|
|
732
|
-
###
|
|
665
|
+
### Configuration
|
|
733
666
|
|
|
734
667
|
| Property | Description |
|
|
735
668
|
| ------------- | ---------------------------------------------------------------------------------------------- |
|
|
@@ -742,7 +675,7 @@ The purpose of this node is to replay a programmable sequence of messages in ord
|
|
|
742
675
|
| Translator | Optional translator-config to convert incoming values. |
|
|
743
676
|
| Sequence | One JSON object per line, each containing at least `delay` (ms) plus the properties to output. |
|
|
744
677
|
|
|
745
|
-
###
|
|
678
|
+
### Control messages (`msg.topic === controlTopic`)
|
|
746
679
|
|
|
747
680
|
- `msg.command = 'start'` / `msg.start = true` → begin playback.
|
|
748
681
|
- `msg.command = 'stop'` / `msg.stop = true` → halt playback.
|
|
@@ -752,13 +685,11 @@ The purpose of this node is to replay a programmable sequence of messages in ord
|
|
|
752
685
|
|
|
753
686
|
Each event in the sequence outputs a message configured in the JSON line. When random delays are enabled, the effective delay is varied within the configured jitter.
|
|
754
687
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
# STAIRCASE LIGHT ULTIMATE
|
|
688
|
+
## Staircase Light Ultimate
|
|
758
689
|
|
|
759
690
|
The purpose of this node is to control staircase lighting with a timer, pre-off warning and optional extension on every trigger.
|
|
760
691
|
|
|
761
|
-
###
|
|
692
|
+
### Configuration
|
|
762
693
|
|
|
763
694
|
| Property | Description |
|
|
764
695
|
| ------------------ | ------------------------------------------------------------------ |
|
|
@@ -773,7 +704,7 @@ The purpose of this node is to control staircase lighting with a timer, pre-off
|
|
|
773
704
|
| On/Off payload | Values emitted on output 1 to turn the light on/off. |
|
|
774
705
|
| Warning payload | Value emitted on output 2 when the warning fires. |
|
|
775
706
|
|
|
776
|
-
###
|
|
707
|
+
### Control messages (`msg.topic === controlTopic`)
|
|
777
708
|
|
|
778
709
|
- `msg.command = 'on'` / `msg.start = true` → start the timer and turn on the light.
|
|
779
710
|
- `msg.command = 'off'` / `msg.stop = true` → switch off immediately.
|
|
@@ -782,35 +713,57 @@ The purpose of this node is to control staircase lighting with a timer, pre-off
|
|
|
782
713
|
|
|
783
714
|
Output 1 delivers the ON/OFF command. Output 2 delivers the warning and includes `msg.remaining` with the seconds left.
|
|
784
715
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
# HYSTERESIS ULTIMATE
|
|
716
|
+
## Hysteresis Ultimate
|
|
788
717
|
|
|
789
718
|
Adds hysteresis to numeric sensor values to avoid rapid ON/OFF bouncing around thresholds.
|
|
790
719
|
|
|
791
720
|
Example flow: [`examples/HysteresisUltimate.json`](examples/HysteresisUltimate.json)
|
|
792
721
|
|
|
793
|
-
###
|
|
722
|
+
### Configuration
|
|
723
|
+
|
|
724
|
+
| Property | Description |
|
|
725
|
+
| ------------------- | ----------- |
|
|
726
|
+
| Name | Optional label shown in the flow editor. |
|
|
727
|
+
| Control topic | Topic used for runtime commands (default `hysteresis`). It is not required for `permanentLockState`. |
|
|
728
|
+
| Mode | `high`: ON at or above the ON threshold and OFF at or below the OFF threshold. `low`: ON at or below the ON threshold and OFF at or above the OFF threshold. Values between the thresholds retain the current state. |
|
|
729
|
+
| ON threshold | Numeric limit that changes the internal state to ON according to the selected mode. |
|
|
730
|
+
| OFF threshold | Numeric limit that changes the internal state to OFF according to the selected mode. |
|
|
731
|
+
| Initial state ON | Initial internal state after deployment or restart. It does not emit at startup and is restored by `msg.reset = true`. |
|
|
732
|
+
| Emit only on change | When enabled, output 1 emits only on transitions. When disabled, every valid numeric input emits the current state. |
|
|
733
|
+
| Input | Message property evaluated as a numeric value (default `msg.payload`). Numbers, booleans and numeric strings are accepted. |
|
|
734
|
+
| Translator | Optional shared translator configuration associated with the input. Hysteresis evaluation uses the numeric value of the selected input property. |
|
|
735
|
+
| On payload | Typed value assigned to `msg.payload` on output 1 while the state is ON. |
|
|
736
|
+
| Off payload | Typed value assigned to `msg.payload` on output 1 while the state is OFF. |
|
|
794
737
|
|
|
795
|
-
|
|
796
|
-
| ------------------- | ------------------------------------------------------------------------------ |
|
|
797
|
-
| Control topic | Topic that receives runtime commands such as threshold updates and reset. |
|
|
798
|
-
| Mode | `high` = ON above threshold, OFF below. `low` = ON below threshold, OFF above. |
|
|
799
|
-
| ON/OFF threshold | Hysteresis limits. |
|
|
800
|
-
| Initial state | Startup output state. |
|
|
801
|
-
| Emit only on change | If enabled, output 1 emits only on state transitions. |
|
|
802
|
-
| Input | Message property evaluated as numeric value (default `payload`). |
|
|
803
|
-
| Translator | Optional translator-config. |
|
|
804
|
-
| On/Off payload | Typed payloads sent on output 1. |
|
|
738
|
+
### Input messages
|
|
805
739
|
|
|
806
|
-
|
|
740
|
+
Normal messages are evaluated using the configured **Input** property. Missing or non-numeric values generate an `invalid_input` diagnostic on output 2.
|
|
741
|
+
|
|
742
|
+
### Control messages (`msg.topic === controlTopic`)
|
|
807
743
|
|
|
808
744
|
- `msg.onThreshold`, `msg.offThreshold` → update thresholds at runtime.
|
|
809
|
-
- `msg.state = true|false` → force state.
|
|
810
|
-
- `msg.reset = true` → restore initial state.
|
|
745
|
+
- `msg.state = true|false` → force the state and emit it on output 1. While locked, it updates the internal state without emitting on output 1.
|
|
746
|
+
- `msg.reset = true` → restore the initial state and emit a `reset` diagnostic.
|
|
811
747
|
- `msg.status = true` → emit current state/thresholds on output 2.
|
|
812
748
|
|
|
813
|
-
|
|
749
|
+
### Permanent output lock
|
|
750
|
+
|
|
751
|
+
Regardless of `msg.topic`, `msg.permanentLockState` accepts:
|
|
752
|
+
|
|
753
|
+
- `lock` → suppress state output until another permanent-lock command arrives.
|
|
754
|
+
- `lockOn` → force ON, emit the configured ON payload once, then suppress state output.
|
|
755
|
+
- `lockOff` → force OFF, emit the configured OFF payload once, then suppress state output.
|
|
756
|
+
- `unlock` → resume normal processing (the unlock message itself is consumed).
|
|
757
|
+
|
|
758
|
+
While locked, normal input messages are ignored and output 1 remains suppressed. Control-topic commands remain active: thresholds can be updated, `state` and `reset` can change the internal state, and `status`/`reset` diagnostics can still be emitted on output 2.
|
|
759
|
+
|
|
760
|
+
### Outputs
|
|
761
|
+
|
|
762
|
+
1. **State output** emits a clone of the input message with:
|
|
763
|
+
- the configured `onPayload` or `offPayload` in `msg.payload`;
|
|
764
|
+
- `msg.event` set to `state_changed` or `state_confirmed`;
|
|
765
|
+
- `msg.hysteresis` containing `state`, `changed`, `mode`, input `value`, `onThreshold` and `offThreshold`.
|
|
766
|
+
2. **Diagnostics** emits state-change, invalid-input, reset and status events. It sets `msg.topic` to `<controlTopic>/event` and places the event details in `msg.payload`.
|
|
814
767
|
|
|
815
768
|
<br/>
|
|
816
769
|
|
|
@@ -121,17 +121,40 @@
|
|
|
121
121
|
|
|
122
122
|
|Property|Description|
|
|
123
123
|
|--|--|
|
|
124
|
-
|
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
|
|
|
124
|
+
| Name | Optional label shown in the flow editor. |
|
|
125
|
+
| Control topic | Topic used for runtime commands. The default is `hysteresis`. It is not required for `permanentLockState`. |
|
|
126
|
+
| Mode | `high`: switch ON when the value is greater than or equal to the ON threshold and OFF when it is less than or equal to the OFF threshold. `low`: switch ON when the value is less than or equal to the ON threshold and OFF when it is greater than or equal to the OFF threshold. Values between the thresholds keep the current state. |
|
|
127
|
+
| ON threshold | Numeric limit that changes the internal state to ON, according to the selected mode. |
|
|
128
|
+
| OFF threshold | Numeric limit that changes the internal state to OFF, according to the selected mode. |
|
|
129
|
+
| Initial state ON | Initial internal state after deployment or restart. It does not emit a message by itself. It is also restored by `msg.reset = true`. |
|
|
130
|
+
| Emit only on change | When enabled, output 1 emits only when the state changes. When disabled, every valid numeric input emits the current ON/OFF state. |
|
|
131
|
+
| Input | Numeric message property to evaluate. The default is `msg.payload`; numbers, booleans and numeric strings are accepted. |
|
|
132
|
+
| Translator | Optional shared translator configuration associated with the input. Hysteresis evaluation uses the numeric value of the selected input property. |
|
|
133
|
+
| On payload | Typed value written to `msg.payload` on output 1 when the state is ON. |
|
|
134
|
+
| Off payload | Typed value written to `msg.payload` on output 1 when the state is OFF. |
|
|
130
135
|
|
|
131
|
-
|
|
136
|
+
### Inputs
|
|
137
|
+
|
|
138
|
+
Normal input messages are evaluated using the configured **Input** property. An absent or non-numeric value produces an `invalid_input` diagnostic on output 2.
|
|
139
|
+
|
|
140
|
+
The following commands are consumed only when `msg.topic` equals **Control topic**:
|
|
132
141
|
|
|
133
142
|
- `msg.onThreshold`, `msg.offThreshold` to update thresholds at runtime.
|
|
134
|
-
- `msg.state = true|false` to force state.
|
|
135
|
-
- `msg.reset = true` to restore initial state.
|
|
143
|
+
- `msg.state = true|false` to force the state and emit it on output 1. While locked, it updates the internal state without emitting on output 1.
|
|
144
|
+
- `msg.reset = true` to restore the configured initial state and emit a `reset` diagnostic.
|
|
136
145
|
- `msg.status = true` to emit current status on output 2.
|
|
137
|
-
|
|
146
|
+
|
|
147
|
+
`msg.permanentLockState` is handled regardless of `msg.topic`:
|
|
148
|
+
|
|
149
|
+
- `"lock"` suppresses state output until another valid permanent-lock command arrives.
|
|
150
|
+
- `"lockOn"` forces ON and emits the configured **On payload** once, then suppresses state output.
|
|
151
|
+
- `"lockOff"` forces OFF and emits the configured **Off payload** once, then suppresses state output.
|
|
152
|
+
- `"unlock"` resumes normal processing. The unlock message itself is consumed.
|
|
153
|
+
|
|
154
|
+
While locked, normal input messages are ignored and output 1 remains suppressed. Control-topic commands remain active: thresholds can be updated, `state` and `reset` can change the internal state, and `status`/`reset` diagnostics can still be emitted on output 2.
|
|
155
|
+
|
|
156
|
+
### Outputs
|
|
157
|
+
|
|
158
|
+
1. **State output**: a clone of the input message with the configured ON/OFF `msg.payload`, `msg.event` (`state_changed` or `state_confirmed`) and `msg.hysteresis`, containing `state`, `changed`, `mode`, input `value`, `onThreshold` and `offThreshold`.
|
|
159
|
+
2. **Diagnostics**: events for state changes, invalid inputs, reset and status. The topic is `<controlTopic>/event`, and `msg.payload` contains the event details.
|
|
160
|
+
</script>
|
|
@@ -18,6 +18,7 @@ module.exports = function (RED) {
|
|
|
18
18
|
let onThreshold = Number(config.onThreshold);
|
|
19
19
|
let offThreshold = Number(config.offThreshold);
|
|
20
20
|
let state = Boolean(config.initialState);
|
|
21
|
+
let permanentLockState = 'unlock';
|
|
21
22
|
|
|
22
23
|
if (!Number.isFinite(onThreshold)) onThreshold = 70;
|
|
23
24
|
if (!Number.isFinite(offThreshold)) offThreshold = 65;
|
|
@@ -47,10 +48,11 @@ module.exports = function (RED) {
|
|
|
47
48
|
function updateStatus(lastValue) {
|
|
48
49
|
const direction = mode === 'low' ? 'LOW' : 'HIGH';
|
|
49
50
|
const valueText = lastValue === undefined ? '-' : Number(lastValue).toFixed(2);
|
|
51
|
+
const lockText = permanentLockState === 'unlock' ? '' : ` ${permanentLockState}`;
|
|
50
52
|
setNodeStatus({
|
|
51
53
|
fill: state ? 'green' : 'grey',
|
|
52
54
|
shape: state ? 'dot' : 'ring',
|
|
53
|
-
text: `${direction} ${valueText} on:${onThreshold} off:${offThreshold}`,
|
|
55
|
+
text: `${direction} ${valueText} on:${onThreshold} off:${offThreshold}${lockText}`,
|
|
54
56
|
});
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -101,7 +103,7 @@ module.exports = function (RED) {
|
|
|
101
103
|
updateStatus(inputValue);
|
|
102
104
|
}
|
|
103
105
|
|
|
104
|
-
function handleControl(msg) {
|
|
106
|
+
function handleControl(msg, suppressStateOutput) {
|
|
105
107
|
let consumed = false;
|
|
106
108
|
|
|
107
109
|
if (msg.reset === true) {
|
|
@@ -134,7 +136,9 @@ module.exports = function (RED) {
|
|
|
134
136
|
|
|
135
137
|
if (Object.prototype.hasOwnProperty.call(msg, 'state')) {
|
|
136
138
|
state = Boolean(msg.state);
|
|
137
|
-
|
|
139
|
+
if (!suppressStateOutput) {
|
|
140
|
+
emitState(msg, true, undefined);
|
|
141
|
+
}
|
|
138
142
|
consumed = true;
|
|
139
143
|
}
|
|
140
144
|
|
|
@@ -156,8 +160,46 @@ module.exports = function (RED) {
|
|
|
156
160
|
return consumed;
|
|
157
161
|
}
|
|
158
162
|
|
|
163
|
+
function handlePermanentLock(msg) {
|
|
164
|
+
if (!Object.prototype.hasOwnProperty.call(msg, 'permanentLockState')) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const command = msg.permanentLockState;
|
|
169
|
+
if (!['unlock', 'lock', 'lockOff', 'lockOn'].includes(command)) {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (command === 'unlock') {
|
|
174
|
+
permanentLockState = 'unlock';
|
|
175
|
+
updateStatus();
|
|
176
|
+
return true;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
permanentLockState = command;
|
|
180
|
+
if (command === 'lockOn' || command === 'lockOff') {
|
|
181
|
+
state = command === 'lockOn';
|
|
182
|
+
emitState(msg, true, undefined);
|
|
183
|
+
} else {
|
|
184
|
+
updateStatus();
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
}
|
|
188
|
+
|
|
159
189
|
node.on('input', (msg) => {
|
|
160
|
-
if (
|
|
190
|
+
if (handlePermanentLock(msg)) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const isLocked = permanentLockState !== 'unlock';
|
|
195
|
+
|
|
196
|
+
if (msg.topic === controlTopic) {
|
|
197
|
+
if (handleControl(msg, isLocked) || isLocked) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (isLocked) {
|
|
161
203
|
return;
|
|
162
204
|
}
|
|
163
205
|
|
|
@@ -76,6 +76,80 @@
|
|
|
76
76
|
"y": 240,
|
|
77
77
|
"wires": [["hys-node"]]
|
|
78
78
|
},
|
|
79
|
+
{
|
|
80
|
+
"id": "hys-lock-comment",
|
|
81
|
+
"type": "comment",
|
|
82
|
+
"z": "hys-flow",
|
|
83
|
+
"name": "Permanent output lock commands (independent of msg.topic)",
|
|
84
|
+
"info": "lock: suppress state output\nlockOn: emit ON once, then suppress state output\nlockOff: emit OFF once, then suppress state output\nunlock: resume normal processing\n\nControl-topic commands and diagnostics remain active while locked.",
|
|
85
|
+
"x": 310,
|
|
86
|
+
"y": 320,
|
|
87
|
+
"wires": []
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "hys-lock",
|
|
91
|
+
"type": "inject",
|
|
92
|
+
"z": "hys-flow",
|
|
93
|
+
"name": "Lock without output",
|
|
94
|
+
"props": [
|
|
95
|
+
{ "p": "permanentLockState", "v": "lock", "vt": "str" }
|
|
96
|
+
],
|
|
97
|
+
"repeat": "",
|
|
98
|
+
"crontab": "",
|
|
99
|
+
"once": false,
|
|
100
|
+
"onceDelay": 0.1,
|
|
101
|
+
"x": 230,
|
|
102
|
+
"y": 360,
|
|
103
|
+
"wires": [["hys-node"]]
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"id": "hys-lock-on",
|
|
107
|
+
"type": "inject",
|
|
108
|
+
"z": "hys-flow",
|
|
109
|
+
"name": "Force ON and lock",
|
|
110
|
+
"props": [
|
|
111
|
+
{ "p": "permanentLockState", "v": "lockOn", "vt": "str" }
|
|
112
|
+
],
|
|
113
|
+
"repeat": "",
|
|
114
|
+
"crontab": "",
|
|
115
|
+
"once": false,
|
|
116
|
+
"onceDelay": 0.1,
|
|
117
|
+
"x": 230,
|
|
118
|
+
"y": 400,
|
|
119
|
+
"wires": [["hys-node"]]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"id": "hys-lock-off",
|
|
123
|
+
"type": "inject",
|
|
124
|
+
"z": "hys-flow",
|
|
125
|
+
"name": "Force OFF and lock",
|
|
126
|
+
"props": [
|
|
127
|
+
{ "p": "permanentLockState", "v": "lockOff", "vt": "str" }
|
|
128
|
+
],
|
|
129
|
+
"repeat": "",
|
|
130
|
+
"crontab": "",
|
|
131
|
+
"once": false,
|
|
132
|
+
"onceDelay": 0.1,
|
|
133
|
+
"x": 230,
|
|
134
|
+
"y": 440,
|
|
135
|
+
"wires": [["hys-node"]]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"id": "hys-unlock",
|
|
139
|
+
"type": "inject",
|
|
140
|
+
"z": "hys-flow",
|
|
141
|
+
"name": "Unlock",
|
|
142
|
+
"props": [
|
|
143
|
+
{ "p": "permanentLockState", "v": "unlock", "vt": "str" }
|
|
144
|
+
],
|
|
145
|
+
"repeat": "",
|
|
146
|
+
"crontab": "",
|
|
147
|
+
"once": false,
|
|
148
|
+
"onceDelay": 0.1,
|
|
149
|
+
"x": 200,
|
|
150
|
+
"y": 480,
|
|
151
|
+
"wires": [["hys-node"]]
|
|
152
|
+
},
|
|
79
153
|
{
|
|
80
154
|
"id": "hys-out",
|
|
81
155
|
"type": "debug",
|
package/package.json
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-boolean-logic-ultimate",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.17",
|
|
4
4
|
"description": "A set of Node-RED enhanced boolean logic and utility nodes, flow interruption, blinker, debouncer, invert, filter, toggle etc.., with persistent values after reboot. Compatible also with Homeassistant values.",
|
|
5
|
-
"author":
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Massimo Saccani",
|
|
7
|
+
"email": "maxsupergiovane@icloud.com",
|
|
8
|
+
"url": "https://youtube.com/@maxsupervibe"
|
|
9
|
+
},
|
|
6
10
|
"dependencies": {
|
|
7
|
-
"fs": "0.0.1-security",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
11
|
+
"fs": "^0.0.1-security",
|
|
12
|
+
"kalmanjs": "^1.1.0",
|
|
13
|
+
"path": "^0.12.7"
|
|
10
14
|
},
|
|
11
15
|
"devDependencies": {
|
|
12
|
-
"chai": "^
|
|
13
|
-
"mocha": "^
|
|
14
|
-
"node-red": "^
|
|
15
|
-
"node-red-node-test-helper": "^0.3.
|
|
16
|
+
"chai": "^6.2.2",
|
|
17
|
+
"mocha": "^11.7.6",
|
|
18
|
+
"node-red": "^5.0.1",
|
|
19
|
+
"node-red-node-test-helper": "^0.3.6"
|
|
16
20
|
},
|
|
17
21
|
"keywords": [
|
|
18
22
|
"node-red",
|
package/test/hysteresis.spec.js
CHANGED
|
@@ -84,4 +84,61 @@ describe('HysteresisUltimate node', function () {
|
|
|
84
84
|
hys.receive({ topic: 'sensor', payload: 58 });
|
|
85
85
|
}).catch(done);
|
|
86
86
|
});
|
|
87
|
+
|
|
88
|
+
it('supports permanent lock, lockOn, lockOff and unlock commands', function (done) {
|
|
89
|
+
const flowId = 'hys-lock';
|
|
90
|
+
const flow = [
|
|
91
|
+
{ id: flowId, type: 'tab', label: 'hys-lock' },
|
|
92
|
+
{
|
|
93
|
+
id: 'hys',
|
|
94
|
+
type: 'HysteresisUltimate',
|
|
95
|
+
z: flowId,
|
|
96
|
+
mode: 'high',
|
|
97
|
+
onThreshold: 70,
|
|
98
|
+
offThreshold: 60,
|
|
99
|
+
emitOnlyOnChange: true,
|
|
100
|
+
onPayload: 'on',
|
|
101
|
+
onPayloadType: 'str',
|
|
102
|
+
offPayload: 'off',
|
|
103
|
+
offPayloadType: 'str',
|
|
104
|
+
wires: [['out'], ['diag']],
|
|
105
|
+
},
|
|
106
|
+
{ id: 'out', type: 'helper', z: flowId },
|
|
107
|
+
{ id: 'diag', type: 'helper', z: flowId },
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
loadHysteresis(flow).then(() => {
|
|
111
|
+
const hys = helper.getNode('hys');
|
|
112
|
+
const out = helper.getNode('out');
|
|
113
|
+
const diag = helper.getNode('diag');
|
|
114
|
+
const outputPayloads = [];
|
|
115
|
+
const diagnostics = [];
|
|
116
|
+
|
|
117
|
+
out.on('input', (msg) => outputPayloads.push(msg.payload));
|
|
118
|
+
diag.on('input', (msg) => diagnostics.push(msg.payload));
|
|
119
|
+
|
|
120
|
+
hys.receive({ permanentLockState: 'lockOn' });
|
|
121
|
+
hys.receive({ payload: 55 });
|
|
122
|
+
hys.receive({ topic: 'hysteresis', onThreshold: 74, status: true });
|
|
123
|
+
hys.receive({ topic: 'hysteresis', state: false });
|
|
124
|
+
hys.receive({ permanentLockState: 'lockOff' });
|
|
125
|
+
hys.receive({ payload: 75 });
|
|
126
|
+
hys.receive({ permanentLockState: 'lock' });
|
|
127
|
+
hys.receive({ payload: 75 });
|
|
128
|
+
hys.receive({ permanentLockState: 'unlock' });
|
|
129
|
+
hys.receive({ payload: 75 });
|
|
130
|
+
|
|
131
|
+
setTimeout(() => {
|
|
132
|
+
try {
|
|
133
|
+
expect(outputPayloads).to.deep.equal(['on', 'off', 'on']);
|
|
134
|
+
expect(diagnostics).to.have.length(2);
|
|
135
|
+
expect(diagnostics[0]).to.include({ event: 'status', state: true, onThreshold: 74 });
|
|
136
|
+
expect(diagnostics[1]).to.include({ event: 'state_changed', state: true, onThreshold: 74 });
|
|
137
|
+
done();
|
|
138
|
+
} catch (error) {
|
|
139
|
+
done(error);
|
|
140
|
+
}
|
|
141
|
+
}, 50);
|
|
142
|
+
}).catch(done);
|
|
143
|
+
});
|
|
87
144
|
});
|