@mschaeffler/node-red-logic 4.1.0 → 4.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/logic_and.js CHANGED
@@ -7,7 +7,7 @@ module.exports = function(RED) {
7
7
  var node = this;
8
8
  var context = this.context();
9
9
  this.topic = config.topic ?? "";
10
- this.property = config.property || "payload";
10
+ this.property = config.property ?? "payload";
11
11
  this.minData = Number( config.minData ?? 1 );
12
12
  this.filter = Boolean( config.filter );
13
13
  this.last = null;
package/logic_blinker.js CHANGED
@@ -5,7 +5,7 @@ module.exports = function(RED) {
5
5
  RED.nodes.createNode(this,config);
6
6
  //this.config = config;
7
7
  var node = this;
8
- this.property = config.property || "payload";
8
+ this.property = config.property ?? "payload";
9
9
  this.onTime = Number( config.onTime ?? 1 ) * tools.timeUnits( config.onTimeUnit );
10
10
  this.offTime = Number( config.offTime ?? 1 ) * tools.timeUnits( config.offTimeUnit );
11
11
  this.firstType = config.outputFirstType ?? "bool";
package/logic_bool.js CHANGED
@@ -6,7 +6,7 @@ module.exports = function(RED) {
6
6
  //this.config = config;
7
7
  var node = this;
8
8
  this.topic = config.topic ?? "";
9
- this.property = config.property || "payload";
9
+ this.property = config.property ?? "payload";
10
10
  this.showState = Boolean( config.showState );
11
11
  this.filter = Boolean( config.filter );
12
12
  this.last = null;
package/logic_not.js CHANGED
@@ -5,7 +5,7 @@ module.exports = function(RED) {
5
5
  RED.nodes.createNode(this,config);
6
6
  //this.config = config;
7
7
  var node = this;
8
- this.property = config.property || "payload";
8
+ this.property = config.property ?? "payload";
9
9
  this.showState = Boolean( config.showState );
10
10
  this.filter = Boolean( config.filter );
11
11
  this.last = null;
package/logic_or.js CHANGED
@@ -7,7 +7,7 @@ module.exports = function(RED) {
7
7
  var node = this;
8
8
  var context = this.context();
9
9
  this.topic = config.topic ?? "";
10
- this.property = config.property || "payload";
10
+ this.property = config.property ?? "payload";
11
11
  this.minData = Number( config.minData ?? 1 );
12
12
  this.filter = Boolean( config.filter );
13
13
  this.last = null;
@@ -5,7 +5,7 @@ module.exports = function(RED) {
5
5
  RED.nodes.createNode(this,config);
6
6
  //this.config = config;
7
7
  var node = this;
8
- this.property = config.property || "payload";
8
+ this.property = config.property ?? "payload";
9
9
  this.delay = Number( config.delay ?? 0 ) * tools.timeUnits( config.delayUnit );
10
10
  this.postrun = Number( config.postrun ?? 0 ) * tools.timeUnits( config.postrunUnit );
11
11
  this.minOn = Number( config.minOn ?? 0 ) * tools.timeUnits( config.minOnUnit );
package/math_3point.js CHANGED
@@ -8,7 +8,7 @@ module.exports = function(RED) {
8
8
  //this.config = config;
9
9
  var node = this;
10
10
  var context = this.context();
11
- this.topic = config.topic || "";
11
+ this.topic = config.topic ?? "";
12
12
  this.property = config.property ?? "payload";
13
13
  this.propertyType = config.propertyType ?? "msg";
14
14
  this.thresholdUpRise = Number( config.thresholdUpRise );
package/math_falling.js CHANGED
@@ -6,7 +6,7 @@ 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
+ this.topic = config.topic ?? "";
10
10
  this.property = config.property ?? "payload";
11
11
  this.propertyType = config.propertyType ?? "msg";
12
12
  this.threshold = Number( config.threshold );
@@ -6,7 +6,7 @@ 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
+ this.topic = config.topic ?? "";
10
10
  this.property = config.property ?? "payload";
11
11
  this.propertyType = config.propertyType ?? "msg";
12
12
  this.threshold_rise = Number( config.threshold_raise );
@@ -0,0 +1,194 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('kalman',{
3
+ category: 'logic',
4
+ color: "#C0DEED",
5
+ defaults: {
6
+ name:{value:""},
7
+ topic:{value:""},
8
+ property:{value:"payload", required:true},
9
+ propertyType:{value:"msg"},
10
+ control:{value:0, required:true},
11
+ controlType:{value:"num"},
12
+ processNoise:{value:1, validate:RED.validators.number(), required:true },
13
+ measurementNoise:{value:1, validate:RED.validators.number(), required:true },
14
+ stateVector:{value:1, validate:RED.validators.number(), required:true },
15
+ controlVector:{value:0, validate:RED.validators.number(), required:true },
16
+ measurementVector:{value:1, validate:RED.validators.number(), required:true },
17
+ adaptionCount:{value:0, validate:RED.validators.number(), required:true },
18
+ contextStore:{value:"none",required:true},
19
+ filter:{value:0, validate:RED.validators.number()},
20
+ filterUnit:{value:"secs"},
21
+ filterVal:{value:0, validate:RED.validators.number()},
22
+ filterMul:{value:10, validate:RED.validators.number()},
23
+ zeroIsZero:{value:false},
24
+ decimals:{validate:RED.validators.number()},
25
+ showState:{value:false}
26
+ },
27
+ inputs:1,
28
+ outputs:1,
29
+ icon:"font-awesome/fa-area-chart",
30
+ label: function() {
31
+ return this.name||this.topic||"kalman";
32
+ },
33
+ labelStyle: function() {
34
+ return this.name?"node_label_italic":"";
35
+ },
36
+ inputLabels: 'input',
37
+ outputLabels: 'output',
38
+ oneditprepare: function() {
39
+ const node = this;
40
+ $("#node-input-property").typedInput({
41
+ type:"msg",
42
+ types:["msg","jsonata"],
43
+ typeField: "#node-input-propertyType"
44
+ });
45
+ $("#node-input-control").typedInput({
46
+ type:"num",
47
+ types:["msg","num"],
48
+ typeField: "#node-input-controlType"
49
+ });
50
+ // populate store names
51
+ $("#node-input-contextStore").empty();
52
+ const defaultStore = RED.settings.hasOwnProperty("context") ? RED.settings.context.default : '';
53
+ RED.settings.context.stores.forEach(function(item){
54
+ if( item ) {
55
+ const opt = $(`<option value="${item}">${item}${item===defaultStore?" (default)":""}</option>`);
56
+ $("#node-input-contextStore").append(opt);
57
+ }
58
+ });
59
+ const currentStore = node.contextStore || '';
60
+ // select the current option
61
+ $("#node-input-contextStore").val(currentStore);
62
+ }
63
+ });
64
+ </script>
65
+
66
+ <script type="text/html" data-template-name="kalman">
67
+ <div class="form-row">
68
+ <label for="node-input-name"><i class="fa fa-tag"></i> name</label>
69
+ <input type="text" id="node-input-name" placeholder="Name">
70
+ </div>
71
+ <div class="form-row">
72
+ <label for="node-input-topic"><i class="fa fa-envelope-o"></i> topic</label>
73
+ <input type="text" id="node-input-topic" placeholder="Topic">
74
+ </div>
75
+ <div class="form-row">
76
+ <label for="node-input-property"> measured value</label>
77
+ <input type="text" id="node-input-property">
78
+ <input type="hidden" id="node-input-propertyType">
79
+ </div>
80
+ <div class="form-row">
81
+ <label for="node-input-control"> control value</label>
82
+ <input type="text" id="node-input-control">
83
+ <input type="hidden" id="node-input-controlType">
84
+ </div>
85
+
86
+ <div class="form-row">
87
+ <label for="node-input-processNoise"> process noise</label>
88
+ <input type="text" id="node-input-processNoise">
89
+ </div>
90
+ <div class="form-row">
91
+ <label for="node-input-measurementNoise"> measure noise</label>
92
+ <input type="text" id="node-input-measurementNoise">
93
+ </div>
94
+ <div class="form-row">
95
+ <label for="node-input-stateVector"> process factor</label>
96
+ <input type="text" id="node-input-stateVector">
97
+ </div>
98
+ <div class="form-row">
99
+ <label for="node-input-controlVector"> control factor</label>
100
+ <input type="text" id="node-input-controlVector">
101
+ </div>
102
+ <div class="form-row">
103
+ <label for="node-input-measurementVector"> measur. factor</label>
104
+ <input type="text" id="node-input-measurementVector">
105
+ </div>
106
+ <div class="form-row">
107
+ <label for="node-input-adaptionCount"> adaption counts</label>
108
+ <input type="number" id="node-input-adaptionCount">
109
+ </div>
110
+ <div class="form-row">
111
+ <label for="node-input-contextStore"><i class="fa fa-database"></i> context store</label>
112
+ <select type="text" id="node-input-contextStore"></select>
113
+ </div>
114
+
115
+ <div class="form-row">
116
+ <label for="node-input-filter"><i class="fa fa-filter"></i> filter time</label>
117
+ <input type="number" id="node-input-filter" style="width:70px;" placeholder="Time">
118
+ <select id="node-input-filterUnit" style="width:140px;">
119
+ <option value="msecs">MilliSeconds</option>
120
+ <option value="secs">Seconds</option>
121
+ <option value="mins">Minutes</option>
122
+ <option value="hours">Hours</option>
123
+ </select>
124
+ </div>
125
+ <div class="form-row">
126
+ <label for="node-input-filterVal"><i class="fa fa-filter"></i> filter value</label>
127
+ <input type="text" id="node-input-filterVal">
128
+ </div>
129
+ <div class="form-row">
130
+ <label for="node-input-filterMul"><i class="fa fa-filter"></i> filter repetition</label>
131
+ <input type="text" id="node-input-filterMul">
132
+ </div>
133
+ <div class="form-row">
134
+ <label for="node-input-decimals"><i class="fa fa-sort-numeric-asc"></i> decimals</label>
135
+ <input type="number" id="node-input-decimals">
136
+ </div>
137
+ <div class="form-row">
138
+ <label for="node-input-zeroIsZero"><i class="fa fa-exclamation-circle"></i> null is null</label>
139
+ <input type="checkbox" id="node-input-zeroIsZero" style="display:inline-block; width:20px; vertical-align:baseline;">
140
+ </div>
141
+ <div class="form-row">
142
+ <label for="node-input-showStatus"><i class="fa fa-star-o"></i> status</label>
143
+ <input type="checkbox" id="node-input-showState" style="display:inline-block; width:20px; vertical-align:baseline;">
144
+ </div>
145
+ </script>
146
+
147
+ <script type="text/html" data-help-name="kalman">
148
+
149
+ <p>Filter the values of one or more data streams wuth an adaptive Kalman filter.</p>
150
+ <p>If the msg property <code>invalid</code> is present in the message, all nodes ignore the message.</p>
151
+
152
+ <h3>Input</h3>
153
+
154
+ <p>The different inputs are differentiated by topics.</p>
155
+ <p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
156
+
157
+ <dl class="message-properties">
158
+ <dt>topic <span class="property-type">string</span></dt>
159
+ <dd> name of the input channel.</dd>
160
+ <dt>payload <span class="property-type">number</span></dt>
161
+ <dd> input value for <code>topic</code>.</dd>
162
+ <dt>control <span class="property-type">number</span></dt>
163
+ <dd> control value, THe message property can be selected with the <code>Control</code> property.</dd>
164
+ </dl>
165
+
166
+ <h3>Output</h3>
167
+
168
+ <dl class="message-properties">
169
+ <dt>payload <span class="property-type">number</span></dt>
170
+ <dd> filtered value.</dd>
171
+ </dl>
172
+
173
+ <h3>Parameter</h3>
174
+
175
+ <dl class="message-properties">
176
+ <dt>Topic <span class="property-type">string</span></dt>
177
+ <dd> defines the topic for the output message, "" is <code>msg.topic</code>.</dd>
178
+ <dt>Property <span class="property-type">string</span></dt>
179
+ <dd> defines the message property to be used as payload.</dd>
180
+
181
+ <dt>Filterzeit <span class="property-type">number</span></dt>
182
+ <dd> send output only after this time.</dd>
183
+ <dt>Filter Wert <span class="property-type">number</span></dt>
184
+ <dd> send output only if change is bigger.</dd>
185
+ <dt>Filter Wiederholungsfaktor <span class="property-type">number</span></dt>
186
+ <dd> do send output if change is lower then <code>Filter Wert</code> after n times <code>Filterzeit</code>.</dd>
187
+ <dt>Nachkommastellen <span class="property-type">number</span></dt>
188
+ <dd> Anzahl an Nachkommastellen..</dd>
189
+ <dt>Null ist Null <span class="property-type">boolean</span></dt>
190
+ <dd> If 0 is received, 0 is send immediately.</dd>
191
+ <dt>Status <span class="property-type">boolean</span></dt>
192
+ <dd> shows the actual value as a node status.</dd>
193
+ </dl>
194
+ </script>
package/math_kalman.js ADDED
@@ -0,0 +1,223 @@
1
+ module.exports = function(RED) {
2
+ var tools = require('./tools.js');
3
+
4
+ function KalmanNode(config) {
5
+ RED.nodes.createNode(this,config);
6
+ //this.config = config;
7
+ var node = this;
8
+ var context = this.context();
9
+ this.topic = config.topic ?? "";
10
+ this.property = config.property ?? "payload";
11
+ this.propertyType = config.propertyType ?? "msg";
12
+ this.control = config.control ?? 0;
13
+ this.controlType = config.controlType ?? "num";
14
+ this.processNoise = Number( config.processNoise ?? 1 );
15
+ this.measurementNoise = Number( config.measurementNoise ?? 1 );
16
+ this.stateVector = Number( config.stateVector ?? 1 );
17
+ this.controlVector = Number( config.controlVector ?? 0 );
18
+ this.measurementVector = Number( config.measurementVector ?? 1 );
19
+ this.adaptionCount = Number( config.adaptionCount ?? 0 );
20
+ this.contextStore = config.contextStore ?? "";
21
+ this.filterTime = Number( config.filter ?? 0 ) * tools.timeUnits( config.filterUnit );
22
+ this.filterValue = Number( config.filterVal ?? 0 );
23
+ this.filterLongTime = this.filterTime * Number( config.filterMul ?? 10 );
24
+ this.zeroIsZero = Boolean( config.zeroIsZero );
25
+ this.round = config.decimals ? Math.pow( 10, Number( config.decimals ) ) : null;
26
+ this.showState = Boolean( config.showState );
27
+ this.data = {};
28
+ this.last = {};
29
+ this.adaptation = {};
30
+ if( this.propertyType === "jsonata" )
31
+ {
32
+ try {
33
+ this.propertyPrepared = RED.util.prepareJSONataExpression( this.property, this );
34
+ }
35
+ catch (e) {
36
+ node.error(RED._("debug.invalid-exp", {error: this.property}));
37
+ return;
38
+ }
39
+ }
40
+ node.status( "" );
41
+ context.get( "data", node.contextStore, function(err,value)
42
+ {
43
+ if( err )
44
+ {
45
+ node.error( err );
46
+ }
47
+ else
48
+ {
49
+ //console.log( "context read", value );
50
+ if( value !== undefined )
51
+ {
52
+ const now = Date.now();
53
+ for( const i in value )
54
+ {
55
+ value[i].time = now;
56
+ value[i].processNoise = node.processNoise;
57
+ }
58
+ node.data = value;
59
+ }
60
+ }
61
+ } );
62
+
63
+ function setStatus(color,text)
64
+ {
65
+ if( node.showState )
66
+ {
67
+ node.status({ fill:color, shape:"dot", text:text });
68
+ }
69
+ }
70
+
71
+ node.on('input', function(msg,send,done) {
72
+ if( msg.invalid )
73
+ {
74
+ done();
75
+ }
76
+ else if( msg.reset || msg.topic==="init" )
77
+ {
78
+ node.data = {};
79
+ node.last = {};
80
+ node.adaptation = {};
81
+ context.set( "data", node.data, node.contextStore );
82
+ node.status( "" );
83
+ done();
84
+ }
85
+ else
86
+ {
87
+ function getPayload(callback)
88
+ {
89
+ if( node.propertyPrepared )
90
+ {
91
+ RED.util.evaluateJSONataExpression( node.propertyPrepared, msg, function(err, value)
92
+ {
93
+ if( err )
94
+ {
95
+ done( err.message );
96
+ }
97
+ else
98
+ {
99
+ callback( value );
100
+ }
101
+ } );
102
+ }
103
+ else
104
+ {
105
+ callback( RED.util.getMessageProperty( msg, node.property ) );
106
+ }
107
+ }
108
+ getPayload( function(value)
109
+ {
110
+ if( node.topic )
111
+ {
112
+ msg.topic = node.topic;
113
+ }
114
+ const payload = Number( value );
115
+ if( ! isNaN( payload ) )
116
+ {
117
+ const control = RED.util.evaluateNodeProperty( node.control, node.controlType, node, msg );
118
+ if( ! isNaN( control ) )
119
+ {
120
+ node.data[msg.topic] ??= {};
121
+ const data = node.data[msg.topic];
122
+ const now = Date.now();
123
+
124
+ function kalmanFilter(measurement,control)
125
+ {
126
+ if( data.estimate === undefined )
127
+ {
128
+ data.processNoise = node.processNoise;
129
+ data.estimate = measurement / node.measurementVector;
130
+ data.covariance = node.measurementNoise / node.measurementVector**2;
131
+ }
132
+ else
133
+ {
134
+ // measurement time
135
+ const deltaTime = ( now - data.time ) / 1000;
136
+ const stateVector = 1 + ( node.stateVector - 1 ) * deltaTime;
137
+ const controlVector = node.controlVector * deltaTime;
138
+ // prediction
139
+ const predX = stateVector * data.estimate + controlVector * control;
140
+ const predCov = stateVector**2 * data.covariance + node.processNoise;
141
+ // innovation
142
+ const innovation = measurement - node.measurementVector * predX;
143
+ // adaptation
144
+ if( node.adaptionCount )
145
+ {
146
+ const adaptation = node.adaptation[msg.topic] ?? [];
147
+ adaptation.push( innovation );
148
+ if( adaptation.length > node.adaptionCount )
149
+ {
150
+ adaptation.shift();
151
+ const mean = adaptation.reduce( (a,b) => a + b ) / adaptation.length;
152
+ const variance = adaptation.reduce( (a,b) => a + ( b - mean ) ** 2, 0 ) / ( adaptation.length - 1 );
153
+ data.r = Math.max( variance, 1e-6 );
154
+ data.r2 = ( 2 * variance + node.processNoise ) / 3;
155
+ }
156
+ node.adaptation[msg.topic] = adaptation;
157
+ }
158
+ // kalman gain
159
+ const gain = predCov * node.measurementVector / ( predCov * node.measurementVector**2 + node.measurementNoise );
160
+ // correction
161
+ data.estimate = predX + gain * innovation;
162
+ data.covariance = ( 1 - gain * node.measurementVector ) * predCov;
163
+ }
164
+ data.time = now;
165
+ return data.estimate;
166
+ }
167
+
168
+ function sendValue(value)
169
+ {
170
+ msg.payload = value;
171
+ node.last[msg.topic] = {value:value,time:now};
172
+ setStatus( "green", tools.formatNumber(value) );
173
+ send( msg );
174
+ }
175
+
176
+ if( node.zeroIsZero && payload === 0 )
177
+ {
178
+ data.estimate = 0;
179
+ sendValue( 0 );
180
+ }
181
+ else
182
+ {
183
+ let value = kalmanFilter( payload, control );
184
+ const help = node.last[msg.topic];
185
+ if( help === undefined ||
186
+ ( help.time + node.filterTime < now && tools.distance( help.value, value ) >= node.filterValue ) ||
187
+ ( node.filterLongTime > 0 && help.time + node.filterLongTime < now ) )
188
+ {
189
+ if( node.round )
190
+ {
191
+ value = Math.round( value * node.round ) / node.round;
192
+ }
193
+ sendValue( value );
194
+ }
195
+ else
196
+ {
197
+ setStatus( "gray", tools.formatNumber(value) );
198
+ }
199
+ }
200
+ context.set( "data", node.data, node.contextStore );
201
+ }
202
+ else
203
+ {
204
+ setStatus( "red", "control is NaN" );
205
+ node.warn( `control is NaN (${msg.topic}=${control})` );
206
+ }
207
+ }
208
+ else
209
+ {
210
+ if( value !== undefined )
211
+ {
212
+ setStatus( "red", "payload is NaN" );
213
+ node.warn( `payload is NaN (${msg.topic}=${value})` );
214
+ }
215
+ }
216
+ done();
217
+ } );
218
+ }
219
+ });
220
+ }
221
+
222
+ RED.nodes.registerType("kalman",KalmanNode);
223
+ }
package/math_mean.html CHANGED
@@ -61,7 +61,7 @@
61
61
  <input type="text" id="node-input-topic" placeholder="Topic">
62
62
  </div>
63
63
  <div class="form-row">
64
- <label for="node-input-input"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
64
+ <label for="node-input-property"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
65
65
  <input type="text" id="node-input-property">
66
66
  <input type="hidden" id="node-input-propertyType">
67
67
  </div>
@@ -154,7 +154,7 @@
154
154
  <dd> do send output if change is lower then <code>Filter Wert</code> after n times <code>Filterzeit</code>.</dd>
155
155
  <dt>Nachkommastellen <span class="property-type">number</span></dt>
156
156
  <dd> Anzahl an Nachkommastellen..</dd>
157
- <dt>Null ist NUll <span class="property-type">boolean</span></dt>
157
+ <dt>Null ist Null <span class="property-type">boolean</span></dt>
158
158
  <dd> If 0 is received, 0 is send immediately.</dd>
159
159
  <dt>Status <span class="property-type">boolean</span></dt>
160
160
  <dd> shows the actual value as a node status.</dd>
package/math_mean.js CHANGED
@@ -6,8 +6,8 @@ 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 || "";
10
- this.property = config.property || "payload";
9
+ this.topic = config.topic ?? "";
10
+ this.property = config.property ?? "payload";
11
11
  this.propertyType = config.propertyType ?? "msg";
12
12
  this.deltaTime = Number( config.deltaTime ?? 60 ) * tools.timeUnits( config.deltaUnit );
13
13
  this.minData = Number( config.minData ?? 1 );
@@ -75,6 +75,10 @@ module.exports = function(RED) {
75
75
  }
76
76
  getPayload( function(value)
77
77
  {
78
+ if( node.topic )
79
+ {
80
+ msg.topic = node.topic;
81
+ }
78
82
  const payload = Number( value );
79
83
  if( ! isNaN( payload ) )
80
84
  {
@@ -95,10 +99,6 @@ module.exports = function(RED) {
95
99
  msg.count = count;
96
100
  last[msg.topic] = {value:value,time:now};
97
101
  context.set( "last", last );
98
- if( node.topic )
99
- {
100
- msg.topic = node.topic;
101
- }
102
102
  node.status({fill:"green",shape:"dot",text:`${item.length} / ${tools.formatNumber(value)}`});
103
103
  send( msg );
104
104
  }
package/math_reduce.js CHANGED
@@ -7,7 +7,7 @@ module.exports = function(RED) {
7
7
  var node = this;
8
8
  var context = this.context();
9
9
  this.topic = config.topic ?? "";
10
- this.property = config.property || "payload";
10
+ this.property = config.property ?? "payload";
11
11
  this.propertyType = config.propertyType ?? "msg";
12
12
  this.minMean = Number( config.minMean ?? 1 );
13
13
  this.maxMean = Number( config.maxMean ?? 1 );
package/math_rising.js CHANGED
@@ -6,7 +6,7 @@ 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
+ this.topic = config.topic ?? "";
10
10
  this.property = config.property ?? "payload";
11
11
  this.propertyType = config.propertyType ?? "msg";
12
12
  this.threshold = Number( config.threshold );
@@ -40,7 +40,6 @@
40
40
  });
41
41
  // populate store names
42
42
  $("#node-input-contextStore").empty();
43
- $("#node-input-contextStore").append(`<option value="none">None</option>`);
44
43
  const defaultStore = RED.settings.hasOwnProperty('context') ? RED.settings.context.default : ''
45
44
  RED.settings.context.stores.forEach(function(item){
46
45
  if( item ) {
@@ -6,11 +6,11 @@ module.exports = function(RED) {
6
6
  //this.config = config;
7
7
  var node = this;
8
8
  var context = this.context();
9
- this.property = config.property || "payload";
9
+ this.property = config.property ?? "payload";
10
10
  this.propertyType = config.propertyType ?? "msg";
11
11
  this.deltaTime = Number( config.deltaTime ?? 60 ) * tools.timeUnits( config.deltaUnit );
12
12
  this.minData = Number( config.minData ?? 1 );
13
- this.contextStore = config.contextStore ?? "none";
13
+ this.contextStore = config.contextStore ?? "";
14
14
  this.showState = Boolean( config.showState );
15
15
  if( this.propertyType === "jsonata" )
16
16
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mschaeffler/node-red-logic",
3
- "version": "4.1.0",
3
+ "version": "4.2.0",
4
4
  "description": "nodes for simple operations.",
5
5
  "license": "LGPL-2.1",
6
6
  "homepage": "https://github.com/m-schaeffler/node-red-my-nodes/tree/main/node-red-logic",
@@ -32,7 +32,8 @@
32
32
  "hysteresisEdge": "math_hysteresis.js",
33
33
  "threePoint": "math_3point.js",
34
34
  "statistics": "math_statistics.js",
35
- "mean": "math_mean.js"
35
+ "mean": "math_mean.js",
36
+ "kalman": "math_kalman.js"
36
37
  }
37
38
  },
38
39
  "author": {
@@ -40,6 +41,6 @@
40
41
  "url": "https://github.com/m-schaeffler"
41
42
  },
42
43
  "scripts": {
43
- "test": "mocha \"test/*_spec.js\""
44
+ "test": "mocha \"test/math_kalman_spec.js\""
44
45
  }
45
46
  }
@@ -1,159 +0,0 @@
1
- <script type="text/javascript">
2
- RED.nodes.registerType('blinker',{
3
- category: 'logic',
4
- color: "#C0DEED",
5
- defaults: {
6
- name:{value:""},
7
- property:{value:"payload",required:true},
8
- onTime:{value:"1",required:true},
9
- onTimeUnit:{value:"secs"},
10
- offTime:{value:"1",required:true},
11
- offTimeUnit:{value:"secs"},
12
- outputOn:{value:true,required:true},
13
- outputOnType:{value:"bool"},
14
- outputPause:{value:false,required:true},
15
- outputPauseType:{value:"bool"},
16
- outputOff:{value:false,required:true},
17
- outputOffType:{value:"bool"},
18
- showState:{value:false}
19
- },
20
- inputs:1,
21
- outputs:1,
22
- icon: "font-awesome/fa-refresh",
23
- label: function() {
24
- return this.name||"blinker";
25
- },
26
- labelStyle: function() {
27
- return this.name?"node_label_italic":"";
28
- },
29
- paletteLabel: "blinker",
30
- inputLabels: 'input',
31
- outputLabels: 'blinken',
32
- oneditprepare: function() {
33
- $("#node-input-property").typedInput({
34
- type:"msg",
35
- types:["msg"],
36
- typeField: "#node-input-property-type"
37
- })
38
- $("#node-input-outputOn").typedInput({
39
- type:"bool",
40
- types:["str","num","bool","json"],
41
- typeField: "#node-input-outputOnType"
42
- })
43
- $("#node-input-outputOff").typedInput({
44
- type:"bool",
45
- types:["str","num","bool","json"],
46
- typeField: "#node-input-outputOffType"
47
- })
48
- }
49
- });
50
- </script>7
51
-
52
- <script type="text/html" data-template-name="blinker">
53
- <div class="form-row">
54
- <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
55
- <input type="text" id="node-input-name" placeholder="Name">
56
- </div>
57
- <div class="form-row">
58
- <label for="node-input-property"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
59
- <input type="text" id="node-input-property">
60
- <input type="hidden" id="node-input-property-type">
61
- </div>
62
- <div class="form-row">
63
- <label for="node-input-onTime"><i class="fa fa-hourglass-start"></i> on time</label>
64
- <input type="number" id="node-input-onTime" style="width:70px;" placeholder="Time">
65
- <select id="node-input-onTimeUnit" style="width:140px;">
66
- <option value="msecs">MilliSeconds</option>
67
- <option value="secs">Seconds</option>
68
- <option value="mins">Minutes</option>
69
- <option value="hours">Hours</option>
70
- </select>
71
- </div>
72
- <div class="form-row">
73
- <label for="node-input-pauseTime"><i class="fa fa-hourglass-end"></i> pause time</label>
74
- <input type="number" id="node-input-ffTime" style="width:70px;" placeholder="Time">
75
- <select id="node-input-offTimeUnit" style="width:140px;">
76
- <option value="msecs">MilliSeconds</option>
77
- <option value="secs">Seconds</option>
78
- <option value="mins">Minutes</option>
79
- <option value="hours">Hours</option>
80
- </select>
81
- </div>
82
- <div class="form-row">
83
- <label for="node-input-outputOn"><i class="fa fa-sign-out"></i> on Output</label>
84
- <input type="text" id="node-input-outputOn">
85
- <input type="hidden" id="node-input-outputOnType">
86
- </div>
87
- <div class="form-row">
88
- <label for="node-input-outputPause"><i class="fa fa-sign-out"></i> pause Output</label>
89
- <input type="text" id="node-input-outputPause">
90
- <input type="hidden" id="node-input-outputPauseType">
91
- </div>
92
- <div class="form-row">
93
- <label for="node-input-outputOff"><i class="fa fa-sign-out"></i> off Output</label>
94
- <input type="text" id="node-input-outputOff">
95
- <input type="hidden" id="node-input-outputOffType">
96
- </div>
97
- <div class="form-row">
98
- <label for="node-input-howStatus"><i class="fa fa-star-o"></i> Status</label>
99
- <input type="checkbox" id="node-input-showState" style="display:inline-block; width:20px; vertical-align:baseline;">
100
- </div>
101
- </script>
102
-
103
- <script type="text/html" data-help-name="blinker">
104
-
105
- <p>Sends the payload converted to boolean delayed. The delay time can de controlled for on and off switching individually.</p>
106
- <p>If the msg property <code>invalid</code> is present in the message, all nodes ignore the message.</p>
107
-
108
- <table>
109
- <tr> <th>type</th> <th>input</th> <th>output</th> </tr>
110
- <tr> <td>boolean</td> <td>false</td> <td>false</td> </tr>
111
- <tr> <td></td> <td>true</td> <td>true</td> </tr>
112
- <tr> <td>number</td> <td>0</td> <td>false</td> </tr>
113
- <tr> <td></td> <td>1</td> <td>true</td> </tr>
114
- <tr> <td>string</td> <td>false</td> <td>false</td> </tr>
115
- <tr> <td></td> <td>true</td> <td>true</td> </tr>
116
- <tr> <td></td> <td>0</td> <td>false</td> </tr>
117
- <tr> <td></td> <td>1</td> <td>true</td> </tr>
118
- <tr> <td></td> <td>off</td> <td>false</td> </tr>
119
- <tr> <td></td> <td>on</td> <td>true</td> </tr>
120
- </table>
121
-
122
- <h3>Input</h3>
123
-
124
- <p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
125
-
126
- <dl class="message-properties">
127
- <dt>payload <span class="property-type"></span></dt>
128
- <dd> input value.</dd>
129
- </dl>
130
-
131
- <h3>Output</h3>
132
-
133
- <dl class="message-properties">
134
- <dt>payload <span class="property-type">boolean</span></dt>
135
- <dd> bool value of payload.</dd>
136
- </dl>
137
-
138
- <h3>Parameter</h3>
139
-
140
- <dl class="message-properties">
141
- <dt>Property <span class="property-type">string</span></dt>
142
- <dd> defines the message property to be used as payload.</dd>
143
- <dt>Delay <span class="property-type">number</span></dt>
144
- <dd> delay time in msec for switching from off to on.</dd>
145
- <dt>Postrun <span class="property-type">number</span></dt>
146
- <dd> delay time in msec for switching from on to off.</dd>
147
- <dt>min on time <span class="property-type">number</span></dt>
148
- <dd> minimal time in msec to be in on state.</dd>
149
- <dt>max on time <span class="property-type">number</span></dt>
150
- <dd> maximal time in msec to be in on state; 0 is infinite.</dd>
151
- <dt>on Output <span class="property-type">multi</span></dt>
152
- <dd> Value to be sent in on case.</dd>
153
- <dt>off Output <span class="property-type">multi</span></dt>
154
- <dd> Value to be sent in off case.</dd>
155
- <dt>Status <span class="property-type">boolean</span></dt>
156
- <dd> shows the actual value as a node status.</dd>
157
- </dl>
158
-
159
- </script>