@frangoteam/fuxa-min 1.2.11 → 1.3.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.
Files changed (50) hide show
  1. package/api/auth/index.js +141 -3
  2. package/api/index.js +18 -2
  3. package/api/jwt-helper.js +3 -1
  4. package/api/resources/index.js +19 -2
  5. package/dist/3rdpartylicenses.txt +139 -7
  6. package/dist/assets/i18n/de.json +10 -0
  7. package/dist/assets/i18n/en.json +14 -3
  8. package/dist/assets/i18n/es.json +12 -0
  9. package/dist/assets/i18n/fr.json +10 -0
  10. package/dist/assets/i18n/ja.json +15 -6
  11. package/dist/assets/i18n/ko.json +12 -0
  12. package/dist/assets/i18n/pt.json +9 -2
  13. package/dist/assets/i18n/ru.json +11 -0
  14. package/dist/assets/i18n/sv.json +10 -1
  15. package/dist/assets/i18n/tr.json +8 -1
  16. package/dist/assets/i18n/ua.json +9 -2
  17. package/dist/assets/i18n/zh-cn.json +10 -0
  18. package/dist/assets/i18n/zh-tw.json +11 -1
  19. package/dist/index.html +2 -2
  20. package/dist/main.bafae830903d548e.js +329 -0
  21. package/dist/polyfills.d7de05f9af2fb559.js +1 -0
  22. package/dist/{runtime.8ef63094e52a66ba.js → runtime.9136a61a9b98f987.js} +1 -1
  23. package/dist/{scripts.40b60f02658462e4.js → scripts.d9e6ee984bf6f3b7.js} +1 -1
  24. package/dist/styles.545e37beb3e671ba.css +1 -0
  25. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.html +56 -5
  26. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-daq.js +8 -2
  27. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.html +56 -5
  28. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-change.js +12 -12
  29. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.html +56 -5
  30. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag-daq-settings.js +14 -10
  31. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.html +56 -5
  32. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-get-tag.js +8 -2
  33. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.html +56 -5
  34. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag-daq-settings.js +24 -20
  35. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.html +56 -5
  36. package/integrations/node-red/node-red-contrib-fuxa/nodes/fuxa-set-tag.js +8 -2
  37. package/main.js +35 -17
  38. package/package.json +10 -5
  39. package/runtime/devices/adsclient/index.js +1 -1
  40. package/runtime/devices/ethernetip/index.js +1 -1
  41. package/runtime/devices/gpio/index.js +1 -1
  42. package/runtime/devices/odbc/index.js +5 -5
  43. package/runtime/devices/template/index.js +14 -14
  44. package/runtime/storage/daqstorage.js +28 -2
  45. package/runtime/storage/questdb/index.js +224 -0
  46. package/runtime/utils.js +5 -0
  47. package/settings.default.js +5 -2
  48. package/dist/main.92522279642ef880.js +0 -329
  49. package/dist/polyfills.c8e7db9850a3ad8b.js +0 -1
  50. package/dist/styles.03cc550382689976.css +0 -1
@@ -4,7 +4,8 @@
4
4
  color: '#a6bbcf',
5
5
  defaults: {
6
6
  name: {value:""},
7
- tag: {value:"", required:true},
7
+ tag: {value:""}, // Keep: tag name for display and backward compatibility
8
+ tagId: {value:""}, // New: unique identifier (optional, for backward compatibility)
8
9
  from: {value:""},
9
10
  to: {value:""}
10
11
  },
@@ -12,17 +13,65 @@
12
13
  outputs:1,
13
14
  icon: "white-globe.png",
14
15
  label: function() {
15
- return this.name||this.tag||"get daq";
16
+ if (this.name) {
17
+ return this.name;
18
+ }
19
+ // Display tag name or tagId
20
+ return this.tag || this.tagId || "get daq";
16
21
  },
