node-red-contrib-uos-nats 0.2.47 → 0.2.48
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/lib/payloads.js +31 -2
- package/nodes/datahub-output.js +5 -6
- package/nodes/datahub-write.js +34 -10
- package/package.json +1 -1
package/lib/payloads.js
CHANGED
|
@@ -115,14 +115,43 @@ export function encodeWriteVariablesCommand(variables) {
|
|
|
115
115
|
|
|
116
116
|
// Encode value based on type
|
|
117
117
|
// Explicitly handle null/undefined by defaulting to safe empty values based on type
|
|
118
|
-
// This prevents "Field 6 must be set" error
|
|
119
118
|
const val = v.value;
|
|
120
|
-
|
|
119
|
+
let targetType = v.dataType; // Optional known type from definition
|
|
120
|
+
|
|
121
|
+
// If targetType is provided, force specific flatbuffer encoding
|
|
122
|
+
if (targetType) {
|
|
123
|
+
targetType = String(targetType).toUpperCase();
|
|
124
|
+
if (targetType === 'BOOLEAN') {
|
|
125
|
+
const boolVal = new VariableValueBooleanT();
|
|
126
|
+
boolVal.value = Boolean(val);
|
|
127
|
+
varT.value = boolVal;
|
|
128
|
+
varT.valueType = VariableValue.Boolean;
|
|
129
|
+
} else if (targetType === 'INT64') {
|
|
130
|
+
const intVal = new VariableValueInt64T();
|
|
131
|
+
intVal.value = BigInt(parseInt(val) || 0); // Ensure BigInt
|
|
132
|
+
varT.value = intVal;
|
|
133
|
+
varT.valueType = VariableValue.Int64;
|
|
134
|
+
} else if (targetType === 'FLOAT64') {
|
|
135
|
+
const floatVal = new VariableValueFloat64T();
|
|
136
|
+
floatVal.value = Number(val);
|
|
137
|
+
varT.value = floatVal;
|
|
138
|
+
varT.valueType = VariableValue.Float64;
|
|
139
|
+
} else {
|
|
140
|
+
// STRING or default
|
|
141
|
+
const strVal = new VariableValueStringT();
|
|
142
|
+
strVal.value = (typeof val === 'object') ? JSON.stringify(val) : String(val);
|
|
143
|
+
varT.value = strVal;
|
|
144
|
+
varT.valueType = VariableValue.String;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Fallback: Infer from value (Risk: Int sent as Float or vice versa)
|
|
148
|
+
else if (typeof val === 'boolean') {
|
|
121
149
|
const boolVal = new VariableValueBooleanT();
|
|
122
150
|
boolVal.value = val;
|
|
123
151
|
varT.value = boolVal;
|
|
124
152
|
varT.valueType = VariableValue.Boolean;
|
|
125
153
|
} else if (Number.isInteger(val)) {
|
|
154
|
+
|
|
126
155
|
const intVal = new VariableValueInt64T();
|
|
127
156
|
intVal.value = BigInt(val);
|
|
128
157
|
varT.value = intVal;
|
package/nodes/datahub-output.js
CHANGED
|
@@ -65,11 +65,10 @@ module.exports = function (RED) {
|
|
|
65
65
|
}
|
|
66
66
|
// Retrieve configuration node
|
|
67
67
|
this.providerId = (config.providerId || 'nodered').trim();
|
|
68
|
-
|
|
69
|
-
this.definitions = config.definitions || [];
|
|
68
|
+
// this.definitions = config.definitions || [];
|
|
70
69
|
|
|
71
70
|
const defMap = new Map();
|
|
72
|
-
|
|
71
|
+
const definitions = [];
|
|
73
72
|
const stateMap = new Map();
|
|
74
73
|
let nextId = 100;
|
|
75
74
|
let fingerprint = 0;
|
|
@@ -92,7 +91,7 @@ module.exports = function (RED) {
|
|
|
92
91
|
stateMap.set(def.id, {
|
|
93
92
|
id: def.id,
|
|
94
93
|
value: defaultValue(dataType),
|
|
95
|
-
|
|
94
|
+
timestamp: BigInt(Date.now()) * 1_000_000n,
|
|
96
95
|
quality: 'GOOD',
|
|
97
96
|
});
|
|
98
97
|
return { def, created: true };
|
|
@@ -139,7 +138,7 @@ module.exports = function (RED) {
|
|
|
139
138
|
const stateObj = {};
|
|
140
139
|
const nowNs = Date.now() * 1_000_000;
|
|
141
140
|
for (const s of stateMap.values()) {
|
|
142
|
-
s.
|
|
141
|
+
s.timestamp = BigInt(Date.now()) * 1_000_000n; // Force refresh timestamp
|
|
143
142
|
stateObj[s.id] = s;
|
|
144
143
|
}
|
|
145
144
|
try {
|
|
@@ -264,7 +263,7 @@ module.exports = function (RED) {
|
|
|
264
263
|
const state = {
|
|
265
264
|
id: def.id,
|
|
266
265
|
value,
|
|
267
|
-
|
|
266
|
+
timestamp: BigInt(Date.now()) * 1_000_000n,
|
|
268
267
|
quality: 'GOOD',
|
|
269
268
|
};
|
|
270
269
|
// states.push(state); // No longer pushing to a temporary 'states' array
|
package/nodes/datahub-write.js
CHANGED
|
@@ -17,20 +17,36 @@ module.exports = function (RED) {
|
|
|
17
17
|
const variable = cached.definition.variables.find(v => v.key === key);
|
|
18
18
|
if (variable) {
|
|
19
19
|
node.debug && node.debug(`Key '${key}' resolved to ID ${variable.id} (cached)`);
|
|
20
|
-
|
|
20
|
+
// Return full object including type
|
|
21
|
+
return { id: variable.id, dataType: variable.dataType };
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
// Query provider definition
|
|
26
|
+
let definition = null;
|
|
25
27
|
try {
|
|
26
28
|
const query = payloads.buildReadProviderDefinitionQuery();
|
|
27
|
-
const subject = `v1.loc.registry.providers.${providerId}.def.qry.read`;
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
// Strategy 1: Direct Query (v1.loc.<provider>.def.qry.read)
|
|
31
|
+
// This is required for providers like Node-RED itself or simple Python scripts
|
|
32
|
+
const directSubject = `v1.loc.${providerId}.def.qry.read`;
|
|
33
|
+
try {
|
|
34
|
+
const response = await nc.request(directSubject, query, { timeout: 1000 });
|
|
35
|
+
definition = payloads.decodeProviderDefinition(response.data);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
node.debug && node.debug(`Direct Query failed: ${err.message}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Strategy 2: Registry Query (v1.loc.registry.providers.<provider>.def.qry.read)
|
|
41
|
+
// Fallback for managed providers
|
|
42
|
+
if (!definition) {
|
|
43
|
+
const registrySubject = `v1.loc.registry.providers.${providerId}.def.qry.read`;
|
|
44
|
+
const response = await nc.request(registrySubject, query, { timeout: 2000 });
|
|
45
|
+
definition = payloads.decodeProviderDefinition(response.data);
|
|
46
|
+
}
|
|
31
47
|
|
|
32
48
|
if (!definition) {
|
|
33
|
-
throw new Error(`Provider ${providerId} not found
|
|
49
|
+
throw new Error(`Provider ${providerId} not found (tried Direct & Registry)`);
|
|
34
50
|
}
|
|
35
51
|
|
|
36
52
|
// Cache the definition
|
|
@@ -45,8 +61,8 @@ module.exports = function (RED) {
|
|
|
45
61
|
throw new Error(`Variable key '${key}' not found in provider ${providerId}`);
|
|
46
62
|
}
|
|
47
63
|
|
|
48
|
-
node.debug && node.debug(`Key '${key}' resolved to ID ${variable.id}`);
|
|
49
|
-
return variable.id;
|
|
64
|
+
node.debug && node.debug(`Key '${key}' resolved to ID ${variable.id} (Type: ${variable.dataType})`);
|
|
65
|
+
return { id: variable.id, dataType: variable.dataType };
|
|
50
66
|
|
|
51
67
|
} catch (err) {
|
|
52
68
|
throw new Error(`Failed to resolve key '${key}': ${err.message}`);
|
|
@@ -71,6 +87,7 @@ module.exports = function (RED) {
|
|
|
71
87
|
this.variableId = config.variableId ? parseInt(config.variableId, 10) : null;
|
|
72
88
|
this.variableKey = config.variableKey?.trim();
|
|
73
89
|
this.resolvedId = null; // Cached resolved ID
|
|
90
|
+
this.resolvedDataType = null; // Cached Data Type for strict writing
|
|
74
91
|
this.payloads = null; // Will be loaded dynamically
|
|
75
92
|
|
|
76
93
|
if (!this.providerId) {
|
|
@@ -131,10 +148,16 @@ module.exports = function (RED) {
|
|
|
131
148
|
|
|
132
149
|
// Resolve variable ID if needed
|
|
133
150
|
let varId = node.resolvedId;
|
|
151
|
+
let varType = node.resolvedDataType;
|
|
152
|
+
|
|
134
153
|
if (!varId && node.variableKey) {
|
|
135
154
|
node.status({ fill: 'yellow', shape: 'dot', text: 'resolving key...' });
|
|
136
|
-
|
|
137
|
-
|
|
155
|
+
const resolved = await resolveVariableKey(nc, node.providerId, node.variableKey, node, node.payloads);
|
|
156
|
+
varId = resolved.id;
|
|
157
|
+
varType = resolved.dataType; // Store resolved type
|
|
158
|
+
|
|
159
|
+
node.resolvedId = varId;
|
|
160
|
+
node.resolvedDataType = varType;
|
|
138
161
|
node.status({ fill: 'green', shape: 'ring', text: 'ready' });
|
|
139
162
|
}
|
|
140
163
|
|
|
@@ -142,7 +165,8 @@ module.exports = function (RED) {
|
|
|
142
165
|
const writeCommand = node.payloads.encodeWriteVariablesCommand([
|
|
143
166
|
{
|
|
144
167
|
id: varId,
|
|
145
|
-
value: value
|
|
168
|
+
value: value,
|
|
169
|
+
dataType: varType // Pass dataType for strict encoding
|
|
146
170
|
}
|
|
147
171
|
]);
|
|
148
172
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-uos-nats",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.48",
|
|
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",
|