@machhub-dev/node-red-nodes 1.0.5 → 1.0.7

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 ADDED
@@ -0,0 +1,371 @@
1
+ # MACHHUB Node-RED Nodes
2
+
3
+ A collection of custom Node-RED nodes for integrating with the MACHHUB platform. These nodes provide seamless connectivity to MACHHUB's tag system, database collections, and real-time data capabilities.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Configuration](#configuration)
9
+ - [Available Nodes](#available-nodes)
10
+ - [MACHHUB Config](#machhub-config)
11
+ - [Tag Read](#tag-read)
12
+ - [Tag Write](#tag-write)
13
+ - [Bulk Tag Write](#bulk-tag-write)
14
+ - [Collection](#collection)
15
+ - [DB Query](#db-query)
16
+ - [Usage Examples](#usage-examples)
17
+ - [License](#license)
18
+
19
+ ## Installation
20
+
21
+ 1. Navigate to your Node-RED user directory (typically `~/.node-red`)
22
+ 2. Install the MACHHUB nodes package:
23
+ ```bash
24
+ npm install <machhub-nodes-package>
25
+ ```
26
+ 3. Restart Node-RED
27
+
28
+ ## Configuration
29
+
30
+ ### MACHHUB Config Node
31
+
32
+ Before using any MACHHUB nodes, you need to configure a connection to your MACHHUB server. You have two options:
33
+
34
+ #### Option 1: Using Config Node (Recommended for multiple servers)
35
+
36
+ 1. Add any MACHHUB node to your flow
37
+ 2. Check "Use Config Node"
38
+ 3. Click the pencil icon to create a new MACHHUB Config
39
+ 4. Fill in the following details:
40
+ - **Name**: A friendly name for this configuration
41
+ - **Host**: MACHHUB server hostname or IP (default: localhost)
42
+ - **HTTP Port**: MACHHUB HTTP API port (default: 6188)
43
+ - **MQTT Port**: MACHHUB MQTT broker port (default: 1883)
44
+ - **Client ID**: Your MACHHUB client ID
45
+ - **Client Secret**: Your MACHHUB client secret
46
+
47
+ #### Option 2: Using machhub.env.json
48
+
49
+ 1. Create a `machhub.env.json` file in your Node-RED working directory
50
+ 2. Leave "Use Config Node" unchecked in your MACHHUB nodes
51
+ 3. The nodes will automatically read configuration from the JSON file
52
+
53
+ ## Available Nodes
54
+
55
+ ### MACHHUB Config
56
+
57
+ **Category:** Config
58
+
59
+ A configuration node that stores connection details for MACHHUB server. This node is referenced by other MACHHUB nodes and doesn't appear in the flow directly.
60
+
61
+ **Properties:**
62
+ - **Name**: Optional friendly name
63
+ - **Host**: MACHHUB server address
64
+ - **HTTP Port**: HTTP API port number
65
+ - **MQTT Port**: MQTT broker port number
66
+ - **Client ID**: Authentication client ID
67
+ - **Client Secret**: Authentication client secret
68
+
69
+ ---
70
+
71
+ ### Tag Read
72
+
73
+ **Category:** MACHHUB
74
+ **Icon:** 🏷️
75
+ **Color:** Purple (#c777f1)
76
+
77
+ Reads data from MACHHUB tags or subscribes to custom MQTT topics.
78
+
79
+ **Configuration:**
80
+ - **Name**: Optional node name
81
+ - **Tag/Topic**: Select from available tags or enter custom topic
82
+ - **Use Config Node**: Toggle between config node and machhub.env.json
83
+
84
+ **Features:**
85
+ - Dropdown list of available tags
86
+ - Manual topic entry support
87
+ - MQTT wildcard support:
88
+ - `+` - Single level wildcard
89
+ - `#` - Multi-level wildcard
90
+
91
+ **Output:**
92
+ - `msg.payload`: Data received from the subscribed topic
93
+
94
+ **Examples:**
95
+ ```
96
+ sensor/temperature → Specific tag
97
+ sensor/+/temperature → All sensors' temperature
98
+ sensor/# → All topics under sensor
99
+ ```
100
+
101
+ ---
102
+
103
+ ### Tag Write
104
+
105
+ **Category:** MACHHUB
106
+ **Icon:** 🏷️
107
+ **Color:** Purple (#c777f1)
108
+
109
+ Writes data to a selected MACHHUB tag.
110
+
111
+ **Configuration:**
112
+ - **Name**: Optional node name
113
+ - **Select Tag**: Choose from available tags
114
+ - **Use Config Node**: Toggle between config node and machhub.env.json
115
+
116
+ **Input:**
117
+ - `msg.payload`: JSON data to publish to the tag
118
+
119
+ **Example:**
120
+ ```javascript
121
+ msg.payload = {
122
+ temperature: 25.5,
123
+ humidity: 60,
124
+ timestamp: Date.now()
125
+ };
126
+ return msg;
127
+ ```
128
+
129
+ ---
130
+
131
+ ### Bulk Tag Write
132
+
133
+ **Category:** MACHHUB
134
+ **Icon:** 🏷️
135
+ **Color:** Purple (#c777f1)
136
+
137
+ Performs bulk write operations to multiple MACHHUB tags simultaneously.
138
+
139
+ **Configuration:**
140
+ - **Name**: Optional node name
141
+ - **Use Config Node**: Toggle between config node and machhub.env.json
142
+
143
+ **Input:**
144
+ - `msg.payload`: Object with tag paths as keys and values to write
145
+
146
+ **Example:**
147
+ ```javascript
148
+ msg.payload = {
149
+ "Namespace1/FolderA/Tag1": 123,
150
+ "Namespace1/FolderA/Tag2": 456,
151
+ "Namespace2/FolderB/Temperature": 25.5
152
+ };
153
+ return msg;
154
+ ```
155
+
156
+ ---
157
+
158
+ ### Collection
159
+
160
+ **Category:** MACHHUB
161
+ **Icon:** 💾
162
+ **Color:** Purple (#c777f1)
163
+
164
+ Performs CRUD operations on MACHHUB database collections.
165
+
166
+ **Configuration:**
167
+ - **Name**: Optional node name
168
+ - **Use Config Node**: Toggle between config node and machhub.env.json
169
+ - **Collection**: Select target collection from dropdown
170
+ - **Action**: Choose operation type
171
+
172
+ **Actions:**
173
+
174
+ #### 1. Select
175
+ Query and filter records from a collection.
176
+
177
+ **Configuration:**
178
+ - **Select Fields**: Comma-separated list of fields to return (leave empty for all)
179
+ - **Filters**: Add filter conditions with operators: `=`, `!=`, `>`, `<`, `>=`, `<=`
180
+
181
+ **Output:**
182
+ ```javascript
183
+ msg.payload = [
184
+ { field1: "value1", field2: "value2" },
185
+ { field1: "value3", field2: "value4" }
186
+ ];
187
+ ```
188
+
189
+ #### 2. Create
190
+ Insert a new record into a collection.
191
+
192
+ **Input:**
193
+ ```javascript
194
+ msg.payload = {
195
+ field1: "value1",
196
+ field2: "value2"
197
+ };
198
+ ```
199
+
200
+ **Output:**
201
+ ```javascript
202
+ msg.payload = {
203
+ id: "table_name:new_record_id",
204
+ field1: "value1",
205
+ field2: "value2"
206
+ };
207
+ ```
208
+
209
+ #### 3. Update
210
+ Modify an existing record in a collection.
211
+
212
+ **Input:**
213
+ ```javascript
214
+ msg.payload = {
215
+ id: "table_name:05nwoy566jasfwgak5r3",
216
+ record: {
217
+ field1: "updated_value1",
218
+ field2: "updated_value2"
219
+ }
220
+ };
221
+ ```
222
+
223
+ #### 4. Delete
224
+ Remove a record from a collection.
225
+
226
+ **Input:**
227
+ ```javascript
228
+ msg.payload = "table_name:05nwoy566jasfwgak5r3";
229
+ ```
230
+
231
+ ---
232
+
233
+ ### DB Query
234
+
235
+ **Category:** MACHHUB
236
+ **Icon:** 🔍
237
+ **Color:** Purple (#c777f1)
238
+
239
+ Execute custom SurrealQL queries against the MACHHUB database.
240
+
241
+ **Configuration:**
242
+ - **Name**: Optional node name
243
+ - **Use Config Node**: Toggle between config node and machhub.env.json
244
+ - **Query**: SurrealQL query to execute
245
+
246
+ **Input (Optional):**
247
+ - `msg.query`: Override the configured query at runtime
248
+
249
+ **Output:**
250
+ - `msg.payload`: Array of query results
251
+
252
+ **Important:** Wrap table names with backticks: `` `domain_id.table_name` ``
253
+
254
+ **Example Queries:**
255
+ ```sql
256
+ SELECT * FROM `domain_id.purchase_orders` WHERE po_number = 'PO_0016'
257
+
258
+ SELECT id, name FROM `domain_id.products` LIMIT 10
259
+
260
+ SELECT COUNT(*) as total FROM `domain_id.orders`
261
+
262
+ SELECT * FROM `domain_id.sensors` WHERE temperature > 25
263
+ ```
264
+
265
+ **Runtime Override Example:**
266
+ ```javascript
267
+ msg.query = "SELECT * FROM `domain_id.purchase_orders` WHERE status = 'pending'";
268
+ return msg;
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Usage Examples
274
+
275
+ ### Example 1: Reading and Writing Tags
276
+
277
+ ```
278
+ [Inject] → [Tag Read] → [Function] → [Tag Write]
279
+ ```
280
+
281
+ **Function Node:**
282
+ ```javascript
283
+ // Read temperature, add 5, write to another tag
284
+ msg.payload = {
285
+ value: msg.payload.value + 5,
286
+ timestamp: Date.now()
287
+ };
288
+ return msg;
289
+ ```
290
+
291
+ ### Example 2: Querying and Filtering Collection Data
292
+
293
+ ```
294
+ [Inject] → [Collection: Select] → [Debug]
295
+ ```
296
+
297
+ **Collection Configuration:**
298
+ - Action: Select
299
+ - Select Fields: `id,name,status`
300
+ - Filters:
301
+ - `status = active`
302
+ - `priority > 5`
303
+
304
+ ### Example 3: Bulk Tag Update
305
+
306
+ ```
307
+ [Inject] → [Function] → [Bulk Tag Write]
308
+ ```
309
+
310
+ **Function Node:**
311
+ ```javascript
312
+ msg.payload = {
313
+ "Production/Line1/Speed": 1500,
314
+ "Production/Line1/Temperature": 85.2,
315
+ "Production/Line1/Status": "Running"
316
+ };
317
+ return msg;
318
+ ```
319
+
320
+ ### Example 4: Custom Database Query
321
+
322
+ ```
323
+ [Inject] → [DB Query] → [Function] → [Debug]
324
+ ```
325
+
326
+ **DB Query Configuration:**
327
+ ```sql
328
+ SELECT * FROM `domain_id.production_data`
329
+ WHERE timestamp > time::now() - 1h
330
+ ORDER BY timestamp DESC
331
+ LIMIT 100
332
+ ```
333
+
334
+ ### Example 5: Create-Read-Update-Delete Workflow
335
+
336
+ ```
337
+ [Inject] → [Collection: Create] → [Collection: Select] → [Function] → [Collection: Update]
338
+ ```
339
+
340
+ ---
341
+
342
+ ## Troubleshooting
343
+
344
+ ### Tags Not Loading
345
+ - Verify MACHHUB server is running and accessible
346
+ - Check Client ID and Client Secret are correct
347
+ - Ensure HTTP Port is correct (default: 6188)
348
+ - Check network connectivity to the MACHHUB server
349
+
350
+ ### Collection Operations Failing
351
+ - Verify the collection exists in the database
352
+ - Check field names match the collection schema
353
+ - Ensure proper permissions are set for the client
354
+
355
+ ### MQTT Subscription Not Receiving Data
356
+ - Verify MQTT Port is correct (default: 1883)
357
+ - Check the topic path is correct
358
+ - Ensure tags are publishing data
359
+ - Verify firewall settings allow MQTT traffic
360
+
361
+ ---
362
+
363
+ ## License
364
+
365
+ See [LICENSE](LICENSE) file for details.
366
+
367
+ ---
368
+
369
+ ## Support
370
+
371
+ For issues, questions, or contributions, please contact your MACHHUB administrator or refer to the MACHHUB documentation.
@@ -112,12 +112,14 @@ class HTTPAPIService {
112
112
  });
113
113
  }
114
114
  // Collection Example
115
- static getCollectionsExample(settings, collectionID) {
115
+ static getCollectionsExample(settings, collectionID, isSelectQuery) {
116
116
  return __awaiter(this, void 0, void 0, function* () {
117
117
  try {
118
118
  const res = yield this.service(settings).request
119
119
  .post('collections/example', undefined, {
120
- collectionID
120
+ collectionID,
121
+ // @ts-ignore: need to pass as boolean not string
122
+ isSelectQuery: isSelectQuery
121
123
  });
122
124
  return res;
123
125
  }
@@ -205,7 +205,8 @@
205
205
  let url = "/collections/example";
206
206
 
207
207
  const requestBody = {
208
- collectionID: collectionID
208
+ collectionID,
209
+ isSelectQuery: $action.val() === "select"
209
210
  };
210
211
 
211
212
  if (useConfigNode) {
@@ -208,7 +208,7 @@ function default_1(RED) {
208
208
  // HTTP endpoint to fetch collection example for admin UI
209
209
  RED.httpAdmin.post("/collections/example", (req, res) => __awaiter(this, void 0, void 0, function* () {
210
210
  try {
211
- const { collectionID, host, httpPort, clientId, clientSecret } = req.body;
211
+ const { collectionID, isSelectQuery, host, httpPort, clientId, clientSecret } = req.body;
212
212
  let configData;
213
213
  // Check if credentials are provided (config node)
214
214
  if (clientId && clientSecret) {
@@ -229,7 +229,7 @@ function default_1(RED) {
229
229
  clientSecret: envConfig.clientSecret
230
230
  };
231
231
  }
232
- const result = yield http_api_services_1.HTTPAPIService.getCollectionsExample(configData, collectionID);
232
+ const result = yield http_api_services_1.HTTPAPIService.getCollectionsExample(configData, collectionID, isSelectQuery);
233
233
  res.json(result);
234
234
  }
235
235
  catch (e) {
@@ -2,6 +2,7 @@
2
2
  RED.nodes.registerType('machhub-config', {
3
3
  category: 'config',
4
4
  defaults: {
5
+ name: { value: "", required: false },
5
6
  host: { value: "localhost", required: true },
6
7
  httpPort: { value: 6188, required: true, validate: RED.validators.number() },
7
8
  mqttPort: { value: 1883, required: true, validate: RED.validators.number() },
@@ -9,12 +10,16 @@
9
10
  clientSecret: { value: "", required: true }
10
11
  },
11
12
  label: function() {
12
- return this.host + ":" + this.httpPort + " / MQTT:" + this.mqttPort;
13
+ return this.name || (this.host + ":" + this.httpPort + " / MQTT:" + this.mqttPort);
13
14
  }
14
15
  });
15
16
  </script>
16
17
 
17
18
  <script type="text/html" data-template-name="machhub-config">
19
+ <div class="form-row">
20
+ <label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
21
+ <input type="text" id="node-config-input-name" placeholder="My MACHHUB Server">
22
+ </div>
18
23
  <div class="form-row">
19
24
  <label for="node-config-input-host"><i class="fa fa-server"></i> Host</label>
20
25
  <input type="text" id="node-config-input-host" placeholder="localhost">
@@ -54,28 +54,32 @@
54
54
  try {
55
55
  // Get the selected machhub config
56
56
  const machhubConfigId = $machhub.val();
57
+ const useConfigNodeChecked = $useConfigNode.is(":checked");
57
58
  let configData = {};
58
59
 
59
- if (machhubConfigId) {
60
+ if (useConfigNodeChecked && machhubConfigId) {
60
61
  const configNode = RED.nodes.node(machhubConfigId);
61
62
  if (configNode) {
62
63
  configData = {
64
+ useConfigNode: "true",
63
65
  host: configNode.host || "127.0.0.1",
64
66
  httpPort: configNode.httpPort || 6188,
65
67
  clientId: configNode.clientId || "",
66
68
  clientSecret: configNode.clientSecret || ""
67
69
  };
68
70
  }
69
- } else if (machhubNodes.length > 0) {
71
+ } else if (useConfigNodeChecked && machhubNodes.length > 0) {
70
72
  // Use first available config
71
73
  const configNode = machhubNodes[0];
72
74
  configData = {
75
+ useConfigNode: "true",
73
76
  host: configNode.host || "127.0.0.1",
74
77
  httpPort: configNode.httpPort || 6188,
75
78
  clientId: configNode.clientId || "",
76
79
  clientSecret: configNode.clientSecret || ""
77
80
  };
78
81
  }
82
+ // If useConfigNode is false, send empty params to use machhub.env.json
79
83
 
80
84
  // Build query string (revert back to working approach)
81
85
  const queryParams = new URLSearchParams(configData).toString();
@@ -100,10 +104,11 @@
100
104
 
101
105
  const tags = await res.json();
102
106
 
103
- // Populate dropdown
107
+ // Populate datalist
108
+ const $datalist = $("#node-input-selectedTag-datalist");
104
109
  if (tags && tags.length > 0) {
105
- let options = tags.map(tag => `<option value="${tag}">${tag}</option>`);
106
- $selected_tag.html(options.join("")); // Set options
110
+ let options = tags.map(tag => `<option value="${tag}">`);
111
+ $datalist.html(options.join("")); // Set options
107
112
  } else {
108
113
  console.log("No tags available from API");
109
114
  }
@@ -114,9 +119,9 @@
114
119
  }
115
120
  } catch (error) {
116
121
  console.error("Error fetching tags:", error);
117
- // Show only the currently selected tag as an option
122
+ // Keep the currently selected tag value
118
123
  if (node.selectedTag) {
119
- $selected_tag.html(`<option value="${node.selectedTag}">${node.selectedTag}</option>`);
124
+ $selected_tag.val(node.selectedTag);
120
125
  }
121
126
  }
122
127
  }
@@ -139,7 +144,8 @@
139
144
  </div>
140
145
  <div class="form-row">
141
146
  <label for="node-input-selectedTag"><i class="fa fa-list"></i> Select Tag</label>
142
- <select id="node-input-selectedTag"></select>
147
+ <input type="text" id="node-input-selectedTag" list="node-input-selectedTag-datalist" placeholder="Start typing or select a tag...">
148
+ <datalist id="node-input-selectedTag-datalist"></datalist>
143
149
  </div>
144
150
  <div class="form-row">
145
151
  <label for="node-input-useConfigNode" style="width: auto; padding-right: 10px;">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@machhub-dev/node-red-nodes",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Node-RED API for MACHHUB EDGE",
5
5
  "scripts": {
6
6
  "build": "yarn clean && npx tsc && yarn copy-files",