@mschaeffler/node-red-logic 3.11.5 → 3.12.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/icons/3point.png +0 -0
- package/math_3point.html +187 -0
- package/math_3point.js +144 -0
- package/math_hysteresis.js +2 -2
- package/package.json +2 -1
package/icons/3point.png
ADDED
|
Binary file
|
package/math_3point.html
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('threePoint',{
|
|
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
|
+
thresholdUpRise:{value:"",required:true,validate:RED.validators.number()},
|
|
11
|
+
thresholdUpFall:{value:"",required:true,validate:function(v){
|
|
12
|
+
const rise = $("#node-input-thresholdUpRise").length ? $("#node-input-thresholdUpRise").val() : this.thresholdUpRise;
|
|
13
|
+
return v!=='' && !isNaN(v) && Number(v)<rise;}
|
|
14
|
+
},
|
|
15
|
+
thresholdLowRise:{value:"",required:true,validate:function(v){
|
|
16
|
+
const fall = $("#node-input-thresholdUpFall").length ? $("#node-input-thresholdUpFall").val() : this.thresholdUpFall;
|
|
17
|
+
return v!=='' && !isNaN(v) && Number(v)<fall;}
|
|
18
|
+
},
|
|
19
|
+
thresholdLowFall:{value:"",required:true,validate:function(v){
|
|
20
|
+
const rise = $("#node-input-thresholdLowRise").length ? $("#node-input-thresholdLowRise").val() : this.thresholdLowRise;
|
|
21
|
+
return v!=='' && !isNaN(v) && Number(v)<rise;}
|
|
22
|
+
},
|
|
23
|
+
outputUpper:{value:"+1",required:true},
|
|
24
|
+
outputUpperType:{value:"num"},
|
|
25
|
+
outputMiddle:{value:"0",required:true},
|
|
26
|
+
outputMiddleType:{value:"num"},
|
|
27
|
+
outputLower:{value:"-1",required:true},
|
|
28
|
+
outputLowerType:{value:"num"},
|
|
29
|
+
noInit:{value:false},
|
|
30
|
+
showState:{value:false}
|
|
31
|
+
},
|
|
32
|
+
inputs:1,
|
|
33
|
+
outputs:1,
|
|
34
|
+
icon: "3point.png",
|
|
35
|
+
label: function() {
|
|
36
|
+
return this.name||this.topic||"3 point";
|
|
37
|
+
},
|
|
38
|
+
labelStyle: function() {
|
|
39
|
+
return this.name?"node_label_italic":"";
|
|
40
|
+
},
|
|
41
|
+
paletteLabel: "3 point",
|
|
42
|
+
inputLabels: 'input',
|
|
43
|
+
outputLabels: 'three point controller trigger',
|
|
44
|
+
oneditprepare: function() {
|
|
45
|
+
$("#node-input-property").typedInput({
|
|
46
|
+
type:"msg",
|
|
47
|
+
types:["msg","jsonata"],
|
|
48
|
+
typeField: "#node-input-propertyType"
|
|
49
|
+
})
|
|
50
|
+
$("#node-input-outputUpper").typedInput({
|
|
51
|
+
type:"bool",
|
|
52
|
+
types:["str","num","bool","json"],
|
|
53
|
+
typeField: "#node-input-outputUpperType"
|
|
54
|
+
})
|
|
55
|
+
$("#node-input-outputMiddle").typedInput({
|
|
56
|
+
type:"bool",
|
|
57
|
+
types:["str","num","bool","json"],
|
|
58
|
+
typeField: "#node-input-outputMiddleType"
|
|
59
|
+
})
|
|
60
|
+
$("#node-input-outputLower").typedInput({
|
|
61
|
+
type:"bool",
|
|
62
|
+
types:["str","num","bool","json"],
|
|
63
|
+
typeField: "#node-input-outputLowerType"
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
</script>
|
|
68
|
+
|
|
69
|
+
<script type="text/html" data-template-name="threePoint">
|
|
70
|
+
<div class="form-row">
|
|
71
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
72
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
73
|
+
</div>
|
|
74
|
+
<div class="form-row">
|
|
75
|
+
<label for="node-input-topic"><i class="fa fa-envelope-o"></i> Topic</label>
|
|
76
|
+
<input type="text" id="node-input-topic" placeholder="Topic">
|
|
77
|
+
</div>
|
|
78
|
+
<div class="form-row">
|
|
79
|
+
<label for="node-input-input"><i class="fa fa-ellipsis-h"></i> Eigenschaft</label>
|
|
80
|
+
<input type="text" id="node-input-property">
|
|
81
|
+
<input type="hidden" id="node-input-propertyType">
|
|
82
|
+
</div>
|
|
83
|
+
<div class="form-row">
|
|
84
|
+
<label for="node-input-thresholdUpRise"><i class="fa fa-chevron-up"></i> upper up threshold</label>
|
|
85
|
+
<input type="text" id="node-input-thresholdUpRise">
|
|
86
|
+
</div>
|
|
87
|
+
<div class="form-row">
|
|
88
|
+
<label for="node-input-thresholdUpFall"><i class="fa fa-chevron-down"></i> upper down threshold</label>
|
|
89
|
+
<input type="text" id="node-input-thresholdUpFall">
|
|
90
|
+
</div>
|
|
91
|
+
<div class="form-row">
|
|
92
|
+
<label for="node-input-thresholdLowRise"><i class="fa fa-chevron-up"></i> lower up threshold</label>
|
|
93
|
+
<input type="text" id="node-input-thresholdLowRise">
|
|
94
|
+
</div>
|
|
95
|
+
<div class="form-row">
|
|
96
|
+
<label for="node-input-thresholdLowFall"><i class="fa fa-chevron-down"></i> lower down threshold</label>
|
|
97
|
+
<input type="text" id="node-input-thresholdLowFall">
|
|
98
|
+
</div>
|
|
99
|
+
<div class="form-row">
|
|
100
|
+
<label for="node-input-outputUpper"><i class="fa fa-sign-out"></i> upper Output</label>
|
|
101
|
+
<input type="text" id="node-input-outputUpper">
|
|
102
|
+
<input type="hidden" id="node-input-outputUpperType">
|
|
103
|
+
</div>
|
|
104
|
+
<div class="form-row">
|
|
105
|
+
<label for="node-input-outputMiddle"><i class="fa fa-sign-out"></i> mid Output</label>
|
|
106
|
+
<input type="text" id="node-input-outputMiddle">
|
|
107
|
+
<input type="hidden" id="node-input-outputMiddleType">
|
|
108
|
+
</div>
|
|
109
|
+
<div class="form-row">
|
|
110
|
+
<label for="node-input-outputLower"><i class="fa fa-sign-out"></i> lower Output</label>
|
|
111
|
+
<input type="text" id="node-input-outputLower">
|
|
112
|
+
<input type="hidden" id="node-input-outputLowerType">
|
|
113
|
+
</div>
|
|
114
|
+
<div class="form-row">
|
|
115
|
+
<label for="node-input-noInit"><i class="fa fa-play"></i> no inits</label>
|
|
116
|
+
<input type="checkbox" id="node-input-noInit" style="display:inline-block; width:20px; vertical-align:baseline;">
|
|
117
|
+
</div>
|
|
118
|
+
<div class="form-row">
|
|
119
|
+
<label for="node-input-showStatus"><i class="fa fa-star-o"></i> Status</label>
|
|
120
|
+
<input type="checkbox" id="node-input-showState" style="display:inline-block; width:20px; vertical-align:baseline;">
|
|
121
|
+
</div>
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
<script type="text/html" data-help-name="threePoint">
|
|
125
|
+
|
|
126
|
+
<p>Message is only forwarded, if the payload rises above an upper limit or falls below a lower limit; there are two pairs of these limits for an upper and a lower threshold.</p>
|
|
127
|
+
<p>Each <code>topic</code> is treated seperatly.</p>
|
|
128
|
+
<p>If the msg property <code>invalid</code> is present in the message, all nodes ignore the message.</p>
|
|
129
|
+
|
|
130
|
+
<h3>Input</h3>
|
|
131
|
+
|
|
132
|
+
<p>The message property to be used as payload can be defined with the <code>Property</code> property.</p>
|
|
133
|
+
|
|
134
|
+
<p>With a input message with <code>msg.topic=="query"</code> or <code>msg.query=true</code>, you can query the latest states of all topics.</p>
|
|
135
|
+
|
|
136
|
+
<dl class="message-properties">
|
|
137
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
138
|
+
<dd> name of the input channel.</dd>
|
|
139
|
+
<dt>payload <span class="property-type"></span></dt>
|
|
140
|
+
<dd> input value for <code>topic</code>.</dd>
|
|
141
|
+
</dl>
|
|
142
|
+
|
|
143
|
+
<h3>Output</h3>
|
|
144
|
+
|
|
145
|
+
<p>Trigger message, in case an edge is detected.</p>
|
|
146
|
+
|
|
147
|
+
<dl class="message-properties">
|
|
148
|
+
<dt>topic <span class="property-type">string</span></dt>
|
|
149
|
+
<dd> name of the input channel.</dd>
|
|
150
|
+
<dt>payload <span class="property-type"></span></dt>
|
|
151
|
+
<dd> output value defines in <code>rise Output</code> or <code>fall Output</code>.</dd>
|
|
152
|
+
<dt>value <span class="property-type">number</span></dt>
|
|
153
|
+
<dd> last input value for <code>topic</code>.</dd>
|
|
154
|
+
<dt>edge <span class="property-type">string</span></dt>
|
|
155
|
+
<dd> <code>+1</code>, <code>0</code> or <code>-1</code> according to detected edge.</dd>
|
|
156
|
+
<dt>init <span class="property-type">boolean</span></dt>
|
|
157
|
+
<dd> <code>true</code> in case of an initialization message without really an edge detection.</dd>
|
|
158
|
+
</dl>
|
|
159
|
+
|
|
160
|
+
<h3>Parameter</h3>
|
|
161
|
+
|
|
162
|
+
<dl class="message-properties">
|
|
163
|
+
<dt>Topic <span class="property-type">string</span></dt>
|
|
164
|
+
<dd> defines the topic for the output message, "" is <code>msg.topic</code>.</dd>
|
|
165
|
+
<dt>Property <span class="property-type">string</span></dt>
|
|
166
|
+
<dd> defines the message property to be used as payload.</dd>
|
|
167
|
+
<dt>upper up Threshold <span class="property-type">number</span></dt>
|
|
168
|
+
<dd> threshold value for the rising edge detection of the upper level.</dd>
|
|
169
|
+
<dt>upper down Threshold <span class="property-type">number</span></dt>
|
|
170
|
+
<dd> threshold value for the falling edge detection of the upper level.</dd>
|
|
171
|
+
<dt>lower up Threshold <span class="property-type">number</span></dt>
|
|
172
|
+
<dd> threshold value for the rising edge detection of the lower level.</dd>
|
|
173
|
+
<dt>lower down Threshold <span class="property-type">number</span></dt>
|
|
174
|
+
<dd> threshold value for the falling edge detection of the lower level.</dd>
|
|
175
|
+
<dt>upper Output <span class="property-type">multi</span></dt>
|
|
176
|
+
<dd> Value to be sent in case of rising above the upper threshold.</dd>
|
|
177
|
+
<dt>mid Output <span class="property-type">multi</span></dt>
|
|
178
|
+
<dd> Value to be sent in case of beeing between the two thresholds.</dd>
|
|
179
|
+
<dt>lower Output <span class="property-type">multi</span></dt>
|
|
180
|
+
<dd> Value to be sent in case of falling below the lower threshold.</dd>
|
|
181
|
+
<dt>no init <span class="property-type">boolean</span></dt>
|
|
182
|
+
<dd> does not send init messages.</dd>
|
|
183
|
+
<dt>Status <span class="property-type">boolean</span></dt>
|
|
184
|
+
<dd> shows the actual value as a node status.</dd>
|
|
185
|
+
</dl>
|
|
186
|
+
|
|
187
|
+
</script>
|
package/math_3point.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
module.exports = function(RED) {
|
|
2
|
+
var tools = require('./tools.js');
|
|
3
|
+
|
|
4
|
+
const colors = {"1":"yellow","0":"gray","-1":"blue"};
|
|
5
|
+
|
|
6
|
+
function ThreePointNode(config) {
|
|
7
|
+
RED.nodes.createNode(this,config);
|
|
8
|
+
//this.config = config;
|
|
9
|
+
var node = this;
|
|
10
|
+
var context = this.context();
|
|
11
|
+
this.topic = config.topic || "";
|
|
12
|
+
this.property = config.property ?? "payload";
|
|
13
|
+
this.propertyType = config.propertyType ?? "msg";
|
|
14
|
+
this.thresholdUpRise = Number( config.thresholdUpRise );
|
|
15
|
+
this.thresholdUpFall = Number( config.thresholdUpFall );
|
|
16
|
+
this.thresholdLowRise = Number( config.thresholdLowRise );
|
|
17
|
+
this.thresholdLowFall = Number( config.thresholdLowFall );
|
|
18
|
+
this.output = {
|
|
19
|
+
"1": RED.util.evaluateNodeProperty( config.outputUpper ?? "+1", config.outputUpperType ?? "num" ),
|
|
20
|
+
"0": RED.util.evaluateNodeProperty( config.outputMiddle ?? "0", config.outputMiddleType ?? "num" ),
|
|
21
|
+
"-1": RED.util.evaluateNodeProperty( config.outputLower ?? "-1", config.outputLowerType ?? "num" )
|
|
22
|
+
};
|
|
23
|
+
this.noInit = Boolean( config.noInit );
|
|
24
|
+
this.showState = Boolean( config.showState );
|
|
25
|
+
if( this.propertyType === "jsonata" )
|
|
26
|
+
{
|
|
27
|
+
try {
|
|
28
|
+
this.propertyPrepared = RED.util.prepareJSONataExpression( this.property, this );
|
|
29
|
+
}
|
|
30
|
+
catch (e) {
|
|
31
|
+
node.error(RED._("debug.invalid-exp", {error: this.property}));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
node.status( "" );
|
|
36
|
+
|
|
37
|
+
function msgSetEdge(msg,edge)
|
|
38
|
+
{
|
|
39
|
+
msg.edge = edge;
|
|
40
|
+
msg.payload = node.output[edge];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
node.on('input', function(msg,send,done) {
|
|
44
|
+
let data = context.get( "data" ) ?? {};
|
|
45
|
+
if( msg.invalid )
|
|
46
|
+
{
|
|
47
|
+
done();
|
|
48
|
+
}
|
|
49
|
+
else if( msg.reset || msg.topic==="init" )
|
|
50
|
+
{
|
|
51
|
+
context.set( "data", {} );
|
|
52
|
+
node.status( "" );
|
|
53
|
+
done();
|
|
54
|
+
}
|
|
55
|
+
else if( msg.query || msg.topic==="query" )
|
|
56
|
+
{
|
|
57
|
+
for( const i in data )
|
|
58
|
+
{
|
|
59
|
+
let help = { topic: i, query: true };
|
|
60
|
+
msgSetEdge( help, data[i].edge );
|
|
61
|
+
send( help );
|
|
62
|
+
}
|
|
63
|
+
done();
|
|
64
|
+
}
|
|
65
|
+
else
|
|
66
|
+
{
|
|
67
|
+
function getPayload(callback)
|
|
68
|
+
{
|
|
69
|
+
if( node.propertyPrepared )
|
|
70
|
+
{
|
|
71
|
+
RED.util.evaluateJSONataExpression( node.propertyPrepared, msg, function(err, value)
|
|
72
|
+
{
|
|
73
|
+
if( err )
|
|
74
|
+
{
|
|
75
|
+
done( err.message );
|
|
76
|
+
}
|
|
77
|
+
else
|
|
78
|
+
{
|
|
79
|
+
callback( value );
|
|
80
|
+
}
|
|
81
|
+
} );
|
|
82
|
+
}
|
|
83
|
+
else
|
|
84
|
+
{
|
|
85
|
+
callback( RED.util.getMessageProperty( msg, node.property ) );
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
getPayload( function(value)
|
|
89
|
+
{
|
|
90
|
+
msg.value = Number( value );
|
|
91
|
+
if( node.topic )
|
|
92
|
+
{
|
|
93
|
+
msg.topic = node.topic;
|
|
94
|
+
}
|
|
95
|
+
let status = { fill:data[msg.topic]?.status??"gray", shape:"dot", text:tools.formatNumber( msg.value ) };
|
|
96
|
+
|
|
97
|
+
if( ! isNaN( msg.value ) )
|
|
98
|
+
{
|
|
99
|
+
const last = data[msg.topic]?.edge;
|
|
100
|
+
|
|
101
|
+
function sendMsg(edge)
|
|
102
|
+
{
|
|
103
|
+
status.fill = colors[edge];
|
|
104
|
+
data[msg.topic] = { edge:edge, status:status.fill };
|
|
105
|
+
context.set( "data", data );
|
|
106
|
+
if( last !== undefined || ! node.noInit )
|
|
107
|
+
{
|
|
108
|
+
msgSetEdge( msg, edge );
|
|
109
|
+
msg.init = last === undefined;
|
|
110
|
+
send( msg );
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if( msg.value > node.thresholdUpRise && last !== +1 )
|
|
115
|
+
{
|
|
116
|
+
sendMsg( +1 );
|
|
117
|
+
}
|
|
118
|
+
else if( node.thresholdLowRise < msg.value && msg.value < node.thresholdUpFall && last !== 0 )
|
|
119
|
+
{
|
|
120
|
+
sendMsg( 0 );
|
|
121
|
+
}
|
|
122
|
+
else if( msg.value < node.thresholdLowFall && last !== -1 )
|
|
123
|
+
{
|
|
124
|
+
sendMsg( -1 );
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else
|
|
128
|
+
{
|
|
129
|
+
status.fill = "red";
|
|
130
|
+
status.text = "not a Number";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if( node.showState )
|
|
134
|
+
{
|
|
135
|
+
node.status( status );
|
|
136
|
+
}
|
|
137
|
+
done();
|
|
138
|
+
} );
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
RED.nodes.registerType("threePoint",ThreePointNode);
|
|
144
|
+
}
|
package/math_hysteresis.js
CHANGED
|
@@ -84,7 +84,7 @@ module.exports = function(RED) {
|
|
|
84
84
|
}
|
|
85
85
|
getPayload( function(value)
|
|
86
86
|
{
|
|
87
|
-
msg.value
|
|
87
|
+
msg.value = Number( value );
|
|
88
88
|
if( node.topic )
|
|
89
89
|
{
|
|
90
90
|
msg.topic = node.topic;
|
|
@@ -97,7 +97,7 @@ module.exports = function(RED) {
|
|
|
97
97
|
|
|
98
98
|
function sendMsg(edge)
|
|
99
99
|
{
|
|
100
|
-
status.fill = edge ? "
|
|
100
|
+
status.fill = edge ? "yellow" : "blue";
|
|
101
101
|
data[msg.topic] = { edge:edge, status:status.fill };
|
|
102
102
|
context.set( "data", data );
|
|
103
103
|
if( last !== undefined || ! node.noInit )
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mschaeffler/node-red-logic",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.12.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",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"fallingEdge": "math_falling.js",
|
|
30
30
|
"raisingEdge": "math_rising.js",
|
|
31
31
|
"hysteresisEdge": "math_hysteresis.js",
|
|
32
|
+
"threePoint": "math_3point.js",
|
|
32
33
|
"statistics": "math_statistics.js",
|
|
33
34
|
"mean": "math_mean.js"
|
|
34
35
|
}
|