@bitpoolos/edge-bacnet 1.4.7 → 1.5.1

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/bacnet_read.html CHANGED
@@ -3,1012 +3,1049 @@
3
3
  -->
4
4
 
5
5
  <script type="text/javascript">
6
- RED.nodes.registerType("Bacnet-Discovery", {
7
- category: "Bitpool BACnet",
8
- color: "#00aeef",
9
- defaults: {
10
- name: { value: "" },
11
- events: { value: true },
12
- json: { value: true },
13
- mqtt: { value: false },
14
- pointJson: { value: false },
15
- hiddenDeployToggle: { value: false },
16
- prevHiddenToggleState: { value: false },
17
- roundDecimal: { value: 2 },
18
- deviceList: [],
19
- pointList: [],
20
- pointsToRead: { value: {} },
21
- readDevices: { value: [] },
22
- object_property_simplePayload: { value: false },
23
- object_property_simpleWithStatus: { value: false },
24
- object_property_fullObject: { value: true },
25
- useDeviceName: { value: true },
6
+ RED.nodes.registerType("Bacnet-Discovery", {
7
+ category: "Bitpool BACnet",
8
+ color: "#00aeef",
9
+ defaults: {
10
+ name: { value: "" },
11
+ events: { value: true },
12
+ json: { value: true },
13
+ mqtt: { value: false },
14
+ pointJson: { value: false },
15
+ hiddenDeployToggle: { value: false },
16
+ prevHiddenToggleState: { value: false },
17
+ roundDecimal: { value: 2 },
18
+ deviceList: [],
19
+ pointList: [],
20
+ pointsToRead: { value: {} },
21
+ readDevices: { value: [] },
22
+ object_property_simplePayload: { value: false },
23
+ object_property_simpleWithStatus: { value: false },
24
+ object_property_fullObject: { value: true },
25
+ useDeviceName: { value: true },
26
+ },
27
+ inputs: 1,
28
+ outputs: 1,
29
+ icon: "bitpool.svg",
30
+ label: function () {
31
+ return this.name || "read";
32
+ },
33
+ paletteLabel: function () {
34
+ return "read";
35
+ },
36
+ oneditprepare: function () {
37
+ let node = this;
38
+
39
+ node.prevHiddenToggleState = node.hiddenDeployToggle;
40
+
41
+ const { createApp, ref, onMounted } = Vue;
42
+
43
+ window.confirmDialogExists = window.confirmDialogExists || false;
44
+ if (node.vm == undefined && !window.confirmDialogExists) {
45
+ let confirmDialog = document.createElement("p-confirm-dialog");
46
+ document.getElementById("node-input-tabs-content").appendChild(confirmDialog);
47
+ window.confirmDialogExists = true;
48
+ }
49
+
50
+ //prime vue app
51
+ const App = {
52
+ data() {
53
+ return {
54
+ devices: ref(),
55
+ readDevices: ref(),
56
+ deviceList: ref(),
57
+ pointList: ref(),
58
+ pointsToRead: ref(),
59
+ nodeService: ref(new NodeService()),
60
+ pollFrequency: ref(),
61
+ deviceCount: ref(),
62
+ progressBarValue: ref(),
63
+ rightClickedDevice: ref(),
64
+ rightClickedPoint: ref(),
65
+ showDeviceNameDialog: ref(false),
66
+ showPointNameDialog: ref(false),
67
+ deviceDisplayNameValue: ref(),
68
+ pointDisplayNameValue: ref(),
69
+ calculateProgressBarWidth: ref(),
70
+ };
26
71
  },
27
- inputs: 1,
28
- outputs: 1,
29
- icon: "bitpool.svg",
30
- label: function () {
31
- return this.name || "read";
32
- },
33
- paletteLabel: function () {
34
- return "read";
35
- },
36
- oneditprepare: function () {
37
- let node = this;
38
-
39
- node.prevHiddenToggleState = node.hiddenDeployToggle;
40
-
41
- const { createApp, ref, onMounted } = Vue;
42
-
43
- //prime vue app
44
- const App = {
45
- data() {
46
- return {
47
- devices: ref(),
48
- readDevices: ref(),
49
- deviceList: ref(),
50
- pointList: ref(),
51
- pointsToRead: ref(),
52
- nodeService: ref(new NodeService()),
53
- pollFrequency: ref(),
54
- deviceCount: ref(),
55
- progressBarValue: ref(),
56
- rightClickedDevice: ref(),
57
- rightClickedPoint: ref(),
58
- showDeviceNameDialog: ref(false),
59
- showPointNameDialog: ref(false),
60
- deviceDisplayNameValue: ref(),
61
- pointDisplayNameValue: ref(),
62
- calculateProgressBarWidth: ref(),
63
- };
64
- },
65
- setup() {
66
- let pointList;
67
- let deviceList;
68
- const selectedKeys = ref(null);
69
- const nodes = ref();
70
- const expandedKeys = ref({});
71
- const expandAll = () => {
72
- for (let node of devices.value) {
73
- expandNode(node);
74
- }
75
-
76
- expandedKeys.value = { ...expandedKeys.value };
77
- };
78
- const collapseAll = () => {
79
- expandedKeys.value = {};
80
- };
81
- const expandNode = (node) => {
82
- if (node.children && node.children.length) {
83
- expandedKeys.value[node.key] = true;
84
-
85
- for (let child of node.children) {
86
- expandNode(child);
87
- }
88
- }
89
- };
90
-
91
- return {
92
- nodes,
93
- expandedKeys,
94
- expandAll,
95
- collapseAll,
96
- expandNode,
97
- };
98
- },
99
- mounted() {
100
- let app = this;
101
- this.getData(true);
102
-
103
- $("#readlist-file-upload").on("change", function (event) {
104
- const input = event.target.files[0];
105
- const reader = new FileReader();
106
-
107
- reader.readAsText(input);
108
-
109
- reader.onload = function (e) {
110
- const text = e.target.result;
111
- let jsonPayload = JSON.parse(text);
112
-
113
- app.nodeService.importReadList(jsonPayload).then(function (result) {
114
- if (result) {
115
- app.pointsToRead = jsonPayload;
116
- app.addToReadDevices(jsonPayload);
117
- }
118
- });
119
- };
120
- });
121
- },
122
- methods: {
123
- getData(initial) {
124
- let app = this;
125
- this.nodeService.getNetworkData().then(function (result) {
126
- //remove after below fixed
127
- app.devices = result.renderList;
128
- //end remove
129
-
130
- app.deviceList = result.deviceList;
131
- app.pointList = result.pointList;
132
- app.pollFrequency = parseInt(result.pollFrequency);
133
- app.deviceCount = result.deviceList.length;
134
-
135
- //progress bar percentage
136
- let progressVal = parseInt((result.renderListCount / result.deviceList.length) * 100);
137
- if (typeof progressVal == "number" && !isNaN(progressVal)) {
138
- app.progressBarValue = progressVal;
139
- } else {
140
- app.progressBarValue = 0;
141
- }
142
-
143
- //set progress bar width based on device count integer digit length
144
- if (app.deviceCount.toString().length >= 5) {
145
- app.calculateProgressBarWidth = "width: 200px;";
146
- } else if (app.deviceCount.toString().length == 4) {
147
- app.calculateProgressBarWidth = "width: 210px;";
148
- } else if (app.deviceCount.toString().length < 4) {
149
- app.calculateProgressBarWidth = "width: 220px;";
150
- }
151
-
152
- app.$forceUpdate();
153
- });
154
-
155
- app.$forceUpdate();
156
- },
157
- rebuildDataModel() {
158
- let app = this;
159
- app.nodeService.rebuildDataModel().then(function (result) {
160
- if (result == true) {
161
- app.progressBarValue = 0;
162
- }
163
- });
164
- app.$forceUpdate();
165
- },
166
- addAllDevices() {
167
- let app = this;
168
- app.devices.forEach(function (device) {
169
- app.addAllClicked({ node: device });
170
- });
171
- app.$forceUpdate();
172
- },
173
- addAllClicked(slotProps) {
174
- //update UI
175
- let app = this;
176
- let clone = JSON.parse(JSON.stringify(slotProps.node));
177
-
178
- while (clone.children.length > 1) {
179
- let child = clone.children[1];
180
- if (child.label.includes('MSTP')) {
181
- child.children.forEach(function (mstpDevice) {
182
- app.addAllClicked({ node: mstpDevice });
183
- });
184
- clone.children.splice(1, 1);
185
- }
186
- }
187
-
188
- if (this.readDevices) {
189
- let foundIndex = this.readDevices.findIndex((ele) => ele.initialName == slotProps.node.initialName);
190
- if (foundIndex == -1) {
191
- this.readDevices.push(clone);
192
- } else if (foundIndex !== -1) {
193
- this.readDevices[foundIndex] = clone;
194
- }
195
- } else {
196
- this.readDevices = [clone];
197
- }
198
- let deviceSlot = this.devices.find((ele) => ele.initialName == slotProps.node.initialName);
199
- if (deviceSlot) {
200
- deviceSlot.showAdded = true;
201
- deviceSlot.children[0].children.forEach(function (child) {
202
- child.showAdded = true;
203
- });
204
- }
205
- slotProps.node.showAdded = true;
206
- this.$forceUpdate();
207
- //update node-red data structure to forward to gateway
208
- let device = this.deviceList.find((ele) => {
209
- if (ele.address.address) {
210
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
211
- } else {
212
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
213
- }
214
- });
215
- let deviceAddress = app.getDeviceAddress(device.address);
216
- let key = `${deviceAddress}-${device.deviceId}`;
217
- let points = this.pointList[key];
218
- if (!this.pointsToRead[key]) {
219
- this.pointsToRead[key] = {};
220
- }
221
- for (let pointName in points) {
222
- let point = this.pointList[key][pointName];
223
- this.pointsToRead[key][point.objectName] = point;
224
- }
225
- //force a deploy state
226
- node.hiddenDeployToggle = !node.prevHiddenToggleState;
227
- },
228
- addPointClicked(slotProps) {
229
- let app = this;
230
- //update UI
231
- const parentDeviceName = slotProps.node.parentDevice;
232
- const slotDeviceId = slotProps.node.parentDeviceId;
233
- let device = this.deviceList.find((ele) => ele.deviceId == slotDeviceId);
234
- let foundDeviceIndex = this.readDevices
235
- ? this.readDevices.findIndex((ele) => ele.deviceId == device.deviceId)
236
- : -1;
237
- let deviceAddress = app.getDeviceAddress(device.address);
238
- let key = `${deviceAddress}-${device.deviceId}`;
239
- let parentDevice = this.devices.find((ele) => ele.ipAddr == deviceAddress);
240
- let childDevice;
241
- if (device.isMstp) {
242
- let indexMap = {
243
- deviceIndex: -1,
244
- mstpNetorkIndex: -1
245
- };
246
- parentDevice.children.forEach(function (child, index) {
247
- if (child.label.includes("MSTP")) {
248
- const tempIndex = child.children.findIndex(
249
- (ele) => ele.deviceId == slotDeviceId
250
- );
251
- if (tempIndex !== -1) {
252
- indexMap.deviceIndex = tempIndex;
253
- indexMap.mstpNetorkIndex = index;
254
- }
255
- }
256
- });
257
-
258
- if (indexMap.deviceIndex !== -1 && indexMap.mstpNetorkIndex !== -1) {
259
- childDevice = parentDevice.children[indexMap.mstpNetorkIndex].children[indexMap.deviceIndex];
260
- }
261
- }
262
-
263
- if (foundDeviceIndex == -1) {
264
- //no read devices present, add new
265
- let newReadParent;
266
- if (childDevice) {
267
- newReadParent = JSON.parse(JSON.stringify(childDevice));
268
- } else {
269
- newReadParent = JSON.parse(JSON.stringify(parentDevice));
270
- }
271
- newReadParent.children[0].children = [];
272
- newReadParent.children[0].children.push(slotProps.node);
273
- while (newReadParent.children.length > 1) {
274
- newReadParent.children.forEach(function (child, index) {
275
- if (child.label.includes("MSTP")) {
276
- newReadParent.children.splice(index, 1);
277
- }
278
- });
279
- }
280
- if (this.readDevices) {
281
- this.readDevices.push(newReadParent);
282
- } else {
283
- this.readDevices = [newReadParent];
284
- }
285
- } else {
286
- // read device found, add point to existing
287
- let pointIndex = this.readDevices[foundDeviceIndex].children[0].children.findIndex(
288
- (ele) => ele.pointName == slotProps.node.pointName
289
- );
290
- if (pointIndex == -1) {
291
- this.readDevices[foundDeviceIndex].children[0].children.push(slotProps.node);
292
- }
293
- }
294
-
295
- //set show added to true
296
- slotProps.node.showAdded = true;
297
- this.$forceUpdate();
298
-
299
- //update node-red data structure
300
- if (!this.pointsToRead[key]) {
301
- this.pointsToRead[key] = {};
302
- }
303
-
304
- let point = this.pointList[key][slotProps.node.pointName];
305
- this.pointsToRead[key][point.objectName] = point;
306
-
307
- //force a deploy state
308
- node.hiddenDeployToggle = !node.prevHiddenToggleState;
309
-
310
- app.$forceUpdate();
311
- },
312
- removeAllDevices() {
313
- let app = this;
314
- let clone = JSON.parse(JSON.stringify(app.readDevices));
315
- clone.forEach(function (device) {
316
- app.removeAllClicked({ node: device });
317
- });
318
-
319
- app.pointsToRead = {};
320
-
321
- app.$forceUpdate();
322
- },
323
- removeAllClicked(slotProps) {
324
- let app = this;
325
-
326
- try {
327
- //update UI
328
- if (app.readDevices.length > 0) {
329
- let foundIndex = app.readDevices.findIndex(
330
- (ele) => ele.key == slotProps.node.key && ele.label == slotProps.node.label
331
- );
332
- if (foundIndex !== -1) app.readDevices.splice(foundIndex, 1);
333
- }
72
+ setup() {
73
+ let pointList;
74
+ let deviceList;
75
+ const selectedKeys = ref(null);
76
+ const nodes = ref();
77
+ const expandedKeys = ref({});
78
+ const expandAll = () => {
79
+ for (let node of devices.value) {
80
+ expandNode(node);
81
+ }
334
82
 
335
- let deviceSlot = app.devices.find((ele) => ele.label == slotProps.node.label);
336
- if (deviceSlot) {
337
- deviceSlot.showAdded = false;
338
- deviceSlot.children.forEach(function (child) {
339
- child.showAdded = false;
340
- });
341
- }
342
- slotProps.node.showAdded = false;
343
- app.$forceUpdate();
344
-
345
- //update node-red data structure
346
- let device = app.deviceList.find((ele) => {
347
- if (ele.address.address) {
348
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
349
- } else {
350
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
351
- }
352
- });
353
- let deviceAddress = app.getDeviceAddress(device.address);
354
- let key = `${deviceAddress}-${device.deviceId}`;
355
- if (app.pointsToRead[key]) {
356
- delete app.pointsToRead[key];
357
- }
83
+ expandedKeys.value = { ...expandedKeys.value };
84
+ };
85
+ const collapseAll = () => {
86
+ expandedKeys.value = {};
87
+ };
88
+ const expandNode = (node) => {
89
+ if (node.children && node.children.length) {
90
+ expandedKeys.value[node.key] = true;
91
+
92
+ for (let child of node.children) {
93
+ expandNode(child);
94
+ }
95
+ }
96
+ };
97
+
98
+ return {
99
+ nodes,
100
+ expandedKeys,
101
+ expandAll,
102
+ collapseAll,
103
+ expandNode,
104
+ };
105
+ },
106
+ mounted() {
107
+ let app = this;
108
+ this.getData(true);
358
109
 
359
- //force a deploy state
360
- node.hiddenDeployToggle = !node.prevHiddenToggleState;
361
- } catch (e) {
362
- //do nothing
363
- }
110
+ $("#readlist-file-upload").on("change", function (event) {
111
+ const input = event.target.files[0];
112
+ const reader = new FileReader();
364
113
 
365
- app.$forceUpdate();
366
- },
367
- removePointClicked(slotProps) {
368
- let app = this;
369
-
370
- //update UI
371
- let parentDeviceName = slotProps.node.parentDevice;
372
- let parentDevice = this.devices.find((ele) => ele.label == parentDeviceName);
373
- const slotDeviceId = slotProps.node.parentDeviceId;
374
- let device = this.deviceList.find((ele) => ele.deviceId == slotDeviceId);
375
- let foundDeviceIndex = this.readDevices
376
- ? this.readDevices.findIndex((ele) => ele.deviceId == device.deviceId)
377
- : -1;
378
- let deviceAddress = app.getDeviceAddress(device.address);
379
- let key = `${deviceAddress}-${device.deviceId}`;
114
+ reader.readAsText(input);
380
115
 
381
- if (foundDeviceIndex !== -1) {
382
- let foundIndex = this.readDevices[foundDeviceIndex].children[0].children.findIndex(
383
- (ele) => ele.pointName == slotProps.node.pointName
384
- );
385
- if (foundIndex !== -1) this.readDevices[foundDeviceIndex].children[0].children.splice(foundIndex, 1);
386
- if (this.readDevices[foundDeviceIndex].children[0].children.length == 0) {
387
- this.readDevices.splice(foundDeviceIndex, 1);
388
- }
389
- }
116
+ reader.onload = function (e) {
117
+ const text = e.target.result;
118
+ let jsonPayload = JSON.parse(text);
390
119
 
391
- //set show added to true
392
- slotProps.node.showAdded = false;
393
- this.$forceUpdate();
394
-
395
- //update node-red data stucture
396
- let point = this.pointList[key][slotProps.node.pointName];
397
- if (this.pointsToRead[key][point.objectName]) delete this.pointsToRead[key][point.objectName];
398
- //if last point is removed, deleted whole entry
399
- if (Object.keys(this.pointsToRead[key]).length == 0) delete this.pointsToRead[key];
400
-
401
- //force a deploy state
402
- node.hiddenDeployToggle = !node.prevHiddenToggleState;
403
-
404
- app.$forceUpdate();
405
- },
406
- exportPointListCsv() {
407
- let app = this;
408
- let csvContent = "ipAddress,deviceId,deviceName,pointName,objectType" + "\r\n";
409
- const keys = Object.keys(app.pointList);
410
- for (key in keys) {
411
- const guid = keys[key];
412
- const ipAddress = guid.split("-")[0];
413
- const deviceId = guid.split("-")[1];
414
- const deviceObject = app.pointList[keys[key]];
415
- const device = app.deviceList.find((ele) => {
416
- if (ele.address.address) {
417
- return ele.address.address == ipAddress && ele.deviceId == deviceId;
418
- } else {
419
- return ele.address == ipAddress && ele.deviceId == deviceId;
420
- }
421
- });
422
- if (device) {
423
- const deviceName = device.deviceName;
424
- const points = Object.keys(deviceObject);
425
- for (point in points) {
426
- csvContent +=
427
- ipAddress +
428
- "," +
429
- deviceId +
430
- "," +
431
- deviceName +
432
- "," +
433
- points[point] +
434
- "," +
435
- deviceObject[points[point]].meta.objectId.type +
436
- "\r\n";
437
-
438
- if (parseInt(point) == points.length - 1 && parseInt(key) == keys.length - 1) {
439
- // last iteration
440
- var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
441
- var link = document.createElement("a");
442
- var url = URL.createObjectURL(csvBlob);
443
- link.setAttribute("href", url);
444
- link.setAttribute("download", "pointslist.csv");
445
- document.body.appendChild(link);
446
- link.click();
447
- }
448
- }
449
- } else {
450
- if (parseInt(key) == keys.length - 1) {
451
- // last iteration
452
- var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
453
- var link = document.createElement("a");
454
- var url = URL.createObjectURL(csvBlob);
455
- link.setAttribute("href", url);
456
- link.setAttribute("download", "pointslist.csv");
457
- document.body.appendChild(link);
458
- link.click();
459
- }
460
- }
461
- }
462
- },
463
- getDeviceAddress(addr) {
464
- switch (typeof addr) {
465
- case "object":
466
- return addr.address;
467
- case "string":
468
- return addr;
469
- default:
470
- return addr;
471
- }
472
- },
473
- isDeviceActive(slotProps) {
474
- let app = this;
475
- if ((Date.now() - slotProps.node.lastSeen) / 1000 < app.pollFrequency + 5) {
476
- return true;
477
- } else if (slotProps.node.isDumbMstpRouter == true || slotProps.node.isDumbMstpRouter == "true") {
478
- return true;
479
- }
480
- return false;
481
- },
482
- isDeviceAdded(slotProps) {
483
- if (slotProps.node.showAdded == true) {
484
- return true;
485
- } else {
486
- return false;
487
- }
488
- },
489
- hasMstpDevices(slotProps) {
490
- if (slotProps.node.children[1] && slotProps.node.children[1].children.length > 0) {
491
- return true;
492
- }
493
- return false;
494
- },
495
- isSlotAdded(slotProps) {
496
- return slotProps.node.showAdded;
497
- },
498
- hasData() {
499
- if (this.devices && this.devices.length > 0) {
500
- return true;
501
- } else {
502
- return false;
503
- }
504
- },
505
- emptyTree() {
506
- if (this.devices.length > 0) {
507
- return true;
508
- }
509
- return false;
510
- },
511
- onDeviceRightClick(slotProps, event) {
512
- let app = this;
513
- app.rightClickedDevice = slotProps;
514
- event.preventDefault();
515
- menu.style.setProperty("--mouse-x", event.clientX + "px");
516
- menu.style.setProperty("--mouse-y", event.clientY + "px");
517
- menu.style.display = "block";
518
- },
519
- onPointRightClick(slotProps, event) {
520
- let app = this;
521
- app.rightClickedPoint = slotProps;
522
- event.preventDefault();
523
- pointMenu.style.setProperty("--mouse-x", event.clientX + "px");
524
- pointMenu.style.setProperty("--mouse-y", event.clientY + "px");
525
- pointMenu.style.display = "block";
526
- },
527
- handleContextMenuClick(type) {
528
- let app = this;
529
- switch (type) {
530
- case "purgeDevice":
531
- app.purgeDevice(app.rightClickedDevice);
532
- break;
533
- case "updatePoints":
534
- app.updatePointsForDevice(app.rightClickedDevice);
535
- break;
536
- case "addAllPoints":
537
- app.addAllClicked(app.rightClickedDevice);
538
- break;
539
- case "removeAllPoints":
540
- app.removeAllClicked(app.rightClickedDevice);
541
- break;
542
- case "setDeviceName":
543
- app.showDeviceNameDialog = true;
544
- app.deviceDisplayNameValue = app.rightClickedDevice.node.label;
545
- break;
546
- default:
547
- break;
548
- }
549
- },
550
- handlePointContextMenuClick(type) {
551
- let app = this;
552
- switch (type) {
553
- case "setPointName":
554
- app.showPointNameDialog = true;
555
- app.pointDisplayNameValue = app.rightClickedPoint.node.label;
556
- break;
557
- case "updatePoint":
558
- app.updatePoint(app.rightClickedPoint);
559
- break;
560
- default:
561
- break;
562
- }
563
- },
564
- purgeDevice(slotProps) {
565
- let app = this;
566
- let device = app.deviceList.find((ele) => {
567
- if (ele.address.address) {
568
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
569
- } else {
570
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
571
- }
572
- });
573
- if (device) {
574
- app.nodeService.purgeDevice(device).then(function (result) { });
575
- }
576
- },
577
- updatePointsForDevice(slotProps) {
578
- let app = this;
579
- let device = app.deviceList.find((ele) => {
580
- if (ele.address.address) {
581
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
582
- } else {
583
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
584
- }
585
- });
586
- if (device) {
587
- app.nodeService.updatePointsForDevice(device).then(function (result) { });
588
- }
589
- },
590
- updatePoint(slotProps) {
591
- let app = this;
592
- let device = app.deviceList.find((ele) => {
593
- if (ele.address.address) {
594
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
595
- } else {
596
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
597
- }
598
- });
599
- if (device) {
600
- app.nodeService.updatePoint(device).then(function (result) { });
601
- }
602
- },
603
- setDeviceName() {
604
- let app = this;
605
- const slotProps = app.rightClickedDevice;
606
- const displayName = app.deviceDisplayNameValue;
607
- let device = app.deviceList.find((ele) => {
608
- if (ele.address.address) {
609
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
610
- } else {
611
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
612
- }
613
- });
614
-
615
- if (device) {
616
- app.nodeService.setDeviceDisplayName(device, displayName).then(function (result) {
617
- if (result) {
618
- slotProps.node.label = displayName;
619
- }
620
- });
621
- }
622
-
623
- app.showDeviceNameDialog = false;
624
- },
625
- setPointName() {
626
- let app = this;
120
+ app.nodeService.importReadList(jsonPayload).then(function (result) {
121
+ if (result) {
122
+ app.pointsToRead = jsonPayload;
123
+ app.addToReadDevices(jsonPayload);
124
+ }
125
+ });
126
+ };
127
+ });
128
+ },
129
+ methods: {
130
+ getData(initial) {
131
+ let app = this;
132
+ this.nodeService.getNetworkData().then(function (result) {
133
+ //remove after below fixed
134
+ app.devices = result.renderList;
135
+ //end remove
136
+
137
+ app.deviceList = result.deviceList;
138
+ app.pointList = result.pointList;
139
+ app.pollFrequency = parseInt(result.pollFrequency);
140
+ app.deviceCount = result.deviceList.length;
141
+
142
+ //progress bar percentage
143
+ let progressVal = parseInt((result.renderListCount / result.deviceList.length) * 100);
144
+ if (typeof progressVal == "number" && !isNaN(progressVal)) {
145
+ app.progressBarValue = progressVal;
146
+ } else {
147
+ app.progressBarValue = 0;
148
+ }
149
+
150
+ //set progress bar width based on device count integer digit length
151
+ if (app.deviceCount.toString().length >= 5) {
152
+ app.calculateProgressBarWidth = "width: 200px;";
153
+ } else if (app.deviceCount.toString().length == 4) {
154
+ app.calculateProgressBarWidth = "width: 210px;";
155
+ } else if (app.deviceCount.toString().length < 4) {
156
+ app.calculateProgressBarWidth = "width: 220px;";
157
+ }
158
+
159
+ app.$forceUpdate();
160
+ });
627
161
 
628
- const slotProps = app.rightClickedPoint;
629
- const pointDisplayName = app.pointDisplayNameValue;
630
- const pointName = slotProps.node.pointName;
162
+ app.$forceUpdate();
163
+ },
164
+ rebuildConfirm() {
165
+ let app = this;
166
+ this.$confirm.require({
167
+ message: "Do you want to delete the data model and UI tree? This action is not reversible",
168
+ header: "Delete Confirmation",
169
+ icon: "pi pi-info-circle",
170
+ acceptClass: "p-button-danger",
171
+ accept: () => {
172
+ //handle accept
173
+ app.rebuildDataModel();
174
+ },
175
+ reject: () => {
176
+ //handle reject
177
+ },
178
+ });
179
+ },
180
+ rebuildDataModel() {
181
+ let app = this;
182
+ app.nodeService.rebuildDataModel().then(function (result) {
183
+ if (result == true) {
184
+ app.progressBarValue = 0;
185
+ }
186
+ });
187
+ app.$forceUpdate();
188
+ },
189
+ addAllDevices() {
190
+ let app = this;
191
+ app.devices.forEach(function (device) {
192
+ app.addAllClicked({ node: device });
193
+ });
194
+ app.$forceUpdate();
195
+ },
196
+ addAllClicked(slotProps) {
197
+ //update UI
198
+ let app = this;
199
+ let clone = JSON.parse(JSON.stringify(slotProps.node));
200
+
201
+ while (clone.children.length > 1) {
202
+ let child = clone.children[1];
203
+ if (child.label.includes("MSTP")) {
204
+ child.children.forEach(function (mstpDevice) {
205
+ app.addAllClicked({ node: mstpDevice });
206
+ });
207
+ clone.children.splice(1, 1);
208
+ }
209
+ }
631
210
 
632
- let device = app.deviceList.find((ele) => {
633
- return ele.deviceName == slotProps.node.parentDevice;
634
- });
211
+ if (this.readDevices) {
212
+ let foundIndex = this.readDevices.findIndex((ele) => ele.initialName == slotProps.node.initialName);
213
+ if (foundIndex == -1) {
214
+ this.readDevices.push(clone);
215
+ } else if (foundIndex !== -1) {
216
+ this.readDevices[foundIndex] = clone;
217
+ }
218
+ } else {
219
+ this.readDevices = [clone];
220
+ }
221
+ let deviceSlot = this.devices.find((ele) => ele.initialName == slotProps.node.initialName);
222
+ if (deviceSlot) {
223
+ deviceSlot.showAdded = true;
224
+ deviceSlot.children[0].children.forEach(function (child) {
225
+ child.showAdded = true;
226
+ });
227
+ }
228
+ slotProps.node.showAdded = true;
229
+ this.$forceUpdate();
230
+ //update node-red data structure to forward to gateway
231
+ let device = this.deviceList.find((ele) => {
232
+ if (ele.address.address) {
233
+ return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
234
+ } else {
235
+ return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
236
+ }
237
+ });
238
+ let deviceAddress = app.getDeviceAddress(device.address);
239
+ let key = `${deviceAddress}-${device.deviceId}`;
240
+ let points = this.pointList[key];
241
+ if (!this.pointsToRead[key]) {
242
+ this.pointsToRead[key] = {};
243
+ }
244
+ for (let pointName in points) {
245
+ let point = this.pointList[key][pointName];
246
+ this.pointsToRead[key][point.objectName] = point;
247
+ }
248
+ //force a deploy state
249
+ node.hiddenDeployToggle = !node.prevHiddenToggleState;
250
+ },
251
+ addPointClicked(slotProps) {
252
+ let app = this;
253
+ //update UI
254
+ const parentDeviceName = slotProps.node.parentDevice;
255
+ const slotDeviceId = slotProps.node.parentDeviceId;
256
+ let device = this.deviceList.find((ele) => ele.deviceId == slotDeviceId);
257
+ let foundDeviceIndex = this.readDevices ? this.readDevices.findIndex((ele) => ele.deviceId == device.deviceId) : -1;
258
+ let deviceAddress = app.getDeviceAddress(device.address);
259
+ let key = `${deviceAddress}-${device.deviceId}`;
260
+ let parentDevice = this.devices.find((ele) => ele.ipAddr == deviceAddress);
261
+ let childDevice;
262
+ if (device.isMstp) {
263
+ let indexMap = {
264
+ deviceIndex: -1,
265
+ mstpNetorkIndex: -1,
266
+ };
267
+ parentDevice.children.forEach(function (child, index) {
268
+ if (child.label.includes("MSTP")) {
269
+ const tempIndex = child.children.findIndex((ele) => ele.deviceId == slotDeviceId);
270
+ if (tempIndex !== -1) {
271
+ indexMap.deviceIndex = tempIndex;
272
+ indexMap.mstpNetorkIndex = index;
273
+ }
274
+ }
275
+ });
635
276
 
636
- if (device) {
637
- let deviceAddress = app.getDeviceAddress(device.address);
638
- let deviceKey = `${deviceAddress}-${device.deviceId}`;
277
+ if (indexMap.deviceIndex !== -1 && indexMap.mstpNetorkIndex !== -1) {
278
+ childDevice = parentDevice.children[indexMap.mstpNetorkIndex].children[indexMap.deviceIndex];
279
+ }
280
+ }
639
281
 
640
- app.nodeService.setPointDisplayName(deviceKey, pointName, pointDisplayName).then(function (result) {
641
- if (result) {
642
- slotProps.node.label = pointDisplayName;
643
- }
644
- });
645
- }
282
+ if (foundDeviceIndex == -1) {
283
+ //no read devices present, add new
284
+ let newReadParent;
285
+ if (childDevice) {
286
+ newReadParent = JSON.parse(JSON.stringify(childDevice));
287
+ } else {
288
+ newReadParent = JSON.parse(JSON.stringify(parentDevice));
289
+ }
290
+ newReadParent.children[0].children = [];
291
+ newReadParent.children[0].children.push(slotProps.node);
292
+ while (newReadParent.children.length > 1) {
293
+ newReadParent.children.forEach(function (child, index) {
294
+ if (child.label.includes("MSTP")) {
295
+ newReadParent.children.splice(index, 1);
296
+ }
297
+ });
298
+ }
299
+ if (this.readDevices) {
300
+ this.readDevices.push(newReadParent);
301
+ } else {
302
+ this.readDevices = [newReadParent];
303
+ }
304
+ } else {
305
+ // read device found, add point to existing
306
+ let pointIndex = this.readDevices[foundDeviceIndex].children[0].children.findIndex(
307
+ (ele) => ele.pointName == slotProps.node.pointName
308
+ );
309
+ if (pointIndex == -1) {
310
+ this.readDevices[foundDeviceIndex].children[0].children.push(slotProps.node);
311
+ }
312
+ }
646
313
 
647
- app.showPointNameDialog = false;
648
- },
649
- settingDeviceName(slotProps) {
650
- let app = this;
651
- if (slotProps.node.settingDisplayName) {
652
- return true;
653
- }
654
- return false;
655
- },
656
- cancelDisplayNameDialog() {
657
- let app = this;
658
- app.deviceDisplayNameValue = "";
659
- app.showDeviceNameDialog = false;
660
- },
661
- cancelPointNameDialog() {
662
- let app = this;
663
- app.pointDisplayNameValue = "";
664
- app.showPointNameDialog = false;
665
- },
666
- exportReadList() {
667
- let app = this;
668
- let exportJson = {};
669
- let deviceIndex = 0;
670
- const devicesToExport = Object.keys(app.pointsToRead);
671
-
672
- doDevice(deviceIndex);
673
-
674
- function doDevice(deviceIndex) {
675
- const key = devicesToExport[deviceIndex];
676
- const device = app.pointsToRead[key];
677
-
678
- let readDevice = app.readDevices.find(ele => ele.ipAddr == key.split("-")[0] && ele.deviceId == key.split("-")[1]);
679
- let deviceName;
680
-
681
- if (readDevice) {
682
- deviceName = readDevice.label
683
- }
314
+ //set show added to true
315
+ slotProps.node.showAdded = true;
316
+ this.$forceUpdate();
684
317
 
685
- exportJson[key] = {};
686
- if (deviceName) {
687
- exportJson[key]["deviceName"] = deviceName;
688
- }
318
+ //update node-red data structure
319
+ if (!this.pointsToRead[key]) {
320
+ this.pointsToRead[key] = {};
321
+ }
689
322
 
690
- const devicePoints = Object.keys(device);
691
-
692
- for (let pointIndex = 0; pointIndex <= devicePoints.length; pointIndex++) {
693
- let pointName = devicePoints[pointIndex];
694
- let pointObject = device[pointName];
695
-
696
- //formatting json payload, still in progress
697
-
698
- if (pointObject) {
699
- exportJson[key][pointName] = {
700
- meta: pointObject.meta,
701
- objectName: pointObject.objectName,
702
- displayName: pointObject.displayName,
703
- };
704
- }
705
-
706
- if (pointIndex == devicePoints.length - 1) {
707
- //all points have been iterated
708
-
709
- if (deviceIndex < devicesToExport.length - 1) {
710
- //more work to do
711
- deviceIndex++;
712
- doDevice(deviceIndex);
713
- } else if (deviceIndex == devicesToExport.length - 1) {
714
- //all read devices complete
715
- let data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportJson));
716
- let aEle = document.getElementById("exportJSON");
717
- aEle.setAttribute("href", "data:" + data);
718
- aEle.setAttribute("download", "bacnet-read-list.json");
719
- aEle.click();
720
- }
721
- }
722
- }
723
- }
724
- },
725
- importReadList() {
726
- let app = this;
727
- $("#readlist-file-upload").click();
728
- },
729
- addToReadDevices(pointsToRead) {
730
- let app = this;
731
-
732
- for (let key in pointsToRead) {
733
- let ip = key.split("-")[0];
734
- let id = key.split("-")[1];
735
- const importedDevice = pointsToRead[key];
736
- let foundIndex = app.devices.findIndex((ele) => ele.ipAddr == ip);
737
-
738
- if (foundIndex !== -1) {
739
- // match ip, check id
740
- if (app.devices[foundIndex].deviceId == id) {
741
- //found device
742
- let treeDevice = app.devices[foundIndex];
743
- let device = app.deviceList.find((ele) => {
744
- if (ele.address.address) {
745
- return ele.address.address == ip && ele.deviceId == id;
746
- } else {
747
- return ele.address == ip && ele.deviceId == id;
748
- }
749
- });
750
-
751
- for (let pointName in importedDevice) {
752
- let point = importedDevice[pointName];
753
- if (pointName == "deviceName") {
754
- app.nodeService.setDeviceDisplayName(device, point);
755
- treeDevice.label = point;
756
- } else {
757
- let pointInTree = treeDevice.children[0].children.find(
758
- (ele) => ele.bacnetInstance == point.meta.objectId.instance && ele.bacnetType == point.meta.objectId.type
759
- );
760
-
761
- if (pointInTree) {
762
- pointInTree.label = point.displayName;
763
-
764
- const isDeviceInReadList = app.readDevices
765
- ? app.readDevices.findIndex((ele) => ele.deviceId == treeDevice.deviceId)
766
- : -1;
767
-
768
- if (isDeviceInReadList == -1) {
769
- //no read devices present, add new
770
- let newReadParent = JSON.parse(JSON.stringify(treeDevice));
771
- newReadParent.children[0].children = [];
772
- newReadParent.children[0].children.push(pointInTree);
773
- if (app.readDevices) {
774
- app.readDevices.push(newReadParent);
775
- } else {
776
- app.readDevices = [newReadParent];
777
- }
778
- } else {
779
- // read device found, add point to existing
780
- let pointIndex = app.readDevices[isDeviceInReadList].children[0].children.findIndex(
781
- (ele) => ele.data == point.objectName
782
- );
783
- if (pointIndex == -1) {
784
- app.readDevices[isDeviceInReadList].children[0].children.push(pointInTree);
785
- } else {
786
- app.readDevices[isDeviceInReadList].children[0].children[pointIndex] = pointInTree;
787
- }
788
- }
789
- }
790
- }
791
- }
792
- } else {
793
- //search mstp devices
794
- let mstpIndex = -1;
795
- let folderIndex = -1;
796
-
797
- app.devices[foundIndex].children.forEach(function (child, index) {
798
- let temporaryIndex = -1;
799
- if (child.label.includes("MSTP")) {
800
- temporaryIndex = child.children.findIndex((ele) => ele.deviceId == id);
801
- }
802
- if (temporaryIndex !== -1) {
803
- mstpIndex = temporaryIndex;
804
- folderIndex = index;
805
- }
806
- });
807
-
808
- if (mstpIndex !== -1 && folderIndex !== -1) {
809
- let mstpDevice = app.devices[foundIndex].children[folderIndex].children[mstpIndex];
810
- let device = app.deviceList.find((ele) => {
811
- if (ele.address.address) {
812
- return ele.address.address == ip && ele.deviceId == id;
813
- } else {
814
- return ele.address == ip && ele.deviceId == id;
815
- }
816
- });
817
-
818
- for (let pointName in importedDevice) {
819
- let point = importedDevice[pointName];
820
- if (pointName == "deviceName") {
821
- app.nodeService.setDeviceDisplayName(device, point);
822
- mstpDevice.label = point;
823
- } else {
824
- let pointInTree = mstpDevice.children[0].children.find(
825
- (ele) => ele.bacnetInstance == point.meta.objectId.instance && ele.bacnetType == point.meta.objectId.type
826
- );
827
-
828
- if (pointInTree) {
829
- pointInTree.label = point.displayName;
830
-
831
- const isDeviceInReadList = app.readDevices
832
- ? app.readDevices.findIndex((ele) => ele.deviceId == mstpDevice.deviceId)
833
- : -1;
834
-
835
- if (isDeviceInReadList == -1) {
836
- //no read devices present, add new
837
- let newReadParent = JSON.parse(JSON.stringify(mstpDevice));
838
- newReadParent.children[0].children = [];
839
- newReadParent.children[0].children.push(pointInTree);
840
- if (app.readDevices) {
841
- app.readDevices.push(newReadParent);
842
- } else {
843
- app.readDevices = [newReadParent];
844
- }
845
- } else {
846
- // read device found, add point to existing
847
- let pointIndex = app.readDevices[isDeviceInReadList].children[0].children.findIndex(
848
- (ele) => ele.data == point.objectName
849
- );
850
- if (pointIndex == -1) {
851
- app.readDevices[isDeviceInReadList].children[0].children.push(pointInTree);
852
- } else {
853
- app.readDevices[isDeviceInReadList].children[0].children[pointIndex] = pointInTree;
854
- }
855
- }
856
- }
857
- }
858
- }
859
- } else {
860
- // not part of device list at all, notify user
861
- }
862
- }
863
- }
864
- }
323
+ let point = this.pointList[key][slotProps.node.pointName];
324
+ this.pointsToRead[key][point.objectName] = point;
865
325
 
866
- app.$forceUpdate();
867
- },
868
- refreshReadListTree() {
869
- this.addToReadDevices(this.pointsToRead);
870
- },
871
- calculateMstpCount(slotProps) {
872
- let count = 0;
873
- slotProps.node.children.forEach(function (child) {
874
- if (child.label.includes("MSTP")) {
875
- count += child.children.length;
876
- }
877
- });
878
-
879
- return count;
880
- },
881
- calculatePointCount(slotProps) {
882
- let count = 0;
883
- return count;
884
- },
885
- },
886
- components: {
887
- "p-tree": primevue.tree,
888
- "p-button": primevue.button,
889
- "p-timeline": primevue.timeline,
890
- "p-progressbar": primevue.progressbar,
891
- "p-dialog": primevue.dialog,
892
- "p-input-text": primevue.inputtext,
893
- },
894
- };
326
+ //force a deploy state
327
+ node.hiddenDeployToggle = !node.prevHiddenToggleState;
895
328
 
896
- let vueapp = createApp(App);
897
- vueapp.use(primevue.config.default);
898
- vueapp.use(primevue.confirmationservice);
899
- node.vm = vueapp.mount("#node-input-tabs-content");
329
+ app.$forceUpdate();
330
+ },
331
+ removeAllDevices() {
332
+ let app = this;
333
+ let clone = JSON.parse(JSON.stringify(app.readDevices));
334
+ clone.forEach(function (device) {
335
+ app.removeAllClicked({ node: device });
336
+ });
900
337
 
901
- //reinstate device data
902
- if (node.readDevices) {
903
- node.vm.$data.readDevices = node.readDevices;
338
+ app.pointsToRead = {};
339
+
340
+ app.$forceUpdate();
341
+ },
342
+ removeAllClicked(slotProps) {
343
+ let app = this;
344
+
345
+ try {
346
+ //update UI
347
+ if (app.readDevices.length > 0) {
348
+ let foundIndex = app.readDevices.findIndex(
349
+ (ele) => ele.key == slotProps.node.key && ele.label == slotProps.node.label
350
+ );
351
+ if (foundIndex !== -1) app.readDevices.splice(foundIndex, 1);
352
+ }
353
+
354
+ let deviceSlot = app.devices.find((ele) => ele.label == slotProps.node.label);
355
+ if (deviceSlot) {
356
+ deviceSlot.showAdded = false;
357
+ deviceSlot.children.forEach(function (child) {
358
+ child.showAdded = false;
359
+ });
360
+ }
361
+ slotProps.node.showAdded = false;
362
+ app.$forceUpdate();
363
+
364
+ //update node-red data structure
365
+ let device = app.deviceList.find((ele) => {
366
+ if (ele.address.address) {
367
+ return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
368
+ } else {
369
+ return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
370
+ }
371
+ });
372
+ let deviceAddress = app.getDeviceAddress(device.address);
373
+ let key = `${deviceAddress}-${device.deviceId}`;
374
+ if (app.pointsToRead[key]) {
375
+ delete app.pointsToRead[key];
376
+ }
377
+
378
+ //force a deploy state
379
+ node.hiddenDeployToggle = !node.prevHiddenToggleState;
380
+ } catch (e) {
381
+ //do nothing
904
382
  }
905
383
 
906
- if (node.pointsToRead) {
907
- node.vm.$data.pointsToRead = node.pointsToRead;
384
+ app.$forceUpdate();
385
+ },
386
+ removePointClicked(slotProps) {
387
+ let app = this;
388
+
389
+ //update UI
390
+ let parentDeviceName = slotProps.node.parentDevice;
391
+ let parentDevice = this.devices.find((ele) => ele.label == parentDeviceName);
392
+ const slotDeviceId = slotProps.node.parentDeviceId;
393
+ let device = this.deviceList.find((ele) => ele.deviceId == slotDeviceId);
394
+ let foundDeviceIndex = this.readDevices ? this.readDevices.findIndex((ele) => ele.deviceId == device.deviceId) : -1;
395
+ let deviceAddress = app.getDeviceAddress(device.address);
396
+ let key = `${deviceAddress}-${device.deviceId}`;
397
+
398
+ if (foundDeviceIndex !== -1) {
399
+ let foundIndex = this.readDevices[foundDeviceIndex].children[0].children.findIndex(
400
+ (ele) => ele.pointName == slotProps.node.pointName
401
+ );
402
+ if (foundIndex !== -1) this.readDevices[foundDeviceIndex].children[0].children.splice(foundIndex, 1);
403
+ if (this.readDevices[foundDeviceIndex].children[0].children.length == 0) {
404
+ this.readDevices.splice(foundDeviceIndex, 1);
405
+ }
908
406
  }
909
407
 
910
- //set checkboxes to config values stored in backend
408
+ //set show added to true
409
+ slotProps.node.showAdded = false;
410
+ this.$forceUpdate();
411
+
412
+ //update node-red data stucture
413
+ let point = this.pointList[key][slotProps.node.pointName];
414
+ if (this.pointsToRead[key][point.objectName]) delete this.pointsToRead[key][point.objectName];
415
+ //if last point is removed, deleted whole entry
416
+ if (Object.keys(this.pointsToRead[key]).length == 0) delete this.pointsToRead[key];
417
+
418
+ //force a deploy state
419
+ node.hiddenDeployToggle = !node.prevHiddenToggleState;
420
+
421
+ app.$forceUpdate();
422
+ },
423
+ exportPointListCsv() {
424
+ let app = this;
425
+ let csvContent = "ipAddress,deviceId,deviceName,pointName,objectType" + "\r\n";
426
+ const keys = Object.keys(app.pointList);
427
+ for (key in keys) {
428
+ const guid = keys[key];
429
+ const ipAddress = guid.split("-")[0];
430
+ const deviceId = guid.split("-")[1];
431
+ const deviceObject = app.pointList[keys[key]];
432
+ const device = app.deviceList.find((ele) => {
433
+ if (ele.address.address) {
434
+ return ele.address.address == ipAddress && ele.deviceId == deviceId;
435
+ } else {
436
+ return ele.address == ipAddress && ele.deviceId == deviceId;
437
+ }
438
+ });
439
+ if (device) {
440
+ const deviceName = device.deviceName;
441
+ const points = Object.keys(deviceObject);
442
+ if (points.length > 0) {
443
+ for (point in points) {
444
+ csvContent +=
445
+ ipAddress +
446
+ "," +
447
+ deviceId +
448
+ "," +
449
+ deviceName +
450
+ "," +
451
+ points[point] +
452
+ "," +
453
+ deviceObject[points[point]].meta.objectId.type +
454
+ "\r\n";
455
+
456
+ if (parseInt(point) == points.length - 1 && parseInt(key) == keys.length - 1) {
457
+ // last iteration
458
+ var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
459
+ var link = document.createElement("a");
460
+ var url = URL.createObjectURL(csvBlob);
461
+ link.setAttribute("href", url);
462
+ link.setAttribute("download", "pointslist.csv");
463
+ document.body.appendChild(link);
464
+ link.click();
465
+ }
466
+ }
467
+ } else {
468
+ if (parseInt(key) == keys.length - 1) {
469
+ // last iteration
470
+ var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
471
+ var link = document.createElement("a");
472
+ var url = URL.createObjectURL(csvBlob);
473
+ link.setAttribute("href", url);
474
+ link.setAttribute("download", "pointslist.csv");
475
+ document.body.appendChild(link);
476
+ link.click();
477
+ }
478
+ }
479
+ } else {
480
+ if (parseInt(key) == keys.length - 1) {
481
+ // last iteration
482
+ var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
483
+ var link = document.createElement("a");
484
+ var url = URL.createObjectURL(csvBlob);
485
+ link.setAttribute("href", url);
486
+ link.setAttribute("download", "pointslist.csv");
487
+ document.body.appendChild(link);
488
+ link.click();
489
+ }
490
+ }
491
+ }
492
+ },
493
+ getDeviceAddress(addr) {
494
+ switch (typeof addr) {
495
+ case "object":
496
+ return addr.address;
497
+ case "string":
498
+ return addr;
499
+ default:
500
+ return addr;
501
+ }
502
+ },
503
+ isDeviceActive(slotProps) {
504
+ let app = this;
505
+ if ((Date.now() - slotProps.node.lastSeen) / 1000 < app.pollFrequency + 5) {
506
+ return true;
507
+ } else if (slotProps.node.isDumbMstpRouter == true || slotProps.node.isDumbMstpRouter == "true") {
508
+ return true;
509
+ }
510
+ return false;
511
+ },
512
+ isDeviceAdded(slotProps) {
513
+ if (slotProps.node.showAdded == true) {
514
+ return true;
515
+ } else {
516
+ return false;
517
+ }
518
+ },
519
+ hasMstpDevices(slotProps) {
520
+ if (slotProps.node.children[1] && slotProps.node.children[1].children.length > 0) {
521
+ return true;
522
+ }
523
+ return false;
524
+ },
525
+ isSlotAdded(slotProps) {
526
+ return slotProps.node.showAdded;
527
+ },
528
+ hasData() {
529
+ if (this.devices && this.devices.length > 0) {
530
+ return true;
531
+ } else {
532
+ return false;
533
+ }
534
+ },
535
+ emptyTree() {
536
+ if (this.devices.length > 0) {
537
+ return true;
538
+ }
539
+ return false;
540
+ },
541
+ onDeviceRightClick(slotProps, event) {
542
+ let app = this;
543
+ app.rightClickedDevice = slotProps;
544
+ event.preventDefault();
545
+ menu.style.setProperty("--mouse-x", event.clientX + "px");
546
+ menu.style.setProperty("--mouse-y", event.clientY + "px");
547
+ menu.style.display = "block";
548
+ },
549
+ onPointRightClick(slotProps, event) {
550
+ let app = this;
551
+ app.rightClickedPoint = slotProps;
552
+ event.preventDefault();
553
+ pointMenu.style.setProperty("--mouse-x", event.clientX + "px");
554
+ pointMenu.style.setProperty("--mouse-y", event.clientY + "px");
555
+ pointMenu.style.display = "block";
556
+ },
557
+ handleContextMenuClick(type) {
558
+ let app = this;
559
+ switch (type) {
560
+ case "purgeDevice":
561
+ app.purgeDevice(app.rightClickedDevice);
562
+ break;
563
+ case "updatePoints":
564
+ app.updatePointsForDevice(app.rightClickedDevice);
565
+ break;
566
+ case "addAllPoints":
567
+ app.addAllClicked(app.rightClickedDevice);
568
+ break;
569
+ case "removeAllPoints":
570
+ app.removeAllClicked(app.rightClickedDevice);
571
+ break;
572
+ case "setDeviceName":
573
+ app.showDeviceNameDialog = true;
574
+ app.deviceDisplayNameValue = app.rightClickedDevice.node.label;
575
+ break;
576
+ default:
577
+ break;
578
+ }
579
+ },
580
+ handlePointContextMenuClick(type) {
581
+ let app = this;
582
+ switch (type) {
583
+ case "setPointName":
584
+ app.showPointNameDialog = true;
585
+ app.pointDisplayNameValue = app.rightClickedPoint.node.label;
586
+ break;
587
+ case "updatePoint":
588
+ app.updatePoint(app.rightClickedPoint);
589
+ break;
590
+ default:
591
+ break;
592
+ }
593
+ },
594
+ purgeDevice(slotProps) {
595
+ let app = this;
596
+ let device = app.deviceList.find((ele) => {
597
+ if (ele.address.address) {
598
+ return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
599
+ } else {
600
+ return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
601
+ }
602
+ });
603
+ if (device) {
604
+ app.nodeService.purgeDevice(device).then(function (result) { });
605
+ }
606
+ },
607
+ updatePointsForDevice(slotProps) {
608
+ let app = this;
609
+ let device = app.deviceList.find((ele) => {
610
+ if (ele.address.address) {
611
+ return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
612
+ } else {
613
+ return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
614
+ }
615
+ });
616
+ if (device) {
617
+ app.nodeService.updatePointsForDevice(device).then(function (result) { });
618
+ }
619
+ },
620
+ updatePoint(slotProps) {
621
+ let app = this;
622
+ let device = app.deviceList.find((ele) => {
623
+ if (ele.address.address) {
624
+ return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
625
+ } else {
626
+ return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
627
+ }
628
+ });
629
+ if (device) {
630
+ app.nodeService.updatePoint(device).then(function (result) { });
631
+ }
632
+ },
633
+ setDeviceName() {
634
+ let app = this;
635
+ const slotProps = app.rightClickedDevice;
636
+ const displayName = app.deviceDisplayNameValue;
637
+ let device = app.deviceList.find((ele) => {
638
+ if (ele.address.address) {
639
+ return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
640
+ } else {
641
+ return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
642
+ }
643
+ });
911
644
 
912
- document.getElementById("node-input-object_property_simplePayload").checked = node.object_property_simplePayload;
913
- document.getElementById("node-input-object_property_simplePayload").onclick = handleCheckboxClick;
914
- document.getElementById("node-input-object_property_simpleWithStatus").checked = node.object_property_simpleWithStatus;
915
- document.getElementById("node-input-object_property_simpleWithStatus").onclick = handleCheckboxClick;
916
- document.getElementById("node-input-object_property_fullObject").checked = node.object_property_fullObject;
917
- document.getElementById("node-input-object_property_fullObject").onclick = handleCheckboxClick;
645
+ if (device) {
646
+ app.nodeService.setDeviceDisplayName(device, displayName).then(function (result) {
647
+ if (result) {
648
+ slotProps.node.label = displayName;
649
+ }
650
+ });
651
+ }
918
652
 
919
- document.getElementById("node-input-roundDecimal").value = node.roundDecimal;
920
- document.getElementById("node-input-json").checked = node.json;
921
- document.getElementById("node-input-json").onclick = handleMsgTypeClick;
922
- document.getElementById("node-input-mqtt").checked = node.mqtt;
923
- document.getElementById("node-input-mqtt").onclick = handleMsgTypeClick;
924
- document.getElementById("node-input-pointJson").checked = node.pointJson;
925
- document.getElementById("node-input-pointJson").onclick = handleMsgTypeClick;
653
+ app.showDeviceNameDialog = false;
654
+ },
655
+ setPointName() {
656
+ let app = this;
926
657
 
927
- document.getElementById("node-input-useDeviceName").checked = node.useDeviceName;
658
+ const slotProps = app.rightClickedPoint;
659
+ const pointDisplayName = app.pointDisplayNameValue;
660
+ const pointName = slotProps.node.pointName;
928
661
 
929
- var menu = document.querySelector(".context-menu");
930
- window.addEventListener("click", (event) => {
931
- menu.style.display = "none";
662
+ let device = app.deviceList.find((ele) => {
663
+ return ele.deviceName == slotProps.node.parentDevice;
932
664
  });
933
665
 
934
- var pointMenu = document.querySelector(".point-context-menu");
935
- window.addEventListener("click", (event) => {
936
- pointMenu.style.display = "none";
937
- });
666
+ if (device) {
667
+ let deviceAddress = app.getDeviceAddress(device.address);
668
+ let deviceKey = `${deviceAddress}-${device.deviceId}`;
938
669
 
939
- function handleCheckboxClick() {
940
- if (this.id == "node-input-object_property_simplePayload") {
941
- document.getElementById("node-input-object_property_fullObject").checked = false;
942
- document.getElementById("node-input-object_property_simpleWithStatus").checked = false;
943
- }
944
- if (this.id == "node-input-object_property_simpleWithStatus") {
945
- document.getElementById("node-input-object_property_fullObject").checked = false;
946
- document.getElementById("node-input-object_property_simplePayload").checked = false;
947
- }
948
- if (this.id == "node-input-object_property_fullObject") {
949
- document.getElementById("node-input-object_property_simplePayload").checked = false;
950
- document.getElementById("node-input-object_property_simpleWithStatus").checked = false;
670
+ app.nodeService.setPointDisplayName(deviceKey, pointName, pointDisplayName).then(function (result) {
671
+ if (result) {
672
+ slotProps.node.label = pointDisplayName;
951
673
  }
674
+ });
952
675
  }
953
676
 
954
- function handleMsgTypeClick() {
955
- if (this.id == "node-input-json") {
956
- document.getElementById("node-input-mqtt").checked = false;
957
- document.getElementById("node-input-pointJson").checked = false;
958
- }
959
- if (this.id == "node-input-mqtt") {
960
- document.getElementById("node-input-json").checked = false;
961
- document.getElementById("node-input-pointJson").checked = false;
677
+ app.showPointNameDialog = false;
678
+ },
679
+ settingDeviceName(slotProps) {
680
+ let app = this;
681
+ if (slotProps.node.settingDisplayName) {
682
+ return true;
683
+ }
684
+ return false;
685
+ },
686
+ cancelDisplayNameDialog() {
687
+ let app = this;
688
+ app.deviceDisplayNameValue = "";
689
+ app.showDeviceNameDialog = false;
690
+ },
691
+ cancelPointNameDialog() {
692
+ let app = this;
693
+ app.pointDisplayNameValue = "";
694
+ app.showPointNameDialog = false;
695
+ },
696
+ exportReadList() {
697
+ let app = this;
698
+ let exportJson = {};
699
+ let deviceIndex = 0;
700
+ const devicesToExport = Object.keys(app.pointsToRead);
701
+
702
+ doDevice(deviceIndex);
703
+
704
+ function doDevice(deviceIndex) {
705
+ const key = devicesToExport[deviceIndex];
706
+ const device = app.pointsToRead[key];
707
+
708
+ let readDevice = app.readDevices.find(
709
+ (ele) => ele.ipAddr == key.split("-")[0] && ele.deviceId == key.split("-")[1]
710
+ );
711
+ let deviceName;
712
+
713
+ if (readDevice) {
714
+ deviceName = readDevice.label;
715
+ }
716
+
717
+ exportJson[key] = {};
718
+ if (deviceName) {
719
+ exportJson[key]["deviceName"] = deviceName;
720
+ }
721
+
722
+ const devicePoints = Object.keys(device);
723
+
724
+ for (let pointIndex = 0; pointIndex <= devicePoints.length; pointIndex++) {
725
+ let pointName = devicePoints[pointIndex];
726
+ let pointObject = device[pointName];
727
+
728
+ //formatting json payload, still in progress
729
+
730
+ if (pointObject) {
731
+ exportJson[key][pointName] = {
732
+ meta: pointObject.meta,
733
+ objectName: pointObject.objectName,
734
+ displayName: pointObject.displayName,
735
+ };
962
736
  }
963
- if (this.id == "node-input-pointJson") {
964
- document.getElementById("node-input-json").checked = false;
965
- document.getElementById("node-input-mqtt").checked = false;
737
+
738
+ if (pointIndex == devicePoints.length - 1) {
739
+ //all points have been iterated
740
+
741
+ if (deviceIndex < devicesToExport.length - 1) {
742
+ //more work to do
743
+ deviceIndex++;
744
+ doDevice(deviceIndex);
745
+ } else if (deviceIndex == devicesToExport.length - 1) {
746
+ //all read devices complete
747
+ let data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportJson));
748
+ let aEle = document.getElementById("exportJSON");
749
+ aEle.setAttribute("href", "data:" + data);
750
+ aEle.setAttribute("download", "bacnet-read-list.json");
751
+ aEle.click();
752
+ }
966
753
  }
754
+ }
967
755
  }
756
+ },
757
+ importReadList() {
758
+ let app = this;
759
+ $("#readlist-file-upload").click();
760
+ },
761
+ addToReadDevices(pointsToRead) {
762
+ let app = this;
763
+
764
+ for (let key in pointsToRead) {
765
+ let ip = key.split("-")[0];
766
+ let id = key.split("-")[1];
767
+ const importedDevice = pointsToRead[key];
768
+ let foundIndex = app.devices.findIndex((ele) => ele.ipAddr == ip);
769
+
770
+ if (foundIndex !== -1) {
771
+ // match ip, check id
772
+ if (app.devices[foundIndex].deviceId == id) {
773
+ //found device
774
+ let treeDevice = app.devices[foundIndex];
775
+ let device = app.deviceList.find((ele) => {
776
+ if (ele.address.address) {
777
+ return ele.address.address == ip && ele.deviceId == id;
778
+ } else {
779
+ return ele.address == ip && ele.deviceId == id;
780
+ }
781
+ });
782
+
783
+ for (let pointName in importedDevice) {
784
+ let point = importedDevice[pointName];
785
+ if (pointName == "deviceName") {
786
+ app.nodeService.setDeviceDisplayName(device, point);
787
+ treeDevice.label = point;
788
+ } else {
789
+ let pointInTree = treeDevice.children[0].children.find(
790
+ (ele) => ele.bacnetInstance == point.meta.objectId.instance && ele.bacnetType == point.meta.objectId.type
791
+ );
792
+
793
+ if (pointInTree) {
794
+ pointInTree.label = point.displayName;
795
+
796
+ const isDeviceInReadList = app.readDevices
797
+ ? app.readDevices.findIndex((ele) => ele.deviceId == treeDevice.deviceId)
798
+ : -1;
799
+
800
+ if (isDeviceInReadList == -1) {
801
+ //no read devices present, add new
802
+ let newReadParent = JSON.parse(JSON.stringify(treeDevice));
803
+ newReadParent.children[0].children = [];
804
+ newReadParent.children[0].children.push(pointInTree);
805
+ if (app.readDevices) {
806
+ app.readDevices.push(newReadParent);
807
+ } else {
808
+ app.readDevices = [newReadParent];
809
+ }
810
+ } else {
811
+ // read device found, add point to existing
812
+ let pointIndex = app.readDevices[isDeviceInReadList].children[0].children.findIndex(
813
+ (ele) => ele.data == point.objectName
814
+ );
815
+ if (pointIndex == -1) {
816
+ app.readDevices[isDeviceInReadList].children[0].children.push(pointInTree);
817
+ } else {
818
+ app.readDevices[isDeviceInReadList].children[0].children[pointIndex] = pointInTree;
819
+ }
820
+ }
821
+ }
822
+ }
823
+ }
824
+ } else {
825
+ //search mstp devices
826
+ let mstpIndex = -1;
827
+ let folderIndex = -1;
828
+
829
+ app.devices[foundIndex].children.forEach(function (child, index) {
830
+ let temporaryIndex = -1;
831
+ if (child.label.includes("MSTP")) {
832
+ temporaryIndex = child.children.findIndex((ele) => ele.deviceId == id);
833
+ }
834
+ if (temporaryIndex !== -1) {
835
+ mstpIndex = temporaryIndex;
836
+ folderIndex = index;
837
+ }
838
+ });
839
+
840
+ if (mstpIndex !== -1 && folderIndex !== -1) {
841
+ let mstpDevice = app.devices[foundIndex].children[folderIndex].children[mstpIndex];
842
+ let device = app.deviceList.find((ele) => {
843
+ if (ele.address.address) {
844
+ return ele.address.address == ip && ele.deviceId == id;
845
+ } else {
846
+ return ele.address == ip && ele.deviceId == id;
847
+ }
848
+ });
968
849
 
969
- //create tabs
970
- let tabs = RED.tabs.create({
971
- id: "node-input-read-tabs",
972
- onchange: function (tab) {
973
- $("#node-input-tabs-content").children().hide();
974
- $("#" + tab.id).show();
975
- },
976
- });
977
-
978
- tabs.addTab({
979
- id: "read-networkTree-tab",
980
- label: "Device List",
981
- });
850
+ for (let pointName in importedDevice) {
851
+ let point = importedDevice[pointName];
852
+ if (pointName == "deviceName") {
853
+ app.nodeService.setDeviceDisplayName(device, point);
854
+ mstpDevice.label = point;
855
+ } else {
856
+ let pointInTree = mstpDevice.children[0].children.find(
857
+ (ele) =>
858
+ ele.bacnetInstance == point.meta.objectId.instance && ele.bacnetType == point.meta.objectId.type
859
+ );
860
+
861
+ if (pointInTree) {
862
+ pointInTree.label = point.displayName;
863
+
864
+ const isDeviceInReadList = app.readDevices
865
+ ? app.readDevices.findIndex((ele) => ele.deviceId == mstpDevice.deviceId)
866
+ : -1;
982
867
 
983
- tabs.addTab({
984
- id: "read-readList-tab",
985
- label: "Read List",
986
- });
868
+ if (isDeviceInReadList == -1) {
869
+ //no read devices present, add new
870
+ let newReadParent = JSON.parse(JSON.stringify(mstpDevice));
871
+ newReadParent.children[0].children = [];
872
+ newReadParent.children[0].children.push(pointInTree);
873
+ if (app.readDevices) {
874
+ app.readDevices.push(newReadParent);
875
+ } else {
876
+ app.readDevices = [newReadParent];
877
+ }
878
+ } else {
879
+ // read device found, add point to existing
880
+ let pointIndex = app.readDevices[isDeviceInReadList].children[0].children.findIndex(
881
+ (ele) => ele.data == point.objectName
882
+ );
883
+ if (pointIndex == -1) {
884
+ app.readDevices[isDeviceInReadList].children[0].children.push(pointInTree);
885
+ } else {
886
+ app.readDevices[isDeviceInReadList].children[0].children[pointIndex] = pointInTree;
887
+ }
888
+ }
889
+ }
890
+ }
891
+ }
892
+ } else {
893
+ // not part of device list at all, notify user
894
+ }
895
+ }
896
+ }
897
+ }
987
898
 
988
- tabs.addTab({
989
- id: "read-properties-tab",
990
- label: "Properties",
899
+ app.$forceUpdate();
900
+ },
901
+ refreshReadListTree() {
902
+ this.addToReadDevices(this.pointsToRead);
903
+ },
904
+ calculateMstpCount(slotProps) {
905
+ let count = 0;
906
+ slotProps.node.children.forEach(function (child) {
907
+ if (child.label.includes("MSTP")) {
908
+ count += child.children.length;
909
+ }
991
910
  });
992
911
 
993
- //remove loading animation
994
- let loadingGif = document.getElementById("loadingGif");
995
- let loadingText = document.getElementById("loadingText");
996
- let table = document.getElementById("read-networkTree-tab-content");
997
- loadingGif.style.display = "none";
998
- loadingText.style.display = "none";
999
- table.style.display = "inherit";
912
+ return count;
913
+ },
914
+ calculatePointCount(slotProps) {
915
+ let count = 0;
916
+ return count;
917
+ },
1000
918
  },
1001
- oneditsave: function () {
1002
- let node = this;
1003
- if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
1004
- if (node.vm.$data.pointsToRead) node.pointsToRead = node.vm.$data.pointsToRead;
919
+ components: {
920
+ "p-tree": primevue.tree,
921
+ "p-button": primevue.button,
922
+ "p-timeline": primevue.timeline,
923
+ "p-progressbar": primevue.progressbar,
924
+ "p-dialog": primevue.dialog,
925
+ "p-input-text": primevue.inputtext,
926
+ "p-confirm-dialog": primevue.confirmdialog,
927
+ "p-confirm-popup": primevue.confirmpopup,
1005
928
  },
1006
- oneditcancel: function () {
1007
- let node = this;
1008
- if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
1009
- if (node.vm.$data.pointsToRead) node.pointsToRead = node.vm.$data.pointsToRead;
929
+ };
930
+
931
+ let vueapp = createApp(App);
932
+ vueapp.use(primevue.config.default);
933
+ vueapp.use(primevue.confirmationservice);
934
+ vueapp.use(primevue.confirmpopup);
935
+
936
+ node.vm = vueapp.mount("#node-input-tabs-content");
937
+
938
+ //reinstate device data
939
+ if (node.readDevices) {
940
+ node.vm.$data.readDevices = node.readDevices;
941
+ }
942
+
943
+ if (node.pointsToRead) {
944
+ node.vm.$data.pointsToRead = node.pointsToRead;
945
+ }
946
+
947
+ //set checkboxes to config values stored in backend
948
+
949
+ document.getElementById("node-input-object_property_simplePayload").checked = node.object_property_simplePayload;
950
+ document.getElementById("node-input-object_property_simplePayload").onclick = handleCheckboxClick;
951
+ document.getElementById("node-input-object_property_simpleWithStatus").checked = node.object_property_simpleWithStatus;
952
+ document.getElementById("node-input-object_property_simpleWithStatus").onclick = handleCheckboxClick;
953
+ document.getElementById("node-input-object_property_fullObject").checked = node.object_property_fullObject;
954
+ document.getElementById("node-input-object_property_fullObject").onclick = handleCheckboxClick;
955
+
956
+ document.getElementById("node-input-roundDecimal").value = node.roundDecimal;
957
+ document.getElementById("node-input-json").checked = node.json;
958
+ document.getElementById("node-input-json").onclick = handleMsgTypeClick;
959
+ document.getElementById("node-input-mqtt").checked = node.mqtt;
960
+ document.getElementById("node-input-mqtt").onclick = handleMsgTypeClick;
961
+ document.getElementById("node-input-pointJson").checked = node.pointJson;
962
+ document.getElementById("node-input-pointJson").onclick = handleMsgTypeClick;
963
+
964
+ document.getElementById("node-input-useDeviceName").checked = node.useDeviceName;
965
+
966
+ var menu = document.querySelector(".context-menu");
967
+ window.addEventListener("click", (event) => {
968
+ menu.style.display = "none";
969
+ });
970
+
971
+ var pointMenu = document.querySelector(".point-context-menu");
972
+ window.addEventListener("click", (event) => {
973
+ pointMenu.style.display = "none";
974
+ });
975
+
976
+ function handleCheckboxClick() {
977
+ if (this.id == "node-input-object_property_simplePayload") {
978
+ document.getElementById("node-input-object_property_fullObject").checked = false;
979
+ document.getElementById("node-input-object_property_simpleWithStatus").checked = false;
980
+ }
981
+ if (this.id == "node-input-object_property_simpleWithStatus") {
982
+ document.getElementById("node-input-object_property_fullObject").checked = false;
983
+ document.getElementById("node-input-object_property_simplePayload").checked = false;
984
+ }
985
+ if (this.id == "node-input-object_property_fullObject") {
986
+ document.getElementById("node-input-object_property_simplePayload").checked = false;
987
+ document.getElementById("node-input-object_property_simpleWithStatus").checked = false;
988
+ }
989
+ }
990
+
991
+ function handleMsgTypeClick() {
992
+ if (this.id == "node-input-json") {
993
+ document.getElementById("node-input-mqtt").checked = false;
994
+ document.getElementById("node-input-pointJson").checked = false;
995
+ }
996
+ if (this.id == "node-input-mqtt") {
997
+ document.getElementById("node-input-json").checked = false;
998
+ document.getElementById("node-input-pointJson").checked = false;
999
+ }
1000
+ if (this.id == "node-input-pointJson") {
1001
+ document.getElementById("node-input-json").checked = false;
1002
+ document.getElementById("node-input-mqtt").checked = false;
1003
+ }
1004
+ }
1005
+
1006
+ //create tabs
1007
+ let tabs = RED.tabs.create({
1008
+ id: "node-input-read-tabs",
1009
+ onchange: function (tab) {
1010
+ $("#node-input-tabs-content").children().hide();
1011
+ $("#" + tab.id).show();
1010
1012
  },
1011
- });
1013
+ });
1014
+
1015
+ tabs.addTab({
1016
+ id: "read-networkTree-tab",
1017
+ label: "Device List",
1018
+ });
1019
+
1020
+ tabs.addTab({
1021
+ id: "read-readList-tab",
1022
+ label: "Read List",
1023
+ });
1024
+
1025
+ tabs.addTab({
1026
+ id: "read-properties-tab",
1027
+ label: "Properties",
1028
+ });
1029
+
1030
+ //remove loading animation
1031
+ let loadingGif = document.getElementById("loadingGif");
1032
+ let loadingText = document.getElementById("loadingText");
1033
+ let table = document.getElementById("read-networkTree-tab-content");
1034
+ loadingGif.style.display = "none";
1035
+ loadingText.style.display = "none";
1036
+ table.style.display = "inherit";
1037
+ },
1038
+ oneditsave: function () {
1039
+ let node = this;
1040
+ if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
1041
+ if (node.vm.$data.pointsToRead) node.pointsToRead = node.vm.$data.pointsToRead;
1042
+ },
1043
+ oneditcancel: function () {
1044
+ let node = this;
1045
+ if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
1046
+ if (node.vm.$data.pointsToRead) node.pointsToRead = node.vm.$data.pointsToRead;
1047
+ },
1048
+ });
1012
1049
  </script>
1013
1050
 
1014
1051
  <script type="text/html" data-template-name="Bacnet-Discovery">
@@ -1132,18 +1169,22 @@
1132
1169
 
1133
1170
  <div class="headerDiv">
1134
1171
  <a class="countStatus" style="margin-left: 15px;"> <span class="bp-deviceCount">{{deviceCount}}</span> Device(s)</a>
1135
- <p-progressbar class="bp-readNode-progressbar" :value="progressBarValue" :show-value="true" :style="calculateProgressBarWidth"></p-progressbar>
1172
+ <p-progressbar
1173
+ class="bp-readNode-progressbar"
1174
+ :value="progressBarValue"
1175
+ :show-value="true"
1176
+ :style="calculateProgressBarWidth"></p-progressbar>
1136
1177
  <div class="buttonGroup">
1137
- <button @click="rebuildDataModel()" class="rebuildDataButton" title="Rebuild Data Model">
1178
+ <button @click="rebuildConfirm()" class="rebuildDataButton" title="Rebuild Data Model">
1138
1179
  <i class="pi pi-wrench" style="color: #969696;"></i>
1139
1180
  </button>
1140
-
1181
+
1141
1182
  <button @click="addAllDevices()" class="reloadButton" title="Add all devices">
1142
1183
  <i class="pi pi-plus" style="color: #62ABE9;"></i> <span>Add all devices</span>
1143
1184
  </button>
1144
1185
 
1145
1186
  <button @click="getData()" class="reloadButton" title="Reload Data">
1146
- <i class="fa fa-refresh" style="color: #4D88B7;"></i> <span>Refresh tree</span>
1187
+ <i class="fa fa-refresh" style="color: #4D88B7;"></i> <span>Refresh tree</span>
1147
1188
  </button>
1148
1189
  </div>
1149
1190
  </div>
@@ -1252,14 +1293,12 @@
1252
1293
  <input type="file" id="readlist-file-upload" accept="application/JSON" class="inputStyle" style="display: none;" />
1253
1294
 
1254
1295
  <button @click="removeAllDevices()" class="removeAllDevicesButton" title="Remove all devices">
1255
- <i class="pi pi-times" title="Remove all points"></i> <a>Remove all devices</a>
1296
+ <i class="pi pi-times" title="Remove all points"></i> <a>Remove all devices</a>
1256
1297
  </button>
1257
1298
 
1258
1299
  <button @click="refreshReadListTree()" class="reloadButton bp-read-list-refresh-button" title="Refresh tree">
1259
- <i class="fa fa-refresh" style="color: #4D88B7;"> </i><span>Refresh tree</span>
1300
+ <i class="fa fa-refresh" style="color: #4D88B7;"> </i><span>Refresh tree</span>
1260
1301
  </button>
1261
-
1262
-
1263
1302
  </div>
1264
1303
 
1265
1304
  <p-tree :value="readDevices">
@@ -1294,9 +1333,7 @@
1294
1333
  >Object Properties</label
1295
1334
  >
1296
1335
 
1297
- <div
1298
- id="node-input-object_properties_group"
1299
- style="display: flex; align-items: flex-start; flex-direction: column;">
1336
+ <div id="node-input-object_properties_group" style="display: flex; align-items: flex-start; flex-direction: column;">
1300
1337
  <div class="objectPropertiesLabel">
1301
1338
  <label
1302
1339
  for="node-input-object_property_simplePayload"
@@ -1346,27 +1383,17 @@
1346
1383
 
1347
1384
  <div class="form-row msgTypeDiv bp-prop-row" style="display: flex;">
1348
1385
  <label for="node-input-msgType" class="bp-prop-heading"> Message type </label>
1349
- <div
1350
- id="node-input-msgType"
1351
- style="display: flex; align-items: flex-start; flex-direction: column;">
1386
+ <div id="node-input-msgType" style="display: flex; align-items: flex-start; flex-direction: column;">
1352
1387
  <!-- class= checkbox-round -->
1353
1388
  <div style="display: flex; flex-direction: row; align-items: flex-start;">
1354
- <input
1355
- class="checkbox-round"
1356
- type="checkbox"
1357
- id="node-input-json"
1358
- style="width: 13px; margin-left: 5px;" /><label
1389
+ <input class="checkbox-round" type="checkbox" id="node-input-json" style="width: 13px; margin-left: 5px;" /><label
1359
1390
  for="node-input-json"
1360
1391
  style="padding-left: 20px; width: fit-content;"
1361
1392
  >Block per device</label
1362
1393
  >
1363
1394
  </div>
1364
1395
  <div style="display: flex; flex-direction: row; align-items: flex-start;">
1365
- <input
1366
- class="checkbox-round"
1367
- type="checkbox"
1368
- id="node-input-mqtt"
1369
- style="width: 13px; margin-left: 5px;" /><label
1396
+ <input class="checkbox-round" type="checkbox" id="node-input-mqtt" style="width: 13px; margin-left: 5px;" /><label
1370
1397
  for="node-input-mqtt"
1371
1398
  style="padding-left: 20px; width: fit-content;"
1372
1399
  >Individual msgs</label
@@ -1387,13 +1414,10 @@
1387
1414
  </div>
1388
1415
 
1389
1416
  <div class="bp-checkbox-row bp-readnode-useDeviceName">
1390
- <label
1391
- for="node-input-useDeviceName"
1392
- style="padding-left: 4px; align-items: start;"
1393
- class="objectPropertiesLabel">
1394
- <span data-i18n="bitpool-bacnet.label.useDeviceName"></span>
1395
- <a style="white-space: nowrap;">Use device name in topic</a>
1396
- <input
1417
+ <label for="node-input-useDeviceName" style="padding-left: 4px; align-items: start;" class="objectPropertiesLabel">
1418
+ <span data-i18n="bitpool-bacnet.label.useDeviceName"></span>
1419
+ <a style="white-space: nowrap;">Use device name in topic</a>
1420
+ <input
1397
1421
  style="margin-left: 10px; bottom: 3px;"
1398
1422
  class=" objectProp bp-checkbox"
1399
1423
  type="checkbox"
@@ -1412,11 +1436,12 @@
1412
1436
  <input style="display: none !important;" type="checkbox" id="node-input-hiddenDeployToggle" />
1413
1437
  </label>
1414
1438
 
1415
- <hr>
1439
+ <hr />
1416
1440
 
1417
1441
  <div class="form-row bp-import-buttons">
1418
1442
  <label for="points-export" class="export-points-button" @click="exportPointListCsv()">
1419
- <i class="fa fa-arrow-circle-down" id="fileLabel"></i> <a id="points-export" style="padding-left: 10px;">Export point list</a>
1443
+ <i class="fa fa-arrow-circle-down" id="fileLabel"></i>
1444
+ <a id="points-export" style="padding-left: 10px;">Export point list</a>
1420
1445
  </label>
1421
1446
  </div>
1422
1447
  </div>
@@ -1428,11 +1453,11 @@
1428
1453
  <h3><strong>Device List</strong></h3>
1429
1454
  <ol class="node-ports">
1430
1455
  <p>
1431
- This tab displays the devices and device points that are a result of a network Discover. The data is broken down and
1432
- listed as Devices, Points for the Device, and Point properties for the Points. On this tab the user may choose specific
1433
- points to read, or all of the points present in a device. The reload button may be used to show any new data that may
1434
- have been recieved by the bitpool BACnet node. Please note: Data can only be shown here once a Discover sucessfully
1435
- recieves a response from online devices on the network
1456
+ This tab displays the devices and device points that are a result of a network Discover. The data is broken down and listed
1457
+ as Devices, Points for the Device, and Point properties for the Points. On this tab the user may choose specific points to
1458
+ read, or all of the points present in a device. The reload button may be used to show any new data that may have been
1459
+ recieved by the bitpool BACnet node. Please note: Data can only be shown here once a Discover sucessfully recieves a
1460
+ response from online devices on the network
1436
1461
  </p>
1437
1462
  </ol>
1438
1463
 
@@ -1444,16 +1469,15 @@
1444
1469
  <h3><strong>Properties</strong></h3>
1445
1470
  <ol class="node-ports">
1446
1471
  <p>
1447
- This tab shows all of the point properties the user may choose to read from the points detailed in the Read List tab.
1448
- Here the user may also choose the output format of the Read data, as MQTT compatible Individual msgs, or a JSON block
1449
- per device.
1472
+ This tab shows all of the point properties the user may choose to read from the points detailed in the Read List tab. Here
1473
+ the user may also choose the output format of the Read data, as MQTT compatible Individual msgs, or a JSON block per device.
1450
1474
  </p>
1451
1475
  </ol>
1452
1476
 
1453
1477
  <h3><strong>Examples</strong></h3>
1454
1478
  <p>
1455
- For example flows, please use the examples section for this node. These examples can be found at: Node-red hamburger menu
1456
- on top right -> Import -> Examples -> @bitpoolos/edge-bacnet
1479
+ For example flows, please use the examples section for this node. These examples can be found at: Node-red hamburger menu on
1480
+ top right -> Import -> Examples -> @bitpoolos/edge-bacnet
1457
1481
  </p>
1458
1482
  <p>
1459
1483
  To find captured examples of settings and flows, please go to our wiki