@bldgblocks/node-red-contrib-control 0.1.33 → 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 +74 -67
- package/nodes/global-setter.html +1 -1
- package/nodes/global-setter.js +168 -188
- 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-point-register.js +126 -0
- 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-service-read.js +58 -0
- 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-service-write.js +83 -0
- 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 +275 -3
- package/package.json +14 -6
- package/nodes/network-read.html +0 -56
- package/nodes/network-read.js +0 -59
- package/nodes/network-register.js +0 -161
- package/nodes/network-write.html +0 -64
- package/nodes/network-write.js +0 -126
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) {
|
|
@@ -14,12 +39,259 @@ module.exports = function(RED) {
|
|
|
14
39
|
}
|
|
15
40
|
});
|
|
16
41
|
}
|
|
17
|
-
|
|
42
|
+
|
|
43
|
+
function sendError(node, msg, done, text, pointId = null) {
|
|
44
|
+
node.status({ fill: "red", shape: "dot", text: text });
|
|
45
|
+
|
|
46
|
+
// Only attempt to send if a message object exists
|
|
47
|
+
if (msg) {
|
|
48
|
+
msg.status = {
|
|
49
|
+
code: "error",
|
|
50
|
+
pointId: pointId || msg.pointId || "unknown",
|
|
51
|
+
message: text
|
|
52
|
+
};
|
|
53
|
+
node.send(msg);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (done) done();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function sendSuccess(node, msg, done, text, pointId, shape = "ring") {
|
|
60
|
+
node.status({ fill: "blue", shape: shape, text: text });
|
|
61
|
+
|
|
62
|
+
if (msg) {
|
|
63
|
+
msg.status = {
|
|
64
|
+
code: "ok",
|
|
65
|
+
pointId: pointId,
|
|
66
|
+
message: text
|
|
67
|
+
};
|
|
68
|
+
node.send(msg);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (done) done();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function getGlobalState(node, path, store) {
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
node.context().global.get(path, store, (err, data) => {
|
|
77
|
+
if (err) reject(err);
|
|
78
|
+
else resolve(data);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function setGlobalState(node, path, store, value) {
|
|
84
|
+
return new Promise((resolve, reject) => {
|
|
85
|
+
node.context().global.set(path, value, store, (err) => {
|
|
86
|
+
if (err) reject(err);
|
|
87
|
+
else resolve();
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function getHighestPriority(state) {
|
|
93
|
+
let value = state.defaultValue;
|
|
94
|
+
let priority = 'default';
|
|
95
|
+
|
|
96
|
+
for (let i = 1; i <= 16; i++) {
|
|
97
|
+
// Check strictly for undefined/null, allow 0 or false
|
|
98
|
+
if (state.priority[i] !== undefined && state.priority[i] !== null) {
|
|
99
|
+
value = state.priority[i];
|
|
100
|
+
priority = String(i);
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return { value, priority };
|
|
105
|
+
}
|
|
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
|
+
|
|
18
272
|
// Usage:
|
|
19
273
|
// const utils = require('./utils')(RED);
|
|
20
274
|
|
|
21
275
|
return {
|
|
22
276
|
requiresEvaluation,
|
|
23
|
-
evaluateNodeProperty
|
|
277
|
+
evaluateNodeProperty,
|
|
278
|
+
sendError,
|
|
279
|
+
sendSuccess,
|
|
280
|
+
getGlobalState,
|
|
281
|
+
setGlobalState,
|
|
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
|
|
24
296
|
};
|
|
25
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
|
-
: payload (object) : A command object containing
|
|
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-read.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
module.exports = function(RED) {
|
|
2
|
-
function NetworkReadNode(config) {
|
|
3
|
-
RED.nodes.createNode(this, config);
|
|
4
|
-
const node = this;
|
|
5
|
-
|
|
6
|
-
node.registry = RED.nodes.getNode(config.registry);
|
|
7
|
-
|
|
8
|
-
node.on("input", function(msg, send, done) {
|
|
9
|
-
send = send || function() { node.send.apply(node, arguments); };
|
|
10
|
-
|
|
11
|
-
let currentPath = null;
|
|
12
|
-
let currentStore = "default";
|
|
13
|
-
|
|
14
|
-
if (node.registry) {
|
|
15
|
-
let currentEntry = node.registry.lookup(msg.pointId);
|
|
16
|
-
|
|
17
|
-
if (!currentEntry) {
|
|
18
|
-
node.status({ fill: "red", shape: "ring", text: `Requested pointId not registered` });
|
|
19
|
-
msg.status = { status: "fail", pointId: msg.pointId, error: `Point Not Registered: ${msg.pointId}` };
|
|
20
|
-
node.send(msg);
|
|
21
|
-
if (done) done();
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
currentPath = currentEntry.path;
|
|
26
|
-
currentStore = currentEntry.store || "default";
|
|
27
|
-
let globalData = node.context().global.get(currentPath, currentStore) || {};
|
|
28
|
-
|
|
29
|
-
if (globalData === null || Object.keys(globalData).length === 0) {
|
|
30
|
-
node.status({ fill: "red", shape: "ring", text: `Global data doesn't exist, waiting...` });
|
|
31
|
-
msg.status = { status: "fail", pointId: msg.pointId, error: `Point Not Found: ${msg.pointId}` };
|
|
32
|
-
node.send(msg);
|
|
33
|
-
if (done) done();
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
msg = { ...globalData };
|
|
38
|
-
node.status({ fill: "blue", shape: "ring", text: `Read (${currentStore})::${msg.metadata.name}::${msg.network.pointId} ` });
|
|
39
|
-
msg.status = { status: "ok", pointId: msg.network.pointId, message: `Data Found. pointId: ${msg.network.pointId} value: ${msg.value}` };
|
|
40
|
-
node.send(msg);
|
|
41
|
-
|
|
42
|
-
if (done) done();
|
|
43
|
-
} else {
|
|
44
|
-
node.status({ fill: "red", shape: "ring", text: `Registry not found. Create config node.` });
|
|
45
|
-
if (done) done();
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// Cleanup
|
|
51
|
-
node.on('close', function(removed, done) {
|
|
52
|
-
if (removed && node.registry) {
|
|
53
|
-
node.registry.unregister(node.pointId, node.id);
|
|
54
|
-
}
|
|
55
|
-
done();
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
RED.nodes.registerType("network-read", NetworkReadNode);
|
|
59
|
-
}
|