@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/units-block.js
CHANGED
|
@@ -1,58 +1,50 @@
|
|
|
1
1
|
|
|
2
2
|
module.exports = function(RED) {
|
|
3
|
+
const utils = require('./utils')(RED);
|
|
3
4
|
function UnitsBlockNode(config) {
|
|
4
5
|
RED.nodes.createNode(this, config);
|
|
5
6
|
const node = this;
|
|
6
7
|
|
|
7
8
|
// Initialize runtime state
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
// Initialize state
|
|
10
|
+
node.name = config.name;
|
|
11
|
+
node.inputProperty = config.inputProperty || "payload";
|
|
12
|
+
node.unit = config.unit;
|
|
12
13
|
|
|
13
14
|
node.on("input", function(msg, send, done) {
|
|
14
15
|
send = send || function() { node.send.apply(node, arguments); };
|
|
15
16
|
|
|
16
17
|
// Validate input
|
|
17
18
|
if (!msg || typeof msg !== "object" || !msg.hasOwnProperty("payload")) {
|
|
18
|
-
|
|
19
|
+
utils.setStatusError(node, "invalid message");
|
|
19
20
|
|
|
20
21
|
if (done) done();
|
|
21
22
|
return;
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
try {
|
|
25
|
-
// Handle configuration messages
|
|
26
|
-
if (msg.hasOwnProperty("context")) {
|
|
27
|
-
// Configuration handling
|
|
28
|
-
if (msg.context === "unit") {
|
|
29
|
-
if (typeof msg.payload === "string") {
|
|
30
|
-
node.runtime.unit = msg.payload;
|
|
31
|
-
node.status({ fill: "green", shape: "dot", text: `unit: ${node.runtime.unit}` });
|
|
32
|
-
} else {
|
|
33
|
-
node.status({ fill: "red", shape: "ring", text: "invalid unit" });
|
|
34
|
-
}
|
|
35
|
-
if (done) done();
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Handle unknown context
|
|
40
|
-
if (msg.context && msg.context !== "unit") {
|
|
41
|
-
node.status({ fill: "yellow", shape: "ring", text: "unknown context" });
|
|
42
|
-
// Continue processing as passthrough
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
26
|
// Process input
|
|
47
|
-
|
|
27
|
+
let input;
|
|
28
|
+
try {
|
|
29
|
+
input = RED.util.getMessageProperty(msg, node.inputProperty);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
input = undefined;
|
|
32
|
+
}
|
|
33
|
+
if (input === undefined) {
|
|
34
|
+
utils.setStatusError(node, "missing or invalid input property");
|
|
35
|
+
if (done) done();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const payloadPreview = input !== null ? (typeof input === "number" ? input.toFixed(2) : JSON.stringify(input).slice(0, 20)) : "none";
|
|
48
40
|
|
|
49
|
-
|
|
41
|
+
utils.setStatusOK(node, `in: ${payloadPreview} unit: ${node.unit !== "" ? node.unit : "none"}`);
|
|
50
42
|
|
|
51
|
-
msg.units = node.
|
|
43
|
+
msg.units = node.unit;
|
|
52
44
|
send(msg);
|
|
53
45
|
if (done) done();
|
|
54
46
|
} catch (error) {
|
|
55
|
-
|
|
47
|
+
utils.setStatusError(node, "processing error");
|
|
56
48
|
|
|
57
49
|
if (done) done(error);
|
|
58
50
|
return;
|
package/nodes/utils.js
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
module.exports = function(RED) {
|
|
2
|
-
|
|
2
|
+
// Shared state across all nodes using this utils module
|
|
3
|
+
// Registries set attached to RED object to ensure a true singleton
|
|
4
|
+
// across multiple invocations of this module function.
|
|
5
|
+
if (!RED._bldgblocks_registries) {
|
|
6
|
+
RED._bldgblocks_registries = new Set();
|
|
7
|
+
}
|
|
8
|
+
const registries = RED._bldgblocks_registries;
|
|
9
|
+
|
|
10
|
+
function registerRegistryNode(node) {
|
|
11
|
+
registries.add(node);
|
|
12
|
+
node.on("close", () => registries.delete(node));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function lookupPointMetadata(pointId) {
|
|
16
|
+
const pid = parseInt(pointId);
|
|
17
|
+
if (isNaN(pid)) return null;
|
|
18
|
+
|
|
19
|
+
for (const reg of registries) {
|
|
20
|
+
if (reg.points && reg.points.has(pid)) {
|
|
21
|
+
return reg.points.get(pid);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function requiresEvaluation(type) { return type === "flow" || type === "global" || type === "msg" || type === "jsonata"; }
|
|
3
28
|
|
|
4
29
|
// Safe evaluation helper (promisified)
|
|
5
30
|
function evaluateNodeProperty(value, type, node, msg) {
|
|
@@ -78,7 +103,172 @@ module.exports = function(RED) {
|
|
|
78
103
|
}
|
|
79
104
|
return { value, priority };
|
|
80
105
|
}
|
|
81
|
-
|
|
106
|
+
|
|
107
|
+
// ============================================================================
|
|
108
|
+
// Status Helper Functions
|
|
109
|
+
// ============================================================================
|
|
110
|
+
// Simplified status reporting with consistent fill/shape/text protocol
|
|
111
|
+
// Usage: utils.setStatusOK(node, "sum: 42.5");
|
|
112
|
+
|
|
113
|
+
function setStatusOK(node, text) {
|
|
114
|
+
node.status({ fill: "green", shape: "dot", text });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function setStatusChanged(node, text) {
|
|
118
|
+
node.status({ fill: "blue", shape: "dot", text });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function setStatusUnchanged(node, text) {
|
|
122
|
+
node.status({ fill: "blue", shape: "ring", text });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function setStatusError(node, text) {
|
|
126
|
+
node.status({ fill: "red", shape: "ring", text });
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function setStatusWarn(node, text) {
|
|
130
|
+
node.status({ fill: "yellow", shape: "ring", text });
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function setStatusBusy(node, text = "busy - dropped msg") {
|
|
134
|
+
node.status({ fill: "yellow", shape: "ring", text });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ============================================================================
|
|
138
|
+
// Validation Helper Functions
|
|
139
|
+
// ============================================================================
|
|
140
|
+
// Common validation patterns used across control blocks
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Validate that msg exists and contains required properties
|
|
144
|
+
* @param {Object} msg - The message object to validate
|
|
145
|
+
* @param {string[]} requiredProps - Array of required property names (e.g., ["payload"])
|
|
146
|
+
* @returns {boolean} true if valid, false otherwise
|
|
147
|
+
*/
|
|
148
|
+
function validateMessage(msg, requiredProps = []) {
|
|
149
|
+
if (!msg || typeof msg !== 'object') {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
return requiredProps.every(prop => msg.hasOwnProperty(prop));
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Validate and parse numeric payload
|
|
157
|
+
* @param {*} payload - The payload to validate
|
|
158
|
+
* @param {Object} options - Validation options {min, max, allowZero}
|
|
159
|
+
* @returns {Object} {valid: boolean, value: number|null, error: string|null}
|
|
160
|
+
*/
|
|
161
|
+
function validateNumericPayload(payload, options = {}) {
|
|
162
|
+
const { min = -Infinity, max = Infinity, allowZero = true } = options;
|
|
163
|
+
|
|
164
|
+
if (payload === null || payload === undefined) {
|
|
165
|
+
return { valid: false, value: null, error: "missing payload" };
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const value = parseFloat(payload);
|
|
169
|
+
|
|
170
|
+
if (isNaN(value)) {
|
|
171
|
+
return { valid: false, value: null, error: "invalid numeric payload" };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!allowZero && value === 0) {
|
|
175
|
+
return { valid: false, value: null, error: "payload cannot be zero" };
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (value < min || value > max) {
|
|
179
|
+
return { valid: false, value: null, error: `payload out of range [${min}, ${max}]` };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return { valid: true, value, error: null };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Validate slot index for multi-slot blocks
|
|
187
|
+
* @param {string|number} slotId - The slot identifier (e.g., "in1", "in2")
|
|
188
|
+
* @param {number} maxSlots - Maximum number of slots available
|
|
189
|
+
* @returns {Object} {valid: boolean, index: number|null, error: string|null}
|
|
190
|
+
*/
|
|
191
|
+
function validateSlotIndex(slotId, maxSlots) {
|
|
192
|
+
if (!slotId) {
|
|
193
|
+
return { valid: false, index: null, error: "missing slot identifier" };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Handle numeric string (e.g., "1") or prefixed (e.g., "in1")
|
|
197
|
+
let indexStr = slotId;
|
|
198
|
+
if (typeof slotId === 'string' && slotId.match(/^[a-z]+(\d+)$/i)) {
|
|
199
|
+
indexStr = slotId.match(/\d+/)[0];
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const index = parseInt(indexStr, 10);
|
|
203
|
+
|
|
204
|
+
if (isNaN(index)) {
|
|
205
|
+
return { valid: false, index: null, error: `invalid slot index: ${slotId}` };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (index < 1 || index > maxSlots) {
|
|
209
|
+
return { valid: false, index: null, error: `slot out of range [1, ${maxSlots}]` };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return { valid: true, index, error: null };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Validate boolean payload
|
|
217
|
+
* @param {*} payload - The payload to validate
|
|
218
|
+
* @returns {Object} {valid: boolean, value: boolean|null, error: string|null}
|
|
219
|
+
*/
|
|
220
|
+
function validateBoolean(payload) {
|
|
221
|
+
if (payload === null || payload === undefined) {
|
|
222
|
+
return { valid: false, value: null, error: "missing boolean payload" };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (typeof payload === 'boolean') {
|
|
226
|
+
return { valid: true, value: payload, error: null };
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (typeof payload === 'string') {
|
|
230
|
+
const lower = payload.toLowerCase();
|
|
231
|
+
if (lower === 'true' || lower === '1' || lower === 'on') {
|
|
232
|
+
return { valid: true, value: true, error: null };
|
|
233
|
+
}
|
|
234
|
+
if (lower === 'false' || lower === '0' || lower === 'off') {
|
|
235
|
+
return { valid: true, value: false, error: null };
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (typeof payload === 'number') {
|
|
240
|
+
return { valid: true, value: payload !== 0, error: null };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return { valid: false, value: null, error: "invalid boolean payload" };
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Validate integer within range
|
|
248
|
+
* @param {*} payload - The payload to validate
|
|
249
|
+
* @param {Object} options - Validation options {min, max}
|
|
250
|
+
* @returns {Object} {valid: boolean, value: number|null, error: string|null}
|
|
251
|
+
*/
|
|
252
|
+
function validateIntRange(payload, options = {}) {
|
|
253
|
+
const { min = -Infinity, max = Infinity } = options;
|
|
254
|
+
|
|
255
|
+
if (payload === null || payload === undefined) {
|
|
256
|
+
return { valid: false, value: null, error: "missing payload" };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const value = parseInt(payload, 10);
|
|
260
|
+
|
|
261
|
+
if (isNaN(value)) {
|
|
262
|
+
return { valid: false, value: null, error: "invalid integer payload" };
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
if (value < min || value > max) {
|
|
266
|
+
return { valid: false, value: null, error: `value out of range [${min}, ${max}]` };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
return { valid: true, value, error: null };
|
|
270
|
+
}
|
|
271
|
+
|
|
82
272
|
// Usage:
|
|
83
273
|
// const utils = require('./utils')(RED);
|
|
84
274
|
|
|
@@ -89,6 +279,19 @@ module.exports = function(RED) {
|
|
|
89
279
|
sendSuccess,
|
|
90
280
|
getGlobalState,
|
|
91
281
|
setGlobalState,
|
|
92
|
-
getHighestPriority
|
|
282
|
+
getHighestPriority,
|
|
283
|
+
setStatusOK,
|
|
284
|
+
setStatusChanged,
|
|
285
|
+
setStatusUnchanged,
|
|
286
|
+
setStatusError,
|
|
287
|
+
setStatusWarn,
|
|
288
|
+
setStatusBusy,
|
|
289
|
+
validateMessage,
|
|
290
|
+
validateNumericPayload,
|
|
291
|
+
validateSlotIndex,
|
|
292
|
+
validateBoolean,
|
|
293
|
+
validateIntRange,
|
|
294
|
+
registerRegistryNode,
|
|
295
|
+
lookupPointMetadata
|
|
93
296
|
};
|
|
94
297
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bldgblocks/node-red-contrib-control",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.36",
|
|
4
4
|
"description": "Sedona-inspired control nodes for Node-RED",
|
|
5
5
|
"keywords": [ "node-red", "sedona", "control", "hvac" ],
|
|
6
6
|
"files": ["nodes/*.js", "nodes/*.html"],
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"frequency-block": "nodes/frequency-block.js",
|
|
34
34
|
"hysteresis-block": "nodes/hysteresis-block.js",
|
|
35
35
|
"interpolate-block": "nodes/interpolate-block.js",
|
|
36
|
+
"join": "nodes/join.js",
|
|
36
37
|
"latch-block": "nodes/latch-block.js",
|
|
37
38
|
"load-sequence-block": "nodes/load-sequence-block.js",
|
|
38
39
|
"max-block": "nodes/max-block.js",
|
|
@@ -66,11 +67,18 @@
|
|
|
66
67
|
"global-setter": "nodes/global-setter.js",
|
|
67
68
|
"history-collector": "nodes/history-collector.js",
|
|
68
69
|
"history-config": "nodes/history-config.js",
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"network-
|
|
72
|
-
"network-
|
|
73
|
-
|
|
70
|
+
"history-service": "nodes/history-service.js",
|
|
71
|
+
"history-buffer": "nodes/history-buffer.js",
|
|
72
|
+
"network-service-read": "nodes/network-service-read.js",
|
|
73
|
+
"network-service-write": "nodes/network-service-write.js",
|
|
74
|
+
"network-service-registry": "nodes/network-service-registry.js",
|
|
75
|
+
"network-service-bridge": "nodes/network-service-bridge.js",
|
|
76
|
+
"network-point-register": "nodes/network-point-register.js",
|
|
77
|
+
"network-point-read": "nodes/network-point-read.js",
|
|
78
|
+
"network-point-write": "nodes/network-point-write.js",
|
|
79
|
+
"alarm-collector": "nodes/alarm-collector.js",
|
|
80
|
+
"alarm-config": "nodes/alarm-config.js",
|
|
81
|
+
"alarm-service": "nodes/alarm-service.js"
|
|
74
82
|
}
|
|
75
83
|
},
|
|
76
84
|
"author": "buildingblocks",
|
package/nodes/network-read.html
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
<script type="text/html" data-template-name="network-read">
|
|
2
|
-
<div class="form-row">
|
|
3
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
4
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
|
5
|
-
</div>
|
|
6
|
-
|
|
7
|
-
<div class="form-row">
|
|
8
|
-
<label for="node-input-registry"><i class="fa fa-book"></i> Registry</label>
|
|
9
|
-
<input type="text" id="node-input-registry">
|
|
10
|
-
</div>
|
|
11
|
-
|
|
12
|
-
<div class="form-tips">
|
|
13
|
-
<b>Input Payload Format:</b><br>
|
|
14
|
-
<pre>
|
|
15
|
-
{
|
|
16
|
-
"action": "read",
|
|
17
|
-
"pointId": 101
|
|
18
|
-
}
|
|
19
|
-
</pre>
|
|
20
|
-
</div>
|
|
21
|
-
</script>
|
|
22
|
-
|
|
23
|
-
<script type="text/javascript">
|
|
24
|
-
RED.nodes.registerType('network-read', {
|
|
25
|
-
category: 'bldgblocks network',
|
|
26
|
-
color: '#3090C7',
|
|
27
|
-
defaults: {
|
|
28
|
-
name: { value: "" },
|
|
29
|
-
registry: { value: "", type: "network-point-registry", required: true }
|
|
30
|
-
},
|
|
31
|
-
inputs: 1,
|
|
32
|
-
outputs: 1,
|
|
33
|
-
icon: "font-awesome/fa-database",
|
|
34
|
-
label: function() {
|
|
35
|
-
return "network read";
|
|
36
|
-
},
|
|
37
|
-
paletteLabel: "network read",
|
|
38
|
-
oneditprepare: function() {
|
|
39
|
-
const nodeId = this.id;
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
</script>
|
|
43
|
-
|
|
44
|
-
<script type="text/markdown" data-help-name="network-read">
|
|
45
|
-
Reads a network point by pointId.
|
|
46
|
-
|
|
47
|
-
### Input
|
|
48
|
-
: action (string) : Not used by the node, used for routing to the correct node over the network when received.
|
|
49
|
-
: pointId (number) : The integer ID of the point.
|
|
50
|
-
|
|
51
|
-
### Output
|
|
52
|
-
: payload (object) : Global data object
|
|
53
|
-
|
|
54
|
-
### Details
|
|
55
|
-
|
|
56
|
-
</script>
|
package/nodes/network-write.html
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
<script type="text/html" data-template-name="network-write">
|
|
2
|
-
<div class="form-row">
|
|
3
|
-
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
4
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
|
5
|
-
</div>
|
|
6
|
-
<div class="form-row">
|
|
7
|
-
<label for="node-input-registry"><i class="fa fa-book"></i> Registry</label>
|
|
8
|
-
<input type="text" id="node-input-registry">
|
|
9
|
-
</div>
|
|
10
|
-
|
|
11
|
-
<div class="form-tips">
|
|
12
|
-
<b>Input Payload Format:</b><br>
|
|
13
|
-
<pre>
|
|
14
|
-
{
|
|
15
|
-
"action": "write",
|
|
16
|
-
"pointId": 101,
|
|
17
|
-
"priority": 8,
|
|
18
|
-
"value": 75.5 // or null || "null" to release
|
|
19
|
-
}
|
|
20
|
-
</pre>
|
|
21
|
-
</div>
|
|
22
|
-
</script>
|
|
23
|
-
|
|
24
|
-
<script type="text/javascript">
|
|
25
|
-
RED.nodes.registerType('network-write', {
|
|
26
|
-
category: 'bldgblocks network',
|
|
27
|
-
color: '#3090C7',
|
|
28
|
-
defaults: {
|
|
29
|
-
name: { value: "" },
|
|
30
|
-
registry: { value: "", type: "network-point-registry", required: true }
|
|
31
|
-
},
|
|
32
|
-
inputs: 1,
|
|
33
|
-
outputs: 1,
|
|
34
|
-
icon: "font-awesome/fa-list-ol",
|
|
35
|
-
label: function() {
|
|
36
|
-
return this.name || "network write";
|
|
37
|
-
},
|
|
38
|
-
paletteLabel: "network write",
|
|
39
|
-
oneditprepare: function() {
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
</script>
|
|
44
|
-
|
|
45
|
-
<script type="text/markdown" data-help-name="network-write">
|
|
46
|
-
Writes network commands to Global Variables using the Priority Array logic.
|
|
47
|
-
|
|
48
|
-
### Input
|
|
49
|
-
: payload (object) : A command object containing
|
|
50
|
-
* `action` (string): Not used by the node, used for routing to the correct node over the network when received.
|
|
51
|
-
* `pointId` (number): The integer ID of the point.
|
|
52
|
-
* `priority` (number): The priority level (1-16) to write to.
|
|
53
|
-
* `value` (any): The value to set. Send `null` to relinquish (clear) this priority level.
|
|
54
|
-
|
|
55
|
-
### Output
|
|
56
|
-
: payload (object) : Confirmation object containing status, pointId, and the new calculated "Winner" value.
|
|
57
|
-
|
|
58
|
-
### Details
|
|
59
|
-
This node acts as the inbound gateway.
|
|
60
|
-
1. It looks up the `pointId` in the selected **Registry** to find the corresponding Global Variable path.
|
|
61
|
-
2. It fetches the current State Object.
|
|
62
|
-
3. It updates the specific slot in the `priority` array based on the command.
|
|
63
|
-
4. It recalculates the "Present Value" (highest priority active).
|
|
64
|
-
5. It saves the Global Variable and emits an update event, triggering any reactive Getters immediately.
|
|
65
|
-
</script>
|