@mschaeffler/node-red-logic 0.0.6 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,45 +12,178 @@ $ npm install @mschaeffler/node-red-logic
12
12
 
13
13
  ## Usage
14
14
 
15
- .
15
+ ### counter
16
+
17
+ A node that just count the messages.
18
+
19
+ #### Output
20
+
21
+ |msg. | type | description |
22
+ |:-------|:-------|:----------------------------------|
23
+ |count | number | number of messages.|
24
+
25
+ ### to bool
26
+
27
+ Converts payload to a bool value:
28
+
29
+ |type|value|is converted to|
30
+ |:---|:----|:--------------|
31
+ |bool|false|false|
32
+ ||true|true|
33
+ |number|0|false|
34
+ ||1|true|
35
+ |string|false|false|
36
+ ||0|false|
37
+ ||off|false|
38
+ ||true|true|
39
+ ||1|true|
40
+ ||on|true|
41
+
42
+ #### Input
43
+
44
+ The message property to be used as payload can be defined with the `Property` property.
45
+
46
+ |msg. | type | description |
47
+ |:-------|:-------|:----------------------------------|
48
+ |payload | | input value. |
49
+
50
+ #### Output
51
+
52
+ |msg. | type | description |
53
+ |:-------|:-------|:----------------------------------|
54
+ |payload | boolean | bool value of payload.|
55
+
56
+ #### Parameters
57
+
58
+ |config| type | description |
59
+ |:-----|:-------|:----------------------------------|
60
+ |Property| string | defines the message property to be used as payload.|
16
61
 
17
62
  ### or
18
63
 
19
- .
64
+ Combines two or more boolean vales with the `or` operator.
65
+
66
+ The input values are converted as described in the `to bool` node.
20
67
 
21
68
  #### Input
22
69
 
23
- .
70
+ The different inputs are differentiated by topics.
71
+
72
+ The message property to be used as payload can be defined with the `Property` property.
24
73
 
25
74
  |msg. | type | description |
26
75
  |:-------|:-------|:----------------------------------|
27
- |topic | string | .|
76
+ |topic | string | name of the input channel. |
28
77
  |payload | boolean| input value for `topic`. |
29
78
 
30
79
  #### Output
31
80
 
32
- .
33
-
34
81
  |msg. | type | description |
35
82
  |:-------|:-------|:----------------------------------|
36
83
  |payload | boolean | result of `or` of all input topics.|
84
+ |count | number | number of data elements.|
37
85
 
38
86
  #### Parameters
39
87
 
40
88
  |config| type | description |
41
89
  |:-----|:-------|:----------------------------------|
42
- | | string | . |
90
+ |Topic | string | defines the topic for the output message.|
91
+ |Property| string | defines the message property to be used as payload.|
92
+ |min. Data|number|min. amount of topics to generate an output.|
43
93
 
44
94
  ### and
45
95
 
46
- .
96
+ Combines two or more boolean vales with the `and` operator.
97
+
98
+ The input values are converted as described in the `to bool` node.
47
99
 
48
100
  #### Input
49
101
 
102
+ The different inputs are differentiated by topics.
103
+
104
+ The message property to be used as payload can be defined with the `Property` property.
105
+
106
+ |msg. | type | description |
107
+ |:-------|:-------|:----------------------------------|
108
+ |topic | string | name of the input channel. |
109
+ |payload | boolean| input value for `topic`. |
110
+
50
111
  #### Output
51
112
 
113
+ |msg. | type | description |
114
+ |:-------|:-------|:----------------------------------|
115
+ |payload | boolean | result of `and` of all input topics.|
116
+ |count | number | number of data elements.|
117
+
52
118
  #### Parameters
53
119
 
