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 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.ch) and is **not** an official Weidmüller product. For questions, feature requests, or support please contact IoTUeli directly.
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, lets you pick individual variables and emits JSON messages.
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 pick a provider from the drop-down. The node queries `/datahub/v1/providers` and lists all registry entries.
42
- - Choose whether you want **all variables**, **single variable**, or **multi selection**. The variable selector is populated from `/datahub/v1/providers/<provider>/variables`.
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, pick an existing provider (e.g. `u_os_adm`) and choose the variables you want to observe. Connect the output to a Debug node.
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.
@@ -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: 'input',
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
- variableMode: { value: 'all' },
20
- variables: { value: '[]' }
8
+ providerId: { value: 'sampleprovider', required: true },
9
+ variablesText: { value: '' }
21
10
  },
22
11
  inputs: 0,
23
12
  outputs: 1,
24
- icon: 'white/datahub-input.svg',
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 providerField = $('#node-input-providerId');
33
- const modeField = $('#node-input-variableMode');
34
- const singleField = $('#node-input-variableSingle');
35
- const multiField = $('#node-input-variableMulti');
36
- const multiContainer = $('#node-input-variableMulti-container');
37
- const singleContainer = $('#node-input-variableSingle-container');
38
- const configField = $('#node-input-connection');
39
- let cachedVariables = [];
40
-
41
- function applyMode() {
42
- const mode = modeField.val();
43
- if (mode === 'single') {
44
- singleContainer.show();
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
- oneditsave: function() {
114
- const mode = $('#node-input-variableMode').val();
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-list"></i> Provider</label>
139
- <select id="node-input-providerId"></select>
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-variableMode"><i class="fa fa-filter"></i> Variables</label>
143
- <select id="node-input-variableMode">
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
- <p>Outputs messages with <code>{{payload.type}}</code> = <code>snapshot</code> or <code>change</code> and a <code>variables</code> array containing the selected Data Hub values.</p>
51
+ <div id="datahub-input-help" class="form-tips"></div>
@@ -27,13 +27,11 @@ module.exports = function (RED) {
27
27
  }
28
28
 
29
29
  this.providerId = config.providerId || 'sampleprovider';
30
- this.variableMode = config.variableMode || 'all';
31
- try {
32
- this.variables = JSON.parse(config.variables || '[]').map(normalizeKey).filter((k) => k);
33
- }
34
- catch (err) {
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 (this.variableMode === 'all' || !this.variables.length) {
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: 'output',
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: 'white/datahub-output.svg',
14
- label: function() {
15
- return this.name || `DataHub Output ${this.providerId || ''}`;
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
- labelStyle: function() {
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
- <p>Send JSON payloads (including nested structures). The node auto-registers variables based on the object keys and publishes them to the configured provider. Nested objects become dot-separated keys (e.g. <code>folder.status</code>).</p>
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.2",
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": [