node-red-contrib-uos-nats 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -80,7 +80,12 @@ Publishes your own data to the Data Hub.
80
80
  - **Provider ID:** Leave empty to use your Client ID (Recommended).
81
81
  - **Input:** Send a JSON object: `{ "machine": { "status": "active" } }`.
82
82
  - **Auto-Discovery:** Automatically creates variable definitions based on your JSON structure.
83
- - **Keep-Alive:** Configurable interval (Default: 300s / 5min) to refresh definitions, preventing timeouts (Provider disappearance) while minimizing traffic.
83
+ - **Bi-Directional:** Enable "Allow external writes" to let other apps write to your variables. Changes are emitted continuously on the **2nd Output**.
84
+ - **Keep-Alive:** Configurable interval (Default: 300s / 5min).
85
+ - **Quality & Timestamp:** Override metadata by sending an object:
86
+ ```json
87
+ { "temp": { "value": 23.5, "quality": "BAD", "timestamp": 1712000000 } }
88
+ ```
84
89
 
85
90
  ---
86
91
 
@@ -156,4 +156,17 @@
156
156
  }
157
157
  }</pre>
158
158
  <p>becomes variables <code>machine.status</code> and <code>machine.details.temp</code> in the Data Hub.</p>
159
+
160
+ <h3>Advanced: Manual Quality & Timestamp</h3>
161
+ <p>You can override the quality and timestamp by sending a value object instead of a raw value:</p>
162
+ <pre>{
163
+ "machine": {
164
+ "temp": {
165
+ "value": 45.2,
166
+ "quality": "BAD",
167
+ "timestamp": 1712000000000
168
+ }
169
+ }
170
+ }</pre>
171
+ <p>Supported Qualities: <code>GOOD</code>, <code>BAD</code>, <code>UNCERTAIN</code>.</p>
159
172
  </script>
@@ -33,7 +33,20 @@ const defaultValue = (type) => {
33
33
  const flattenPayload = (value, prefix = '') => {
34
34
  const entries = [];
35
35
  const path = (key) => (prefix ? `${prefix}.${key}` : key);
36
+
37
+ // Extended Value Object Detection:
38
+ // If object has 'value' AND ('quality' OR 'timestamp'), treat as single leaf with metadata.
36
39
  if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
40
+ if ('value' in value && ('quality' in value || 'timestamp' in value)) {
41
+ entries.push({
42
+ key: prefix || 'value', // If root is the object
43
+ value: value.value,
44
+ quality: value.quality,
45
+ timestamp: value.timestamp
46
+ });
47
+ return entries;
48
+ }
49
+
37
50
  Object.entries(value).forEach(([key, val]) => {
38
51
  if (val !== undefined) {
39
52
  entries.push(...flattenPayload(val, path(key)));
@@ -363,7 +376,8 @@ module.exports = function (RED) {
363
376
 
364
377
  let definitionsChanged = false;
365
378
 
366
- entries.forEach(({ key, value }) => {
379
+ entries.forEach((entry) => {
380
+ const { key, value } = entry;
367
381
  // Ensure we don't accidentally send undefined/null as value if logic slipped through
368
382
  if (value === undefined || value === null) return;
369
383
 
@@ -371,11 +385,30 @@ module.exports = function (RED) {
371
385
  if (created) {
372
386
  definitionsChanged = true;
373
387
  }
388
+
389
+ // Handle custom timestamp
390
+ let ts = BigInt(Date.now()) * 1_000_000n;
391
+ if (entry.timestamp) {
392
+ try {
393
+ // Support Date object or number (ms)
394
+ const ms = (entry.timestamp instanceof Date) ? entry.timestamp.getTime() : Number(entry.timestamp);
395
+ if (!isNaN(ms)) {
396
+ ts = BigInt(Math.floor(ms)) * 1_000_000n;
397
+ }
398
+ } catch (e) { /* ignore */ }
399
+ }
400
+
401
+ // Handle custom quality
402
+ let qual = 'GOOD';
403
+ if (entry.quality) {
404
+ qual = String(entry.quality).toUpperCase();
405
+ }
406
+
374
407
  const state = {
375
408
  id: def.id,
376
409
  value,
377
- timestamp: BigInt(Date.now()) * 1_000_000n,
378
- quality: 'GOOD',
410
+ timestamp: ts,
411
+ quality: qual,
379
412
  };
380
413
  // states.push(state); // No longer pushing to a temporary 'states' array
381
414
  stateMap.set(def.id, state); // Update the global stateMap
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-uos-nats",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Node-RED nodes for Weidmüller u-OS Data Hub. Read, write, and provide variables via NATS protocol with OAuth2 authentication. Features: Variable Key resolution, custom icons, example flows, and provider definition caching.",
5
5
  "author": {
6
6
  "name": "IoTUeli",