node-red-contrib-uos-nats 0.1.2 → 0.1.3
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 +5 -5
- package/nodes/datahub-input.html +24 -130
- package/nodes/datahub-input.js +6 -11
- package/nodes/datahub-output.html +17 -8
- package/package.json +9 -1
package/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
# node-red-contrib-uos-nats
|
|
2
2
|
|
|
3
|
-
**Note:** This custom Node-RED package is built and maintained by [IoTUeli](https://www.iotueli
|
|
3
|
+
**Note:** This custom Node-RED package is built and maintained by [IoTUeli](https://www.linkedin.com/in/iotueli/) and is **not** an official Weidmüller product. For questions, feature requests, or support please contact IoTUeli directly. Repository: <https://github.com/uiff/nats-NodeRed-Node-uc20>
|
|
4
4
|
|
|
5
5
|
Node-RED nodes to read and write u-OS Data Hub variables via NATS. This package exposes three building blocks:
|
|
6
6
|
|
|
7
7
|
1. **u-OS Config** – stores host, OAuth client credentials and manages the shared NATS connection.
|
|
8
|
-
2. **DataHub Input** – subscribes to an existing provider
|
|
8
|
+
2. **DataHub Input** – subscribes to an existing provider and emits JSON messages. Enter the provider ID and optional comma-separated variable names.
|
|
9
9
|
3. **DataHub Output** – automatically registers a provider (default `nodered`), flattens incoming JSON structures and publishes them to the Data Hub.
|
|
10
10
|
|
|
11
11
|
The nodes reuse the FlatBuffer helpers from the standalone Node sample, so they speak the native NATS API.
|
|
@@ -38,8 +38,8 @@ The config node automatically fetches tokens via Client Credentials flow and exp
|
|
|
38
38
|
|
|
39
39
|
## DataHub Input Node
|
|
40
40
|
|
|
41
|
-
- Select the u-OS config node and
|
|
42
|
-
-
|
|
41
|
+
- Select the u-OS config node and enter the provider ID (e.g. `u_os_adm`).
|
|
42
|
+
- Optionally provide a comma-separated list of variable keys (leave empty to receive all).
|
|
43
43
|
- The node outputs messages with the structure:
|
|
44
44
|
```json
|
|
45
45
|
{
|
|
@@ -68,7 +68,7 @@ The config node automatically fetches tokens via Client Credentials flow and exp
|
|
|
68
68
|
## Example Flow
|
|
69
69
|
|
|
70
70
|
1. Drop a **u-OS Config** node, fill in host/port and OAuth credentials from the Control Center.
|
|
71
|
-
2. Add a **DataHub Input** node, select the config,
|
|
71
|
+
2. Add a **DataHub Input** node, select the config, enter the provider ID and optional comma-separated variable list. Connect the output to a Debug node.
|
|
72
72
|
3. Add a **DataHub Output** node, leave provider ID = `nodered` and send structured JSON (e.g. from a Function node). The values instantly appear in the Data Hub under the provider `nodered`.
|
|
73
73
|
|
|
74
74
|
> Tip: Because both nodes rely on the Control Center HTTP API for metadata they inherit the same permissions as your OAuth client. Make sure the client has at least `hub.variables.readonly` for the input node and `hub.variables.provide hub.variables.readwrite` for the output node.
|
package/nodes/datahub-input.html
CHANGED
|
@@ -1,131 +1,37 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
|
-
(function() {
|
|
3
|
-
function fetchProviders(configId) {
|
|
4
|
-
if (!configId) return Promise.resolve([]);
|
|
5
|
-
return $.getJSON(`uos/providers/${configId}`);
|
|
6
|
-
}
|
|
7
|
-
function fetchVariables(configId, providerId) {
|
|
8
|
-
if (!configId || !providerId) return Promise.resolve([]);
|
|
9
|
-
return $.getJSON(`uos/providers/${configId}/${providerId}/variables`);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
2
|
RED.nodes.registerType('datahub-input', {
|
|
13
|
-
category: '
|
|
3
|
+
category: 'DataHub-NATS',
|
|
14
4
|
color: '#ff9f43',
|
|
15
5
|
defaults: {
|
|
16
6
|
name: { value: '' },
|
|
17
7
|
connection: { type: 'uos-config', required: true },
|
|
18
|
-
providerId: { value: '', required: true },
|
|
19
|
-
|
|
20
|
-
variables: { value: '[]' }
|
|
8
|
+
providerId: { value: 'sampleprovider', required: true },
|
|
9
|
+
variablesText: { value: '' }
|
|
21
10
|
},
|
|
22
11
|
inputs: 0,
|
|
23
12
|
outputs: 1,
|
|
24
|
-
icon:
|
|
25
|
-
label: function() {
|
|
26
|
-
return this.name || `DataHub Input ${this.providerId || ''}`;
|
|
27
|
-
},
|
|
28
|
-
labelStyle: function() {
|
|
29
|
-
return this.name ? 'node_label_italic' : '';
|
|
30
|
-
},
|
|
13
|
+
icon: "white/datahub-input.svg",
|
|
31
14
|
oneditprepare: function() {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
multiContainer.hide();
|
|
46
|
-
} else if (mode === 'multi') {
|
|
47
|
-
singleContainer.hide();
|
|
48
|
-
multiContainer.show();
|
|
49
|
-
} else {
|
|
50
|
-
singleContainer.hide();
|
|
51
|
-
multiContainer.hide();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function populateVariables(list) {
|
|
56
|
-
cachedVariables = list;
|
|
57
|
-
singleField.empty();
|
|
58
|
-
multiField.empty();
|
|
59
|
-
list.forEach(v => {
|
|
60
|
-
$('<option>').val(v.key).text(v.key).appendTo(singleField);
|
|
61
|
-
$('<option>').val(v.key).text(v.key).appendTo(multiField);
|
|
62
|
-
});
|
|
63
|
-
const stored = [];
|
|
64
|
-
try { stored.push(...JSON.parse($('#node-input-variables').val() || '[]')); } catch(e) {}
|
|
65
|
-
if (stored.length) {
|
|
66
|
-
singleField.val(stored[0] || '');
|
|
67
|
-
multiField.val(stored);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function loadVariables() {
|
|
72
|
-
const cfg = configField.val();
|
|
73
|
-
const provider = providerField.val();
|
|
74
|
-
if (!cfg || !provider) {
|
|
75
|
-
populateVariables([]);
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
fetchVariables(cfg, provider).then((vars) => {
|
|
79
|
-
const normalized = (vars || []).map(v => ({ key: v.key || v.id }));
|
|
80
|
-
populateVariables(normalized);
|
|
81
|
-
}).catch(() => populateVariables([]));
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function loadProviders() {
|
|
85
|
-
const node = this;
|
|
86
|
-
const cfg = configField.val();
|
|
87
|
-
providerField.empty();
|
|
88
|
-
if (!cfg) {
|
|
89
|
-
providerField.append('<option value="">-- select config first --</option>');
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
fetchProviders(cfg).then((providers) => {
|
|
93
|
-
providerField.append('<option value="">-- choose provider --</option>');
|
|
94
|
-
(providers || []).forEach((p) => {
|
|
95
|
-
$('<option>').val(p.id).text(p.id).appendTo(providerField);
|
|
96
|
-
});
|
|
97
|
-
if (node.providerId) {
|
|
98
|
-
providerField.val(node.providerId);
|
|
99
|
-
}
|
|
100
|
-
loadVariables();
|
|
101
|
-
}).catch(() => {
|
|
102
|
-
providerField.append('<option value="">(error loading providers)</option>');
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
modeField.on('change', applyMode);
|
|
107
|
-
providerField.on('change', loadVariables);
|
|
108
|
-
configField.on('change', loadProviders.bind(this));
|
|
109
|
-
|
|
110
|
-
applyMode();
|
|
111
|
-
loadProviders.call(this);
|
|
15
|
+
const help = `
|
|
16
|
+
<b>DataHub Input node</b><br>
|
|
17
|
+
<ul>
|
|
18
|
+
<li><b>u-OS Config</b>: choose the config node with host and OAuth credentials.</li>
|
|
19
|
+
<li><b>Provider ID</b>: e.g. <code>sampleprovider</code> or <code>u_os_adm</code>.</li>
|
|
20
|
+
<li><b>Variables</b>: leave empty for all variables or enter comma-separated keys like <code>diagnostics.status_text,diagnostics.error_count</code>.</li>
|
|
21
|
+
</ul>
|
|
22
|
+
The node outputs messages of the form <code>{ type: 'snapshot'|'change', variables: [...] }</code>.
|
|
23
|
+
`;
|
|
24
|
+
$('#datahub-input-help').html(help);
|
|
25
|
+
},
|
|
26
|
+
label: function () {
|
|
27
|
+
return this.name || `Input ${this.providerId || ''}`;
|
|
112
28
|
},
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
let selected = [];
|
|
116
|
-
if (mode === 'single') {
|
|
117
|
-
const val = $('#node-input-variableSingle').val();
|
|
118
|
-
if (val) selected = [val];
|
|
119
|
-
} else if (mode === 'multi') {
|
|
120
|
-
selected = $('#node-input-variableMulti').val() || [];
|
|
121
|
-
}
|
|
122
|
-
$('#node-input-variables').val(JSON.stringify(selected));
|
|
29
|
+
labelStyle: function () {
|
|
30
|
+
return this.name ? 'node_label_italic' : '';
|
|
123
31
|
}
|
|
124
32
|
});
|
|
125
|
-
})();
|
|
126
33
|
</script>
|
|
127
34
|
|
|
128
|
-
<input type="hidden" id="node-input-variables">
|
|
129
35
|
<div class="form-row">
|
|
130
36
|
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
131
37
|
<input type="text" id="node-input-name">
|
|
@@ -135,23 +41,11 @@
|
|
|
135
41
|
<input type="text" id="node-input-connection">
|
|
136
42
|
</div>
|
|
137
43
|
<div class="form-row">
|
|
138
|
-
<label for="node-input-providerId"><i class="fa fa-
|
|
139
|
-
<
|
|
44
|
+
<label for="node-input-providerId"><i class="fa fa-id-badge"></i> Provider ID</label>
|
|
45
|
+
<input type="text" id="node-input-providerId" placeholder="sampleprovider">
|
|
140
46
|
</div>
|
|
141
47
|
<div class="form-row">
|
|
142
|
-
<label for="node-input-
|
|
143
|
-
<
|
|
144
|
-
<option value="all">All variables</option>
|
|
145
|
-
<option value="single">Single variable</option>
|
|
146
|
-
<option value="multi">Multi selection</option>
|
|
147
|
-
</select>
|
|
148
|
-
</div>
|
|
149
|
-
<div class="form-row" id="node-input-variableSingle-container" style="display:none;">
|
|
150
|
-
<label><i class="fa fa-bullseye"></i> Variable</label>
|
|
151
|
-
<select id="node-input-variableSingle" style="width:100%"></select>
|
|
152
|
-
</div>
|
|
153
|
-
<div class="form-row" id="node-input-variableMulti-container" style="display:none;">
|
|
154
|
-
<label><i class="fa fa-list-ul"></i> Variables</label>
|
|
155
|
-
<select id="node-input-variableMulti" multiple size="8" style="width:100%"> </select>
|
|
48
|
+
<label for="node-input-variablesText"><i class="fa fa-list"></i> Variables (comma separated)</label>
|
|
49
|
+
<input type="text" id="node-input-variablesText" placeholder="diagnostics.status_text,diagnostics.error_count">
|
|
156
50
|
</div>
|
|
157
|
-
<
|
|
51
|
+
<div id="datahub-input-help" class="form-tips"></div>
|
package/nodes/datahub-input.js
CHANGED
|
@@ -27,13 +27,11 @@ module.exports = function (RED) {
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
this.providerId = config.providerId || 'sampleprovider';
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
this.variables = [];
|
|
36
|
-
}
|
|
30
|
+
const text = config.variablesText || '';
|
|
31
|
+
this.variables = text
|
|
32
|
+
.split(',')
|
|
33
|
+
.map((entry) => (entry ? String(entry).trim() : ''))
|
|
34
|
+
.filter((entry) => entry.length > 0);
|
|
37
35
|
|
|
38
36
|
let nc;
|
|
39
37
|
let sub;
|
|
@@ -41,13 +39,10 @@ module.exports = function (RED) {
|
|
|
41
39
|
const defMap = new Map();
|
|
42
40
|
|
|
43
41
|
const shouldInclude = (key) => {
|
|
44
|
-
if (
|
|
42
|
+
if (!this.variables.length) {
|
|
45
43
|
return true;
|
|
46
44
|
}
|
|
47
45
|
const needle = normalizeKey(key);
|
|
48
|
-
if (this.variableMode === 'single') {
|
|
49
|
-
return needle === this.variables[0];
|
|
50
|
-
}
|
|
51
46
|
return this.variables.includes(needle);
|
|
52
47
|
};
|
|
53
48
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
<script type="text/javascript">
|
|
2
|
-
(function() {
|
|
3
2
|
RED.nodes.registerType('datahub-output', {
|
|
4
|
-
category: '
|
|
3
|
+
category: 'DataHub-NATS',
|
|
5
4
|
color: '#ff9f43',
|
|
6
5
|
defaults: {
|
|
7
6
|
name: { value: '' },
|
|
@@ -10,15 +9,25 @@
|
|
|
10
9
|
},
|
|
11
10
|
inputs: 1,
|
|
12
11
|
outputs: 1,
|
|
13
|
-
icon:
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
icon: "white/datahub-output.svg",
|
|
13
|
+
oneditprepare: function() {
|
|
14
|
+
const help = `
|
|
15
|
+
<b>DataHub Output node</b><br>
|
|
16
|
+
<ul>
|
|
17
|
+
<li><b>u-OS Config</b>: select the config node.</li>
|
|
18
|
+
<li><b>Provider ID</b>: defaults to <code>nodered</code> (will be registered automatically).</li>
|
|
19
|
+
</ul>
|
|
20
|
+
Send any JSON payload → nested objects become dot-separated keys (e.g. <code>{ diagnostics: { status_text: 'ok' } }</code> ⇢ <code>diagnostics.status_text</code>).
|
|
21
|
+
`;
|
|
22
|
+
$('#datahub-output-help').html(help);
|
|
16
23
|
},
|
|
17
|
-
|
|
24
|
+
label: function () {
|
|
25
|
+
return this.name || `Output ${this.providerId || ''}`;
|
|
26
|
+
},
|
|
27
|
+
labelStyle: function () {
|
|
18
28
|
return this.name ? 'node_label_italic' : '';
|
|
19
29
|
}
|
|
20
30
|
});
|
|
21
|
-
})();
|
|
22
31
|
</script>
|
|
23
32
|
|
|
24
33
|
<div class="form-row">
|
|
@@ -33,4 +42,4 @@
|
|
|
33
42
|
<label for="node-input-providerId"><i class="fa fa-id-badge"></i> Provider ID</label>
|
|
34
43
|
<input type="text" id="node-input-providerId" placeholder="nodered">
|
|
35
44
|
</div>
|
|
36
|
-
<
|
|
45
|
+
<div id="datahub-output-help" class="form-tips"></div>
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-uos-nats",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Node-RED nodes for u-OS Data Hub via NATS",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/uiff/nats-NodeRed-Node-uc20.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/uiff/nats-NodeRed-Node-uc20",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/uiff/nats-NodeRed-Node-uc20/issues"
|
|
12
|
+
},
|
|
5
13
|
"license": "MIT",
|
|
6
14
|
"main": "nodes/uos-provider.js",
|
|
7
15
|
"keywords": [
|