@bldgblocks/node-red-contrib-control 0.1.34 → 0.1.36
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/nodes/accumulate-block.html +18 -8
- package/nodes/accumulate-block.js +39 -44
- package/nodes/add-block.html +1 -1
- package/nodes/add-block.js +18 -11
- package/nodes/alarm-collector.html +260 -0
- package/nodes/alarm-collector.js +292 -0
- package/nodes/alarm-config.html +129 -0
- package/nodes/alarm-config.js +126 -0
- package/nodes/alarm-service.html +96 -0
- package/nodes/alarm-service.js +142 -0
- package/nodes/analog-switch-block.js +25 -36
- package/nodes/and-block.js +44 -15
- package/nodes/average-block.js +46 -41
- package/nodes/boolean-switch-block.js +10 -28
- package/nodes/boolean-to-number-block.html +18 -5
- package/nodes/boolean-to-number-block.js +24 -16
- package/nodes/cache-block.js +24 -37
- package/nodes/call-status-block.html +91 -32
- package/nodes/call-status-block.js +398 -115
- package/nodes/changeover-block.html +5 -0
- package/nodes/changeover-block.js +167 -162
- package/nodes/comment-block.html +1 -1
- package/nodes/comment-block.js +14 -9
- package/nodes/compare-block.html +14 -4
- package/nodes/compare-block.js +23 -18
- package/nodes/contextual-label-block.html +5 -0
- package/nodes/contextual-label-block.js +6 -16
- package/nodes/convert-block.html +25 -39
- package/nodes/convert-block.js +31 -16
- package/nodes/count-block.html +11 -5
- package/nodes/count-block.js +34 -32
- package/nodes/delay-block.js +58 -53
- package/nodes/divide-block.js +43 -45
- package/nodes/edge-block.html +17 -10
- package/nodes/edge-block.js +43 -41
- package/nodes/enum-switch-block.js +6 -6
- package/nodes/frequency-block.html +6 -1
- package/nodes/frequency-block.js +64 -74
- package/nodes/global-getter.html +51 -15
- package/nodes/global-getter.js +43 -13
- package/nodes/global-setter.html +1 -1
- package/nodes/global-setter.js +40 -12
- package/nodes/history-buffer.html +96 -0
- package/nodes/history-buffer.js +461 -0
- package/nodes/history-collector.html +29 -1
- package/nodes/history-collector.js +37 -16
- package/nodes/history-config.html +13 -1
- package/nodes/history-service.html +84 -0
- package/nodes/history-service.js +52 -0
- package/nodes/hysteresis-block.html +5 -0
- package/nodes/hysteresis-block.js +13 -16
- package/nodes/interpolate-block.html +20 -2
- package/nodes/interpolate-block.js +39 -50
- package/nodes/join.html +78 -0
- package/nodes/join.js +78 -0
- package/nodes/latch-block.js +12 -14
- package/nodes/load-sequence-block.js +102 -110
- package/nodes/max-block.js +26 -26
- package/nodes/memory-block.js +57 -58
- package/nodes/min-block.js +26 -25
- package/nodes/minmax-block.js +35 -34
- package/nodes/modulo-block.js +45 -43
- package/nodes/multiply-block.js +43 -41
- package/nodes/negate-block.html +17 -7
- package/nodes/negate-block.js +25 -19
- package/nodes/network-point-read.html +128 -0
- package/nodes/network-point-read.js +230 -0
- package/nodes/{network-register.html → network-point-register.html} +94 -7
- package/nodes/{network-register.js → network-point-register.js} +18 -4
- package/nodes/network-point-write.html +149 -0
- package/nodes/network-point-write.js +222 -0
- package/nodes/network-service-bridge.html +131 -0
- package/nodes/network-service-bridge.js +376 -0
- package/nodes/network-service-read.html +81 -0
- package/nodes/{network-read.js → network-service-read.js} +4 -3
- package/nodes/{network-point-registry.html → network-service-registry.html} +19 -4
- package/nodes/{network-point-registry.js → network-service-registry.js} +7 -2
- package/nodes/network-service-write.html +89 -0
- package/nodes/{network-write.js → network-service-write.js} +3 -3
- package/nodes/nullify-block.js +13 -15
- package/nodes/on-change-block.html +17 -9
- package/nodes/on-change-block.js +49 -46
- package/nodes/oneshot-block.html +13 -10
- package/nodes/oneshot-block.js +57 -75
- package/nodes/or-block.js +44 -15
- package/nodes/pid-block.html +54 -4
- package/nodes/pid-block.js +459 -248
- package/nodes/priority-block.js +24 -35
- package/nodes/rate-limit-block.js +70 -72
- package/nodes/rate-of-change-block.html +33 -14
- package/nodes/rate-of-change-block.js +74 -62
- package/nodes/round-block.html +14 -9
- package/nodes/round-block.js +32 -25
- package/nodes/saw-tooth-wave-block.js +49 -76
- package/nodes/scale-range-block.html +12 -6
- package/nodes/scale-range-block.js +46 -39
- package/nodes/sine-wave-block.js +49 -57
- package/nodes/string-builder-block.js +6 -6
- package/nodes/subtract-block.js +38 -34
- package/nodes/thermistor-block.js +44 -44
- package/nodes/tick-tock-block.js +32 -32
- package/nodes/time-sequence-block.js +30 -42
- package/nodes/triangle-wave-block.js +49 -69
- package/nodes/tstat-block.js +34 -44
- package/nodes/units-block.html +90 -69
- package/nodes/units-block.js +22 -30
- package/nodes/utils.js +206 -3
- package/package.json +14 -6
- package/nodes/network-read.html +0 -56
- package/nodes/network-write.html +0 -65
package/nodes/memory-block.js
CHANGED
|
@@ -10,16 +10,15 @@ module.exports = function(RED) {
|
|
|
10
10
|
const node = this;
|
|
11
11
|
|
|
12
12
|
// Initialize runtime state
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
};
|
|
13
|
+
// Initialize state
|
|
14
|
+
node.name = config.name;
|
|
15
|
+
node.writePeriod = config.writePeriod;
|
|
16
|
+
node.transferProperty = config.transferProperty;
|
|
17
|
+
node.writeOnUpdate = config.writeOnUpdate === true;
|
|
18
|
+
node.storedMsg = null;
|
|
20
19
|
|
|
21
20
|
// Resolve typed inputs
|
|
22
|
-
node.
|
|
21
|
+
node.writePeriod = parseFloat(RED.util.evaluateNodeProperty( config.writePeriod, config.writePeriodType, node ));
|
|
23
22
|
|
|
24
23
|
// File path for persistent storage
|
|
25
24
|
const filePath = path.join(RED.settings.userDir, `memory-${node.id}.json`);
|
|
@@ -31,12 +30,12 @@ module.exports = function(RED) {
|
|
|
31
30
|
async function loadStoredMessage() {
|
|
32
31
|
try {
|
|
33
32
|
const data = await fs.readFile(filePath, "utf8");
|
|
34
|
-
node.
|
|
35
|
-
const payloadStr = node.
|
|
36
|
-
|
|
33
|
+
node.storedMsg = JSON.parse(data);
|
|
34
|
+
const payloadStr = node.storedMsg[node.transferProperty] != null ? String(node.storedMsg[node.transferProperty]).substring(0, 20) : "null";
|
|
35
|
+
utils.setStatusOK(node, `loaded: ${payloadStr}`);
|
|
37
36
|
} catch (err) {
|
|
38
37
|
if (err.code !== "ENOENT") {
|
|
39
|
-
|
|
38
|
+
utils.setStatusError(node, "file error");
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
}
|
|
@@ -50,7 +49,7 @@ module.exports = function(RED) {
|
|
|
50
49
|
}
|
|
51
50
|
return null;
|
|
52
51
|
} catch (err) {
|
|
53
|
-
|
|
52
|
+
utils.setStatusError(node, "file read error");
|
|
54
53
|
node.error("Failed to read stored message: " + err.message);
|
|
55
54
|
return null;
|
|
56
55
|
}
|
|
@@ -63,13 +62,13 @@ module.exports = function(RED) {
|
|
|
63
62
|
await fs.writeFile(filePath, JSON.stringify(lastUpdateMsg));
|
|
64
63
|
lastUpdateMsg = null;
|
|
65
64
|
} catch (err) {
|
|
66
|
-
|
|
65
|
+
utils.setStatusError(node, "file error");
|
|
67
66
|
node.error("Failed to save message: " + err.message);
|
|
68
67
|
}
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
// Initialize (load only if writeOnUpdate is false)
|
|
72
|
-
if (!node.
|
|
71
|
+
if (!node.writeOnUpdate) {
|
|
73
72
|
loadStoredMessage().catch(err => {
|
|
74
73
|
node.error("Failed to load stored message: " + err.message);
|
|
75
74
|
});
|
|
@@ -80,14 +79,14 @@ module.exports = function(RED) {
|
|
|
80
79
|
|
|
81
80
|
// Guard against invalid message
|
|
82
81
|
if (!msg) {
|
|
83
|
-
|
|
82
|
+
utils.setStatusError(node, "invalid message");
|
|
84
83
|
if (done) done();
|
|
85
84
|
return;
|
|
86
85
|
}
|
|
87
86
|
|
|
88
87
|
// Evaluate typed-inputs if needed
|
|
89
88
|
if (utils.requiresEvaluation(config.writePeriodType)) {
|
|
90
|
-
node.
|
|
89
|
+
node.writePeriod = parseFloat(RED.util.evaluateNodeProperty( config.writePeriod, config.writePeriodType, node, msg ));
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
// Initialize output array: [Output 1, Output 2]
|
|
@@ -96,8 +95,8 @@ module.exports = function(RED) {
|
|
|
96
95
|
// Handle context
|
|
97
96
|
if (!msg.hasOwnProperty("context") || !msg.context || typeof msg.context !== "string") {
|
|
98
97
|
// Pass-through message to Output 2
|
|
99
|
-
const payloadStr = msg[node.
|
|
100
|
-
|
|
98
|
+
const payloadStr = msg[node.transferProperty] != null ? String(msg[node.transferProperty]).substring(0, 20) : "null";
|
|
99
|
+
utils.setStatusChanged(node, `in: ${payloadStr}, out2: ${payloadStr}`);
|
|
101
100
|
output[1] = msg;
|
|
102
101
|
send(output);
|
|
103
102
|
if (done) done();
|
|
@@ -105,30 +104,30 @@ module.exports = function(RED) {
|
|
|
105
104
|
}
|
|
106
105
|
|
|
107
106
|
if (msg.context === "update") {
|
|
108
|
-
if (!msg.hasOwnProperty(node.
|
|
109
|
-
|
|
107
|
+
if (!msg.hasOwnProperty(node.transferProperty)) {
|
|
108
|
+
utils.setStatusError(node, `missing ${node.transferProperty}`);
|
|
110
109
|
if (done) done();
|
|
111
110
|
return;
|
|
112
111
|
}
|
|
113
|
-
const payloadStr = msg[node.
|
|
114
|
-
if (node.
|
|
112
|
+
const payloadStr = msg[node.transferProperty] != null ? String(msg[node.transferProperty]).substring(0, 20) : "null";
|
|
113
|
+
if (node.writeOnUpdate) {
|
|
115
114
|
// Write directly to file, do not store in memory
|
|
116
115
|
try {
|
|
117
116
|
fs.writeFile(filePath, JSON.stringify(msg)).catch(err => {
|
|
118
|
-
|
|
117
|
+
utils.setStatusError(node, "file error");
|
|
119
118
|
node.error("Failed to save message: " + err.message);
|
|
120
119
|
});
|
|
121
|
-
|
|
120
|
+
utils.setStatusOK(node, `updated: ${payloadStr}`);
|
|
122
121
|
} catch (err) {
|
|
123
|
-
|
|
122
|
+
utils.setStatusError(node, "file error");
|
|
124
123
|
node.error("Failed to save message: " + err.message);
|
|
125
124
|
}
|
|
126
125
|
} else {
|
|
127
126
|
// Original behavior: store in memory and context, delay write
|
|
128
|
-
node.
|
|
129
|
-
node.context().set("storedMsg", node.
|
|
130
|
-
lastUpdateMsg = node.
|
|
131
|
-
|
|
127
|
+
node.storedMsg = RED.util.cloneMessage(msg);
|
|
128
|
+
node.context().set("storedMsg", node.storedMsg);
|
|
129
|
+
lastUpdateMsg = node.storedMsg;
|
|
130
|
+
utils.setStatusOK(node, `updated: ${payloadStr}`);
|
|
132
131
|
if (writeTimeout) clearTimeout(writeTimeout);
|
|
133
132
|
writeTimeout = setTimeout(() => {
|
|
134
133
|
saveMessage();
|
|
@@ -139,15 +138,15 @@ module.exports = function(RED) {
|
|
|
139
138
|
}
|
|
140
139
|
|
|
141
140
|
if (msg.context === "execute") {
|
|
142
|
-
let storedMsg = node.
|
|
141
|
+
let storedMsg = node.writeOnUpdate ? readStoredMessageSync() : node.storedMsg;
|
|
143
142
|
if (storedMsg !== null) {
|
|
144
143
|
const outMsg = RED.util.cloneMessage(msg);
|
|
145
|
-
outMsg[node.
|
|
146
|
-
const payloadStr = outMsg[node.
|
|
147
|
-
|
|
144
|
+
outMsg[node.transferProperty] = storedMsg[node.transferProperty];
|
|
145
|
+
const payloadStr = outMsg[node.transferProperty] != null ? String(outMsg[node.transferProperty]).substring(0, 20) : "null";
|
|
146
|
+
utils.setStatusChanged(node, `in: execute, out2: ${payloadStr}`);
|
|
148
147
|
output[1] = outMsg;
|
|
149
148
|
} else {
|
|
150
|
-
|
|
149
|
+
utils.setStatusUnchanged(node, `in: execute, out2: null`);
|
|
151
150
|
output[1] = { payload: null };
|
|
152
151
|
}
|
|
153
152
|
send(output);
|
|
@@ -156,51 +155,51 @@ module.exports = function(RED) {
|
|
|
156
155
|
}
|
|
157
156
|
|
|
158
157
|
if (msg.context === "executeWithFallback") {
|
|
159
|
-
let storedMsg = node.
|
|
158
|
+
let storedMsg = node.writeOnUpdate ? readStoredMessageSync() : node.storedMsg;
|
|
160
159
|
if (storedMsg !== null) {
|
|
161
160
|
const outMsg = RED.util.cloneMessage(msg);
|
|
162
|
-
outMsg[node.
|
|
163
|
-
const payloadStr = outMsg[node.
|
|
164
|
-
|
|
161
|
+
outMsg[node.transferProperty] = storedMsg[node.transferProperty];
|
|
162
|
+
const payloadStr = outMsg[node.transferProperty] != null ? String(outMsg[node.transferProperty]).substring(0, 20) : "null";
|
|
163
|
+
utils.setStatusChanged(node, `in: executeWithFallback, out2: ${payloadStr}`);
|
|
165
164
|
output[1] = outMsg;
|
|
166
165
|
} else {
|
|
167
166
|
let value;
|
|
168
|
-
if (msg.hasOwnProperty(node.
|
|
169
|
-
value = msg[node.
|
|
167
|
+
if (msg.hasOwnProperty(node.transferProperty)) {
|
|
168
|
+
value = msg[node.transferProperty];
|
|
170
169
|
}
|
|
171
170
|
else if (msg.hasOwnProperty("fallback")) {
|
|
172
171
|
value = msg.fallback;
|
|
173
172
|
} else {
|
|
174
|
-
|
|
173
|
+
utils.setStatusError(node, `missing ${node.transferProperty}`);
|
|
175
174
|
if (done) done();
|
|
176
175
|
return;
|
|
177
176
|
}
|
|
178
177
|
|
|
179
|
-
if (node.
|
|
178
|
+
if (node.writeOnUpdate) {
|
|
180
179
|
// Write directly to file
|
|
181
180
|
try {
|
|
182
|
-
fs.writeFile(filePath, JSON.stringify({ [node.
|
|
183
|
-
|
|
181
|
+
fs.writeFile(filePath, JSON.stringify({ [node.transferProperty]: value })).catch(err => {
|
|
182
|
+
utils.setStatusError(node, "file error");
|
|
184
183
|
node.error("Failed to save message: " + err.message);
|
|
185
184
|
});
|
|
186
185
|
} catch (err) {
|
|
187
|
-
|
|
186
|
+
utils.setStatusError(node, "file error");
|
|
188
187
|
node.error("Failed to save message: " + err.message);
|
|
189
188
|
}
|
|
190
189
|
} else {
|
|
191
190
|
// Store in memory and context
|
|
192
|
-
node.
|
|
193
|
-
node.context().set("storedMsg", node.
|
|
194
|
-
lastUpdateMsg = node.
|
|
191
|
+
node.storedMsg = { [node.transferProperty]: value };
|
|
192
|
+
node.context().set("storedMsg", node.storedMsg);
|
|
193
|
+
lastUpdateMsg = node.storedMsg;
|
|
195
194
|
if (writeTimeout) clearTimeout(writeTimeout);
|
|
196
195
|
writeTimeout = setTimeout(() => {
|
|
197
196
|
saveMessage();
|
|
198
197
|
}, writePeriod);
|
|
199
198
|
}
|
|
200
199
|
const outMsg = RED.util.cloneMessage(msg);
|
|
201
|
-
outMsg[node.
|
|
202
|
-
const payloadStr = msg[node.
|
|
203
|
-
|
|
200
|
+
outMsg[node.transferProperty] = value;
|
|
201
|
+
const payloadStr = msg[node.transferProperty] != null ? String(msg[node.transferProperty]).substring(0, 20) : "null";
|
|
202
|
+
utils.setStatusChanged(node, `in: executeWithFallback, out2: ${payloadStr}`);
|
|
204
203
|
output[1] = outMsg;
|
|
205
204
|
}
|
|
206
205
|
send(output);
|
|
@@ -209,29 +208,29 @@ module.exports = function(RED) {
|
|
|
209
208
|
}
|
|
210
209
|
|
|
211
210
|
if (msg.context === "query") {
|
|
212
|
-
const hasValue = node.
|
|
213
|
-
|
|
211
|
+
const hasValue = node.writeOnUpdate ? fsSync.existsSync(filePath) : node.storedMsg !== null;
|
|
212
|
+
utils.setStatusChanged(node, `in: query, out1: ${hasValue}`);
|
|
214
213
|
output[0] = { payload: hasValue };
|
|
215
214
|
send(output);
|
|
216
215
|
if (done) done();
|
|
217
216
|
return;
|
|
218
217
|
}
|
|
219
218
|
|
|
220
|
-
|
|
219
|
+
utils.setStatusWarn(node, "unknown context");
|
|
221
220
|
if (done) done("Unknown context");
|
|
222
221
|
});
|
|
223
222
|
|
|
224
223
|
node.on("close", function(done) {
|
|
225
224
|
if (writeTimeout) clearTimeout(writeTimeout);
|
|
226
|
-
if (!node.
|
|
225
|
+
if (!node.writeOnUpdate && lastUpdateMsg) {
|
|
227
226
|
saveMessage()
|
|
228
227
|
.then(() => {
|
|
229
|
-
|
|
228
|
+
utils.setStatusOK(node, "");
|
|
230
229
|
done();
|
|
231
230
|
})
|
|
232
231
|
.catch(err => {
|
|
233
232
|
node.error("Failed to save message on close: " + err.message);
|
|
234
|
-
|
|
233
|
+
utils.setStatusError(node, "save error");
|
|
235
234
|
done();
|
|
236
235
|
});
|
|
237
236
|
} else {
|
package/nodes/min-block.js
CHANGED
|
@@ -7,10 +7,9 @@ module.exports = function(RED) {
|
|
|
7
7
|
node.isBusy = false;
|
|
8
8
|
|
|
9
9
|
// Initialize runtime state
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
};
|
|
10
|
+
// Initialize state
|
|
11
|
+
node.name = config.name;
|
|
12
|
+
node.min = parseFloat(config.min);
|
|
14
13
|
|
|
15
14
|
// Store last output value for status
|
|
16
15
|
let lastOutput = null;
|
|
@@ -20,7 +19,7 @@ module.exports = function(RED) {
|
|
|
20
19
|
|
|
21
20
|
// Guard against invalid message
|
|
22
21
|
if (!msg) {
|
|
23
|
-
|
|
22
|
+
utils.setStatusError(node, "invalid message");
|
|
24
23
|
if (done) done();
|
|
25
24
|
return;
|
|
26
25
|
}
|
|
@@ -31,7 +30,7 @@ module.exports = function(RED) {
|
|
|
31
30
|
// Check busy lock
|
|
32
31
|
if (node.isBusy) {
|
|
33
32
|
// Update status to let user know they are pushing too fast
|
|
34
|
-
|
|
33
|
+
utils.setStatusBusy(node, "busy - dropped msg");
|
|
35
34
|
if (done) done();
|
|
36
35
|
return;
|
|
37
36
|
}
|
|
@@ -46,13 +45,13 @@ module.exports = function(RED) {
|
|
|
46
45
|
utils.requiresEvaluation(config.minType)
|
|
47
46
|
? utils.evaluateNodeProperty(config.min, config.minType, node, msg)
|
|
48
47
|
.then(val => parseFloat(val))
|
|
49
|
-
: Promise.resolve(node.
|
|
48
|
+
: Promise.resolve(node.min),
|
|
50
49
|
);
|
|
51
50
|
|
|
52
51
|
const results = await Promise.all(evaluations);
|
|
53
52
|
|
|
54
53
|
// Update runtime with evaluated values
|
|
55
|
-
if (!isNaN(results[0])) node.
|
|
54
|
+
if (!isNaN(results[0])) node.min = results[0];
|
|
56
55
|
} catch (err) {
|
|
57
56
|
node.error(`Error evaluating properties: ${err.message}`);
|
|
58
57
|
if (done) done();
|
|
@@ -63,8 +62,8 @@ module.exports = function(RED) {
|
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
// Validate
|
|
66
|
-
if (isNaN(node.
|
|
67
|
-
|
|
65
|
+
if (isNaN(node.min)) {
|
|
66
|
+
utils.setStatusError(node, "invalid evaluated values");
|
|
68
67
|
if (done) done();
|
|
69
68
|
return;
|
|
70
69
|
}
|
|
@@ -72,22 +71,22 @@ module.exports = function(RED) {
|
|
|
72
71
|
// Handle context updates
|
|
73
72
|
if (msg.hasOwnProperty("context")) {
|
|
74
73
|
if (!msg.hasOwnProperty("payload")) {
|
|
75
|
-
|
|
74
|
+
utils.setStatusError(node, "missing payload for min");
|
|
76
75
|
if (done) done();
|
|
77
76
|
return;
|
|
78
77
|
}
|
|
79
78
|
if (msg.context === "min" || msg.context === "setpoint") {
|
|
80
79
|
const minValue = parseFloat(msg.payload);
|
|
81
80
|
if (!isNaN(minValue) && minValue >= 0) {
|
|
82
|
-
node.
|
|
83
|
-
|
|
81
|
+
node.min = minValue;
|
|
82
|
+
utils.setStatusOK(node, `min: ${minValue}`);
|
|
84
83
|
} else {
|
|
85
|
-
|
|
84
|
+
utils.setStatusError(node, "invalid min");
|
|
86
85
|
}
|
|
87
86
|
if (done) done();
|
|
88
87
|
return;
|
|
89
88
|
} else {
|
|
90
|
-
|
|
89
|
+
utils.setStatusWarn(node, "unknown context");
|
|
91
90
|
if (done) done();
|
|
92
91
|
return;
|
|
93
92
|
}
|
|
@@ -95,28 +94,30 @@ module.exports = function(RED) {
|
|
|
95
94
|
|
|
96
95
|
// Validate input payload
|
|
97
96
|
if (!msg.hasOwnProperty("payload")) {
|
|
98
|
-
|
|
97
|
+
utils.setStatusError(node, "missing payload");
|
|
99
98
|
if (done) done();
|
|
100
99
|
return;
|
|
101
100
|
}
|
|
102
101
|
|
|
103
|
-
const
|
|
104
|
-
if (
|
|
105
|
-
|
|
102
|
+
const numVal = utils.validateNumericPayload(msg.payload);
|
|
103
|
+
if (!numVal.valid) {
|
|
104
|
+
utils.setStatusError(node, numVal.error);
|
|
106
105
|
if (done) done();
|
|
107
106
|
return;
|
|
108
107
|
}
|
|
108
|
+
const inputValue = numVal.value;
|
|
109
109
|
|
|
110
110
|
// Cap input at min
|
|
111
|
-
const outputValue = Math.max(inputValue, node.
|
|
111
|
+
const outputValue = Math.max(inputValue, node.min);
|
|
112
112
|
|
|
113
113
|
// Update status and send output
|
|
114
114
|
msg.payload = outputValue;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
const statusText = `in: ${inputValue.toFixed(2)}, out: ${outputValue.toFixed(2)}`;
|
|
116
|
+
if (lastOutput === outputValue) {
|
|
117
|
+
utils.setStatusUnchanged(node, statusText);
|
|
118
|
+
} else {
|
|
119
|
+
utils.setStatusChanged(node, statusText);
|
|
120
|
+
}
|
|
120
121
|
lastOutput = outputValue;
|
|
121
122
|
send(msg);
|
|
122
123
|
|
package/nodes/minmax-block.js
CHANGED
|
@@ -7,11 +7,10 @@ module.exports = function(RED) {
|
|
|
7
7
|
node.isBusy = false;
|
|
8
8
|
|
|
9
9
|
// Initialize runtime state
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
};
|
|
10
|
+
// Initialize state
|
|
11
|
+
node.name = config.name;
|
|
12
|
+
node.min = parseFloat(config.min);
|
|
13
|
+
node.max = parseFloat(config.max);
|
|
15
14
|
|
|
16
15
|
// Store last output value for status
|
|
17
16
|
let lastOutput = null;
|
|
@@ -21,7 +20,7 @@ module.exports = function(RED) {
|
|
|
21
20
|
|
|
22
21
|
// Guard against invalid message
|
|
23
22
|
if (!msg) {
|
|
24
|
-
|
|
23
|
+
utils.setStatusError(node, "invalid message");
|
|
25
24
|
if (done) done();
|
|
26
25
|
return;
|
|
27
26
|
}
|
|
@@ -32,7 +31,7 @@ module.exports = function(RED) {
|
|
|
32
31
|
// Check busy lock
|
|
33
32
|
if (node.isBusy) {
|
|
34
33
|
// Update status to let user know they are pushing too fast
|
|
35
|
-
|
|
34
|
+
utils.setStatusBusy(node, "busy - dropped msg");
|
|
36
35
|
if (done) done();
|
|
37
36
|
return;
|
|
38
37
|
}
|
|
@@ -47,21 +46,21 @@ module.exports = function(RED) {
|
|
|
47
46
|
utils.requiresEvaluation(config.minType)
|
|
48
47
|
? utils.evaluateNodeProperty(config.min, config.minType, node, msg)
|
|
49
48
|
.then(val => parseFloat(val))
|
|
50
|
-
: Promise.resolve(node.
|
|
49
|
+
: Promise.resolve(node.min),
|
|
51
50
|
);
|
|
52
51
|
|
|
53
52
|
evaluations.push(
|
|
54
53
|
utils.requiresEvaluation(config.maxType)
|
|
55
54
|
? utils.evaluateNodeProperty(config.max, config.maxType, node, msg)
|
|
56
55
|
.then(val => parseFloat(val))
|
|
57
|
-
: Promise.resolve(node.
|
|
56
|
+
: Promise.resolve(node.max),
|
|
58
57
|
);
|
|
59
58
|
|
|
60
59
|
const results = await Promise.all(evaluations);
|
|
61
60
|
|
|
62
61
|
// Update runtime with evaluated values
|
|
63
|
-
if (!isNaN(results[0])) node.
|
|
64
|
-
if (!isNaN(results[1])) node.
|
|
62
|
+
if (!isNaN(results[0])) node.min = results[0];
|
|
63
|
+
if (!isNaN(results[1])) node.max = results[1];
|
|
65
64
|
} catch (err) {
|
|
66
65
|
node.error(`Error evaluating properties: ${err.message}`);
|
|
67
66
|
if (done) done();
|
|
@@ -72,8 +71,8 @@ module.exports = function(RED) {
|
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
// Validate min and max
|
|
75
|
-
if (isNaN(node.
|
|
76
|
-
|
|
74
|
+
if (isNaN(node.min) || isNaN(node.max) || node.min > node.max) {
|
|
75
|
+
utils.setStatusError(node, `invalid min/max`);
|
|
77
76
|
if (done) done();
|
|
78
77
|
return;
|
|
79
78
|
}
|
|
@@ -81,32 +80,32 @@ module.exports = function(RED) {
|
|
|
81
80
|
// Handle context updates
|
|
82
81
|
if (msg.hasOwnProperty("context")) {
|
|
83
82
|
if (!msg.hasOwnProperty("payload")) {
|
|
84
|
-
|
|
83
|
+
utils.setStatusError(node, `missing payload for ${msg.context}`);
|
|
85
84
|
if (done) done();
|
|
86
85
|
return;
|
|
87
86
|
}
|
|
88
87
|
const value = parseFloat(msg.payload);
|
|
89
88
|
if (isNaN(value) || value < 0) {
|
|
90
|
-
|
|
89
|
+
utils.setStatusError(node, `invalid ${msg.context}`);
|
|
91
90
|
if (done) done();
|
|
92
91
|
return;
|
|
93
92
|
}
|
|
94
93
|
if (msg.context === "min") {
|
|
95
|
-
if (value < node.
|
|
96
|
-
node.
|
|
97
|
-
|
|
94
|
+
if (value < node.max) {
|
|
95
|
+
node.min = value;
|
|
96
|
+
utils.setStatusOK(node, `min: ${node.min}`);
|
|
98
97
|
} else {
|
|
99
|
-
|
|
98
|
+
utils.setStatusWarn(node, `Context update aborted. Payload more than max`);
|
|
100
99
|
}
|
|
101
100
|
} else if (msg.context === "max") {
|
|
102
|
-
if (value > node.
|
|
103
|
-
node.
|
|
104
|
-
|
|
101
|
+
if (value > node.min) {
|
|
102
|
+
node.max = value;
|
|
103
|
+
utils.setStatusOK(node, `max: ${node.max}`);
|
|
105
104
|
} else {
|
|
106
|
-
|
|
105
|
+
utils.setStatusWarn(node, `Context update aborted. Payload less than min`);
|
|
107
106
|
}
|
|
108
107
|
} else {
|
|
109
|
-
|
|
108
|
+
utils.setStatusWarn(node, "unknown context");
|
|
110
109
|
if (done) done();
|
|
111
110
|
return;
|
|
112
111
|
}
|
|
@@ -116,28 +115,30 @@ module.exports = function(RED) {
|
|
|
116
115
|
|
|
117
116
|
// Validate input payload
|
|
118
117
|
if (!msg.hasOwnProperty("payload")) {
|
|
119
|
-
|
|
118
|
+
utils.setStatusError(node, "missing payload");
|
|
120
119
|
if (done) done();
|
|
121
120
|
return;
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
|
|
123
|
+
const numVal = utils.validateNumericPayload(msg.payload);
|
|
124
|
+
if (!numVal.valid) {
|
|
125
|
+
utils.setStatusError(node, numVal.error);
|
|
127
126
|
if (done) done();
|
|
128
127
|
return;
|
|
129
128
|
}
|
|
129
|
+
const inputValue = numVal.value;
|
|
130
130
|
|
|
131
131
|
// Clamp input to [min, max]
|
|
132
|
-
const outputValue = Math.min(Math.max(inputValue, node.
|
|
132
|
+
const outputValue = Math.min(Math.max(inputValue, node.min), node.max);
|
|
133
133
|
|
|
134
134
|
// Update status and send output
|
|
135
135
|
msg.payload = outputValue;
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
136
|
+
const statusText = `in: ${inputValue.toFixed(2)}, out: ${outputValue.toFixed(2)}`;
|
|
137
|
+
if (lastOutput === outputValue) {
|
|
138
|
+
utils.setStatusUnchanged(node, statusText);
|
|
139
|
+
} else {
|
|
140
|
+
utils.setStatusChanged(node, statusText);
|
|
141
|
+
}
|
|
141
142
|
lastOutput = outputValue;
|
|
142
143
|
send(msg);
|
|
143
144
|
|