@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.
Files changed (113) hide show
  1. package/nodes/accumulate-block.html +18 -8
  2. package/nodes/accumulate-block.js +39 -44
  3. package/nodes/add-block.html +1 -1
  4. package/nodes/add-block.js +18 -11
  5. package/nodes/alarm-collector.html +260 -0
  6. package/nodes/alarm-collector.js +292 -0
  7. package/nodes/alarm-config.html +129 -0
  8. package/nodes/alarm-config.js +126 -0
  9. package/nodes/alarm-service.html +96 -0
  10. package/nodes/alarm-service.js +142 -0
  11. package/nodes/analog-switch-block.js +25 -36
  12. package/nodes/and-block.js +44 -15
  13. package/nodes/average-block.js +46 -41
  14. package/nodes/boolean-switch-block.js +10 -28
  15. package/nodes/boolean-to-number-block.html +18 -5
  16. package/nodes/boolean-to-number-block.js +24 -16
  17. package/nodes/cache-block.js +24 -37
  18. package/nodes/call-status-block.html +91 -32
  19. package/nodes/call-status-block.js +398 -115
  20. package/nodes/changeover-block.html +5 -0
  21. package/nodes/changeover-block.js +167 -162
  22. package/nodes/comment-block.html +1 -1
  23. package/nodes/comment-block.js +14 -9
  24. package/nodes/compare-block.html +14 -4
  25. package/nodes/compare-block.js +23 -18
  26. package/nodes/contextual-label-block.html +5 -0
  27. package/nodes/contextual-label-block.js +6 -16
  28. package/nodes/convert-block.html +25 -39
  29. package/nodes/convert-block.js +31 -16
  30. package/nodes/count-block.html +11 -5
  31. package/nodes/count-block.js +34 -32
  32. package/nodes/delay-block.js +58 -53
  33. package/nodes/divide-block.js +43 -45
  34. package/nodes/edge-block.html +17 -10
  35. package/nodes/edge-block.js +43 -41
  36. package/nodes/enum-switch-block.js +6 -6
  37. package/nodes/frequency-block.html +6 -1
  38. package/nodes/frequency-block.js +64 -74
  39. package/nodes/global-getter.html +51 -15
  40. package/nodes/global-getter.js +74 -67
  41. package/nodes/global-setter.html +1 -1
  42. package/nodes/global-setter.js +168 -188
  43. package/nodes/history-buffer.html +96 -0
  44. package/nodes/history-buffer.js +461 -0
  45. package/nodes/history-collector.html +29 -1
  46. package/nodes/history-collector.js +37 -16
  47. package/nodes/history-config.html +13 -1
  48. package/nodes/history-service.html +84 -0
  49. package/nodes/history-service.js +52 -0
  50. package/nodes/hysteresis-block.html +5 -0
  51. package/nodes/hysteresis-block.js +13 -16
  52. package/nodes/interpolate-block.html +20 -2
  53. package/nodes/interpolate-block.js +39 -50
  54. package/nodes/join.html +78 -0
  55. package/nodes/join.js +78 -0
  56. package/nodes/latch-block.js +12 -14
  57. package/nodes/load-sequence-block.js +102 -110
  58. package/nodes/max-block.js +26 -26
  59. package/nodes/memory-block.js +57 -58
  60. package/nodes/min-block.js +26 -25
  61. package/nodes/minmax-block.js +35 -34
  62. package/nodes/modulo-block.js +45 -43
  63. package/nodes/multiply-block.js +43 -41
  64. package/nodes/negate-block.html +17 -7
  65. package/nodes/negate-block.js +25 -19
  66. package/nodes/network-point-read.html +128 -0
  67. package/nodes/network-point-read.js +230 -0
  68. package/nodes/{network-register.html → network-point-register.html} +94 -7
  69. package/nodes/network-point-register.js +126 -0
  70. package/nodes/network-point-write.html +149 -0
  71. package/nodes/network-point-write.js +222 -0
  72. package/nodes/network-service-bridge.html +131 -0
  73. package/nodes/network-service-bridge.js +376 -0
  74. package/nodes/network-service-read.html +81 -0
  75. package/nodes/network-service-read.js +58 -0
  76. package/nodes/{network-point-registry.html → network-service-registry.html} +19 -4
  77. package/nodes/{network-point-registry.js → network-service-registry.js} +7 -2
  78. package/nodes/network-service-write.html +89 -0
  79. package/nodes/network-service-write.js +83 -0
  80. package/nodes/nullify-block.js +13 -15
  81. package/nodes/on-change-block.html +17 -9
  82. package/nodes/on-change-block.js +49 -46
  83. package/nodes/oneshot-block.html +13 -10
  84. package/nodes/oneshot-block.js +57 -75
  85. package/nodes/or-block.js +44 -15
  86. package/nodes/pid-block.html +54 -4
  87. package/nodes/pid-block.js +459 -248
  88. package/nodes/priority-block.js +24 -35
  89. package/nodes/rate-limit-block.js +70 -72
  90. package/nodes/rate-of-change-block.html +33 -14
  91. package/nodes/rate-of-change-block.js +74 -62
  92. package/nodes/round-block.html +14 -9
  93. package/nodes/round-block.js +32 -25
  94. package/nodes/saw-tooth-wave-block.js +49 -76
  95. package/nodes/scale-range-block.html +12 -6
  96. package/nodes/scale-range-block.js +46 -39
  97. package/nodes/sine-wave-block.js +49 -57
  98. package/nodes/string-builder-block.js +6 -6
  99. package/nodes/subtract-block.js +38 -34
  100. package/nodes/thermistor-block.js +44 -44
  101. package/nodes/tick-tock-block.js +32 -32
  102. package/nodes/time-sequence-block.js +30 -42
  103. package/nodes/triangle-wave-block.js +49 -69
  104. package/nodes/tstat-block.js +34 -44
  105. package/nodes/units-block.html +90 -69
  106. package/nodes/units-block.js +22 -30
  107. package/nodes/utils.js +275 -3
  108. package/package.json +14 -6
  109. package/nodes/network-read.html +0 -56
  110. package/nodes/network-read.js +0 -59
  111. package/nodes/network-register.js +0 -161
  112. package/nodes/network-write.html +0 -64
  113. package/nodes/network-write.js +0 -126
@@ -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
- node.runtime = {
9
- name: config.name,
10
- unit: config.unit
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
- node.status({ fill: "red", shape: "ring", text: "invalid message" });
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
- const payloadPreview = msg.payload !== null ? (typeof msg.payload === "number" ? msg.payload.toFixed(2) : JSON.stringify(msg.payload).slice(0, 20)) : "none";
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
- node.status({ fill: "blue", shape: "dot", text: `in: ${payloadPreview} unit: ${node.runtime.unit !== "" ? node.runtime.unit : "none"}` });
41
+ utils.setStatusOK(node, `in: ${payloadPreview} unit: ${node.unit !== "" ? node.unit : "none"}`);
50
42
 
51
- msg.units = node.runtime.unit;
43
+ msg.units = node.unit;
52
44
  send(msg);
53
45
  if (done) done();
54
46
  } catch (error) {
55
- node.status({ fill: "red", shape: "ring", text: "processing error" });
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
- function requiresEvaluation(type) { return type === "flow" || type === "global" || type === "msg"; }
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.33",
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
- "network-read": "nodes/network-read.js",
70
- "network-register": "nodes/network-register.js",
71
- "network-write": "nodes/network-write.js",
72
- "network-point-registry": "nodes/network-point-registry.js"
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",
@@ -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>
@@ -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
- }