17
22
  oneditprepare: function() {
23
+ var node = this;
24
+ var tagMap = {}; // Use tag.id as key to avoid tag.name duplication issues
25
+
18
26
  $.getJSON('/nodered/fuxa/devices', function(data) {
19
27
  var datalist = $('#fuxa-tags-daq');
20
28
  datalist.empty();
29
+
21
30
  data.forEach(function(device) {
22
31
  device.tags.forEach(function(tag) {
23
- datalist.append('<option value="' + tag.name + '">' + device.name + ' - ' + tag.name + '</option>');
32
+ var fullName = device.name + ' - ' + tag.name;
33
+ // datalist option value format: tag.name(tag.id)
34
+ var optionValue = tag.name + '(' + tag.id + ')';
35
+ datalist.append('<option value="' + optionValue + '">' + fullName + '</option>');
36
+ tagMap[tag.id] = {
37
+ name: tag.name,
38
+ deviceName: device.name,
39
+ fullName: fullName
40
+ };
24
41
  });
25
42
  });
43
+
44
+ // Listen for tagSelected input changes
45
+ $('#node-input-tagSelected').on('change', function() {
46
+ var selectedValue = $(this).val();
47
+ // Parse format: tag.name(tag.id)
48
+ var match = selectedValue.match(/^(.+)\(([^)]+)\)$/);
49
+ if (match) {
50
+ var tagName = match[1];
51
+ var tagId = match[2];
52
+
53
+ // Set the actual stored fields
54
+ $('#node-input-tag').val(tagName);
55
+ $('#node-input-tagId').val(tagId);
56
+ }
57
+ });
58
+
59
+ // Initialize display (when editing existing node)
60
+ if (node.tagId && tagMap[node.tagId]) {
61
+ // Has tagId, construct tagSelected value
62
+ var tagName = node.tag || tagMap[node.tagId].name;
63
+ $('#node-input-tagSelected').val(tagName + '(' + node.tagId + ')');
64
+ } else if (node.tag && !node.tagId) {
65
+ // Old node: only has tag (tag.name), need to find corresponding tagId
66
+ // Note: if there are duplicate names, only the first match will be found
67
+ for (var tagId in tagMap) {
68
+ if (tagMap[tagId].name === node.tag) {
69
+ $('#node-input-tagSelected').val(node.tag + '(' + tagId + ')');
70
+ $('#node-input-tagId').val(tagId);
71
+ break;
72
+ }
73
+ }
74
+ }
26
75
  });
27
76
 
28
77
  // Convert timestamp format for datetime-local inputs
@@ -64,10 +113,12 @@
64
113
  <input type="text" id="node-input-name" placeholder="Name">
65
114
  </div>
66
115
  <div class="form-row">
67
- <label for="node-input-tag"><i class="fa fa-tag"></i> Tag</label>
68
- <input type="text" id="node-input-tag" list="fuxa-tags-daq" placeholder="Tag Name">
116
+ <label for="node-input-tagSelected"><i class="fa fa-tag"></i> Tag</label>
117
+ <input type="text" id="node-input-tagSelected" list="fuxa-tags-daq" placeholder="Select Tag">
69
118
  <datalist id="fuxa-tags-daq"></datalist>
70
119
  </div>
120
+ <input type="hidden" id="node-input-tag">
121
+ <input type="hidden" id="node-input-tagId">
71
122
  <div class="form-row">
72
123
  <label for="node-input-from"><i class="fa fa-clock-o"></i> From (timestamp)</label>
73
124
  <input type="datetime-local" id="node-input-from" placeholder="From timestamp (optional)">