120
+ |config| type | description |
121
+ |:-----|:-------|:----------------------------------|
122
+ |Topic | string | defines the topic for the output message.|
123
+ |Property| string | defines the message property to be used as payload.|
124
+ |min. Data|number|min. amount of topics to generate an output.|
125
+
126
+ ### to number
127
+
128
+ Converts payload to a number.
129
+
130
+ #### Input
131
+
132
+ The message property to be used as payload can be defined with the `Property` property.
133
+
134
+ |msg. | type | description |
135
+ |:-------|:-------|:----------------------------------|
136
+ |payload | | input value. |
137
+
138
+ #### Output
139
+
140
+ |msg. | type | description |
141
+ |:-------|:-------|:----------------------------------|
142
+ |payload | number | number value of payload.|
143
+
144
+ #### Parameters
145
+
146
+ |config| type | description |
147
+ |:-----|:-------|:----------------------------------|
148
+ |Property| string | defines the message property to be used as payload.|
149
+
150
+ ### reduce
151
+
152
+ Combines two or more streams of data (topics) into one single value.
153
+
154
+ Each stream can be debounced by arithmatic mean.
155
+
156
+ #### Input
157
+
158
+ The different inputs are differentiated by topics.
159
+
160
+ The message property to be used as payload can be defined with the `Property` property.
161
+
162
+ |msg. | type | description |
163
+ |:-------|:-------|:----------------------------------|
164
+ |topic | string | name of the input channel. |
165
+ |payload | number | input value for `topic`. |
166
+
167
+ #### Output
168
+
169
+ |msg. | type | description |
170
+ |:-------|:-------|:----------------------------------|
171
+ |payload | number | result of combining of all input topics.|
172
+ |count | number | number of data elements.|
173
+
174
+ #### Parameters
175
+
176
+ |config| type | description |
177
+ |:-----|:-------|:----------------------------------|
178
+ |Topic | string | defines the topic for the output message.|
179
+ |Property| string | defines the message property to be used as payload.|
180
+ |min. Mean|number|min. amount of values for the arithmatic mean of one topic.|
181
+ |max. Mean|number|max. amount of values for the arithmatic mean of one topic.|
182
+ |min. Data|number|min. amount of topics to generate an output.|
183
+ |Algorithm|string|algorithm to combine the values.|
184
+
185
+ #### Algorithms
186
+
54
187
  ## Example Flow
55
188
 