@@ -6,7 +6,13 @@ module.exports = function(RED) {
6
6
 
7
7
  this.on('input', async function(msg) {
8
8
  try {
9
- var tagId = fuxa.getTagId(config.tag, null);
9
+ // Prefer config.tagId, fallback to config.tag for backward compatibility
10
+ var tagId = config.tagId;
11
+ if (!tagId && config.tag) {
12
+ // Backward compatibility: old nodes use tag.name, need to convert to tagId
13
+ tagId = fuxa.getTagId(config.tag, null);
14
+ }
15
+
10
16
  if (tagId) {
11
17
  var fromts = config.from || msg.from || Date.now() - 3600000; // default 1 hour ago
12
18
  var tots = config.to || msg.to || Date.now();
@@ -14,7 +20,7 @@ module.exports = function(RED) {
14
20
  msg.payload = data;
15
21
  node.send(msg);
16
22
  } else {
17
- node.error('Tag not found: ' + config.tag, msg);
23
+ node.error('Tag not found: ' + (config.tag || config.tagId), msg);
18
24
  }
19
25
  } catch (err) {
20
26
  node.error(err, msg);
@@ -4,23 +4,72 @@
4
4
  color: '#a6bbcf',
5
5
  defaults: {
6
6
  name: {value:""},
7
- tag: {value:"", required:true}
7
+ tag: {value:""}, // Keep: tag name for display and backward compatibility
8
+ tagId: {value:""} // New: unique identifier (optional, for backward compatibility)
8
9
  },
9
10
  inputs:0,
10
11
  outputs:1,
11
12
  icon: "white-globe.png",
12
13
  label: function() {
13
- return this.name||this.tag||"get tag change";
14
+ if (this.name) {
15
+ return this.name;
16
+ }
17
+ // Display tag name or tagId
18
+ return this.tag || this.tagId || "get tag change";
14
19
  },
15
20
  oneditprepare: function() {
21
+ var node = this;
22
+ var tagMap = {}; // Use tag.id as key to avoid tag.name duplication issues
23
+
16
24
  $.getJSON('/nodered/fuxa/devices', function(data) {
17
25
  var datalist = $('#fuxa-change-tags');
18
26
  datalist.empty();
27
+
19
28
  data.forEach(function(device) {
20
29
  device.tags.forEach(function(tag) {
21
- datalist.append('<option value="' + tag.name + '">' + device.name + ' - ' + tag.name + '</option>');
30
+ var fullName = device.name + ' - ' + tag.name;
31
+ // datalist option value format: tag.name(tag.id)
32
+ var optionValue = tag.name + '(' + tag.id + ')';
33
+ datalist.append('<option value="' + optionValue + '">' + fullName + '</option>');
34
+ tagMap[tag.id] = {
35
+ name: tag.name,
36
+ deviceName: device.name,
37
+ fullName: fullName
38
+ };
22
39
  });
23
40
  });
41
+
42
+ // Listen for tagSelected input changes
43
+ $('#node-input-tagSelected').on('change', function() {
44
+ var selectedValue = $(this).val();
45
+ // Parse format: tag.name(tag.id)
46
+ var match = selectedValue.match(/^(.+)\(([^)]+)\)$/);
47
+ if (match) {
48
+ var tagName = match[1];
49
+ var tagId = match[2];
50
+
51
+ // Set the actual stored fields
52
+ $('#node-input-tag').val(tagName);
53
+ $('#node-input-tagId').val(tagId);
54
+ }
55
+ });
56
+
57
+ // Initialize display (when editing existing node)
58
+ if (node.tagId && tagMap[node.tagId]) {
59
+ // Has tagId, construct tagSelected value
60
+ var tagName = node.tag || tagMap[node.tagId].name;
61
+ $('#node-input-tagSelected').val(tagName + '(' + node.tagId + ')');
62
+ } else if (node.tag && !node.tagId) {
63
+ // Old node: only has tag (tag.name), need to find corresponding tagId
64
+ // Note: if there are duplicate names, only the first match will be found
65
+ for (var tagId in tagMap) {
66
+ if (tagMap[tagId].name === node.tag) {
67
+ $('#node-input-tagSelected').val(node.tag + '(' + tagId + ')');
68
+ $('#node-input-tagId').val(tagId);
69
+ break;
70
+ }
71
+ }
72
+ }
24
73
  });
25
74
  }
26
75
  });
@@ -32,10 +81,12 @@
32
81
  <input type="text" id="node-input-name" placeholder="Name">
33
82
  </div>
34
83
  <div class="form-row">
35
- <label for="node-input-tag"><i class="fa fa-tag"></i> Tag</label>
36
- <input type="text" id="node-input-tag" list="fuxa-change-tags" placeholder="Tag Name">
84
+ <label for="node-input-tagSelected"><i class="fa fa-tag"></i> Tag</label>
85
+ <input type="text" id="node-input-tagSelected" list="fuxa-change-tags" placeholder="Select Tag">
37
86
  <datalist id="fuxa-change-tags"></datalist>
38
87
  </div>
88
+ <input type="hidden" id="node-input-tag">
89
+ <input type="hidden" id="node-input-tagId">
39
90
  </script>
40
91
 
41
92
  <script type="text/x-red" data-help-name="get-tag-change">
@@ -7,26 +7,26 @@ module.exports = function(RED) {
7
7
  // Store previous values to detect actual changes
8
8
  var previousValues = {};
9
9
 
10
+ // Prefer config.tagId, fallback to config.tag for backward compatibility
11
+ var configuredTagId = config.tagId;
12
+ if (!configuredTagId && config.tag) {
13
+ // Backward compatibility: old nodes use tag.name, need to convert to tagId
14
+ configuredTagId = fuxa.getTagId(config.tag, null);
15
+ }
16
+
10
17
  // Initialize previous value for the configured tag
11
- if (config.tag) {
12
- var tagId = fuxa.getTagId(config.tag, null);
13
- if (tagId) {
14
- // Initialize previous value
15
- var initialValue = fuxa.getTag(tagId);
16
- if (initialValue !== undefined) {
17
- previousValues[tagId] = initialValue;
18
- }
18
+ if (configuredTagId) {
19
+ var initialValue = fuxa.getTag(configuredTagId);
20
+ if (initialValue !== undefined) {
21
+ previousValues[configuredTagId] = initialValue;
19
22
  }
20
23
  }
21
24
 
22
- // Event listener for device value changes (raw events from devices)
25
+ // Event listener for device value changes (raw events from devices)
23
26
  var deviceEventListener = function(deviceEvent) {
24
27
  try {
25
28
  // deviceEvent format: { id: deviceId, values: { tagId: tagObject, ... } }
26
29
  if (deviceEvent && deviceEvent.values) {
27
- // Check if any of the changed values match our configured tag
28
- var configuredTagId = fuxa.getTagId(config.tag, null);
29
-
30
30
  if (configuredTagId && deviceEvent.values[configuredTagId]) {
31
31
  var tagData = deviceEvent.values[configuredTagId];
32
32
 
@@ -4,23 +4,72 @@
4
4
  color: '#a6bbcf',
5
5
  defaults: {
6
6
  name: {value:""},
7
- tag: {value:"", required:true}
7
+ tag: {value:""}, // Keep: tag name for display and backward compatibility
8
+ tagId: {value:""} // New: unique identifier (optional, for backward compatibility)
8
9
  },
9
10
  inputs:1,
10
11
  outputs:1,
11
12
  icon: "white-globe.png",
12
13
  label: function() {
13
- return this.name||this.tag||"get tag daq settings";
14
+ if (this.name) {
15
+ return this.name;
16
+ }
17
+ // Display tag name or tagId
18
+ return this.tag || this.tagId || "get tag daq settings";
14
19
  },
15
20
  oneditprepare: function() {
21
+ var node = this;
22
+ var tagMap = {}; // Use tag.id as key to avoid tag.name duplication issues
23
+
16
24
  $.getJSON('/nodered/fuxa/devices', function(data) {
17
25
  var datalist = $('#fuxa-tags-daq-settings');
18
26
  datalist.empty();
27
+
19
28
  data.forEach(function(device) {
20
29
  device.tags.forEach(function(tag) {
21
- datalist.append('<option value="' + tag.name + '">' + device.name + ' - ' + tag.name + '</option>');
30
+ var fullName = device.name + ' - ' + tag.name;
31
+ // datalist option value format: tag.name(tag.id)
32
+ var optionValue = tag.name + '(' + tag.id + ')';
33
+ datalist.append('<option value="' + optionValue + '">' + fullName + '</option>');
34
+ tagMap[tag.id] = {
35
+ name: tag.name,
36
+ deviceName: device.name,
37
+ fullName: fullName
38
+ };
22
39
  });
23
40
  });
41
+
42
+ // Listen for tagSelected input changes
43
+ $('#node-input-tagSelected').on('change', function() {
44
+ var selectedValue = $(this).val();
45
+ // Parse format: tag.name(tag.id)
46
+ var match = selectedValue.match(/^(.+)\(([^)]+)\)$/);
47
+ if (match) {
48
+ var tagName = match[1];
49
+ var tagId = match[2];
50
+
51
+ // Set the actual stored fields
52
+ $('#node-input-tag').val(tagName);
53
+ $('#node-input-tagId').val(tagId);
54
+ }
55
+ });
56
+
57
+ // Initialize display (when editing existing node)
58
+ if (node.tagId && tagMap[node.tagId]) {
59
+ // Has tagId, construct tagSelected value
60
+ var tagName = node.tag || tagMap[node.tagId].name;
61
+ $('#node-input-tagSelected').val(tagName + '(' + node.tagId + ')');
62
+ } else if (node.tag && !node.tagId) {
63
+ // Old node: only has tag (tag.name), need to find corresponding tagId
64
+ // Note: if there are duplicate names, only the first match will be found
65
+ for (var tagId in tagMap) {
66
+ if (tagMap[tagId].name === node.tag) {
67
+ $('#node-input-tagSelected').val(node.tag + '(' + tagId + ')');
68
+ $('#node-input-tagId').val(tagId);
69
+ break;
70
+ }
71
+ }
72
+ }
24
73
  });
25
74
  }
26
75
  });
@@ -32,10 +81,12 @@
32
81
  <input type="text" id="node-input-name" placeholder="Name">
33
82
  </div>
34
83
  <div class="form-row">
35
- <label for="node-input-tag"><i class="fa fa-tag"></i> Tag</label>
36
- <input type="text" id="node-input-tag" list="fuxa-tags-daq-settings" placeholder="Tag Name">
84
+ <label for="node-input-tagSelected"><i class="fa fa-tag"></i> Tag</label>
85
+ <input type="text" id="node-input-tagSelected" list="fuxa-tags-daq-settings" placeholder="Select Tag">
37
86
  <datalist id="fuxa-tags-daq-settings"></datalist>
38
87
  </div>
88
+ <input type="hidden" id="node-input-tag">
89
+ <input type="hidden" id="node-input-tagId">
39
90
  </script>
40
91
 
41
92
  <script type="text/x-red" data-help-name="get-tag-daq-settings">
@@ -6,18 +6,22 @@ module.exports = function(RED) {
6
6
 
7
7
  this.on('input', async function(msg) {
8
8
  try {
9
- var tagName = config.tag || msg.tag;
10
- if (tagName) {
11
- var tagId = fuxa.getTagId(tagName, null);
12
- if (tagId) {
13
- var settings = await fuxa.getTagDaqSettings(tagId);
14
- msg.payload = settings;
15
- node.send(msg);
16
- } else {
17
- node.error('Tag not found: ' + tagName, msg);
9
+ // Prefer config.tagId, fallback to config.tag or msg.tag for backward compatibility
10
+ var tagId = config.tagId;
11
+ if (!tagId) {
12
+ var tagName = config.tag || msg.tag;
13
+ if (tagName) {
14
+ // Backward compatibility: old nodes use tag.name, need to convert to tagId
15
+ tagId = fuxa.getTagId(tagName, null);
18
16
  }
17
+ }
18
+
19
+ if (tagId) {
20
+ var settings = await fuxa.getTagDaqSettings(tagId);
21
+ msg.payload = settings;
22
+ node.send(msg);
19
23
  } else {
20
- node.error('Tag name not specified', msg);
24
+ node.error('Tag not found: ' + (config.tag || msg.tag || config.tagId), msg);
21
25
  }
22
26
  } catch (err) {
23
27
  node.error(err, msg);
@@ -4,23 +4,72 @@
4
4
  color: '#a6bbcf',
5
5
  defaults: {
6
6
  name: {value:""},
7
- tag: {value:"", required:true}
7
+ tag: {value:""}, // Keep: tag name for display and backward compatibility
8
+ tagId: {value:""} // New: unique identifier (optional, for backward compatibility)
8
9
  },
9
10
  inputs:1,
10
11
  outputs:1,
11
12
  icon: "white-globe.png",
12
13
  label: function() {
13
- return this.name||this.tag||"get tag";
14
+ if (this.name) {
15
+ return this.name;
16
+ }
17
+ // Display tag name or tagId
18
+ return this.tag || this.tagId || "get tag";
14
19
  },
15
20
  oneditprepare: function() {
21
+ var node = this;
22
+ var tagMap = {}; // Use tag.id as key to avoid tag.name duplication issues
23
+
16
24
  $.getJSON('/nodered/fuxa/devices', function(data) {
17
25
  var datalist = $('#fuxa-tags');
18
26
  datalist.empty();
27
+
19
28
  data.forEach(function(device) {
20
29
  device.tags.forEach(function(tag) {
21
- datalist.append('<option value="' + tag.name + '">' + device.name + ' - ' + tag.name + '</option>');
30
+ var fullName = device.name + ' - ' + tag.name;
31
+ // datalist option value format: tag.name(tag.id)
32
+ var optionValue = tag.name + '(' + tag.id + ')';
33
+ datalist.append('<option value="' + optionValue + '">' + fullName + '</option>');
34
+ tagMap[tag.id] = {
35
+ name: tag.name,
36
+ deviceName: device.name,
37
+ fullName: fullName
38
+ };
22
39
  });
23
40
  });
41
+
42
+ // Listen for tagSelected input changes
43
+ $('#node-input-tagSelected').on('change', function() {
44
+ var selectedValue = $(this).val();
45
+ // Parse format: tag.name(tag.id)
46
+ var match = selectedValue.match(/^(.+)\(([^)]+)\)$/);
47
+ if (match) {
48
+ var tagName = match[1];
49
+ var tagId = match[2];
50
+
51
+ // Set the actual stored fields
52
+ $('#node-input-tag').val(tagName);
53
+ $('#node-input-tagId').val(tagId);
54
+ }
55
+ });
56
+
57
+ // Initialize display (when editing existing node)
58
+ if (node.tagId && tagMap[node.tagId]) {
59
+ // Has tagId, construct tagSelected value
60
+ var tagName = node.tag || tagMap[node.tagId].name;
61
+ $('#node-input-tagSelected').val(tagName + '(' + node.tagId + ')');
62
+ } else if (node.tag && !node.tagId) {
63
+ // Old node: only has tag (tag.name), need to find corresponding tagId
64
+ // Note: if there are duplicate names, only the first match will be found
65
+ for (var tagId in tagMap) {
66
+ if (tagMap[tagId].name === node.tag) {
67
+ $('#node-input-tagSelected').val(node.tag + '(' + tagId + ')');
68
+ $('#node-input-tagId').val(tagId);
69
+ break;
70
+ }
71
+ }
72
+ }
24
73
  });
25
74
  }
26
75
  });
@@ -32,10 +81,12 @@
32
81
  <input type="text" id="node-input-name" placeholder="Name">
33
82
  </div>
34
83
  <div class="form-row">
35
- <label for="node-input-tag"><i class="fa fa-tag"></i> Tag</label>
36
- <input type="text" id="node-input-tag" list="fuxa-tags" placeholder="Tag Name">
84
+ <label for="node-input-tagSelected"><i class="fa fa-tag"></i> Tag</label>
85
+ <input type="text" id="node-input-tagSelected" list="fuxa-tags" placeholder="Select Tag">
37
86
  <datalist id="fuxa-tags"></datalist>
38
87
  </div>
88
+ <input type="hidden" id="node-input-tag">
89
+ <input type="hidden" id="node-input-tagId">
39
90
  </script>
40
91
 
41
92
  <script type="text/x-red" data-help-name="get-tag">
@@ -7,14 +7,20 @@ module.exports = function(RED) {
7
7
 
8
8
  this.on('input', function(msg) {
9
9
  try {
10
- var tagId = fuxa.getTagId(config.tag, null);
10
+ // Prefer config.tagId, fallback to config.tag for backward compatibility
11
+ var tagId = config.tagId;
12
+ if (!tagId && config.tag) {
13
+ // Backward compatibility: old nodes use tag.name, need to convert to tagId
14
+ tagId = fuxa.getTagId(config.tag, null);
15
+ }
16
+
11
17
  if (tagId) {
12
18
  var value = fuxa.getTag(tagId);
13
19
  msg.payload = value;
14
20
  msg.topic = config.tag; // Set topic to tag name for join operations
15
21
  node.send(msg);
16
22
  } else {
17
- node.error('Tag not found: ' + config.tag, msg);
23
+ node.error('Tag not found: ' + (config.tag || config.tagId), msg);
18
24
  }
19
25
  } catch (err) {
20
26
  node.error(err, msg);
@@ -4,7 +4,8 @@
4
4
  color: '#a6bbcf',
5
5
  defaults: {
6
6
  name: {value:""},
7
- tag: {value:"", required:true},
7
+ tag: {value:""}, // Keep: tag name for display and backward compatibility
8
+ tagId: {value:""}, // New: unique identifier (optional, for backward compatibility)
8
9
  enabled: {value:true},
9
10
  interval: {value:1000},
10
11
  deadband: {value:0}
@@ -13,17 +14,65 @@
13
14
  outputs:1,
14
15
  icon: "white-globe.png",
15
16
  label: function() {
16
- return this.name||this.tag||"set tag daq settings";
17
+ if (this.name) {
18
+ return this.name;
19
+ }
20
+ // Display tag name or tagId
21
+ return this.tag || this.tagId || "set tag daq settings";
17
22
  },
18
23
  oneditprepare: function() {
24
+ var node = this;
25
+ var tagMap = {}; // Use tag.id as key to avoid tag.name duplication issues
26
+
19
27
  $.getJSON('/nodered/fuxa/devices', function(data) {
20
28
  var datalist = $('#fuxa-tags-set-daq-settings');
21
29
  datalist.empty();
30
+
22
31
  data.forEach(function(device) {
23
32
  device.tags.forEach(function(tag) {
24
- datalist.append('<option value="' + tag.name + '">' + device.name + ' - ' + tag.name + '</option>');
33
+ var fullName = device.name + ' - ' + tag.name;
34
+ // datalist option value format: tag.name(tag.id)
35
+ var optionValue = tag.name + '(' + tag.id + ')';
36
+ datalist.append('<option value="' + optionValue + '">' + fullName + '</option>');
37
+ tagMap[tag.id] = {
38
+ name: tag.name,
39
+ deviceName: device.name,
40
+ fullName: fullName
41
+ };
25
42
  });
26
43
  });
44
+
45
+ // Listen for tagSelected input changes
46
+ $('#node-input-tagSelected').on('change', function() {
47
+ var selectedValue = $(this).val();
48
+ // Parse format: tag.name(tag.id)
49
+ var match = selectedValue.match(/^(.+)\(([^)]+)\)$/);
50
+ if (match) {
51
+ var tagName = match[1];
52
+ var tagId = match[2];
53
+
54
+ // Set the actual stored fields
55
+ $('#node-input-tag').val(tagName);
56
+ $('#node-input-tagId').val(tagId);
57
+ }
58
+ });
59
+
60
+ // Initialize display (when editing existing node)
61
+ if (node.tagId && tagMap[node.tagId]) {
62
+ // Has tagId, construct tagSelected value
63
+ var tagName = node.tag || tagMap[node.tagId].name;
64
+ $('#node-input-tagSelected').val(tagName + '(' + node.tagId + ')');
65
+ } else if (node.tag && !node.tagId) {
66
+ // Old node: only has tag (tag.name), need to find corresponding tagId
67
+ // Note: if there are duplicate names, only the first match will be found
68
+ for (var tagId in tagMap) {
69
+ if (tagMap[tagId].name === node.tag) {
70
+ $('#node-input-tagSelected').val(node.tag + '(' + tagId + ')');
71
+ $('#node-input-tagId').val(tagId);
72
+ break;
73
+ }
74
+ }
75
+ }
27
76
  });
28
77
  }
29
78
  });
@@ -35,10 +84,12 @@
35
84
  <input type="text" id="node-input-name" placeholder="Name">
36
85
  </div>
37
86
  <div class="form-row">
38
- <label for="node-input-tag"><i class="fa fa-tag"></i> Tag</label>
39
- <input type="text" id="node-input-tag" list="fuxa-tags-set-daq-settings" placeholder="Tag Name">
87
+ <label for="node-input-tagSelected"><i class="fa fa-tag"></i> Tag</label>
88
+ <input type="text" id="node-input-tagSelected" list="fuxa-tags-set-daq-settings" placeholder="Select Tag">
40
89
  <datalist id="fuxa-tags-set-daq-settings"></datalist>
41
90
  </div>
91
+ <input type="hidden" id="node-input-tag">
92
+ <input type="hidden" id="node-input-tagId">
42
93
  <div class="form-row">
43
94
  <label for="node-input-enabled">&nbsp;</label>
44
95
  <input type="checkbox" id="node-input-enabled" style="display:inline-block; width:15px; vertical-align:baseline;">
@@ -6,29 +6,33 @@ module.exports = function(RED) {
6
6
 
7
7
  this.on('input', async function(msg) {
8
8
  try {
9
- var tagName = config.tag || msg.tag;
10
- if (tagName) {
11
- var tagId = fuxa.getTagId(tagName, null);
12
- if (tagId) {
13
- var settings = {
14
- enabled: config.enabled,
15
- interval: config.interval,
16
- deadband: config.deadband
17
- };
9
+ // Prefer config.tagId, fallback to config.tag or msg.tag for backward compatibility
10
+ var tagId = config.tagId;
11
+ if (!tagId) {
12
+ var tagName = config.tag || msg.tag;
13
+ if (tagName) {
14
+ // Backward compatibility: old nodes use tag.name, need to convert to tagId
15
+ tagId = fuxa.getTagId(tagName, null);
16
+ }
17
+ }
18
+
19
+ if (tagId) {
20
+ var settings = {
21
+ enabled: config.enabled,
22
+ interval: config.interval,
23
+ deadband: config.deadband
24
+ };
18
25
 
19
- // Override with message properties if provided
20
- if (msg.enabled !== undefined) settings.enabled = msg.enabled;
21
- if (msg.interval !== undefined) settings.interval = msg.interval;
22
- if (msg.deadband !== undefined) settings.deadband = msg.deadband;
26
+ // Override with message properties if provided
27
+ if (msg.enabled !== undefined) settings.enabled = msg.enabled;
28
+ if (msg.interval !== undefined) settings.interval = msg.interval;
29
+ if (msg.deadband !== undefined) settings.deadband = msg.deadband;
23
30
 
24
- var result = await fuxa.setTagDaqSettings(tagId, settings);
25
- msg.payload = result;
26
- node.send(msg);
27
- } else {
28
- node.error('Tag not found: ' + tagName, msg);
29
- }
31
+ var result = await fuxa.setTagDaqSettings(tagId, settings);
32
+ msg.payload = result;
33
+ node.send(msg);
30
34
  } else {
31
- node.error('Tag name not specified', msg);
35
+ node.error('Tag not found: ' + (config.tag || msg.tag || config.tagId), msg);
32
36
  }
33
37
  } catch (err) {
34
38
  node.error(err, msg);