56
189
  [example flow](https://github.com/m-schaeffler/node-red-my-nodes/raw/main/node-red-logic/examples/logic.json)
package/counter.html CHANGED
@@ -27,6 +27,11 @@
27
27
 
28
28
  <p>A node that just count the messages.</p>
29
29
 
30
- <h3>Input</h3>
30
+ <h3>Output</h3>
31
+
32
+ <dl class="message-properties">
33
+ <dt>count <span class="property-type">number</span></dt>
34
+ <dd> number of messages.</dd>
35
+ </dl>
31
36
 
32
37
  </script>
package/counter.js CHANGED
@@ -7,20 +7,18 @@ module.exports = function(RED) {
7
7
  var context = this.context();
8
8
 
9
9
  node.on('input', function(msg,send,done) {
10
- let data = context.get( "data" ) ?? 0;
10
+ msg.count = context.get( "count" ) ?? 0;
11
11
  if( msg.reset || msg.topic==="init" )
12
12
  {
13
- data = 0;
13
+ msg.count = 0;
14
14
  }
15
15
  else
16
16
  {
17
- data++;
17
+ msg.count++;
18
18
  }
19
- context.set( "data", data );
19
+ context.set( "count", msg.count );
20
20
 
21
- msg.count = data;
22
-
23
- node.status( data );
21
+ node.status( msg.count );
24
22
  send( msg );
25
23
  done();
26
24
  });
package/logic_and.html CHANGED
@@ -4,14 +4,17 @@
4
4
  color: "#C0DEED",
5
5
  defaults: {
6
6
  name:{value:""},
7
- property:{value:"payload",required:true},
8
- minData:{value:"1",validate:RED.validators.number(),required:true}
7
+ topic:{value:""},
8
+ property:{value:"payload", required:true},
9
+ minData:{value:"1", required:true, validate:function(v){
10
+ return v!=='' && !isNaN(v) && Number(v)>0;
11
+ }}
9
12
  },
10
13
  inputs:1,
11
14
  outputs:1,
12
15
  icon: "font-awesome/fa-chevron-up",
13
16
  label: function() {
14
- return this.name||"and";
17
+ return this.name||this.topic||"and";
15
18
  },
16
19
  inputLabels: 'input',
17
20
  outputLabels: 'and',
@@ -30,6 +33,10 @@
30
33
  <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
31
34
  <input type="text" id="node-input-name" placeholder="Name">
32
35
  </div>
36
+ <div class="form-row">
37
+ <label for="node-input-topic"><i class="fa fa-envelope-o"></i> Topic</label>
38
+ <input type="text" id="node-input-topic" placeholder="Topic">
39
+ </div>
33
40
  <div class="form-row">
34
41
  <label for="node-input-input"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
35
42
  <input type="text" id="node-input-property">
@@ -43,8 +50,39 @@
43
50
 
44
51
  <script type="text/html" data-help-name="and">
45
52
 
46
- <p>.</p>
53
+ <p>.Combines two or more boolean vales with the <code>and</code> operator.</p>
54
+ <p>The input values are converted as described in the <code>to bool</code> node.</p>
47
55
 
48
56
  <h3>Input</h3>
57
+
58
+ <p>The different inputs are differentiated by topics.</p>
59
+ <p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
60
+
61
+ <dl class="message-properties">
62
+ <dt>topic <span class="property-type">string</span></dt>
63
+ <dd> name of the input channel.</dd>
64
+ <dt>payload <span class="property-type">boolean</span></dt>
65
+ <dd> input value for <code>topic</code>.</dd>
66
+ </dl>
67
+
68
+ <h3>Output</h3>
69
+
70
+ <dl class="message-properties">
71
+ <dt>payload <span class="property-type">boolean</span></dt>
72
+ <dd> result of <code>and</code> of all input topics.</dd>
73
+ <dt>count <span class="property-type">number</span></dt>
74
+ <dd> number of data elements.</dd>
75
+ </dl>
76
+
77
+ <h3>Parameter</h3>
49
78
 
79
+ <dl class="message-properties">
80
+ <dt>Topic <span class="property-type">string</span></dt>
81
+ <dd> defines the topic for the output message.</dd>
82
+ <dt>Property <span class="property-type">string</span></dt>
83
+ <dd> defines the message property to be used as payload.</dd>
84
+ <dt>min. Data <span class="property-type">number</span></dt>
85
+ <dd> min. amount of topics to generate an output.</dd>
86
+ </dl>
87
+
50
88
  </script>
package/logic_and.js CHANGED
@@ -6,35 +6,40 @@ module.exports = function(RED) {
6
6
  //this.config = config;
7
7
  var node = this;
8
8
  var context = this.context();
9
+ this.topic = config.topic;
9
10
  this.property = config.property || "payload";
10
11
  this.minData = Number( config.minData );
11
12
 
12
13
  node.on('input', function(msg,send,done) {
13
14
  const payload = tools.property2boolean( RED.util.getMessageProperty( msg, node.property ) );
14
15
 
15
- let data = context.get( "data" ) ?? {};
16
- data[msg.topic] = payload;
17
- context.set( "data", data );
18
-
19
- msg.payload = true;
20
- let count = 0;
21
- for( const item in data )
16
+ if( payload !=== null )
22
17
  {
23
- count++;
24
- if( ! data[item] )
18
+ let data = context.get( "data" ) ?? {};
19
+ data[msg.topic] = payload;
20
+ context.set( "data", data );
21
+
22
+ msg.topic = node.topic;
23
+ msg.payload = true;
24
+ msg.count = 0;
25
+ for( const item in data )
25
26
  {
26
- msg.payload = false;
27
+ msg.count++;
28
+ if( ! data[item] )
29
+ {
30
+ msg.payload = false;
31
+ }
27
32
  }
28
- }
29
33
 
30
- if( count >= node.minData )
31
- {
32
- node.status( msg.payload );
33
- send( msg );
34
- }
35
- else
36
- {
37
- node.status( "waiting for data" );
34
+ if( msg.count >= node.minData )
35
+ {
36
+ node.status( msg.payload );
37
+ send( msg );
38
+ }
39
+ else
40
+ {
41
+ node.status( "waiting for data" );
42
+ }
38
43
  }
39
44
 
40
45
  done();
package/logic_bool.html CHANGED
@@ -39,8 +39,43 @@
39
39
 
40
40
  <script type="text/html" data-help-name="tobool">
41
41
 
42
- <p>.</p>
42
+ <p>Converts payload to a bool value:</p>
43
+
44
+ <table>
45
+ <tr> <th>type</th> <th>input</th> <th>output</th> </tr>
46
+ <tr> <td>boolean</td> <td>false</td> <td>false</td> </tr>
47
+ <tr> <td></td> <td>true</td> <td>true</td> </tr>
48
+ <tr> <td>number</td> <td>0</td> <td>false</td> </tr>
49
+ <tr> <td></td> <td>1</td> <td>true</td> </tr>
50
+ <tr> <td>string</td> <td>false</td> <td>false</td> </tr>
51
+ <tr> <td></td> <td>true</td> <td>true</td> </tr>
52
+ <tr> <td></td> <td>0</td> <td>false</td> </tr>
53
+ <tr> <td></td> <td>1</td> <td>true</td> </tr>
54
+ <tr> <td></td> <td>on</td> <td>false</td> </tr>
55
+ <tr> <td></td> <td>off</td> <td>true</td> </tr>
56
+ </table>
43
57
 
44
58
  <h3>Input</h3>
59
+
60
+ <p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
61
+
62
+ <dl class="message-properties">
63
+ <dt>payload <span class="property-type"></span></dt>
64
+ <dd> input value.</dd>
65
+ </dl>
66
+
67
+ <h3>Output</h3>
68
+
69
+ <dl class="message-properties">
70
+ <dt>payload <span class="property-type">boolean</span></dt>
71
+ <dd> bool value of payload.</dd>
72
+ </dl>
73
+
74
+ <h3>Parameter</h3>
45
75
 
76
+ <dl class="message-properties">
77
+ <dt>Property <span class="property-type">string</span></dt>
78
+ <dd> defines the message property to be used as payload.</dd>
79
+ </dl>
80
+
46
81
  </script>
package/logic_bool.js CHANGED
@@ -10,8 +10,15 @@ module.exports = function(RED) {
10
10
  node.on('input', function(msg,send,done) {
11
11
  msg.payload = tools.property2boolean( RED.util.getMessageProperty( msg, node.property ) );
12
12
 
13
- node.status( msg.payload );
14
- send( msg );
13
+ if( msg.payload !== null )
14
+ {
15
+ node.status( msg.payload );
16
+ send( msg );
17
+ }
18
+ else
19
+ {
20
+ node.status( "error" );
21
+ }
15
22
  done();
16
23
  });
17
24
  }
package/logic_or.html CHANGED
@@ -4,14 +4,17 @@
4
4
  color: "#C0DEED",
5
5
  defaults: {
6
6
  name:{value:""},
7
- property:{value:"payload",required:true},
8
- minData:{value:"1",validate:RED.validators.number(),required:true}
7
+ topic:{value:""},
8
+ property:{value:"payload", required:true},
9
+ minData:{value:"1", required:true, validate:function(v){
10
+ return v!=='' && !isNaN(v) && Number(v)>0;
11
+ }}
9
12
  },
10
13
  inputs:1,
11
14
  outputs:1,
12
15
  icon: "font-awesome/fa-chevron-down",
13
16
  label: function() {
14
- return this.name||"or";
17
+ return this.name||this.topic||"or";
15
18
  },
16
19
  inputLabels: 'input',
17
20
  outputLabels: 'or',
@@ -30,6 +33,10 @@
30
33
  <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
31
34
  <input type="text" id="node-input-name" placeholder="Name">
32
35
  </div>
36
+ <div class="form-row">
37
+ <label for="node-input-topic"><i class="fa fa-envelope-o"></i> Topic</label>
38
+ <input type="text" id="node-input-topic" placeholder="Topic">
39
+ </div>
33
40
  <div class="form-row">
34
41
  <label for="node-input-input"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
35
42
  <input type="text" id="node-input-property">
@@ -43,8 +50,39 @@
43
50
 
44
51
  <script type="text/html" data-help-name="or">
45
52
 
46
- <p>.</p>
53
+ <p>Combines two or more boolean vales with the <code>or</code> operator.</p>
54
+ <p>The input values are converted as described in the <code>to bool</code> node.</p>
47
55
 
48
56
  <h3>Input</h3>
57
+
58
+ <p>The different inputs are differentiated by topics.</p>
59
+ <p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
60
+
61
+ <dl class="message-properties">
62
+ <dt>topic <span class="property-type">string</span></dt>
63
+ <dd> name of the input channel.</dd>
64
+ <dt>payload <span class="property-type">boolean</span></dt>
65
+ <dd> input value for <code>topic</code>.</dd>
66
+ </dl>
67
+
68
+ <h3>Output</h3>
69
+
70
+ <dl class="message-properties">
71
+ <dt>payload <span class="property-type">boolean</span></dt>
72
+ <dd> result of <code>or</code> of all input topics.</dd>
73
+ <dt>count <span class="property-type">number</span></dt>
74
+ <dd> number of data elements.</dd>
75
+ </dl>
76
+
77
+ <h3>Parameter</h3>
49
78
 
79
+ <dl class="message-properties">
80
+ <dt>Topic <span class="property-type">string</span></dt>
81
+ <dd> defines the topic for the output message.</dd>
82
+ <dt>Property <span class="property-type">string</span></dt>
83
+ <dd> defines the message property to be used as payload.</dd>
84
+ <dt>min. Data <span class="property-type">number</span></dt>
85
+ <dd> min. amount of topics to generate an output.</dd>
86
+ </dl>
87
+
50
88
  </script>
package/logic_or.js CHANGED
@@ -6,35 +6,40 @@ module.exports = function(RED) {
6
6
  //this.config = config;
7
7
  var node = this;
8
8
  var context = this.context();
9
+ this.topic = config.topic;
9
10
  this.property = config.property || "payload";
10
11
  this.minData = Number( config.minData );
11
12
 
12
13
  node.on('input', function(msg,send,done) {
13
14
  const payload = tools.property2boolean( RED.util.getMessageProperty( msg, node.property ) );
14
15
 
15
- let data = context.get( "data" ) ?? {};
16
- data[msg.topic] = payload;
17
- context.set( "data", data );
18
-
19
- msg.payload = false;
20
- let count = 0;
21
- for( const item in data )
16
+ if( payload !== null )
22
17
  {
23
- count++;
24
- if( data[item] )
18
+ let data = context.get( "data" ) ?? {};
19
+ data[msg.topic] = payload;
20
+ context.set( "data", data );
21
+
22
+ msg.topic = node.topic;
23
+ msg.payload = false;
24
+ msg.count = 0;
25
+ for( const item in data )
25
26
  {
26
- msg.payload = true;
27
+ msg.count++;
28
+ if( data[item] )
29
+ {
30
+ msg.payload = true;
31
+ }
27
32
  }
28
- }
29
33
 
30
- if( count >= node.minData )
31
- {
32
- node.status( msg.payload );
33
- send( msg );
34
- }
35
- else
36
- {
37
- node.status( "waiting for data" );
34
+ if( msg.count >= node.minData )
35
+ {
36
+ node.status( msg.payload );
37
+ send( msg );
38
+ }
39
+ else
40
+ {
41
+ node.status( "waiting for data" );
42
+ }
38
43
  }
39
44
 
40
45
  done();
@@ -0,0 +1,67 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('tonumber',{
3
+ category: 'function',
4
+ color: "#C0DEED",
5
+ defaults: {
6
+ name:{value:""},
7
+ property:{value:"payload",required:true}
8
+ },
9
+ inputs:1,
10
+ outputs:1,
11
+ icon: "font-awesome/fa-adjust",
12
+ label: function() {
13
+ return this.name||"to number";
14
+ },
15
+ paletteLabel: "to number",
16
+ inputLabels: 'input',
17
+ outputLabels: 'number',
18
+ oneditprepare: function() {
19
+ $("#node-input-property").typedInput({
20
+ type:"msg",
21
+ types:["msg"],
22
+ typeField: "#node-input-property-type"
23
+ })
24
+ }
25
+ });
26
+ </script>
27
+
28
+ <script type="text/html" data-template-name="tonumber">
29
+ <div class="form-row">
30
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
31
+ <input type="text" id="node-input-name" placeholder="Name">
32
+ </div>
33
+ <div class="form-row">
34
+ <label for="node-input-input"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
35
+ <input type="text" id="node-input-property">
36
+ <input type="hidden" id="node-input-property-type">
37
+ </div>
38
+ </script>
39
+
40
+ <script type="text/html" data-help-name="tonumber">
41
+
42
+ <p>Converts payload to a number.</p>
43
+
44
+ <h3>Input</h3>
45
+
46
+ <p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
47
+
48
+ <dl class="message-properties">
49
+ <dt>payload <span class="property-type"></span></dt>
50
+ <dd> input value.</dd>
51
+ </dl>
52
+
53
+ <h3>Output</h3>
54
+
55
+ <dl class="message-properties">
56
+ <dt>payload <span class="property-type">number</span></dt>
57
+ <dd> number value of payload.</dd>
58
+ </dl>
59
+
60
+ <h3>Parameter</h3>
61
+
62
+ <dl class="message-properties">
63
+ <dt>Property <span class="property-type">string</span></dt>
64
+ <dd> defines the message property to be used as payload.</dd>
65
+ </dl>
66
+
67
+ </script>
package/math_number.js ADDED
@@ -0,0 +1,26 @@
1
+ module.exports = function(RED) {
2
+
3
+ function NumberNode(config) {
4
+ RED.nodes.createNode(this,config);
5
+ //this.config = config;
6
+ var node = this;
7
+ this.property = config.property || "payload";
8
+
9
+ node.on('input', function(msg,send,done) {
10
+ msg.payload = Number( RED.util.getMessageProperty( msg, node.property ) );
11
+
12
+ if( ! isNaN( msg.payload ) )
13
+ {
14
+ node.status( msg.payload );
15
+ send( msg );
16
+ }
17
+ else
18
+ {
19
+ node.status( "not a Number" );
20
+ }
21
+ done();
22
+ });
23
+ }
24
+
25
+ RED.nodes.registerType("tonumber",NumberNode);
26
+ }
@@ -0,0 +1,138 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('reduce',{
3
+ category: 'function',
4
+ color: "#C0DEED",
5
+ defaults: {
6
+ name:{value:""},
7
+ topic:{value:""},
8
+ property:{value:"payload", required:true},
9
+ minMean:{value:"1", required:true, validate:function(v){
10
+ return v!=='' && !isNaN(v) && Number(v)>0;}
11
+ },
12
+ maxMean:{value:"1", required:true, validate:function(v){
13
+ const minMean = $("#node-input-minMean").length ? $("#node-input-minMean").val() : this.minMean;
14
+ return v!=='' && !isNaN(v) && Number(v)>=minMean;}
15
+ },
16
+ minData:{value:"1", required:true, validate:function(v){
17
+ return v!=='' && !isNaN(v) && Number(v)>0;}
18
+ },
19
+ algo:{value:"", required:true}
20
+ },
21
+ inputs:1,
22
+ outputs:1,
23
+ icon: function() {
24
+ switch( this.algo )
25
+ {
26
+ case "add": return "font-awesome/fa-plus";
27
+ case "mean": return "font-awesome/fa-indent";
28
+ case "prod": return "font-awesome/fa-asterisk";
29
+ case "min": return "font-awesome/fa-sort-numeric-desc";
30
+ case "max": return "font-awesome/fa-sort-numeric-asc";
31
+ default: return "font-awesome/fa-flask";
32
+ }
33
+ },
34
+ label: function() {
35
+ return this.name||this.topic||this.algo||"reduce";
36
+ },
37
+ inputLabels: 'input',
38
+ outputLabels: 'output',
39
+ oneditprepare: function() {
40
+ $("#node-input-property").typedInput({
41
+ type:"msg",
42
+ types:["msg"],
43
+ typeField: "#node-input-property-type"
44
+ });
45
+ $("#node-input-algo").typedInput({
46
+ types:[{
47
+ value:"algo",
48
+ options: [
49
+ { value: "add", label: "Addition"},
50
+ { value: "mean", label: "Mean Value"},
51
+ { value: "prod", label: "Product"},
52
+ { value: "min", label: "Minimum" },
53
+ { value: "max", label: "Maximum" }
54
+ ]
55
+ }]
56
+ })
57
+ }
58
+ });
59
+ </script>
60
+
61
+ <script type="text/html" data-template-name="reduce">
62
+ <div class="form-row">
63
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
64
+ <input type="text" id="node-input-name" placeholder="Name">
65
+ </div>
66
+ <div class="form-row">
67
+ <label for="node-input-topic"><i class="fa fa-envelope-o"></i> Topic</label>
68
+ <input type="text" id="node-input-topic" placeholder="Topic">
69
+ </div>
70
+ <div class="form-row">
71
+ <label for="node-input-input"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
72
+ <input type="text" id="node-input-property">
73
+ <input type="hidden" id="node-input-property-type">
74
+ </div>
75
+ <div class="form-row">
76
+ <label for="node-input-minMean"><i class="fa fa-hourglass-o"></i> min. Mean</label>
77
+ <input type="text" id="node-input-minMean">
78
+ </div>
79
+ <div class="form-row">
80
+ <label for="node-input-maxMean"><i class="fa fa-hourglass"></i> max. Mean</label>
81
+ <input type="text" id="node-input-maxMean">
82
+ </div>
83
+ <div class="form-row">
84
+ <label for="node-input-minData"><i class="fa fa-check-square-o "></i> min. Data</label>
85
+ <input type="text" id="node-input-minData">
86
+ </div>
87
+ <div class="form-row">
88
+ <label for="node-input-algo"><i class="fa fa-flask"></i> Algorithm</label>
89
+ <input type="text" id="node-input-algo">
90
+ </div>
91
+ </script>
92
+
93
+ <script type="text/html" data-help-name="reduce">
94
+
95
+ <p>Combines two or more streams of data (topics) into one single value.</p>
96
+ <p>Each stream can be debounced by arithmatic mean.</p>
97
+
98
+ <h3>Input</h3>
99
+
100
+ <p>The different inputs are differentiated by topics.</p>
101
+ <p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
102
+
103
+ <dl class="message-properties">
104
+ <dt>topic <span class="property-type">string</span></dt>
105
+ <dd> name of the input channel.</dd>
106
+ <dt>payload <span class="property-type">number</span></dt>
107
+ <dd> input value for <code>topic</code>.</dd>
108
+ </dl>
109
+
110
+ <h3>Output</h3>
111
+
112
+ <dl class="message-properties">
113
+ <dt>payload <span class="property-type">number</span></dt>
114
+ <dd> result of combining of all input topics.</dd>
115
+ <dt>count <span class="property-type">number</span></dt>
116
+ <dd> number of data elements.</dd>
117
+ </dl>
118
+
119
+ <h3>Parameter</h3>
120
+
121
+ <dl class="message-properties">
122
+ <dt>Topic <span class="property-type">string</span></dt>
123
+ <dd> defines the topic for the output message.</dd>
124
+ <dt>Property <span class="property-type">string</span></dt>
125
+ <dd> defines the message property to be used as payload.</dd>
126
+ <dt>min. Mean <span class="property-type">number</span></dt>
127
+ <dd> min. amount of values for the arithmatic mean of one topic.</dd>
128
+ <dt>max. Mean <span class="property-type">number</span></dt>
129
+ <dd> max. amount of values for the arithmatic mean of one topic.</dd>
130
+ <dt>min. Data <span class="property-type">number</span></dt>
131
+ <dd> min. amount of topics to generate an output.</dd>
132
+ <dt>Algorithm <span class="property-type">string</span></dt>
133
+ <dd> algorithm to combine the values.</dd>
134
+ </dl>
135
+
136
+ <h3>Algorithms</h3>
137
+
138
+ </script>
package/math_reduce.js ADDED
@@ -0,0 +1,88 @@
1
+ module.exports = function(RED) {
2
+
3
+ function ReduceNode(config) {
4
+ RED.nodes.createNode(this,config);
5
+ //this.config = config;
6
+ var node = this;
7
+ var context = this.context();
8
+ this.topic = config.topic;
9
+ this.property = config.property || "payload";
10
+ this.minMean = Number( config.minMean );
11
+ this.maxMean = Number( config.maxMean );
12
+ this.minData = Number( config.minData );
13
+ this.algo = config.algo;
14
+
15
+ node.on('input', function(msg,send,done) {
16
+ if( msg.reset || msg.topic==="init" )
17
+ {
18
+ context.set( "data", {} );
19
+ node.status( "" );
20
+ }
21
+ else
22
+ {
23
+ const payload = Number( RED.util.getMessageProperty( msg, node.property ) );
24
+ if( ! isNaN( payload ) )
25
+ {
26
+ let data = context.get( "data" ) ?? {};
27
+ let item = data[msg.topic] ?? [];
28
+ item.push( payload )
29
+ data[msg.topic] = item;
30
+
31
+ msg.topic = node.topic;
32
+ msg.count = 0;
33
+ switch( node.algo )
34
+ {
35
+ case "add":
36
+ case "mean": msg.payload = 0; break;
37
+ case "prod": msg.payload = 1; break;
38
+ case "min": msg.payload = Number.MAX_SAFE_INTEGER; break;
39
+ case "max": msg.payload = Number.MIN_SAFE_INTEGER; break;
40
+ default: done( "invalid algo: "+node.algo ); return;
41
+ }
42
+ for( const key in data )
43
+ {
44
+ if( data[key].length >= node.minMean )
45
+ {
46
+ msg.count++;
47
+ while( data[key].length > node.maxMean )
48
+ {
49
+ data[key].shift();
50
+ }
51
+ const help = data[key].reduce( (accumulator,value)=>accumulator+value ) / data[key].length;
52
+ switch( node.algo )
53
+ {
54
+ case "add":
55
+ case "mean": msg.payload += help; break;
56
+ case "prod": msg.payload *= help; break;
57
+ case "min": msg.payload = Math.min( msg.payload, help ); break;
58
+ case "max": msg.payload = Math.max( msg.payload, help ); break;
59
+ }
60
+ }
61
+ }
62
+ context.set( "data", data );
63
+
64
+ if( msg.count >= node.minData )
65
+ {
66
+ switch( node.algo )
67
+ {
68
+ case "mean": msg.payload /= msg.count; break;
69
+ }
70
+ node.status({fill:"green",shape:"dot",text:msg.payload});
71
+ send( msg );
72
+ }
73
+ else
74
+ {
75
+ node.status({fill:"gray",shape:"dot",text:"to less data"});
76
+ }
77
+ }
78
+ else
79
+ {
80
+ node.status({fill:"red",shape:"dot",text:"payload is NaN"});
81
+ }
82
+ }
83
+ done();
84
+ });
85
+ }
86
+
87
+ RED.nodes.registerType("reduce",ReduceNode);
88
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mschaeffler/node-red-logic",
3
- "version": "0.0.6",
3
+ "version": "0.2.0",
4
4
  "description": "nodes for simple mathematical operations.",
5
5
  "license": "LGPL-2.1",
6
6
  "homepage": "https://github.com/m-schaeffler/node-red-my-nodes/tree/main/node-red-logic",
@@ -17,11 +17,12 @@
17
17
  "node-red": {
18
18
  "version": ">=1.3.7",
19
19
  "nodes": {
20
+ "counter":"counter.js",
21
+ "tobool":"logic_bool.js",
22
+ "tonumber":"math_number.js",
20
23
  "or":"logic_or.js",
21
24
  "and":"logic_and.js",
22
- "tobool":"logic_bool.js",
23
- "counter":"counter.js",
24
- "plus":"math_plus.js"
25
+ "reduce":"math_reduce.js"
25
26
  }
26
27
  },
27
28
  "author": {
package/math_plus.html DELETED
@@ -1,50 +0,0 @@
1
- <script type="text/javascript">
2
- RED.nodes.registerType('plus',{
3
- category: 'function',
4
- color: "#C0DEED",
5
- defaults: {
6
- name:{value:""},
7
- property:{value:"payload",required:true},
8
- minData:{value:"1",validate:RED.validators.number(),required:true}
9
- },
10
- inputs:1,
11
- outputs:1,
12
- icon: "font-awesome/fa-plus",
13
- label: function() {
14
- return this.name||"plus";
15
- },
16
- inputLabels: 'input',
17
- outputLabels: 'plus',
18
- oneditprepare: function() {
19
- $("#node-input-property").typedInput({
20
- type:"msg",
21
- types:["msg"],
22
- typeField: "#node-input-property-type"
23
- })
24
- }
25
- });
26
- </script>
27
-
28
- <script type="text/html" data-template-name="plus">
29
- <div class="form-row">
30
- <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
31
- <input type="text" id="node-input-name" placeholder="Name">
32
- </div>
33
- <div class="form-row">
34
- <label for="node-input-input"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
35
- <input type="text" id="node-input-property">
36
- <input type="hidden" id="node-input-property-type">
37
- </div>
38
- <div class="form-row">
39
- <label for="node-input-minData"><i class="fa fa-tag"></i> min. Data</label>
40
- <input type="text" id="node-input-minData">
41
- </div>
42
- </script>
43
-
44
- <script type="text/html" data-help-name="plus">
45
-
46
- <p>.</p>
47
-
48
- <h3>Input</h3>
49
-
50
- </script>
package/math_plus.js DELETED
@@ -1,41 +0,0 @@
1
- module.exports = function(RED) {
2
-
3
- function PlusNode(config) {
4
- RED.nodes.createNode(this,config);
5
- //this.config = config;
6
- var node = this;
7
- var context = this.context();
8
- this.property = config.property || "payload";
9
- this.minData = Number( config.minData );
10
-
11
- node.on('input', function(msg,send,done) {
12
- const payload = Number( RED.util.getMessageProperty( msg, node.property ) );
13
-
14
- let data = context.get( "data" ) ?? {};
15
- data[msg.topic] = payload;
16
- context.set( "data", data );
17
-
18
- msg.payload = 0;
19
- let count = 0;
20
- for( const item in data )
21
- {
22
- count++;
23
- msg.payload += data[item];
24
- }
25
-
26
- if( count >= node.minData )
27
- {
28
- node.status( msg.payload );
29
- send( msg );
30
- }
31
- else
32
- {
33
- node.status( "waiting for data" );
34
- }
35
-
36
- done();
37
- });
38
- }
39
-
40
- RED.nodes.registerType("plus",PlusNode);
41
- }