@bitpoolos/edge-bacnet 1.5.0 → 1.5.2

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,1025 +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
- if (points.length > 0) {
426
- for (point in points) {
427
- csvContent +=
428
- ipAddress +
429
- "," +
430
- deviceId +
431
- "," +
432
- deviceName +
433
- "," +
434
- points[point] +
435
- "," +
436
- deviceObject[points[point]].meta.objectId.type +
437
- "\r\n";
438
-
439
- if (parseInt(point) == points.length - 1 && parseInt(key) == keys.length - 1) {
440
- // last iteration
441
- var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
442
- var link = document.createElement("a");
443
- var url = URL.createObjectURL(csvBlob);
444
- link.setAttribute("href", url);
445
- link.setAttribute("download", "pointslist.csv");
446
- document.body.appendChild(link);
447
- link.click();
448
- }
449
- }
450
- } else {
451
- if (parseInt(key) == keys.length - 1) {
452
- // last iteration
453
- var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
454
- var link = document.createElement("a");
455
- var url = URL.createObjectURL(csvBlob);
456
- link.setAttribute("href", url);
457
- link.setAttribute("download", "pointslist.csv");
458
- document.body.appendChild(link);
459
- link.click();
460
- }
461
- }
462
- } else {
463
- if (parseInt(key) == keys.length - 1) {
464
- // last iteration
465
- var csvBlob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
466
- var link = document.createElement("a");
467
- var url = URL.createObjectURL(csvBlob);
468
- link.setAttribute("href", url);
469
- link.setAttribute("download", "pointslist.csv");
470
- document.body.appendChild(link);
471
- link.click();
472
- }
473
- }
474
- }
475
- },
476
- getDeviceAddress(addr) {
477
- switch (typeof addr) {
478
- case "object":
479
- return addr.address;
480
- case "string":
481
- return addr;
482
- default:
483
- return addr;
484
- }
485
- },
486
- isDeviceActive(slotProps) {
487
- let app = this;
488
- if ((Date.now() - slotProps.node.lastSeen) / 1000 < app.pollFrequency + 5) {
489
- return true;
490
- } else if (slotProps.node.isDumbMstpRouter == true || slotProps.node.isDumbMstpRouter == "true") {
491
- return true;
492
- }
493
- return false;
494
- },
495
- isDeviceAdded(slotProps) {
496
- if (slotProps.node.showAdded == true) {
497
- return true;
498
- } else {
499
- return false;
500
- }
501
- },
502
- hasMstpDevices(slotProps) {
503
- if (slotProps.node.children[1] && slotProps.node.children[1].children.length > 0) {
504
- return true;
505
- }
506
- return false;
507
- },
508
- isSlotAdded(slotProps) {
509
- return slotProps.node.showAdded;
510
- },
511
- hasData() {
512
- if (this.devices && this.devices.length > 0) {
513
- return true;
514
- } else {
515
- return false;
516
- }
517
- },
518
- emptyTree() {
519
- if (this.devices.length > 0) {
520
- return true;
521
- }
522
- return false;
523
- },
524
- onDeviceRightClick(slotProps, event) {
525
- let app = this;
526
- app.rightClickedDevice = slotProps;
527
- event.preventDefault();
528
- menu.style.setProperty("--mouse-x", event.clientX + "px");
529
- menu.style.setProperty("--mouse-y", event.clientY + "px");
530
- menu.style.display = "block";
531
- },
532
- onPointRightClick(slotProps, event) {
533
- let app = this;
534
- app.rightClickedPoint = slotProps;
535
- event.preventDefault();
536
- pointMenu.style.setProperty("--mouse-x", event.clientX + "px");
537
- pointMenu.style.setProperty("--mouse-y", event.clientY + "px");
538
- pointMenu.style.display = "block";
539
- },
540
- handleContextMenuClick(type) {
541
- let app = this;
542
- switch (type) {
543
- case "purgeDevice":
544
- app.purgeDevice(app.rightClickedDevice);
545
- break;
546
- case "updatePoints":
547
- app.updatePointsForDevice(app.rightClickedDevice);
548
- break;
549
- case "addAllPoints":
550
- app.addAllClicked(app.rightClickedDevice);
551
- break;
552
- case "removeAllPoints":
553
- app.removeAllClicked(app.rightClickedDevice);
554
- break;
555
- case "setDeviceName":
556
- app.showDeviceNameDialog = true;
557
- app.deviceDisplayNameValue = app.rightClickedDevice.node.label;
558
- break;
559
- default:
560
- break;
561
- }
562
- },
563
- handlePointContextMenuClick(type) {
564
- let app = this;
565
- switch (type) {
566
- case "setPointName":
567
- app.showPointNameDialog = true;
568
- app.pointDisplayNameValue = app.rightClickedPoint.node.label;
569
- break;
570
- case "updatePoint":
571
- app.updatePoint(app.rightClickedPoint);
572
- break;
573
- default:
574
- break;
575
- }
576
- },
577
- purgeDevice(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.purgeDevice(device).then(function (result) { });
588
- }
589
- },
590
- updatePointsForDevice(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.updatePointsForDevice(device).then(function (result) { });
601
- }
602
- },
603
- updatePoint(slotProps) {
604
- let app = this;
605
- let device = app.deviceList.find((ele) => {
606
- if (ele.address.address) {
607
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
608
- } else {
609
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
610
- }
611
- });
612
- if (device) {
613
- app.nodeService.updatePoint(device).then(function (result) { });
614
- }
615
- },
616
- setDeviceName() {
617
- let app = this;
618
- const slotProps = app.rightClickedDevice;
619
- const displayName = app.deviceDisplayNameValue;
620
- let device = app.deviceList.find((ele) => {
621
- if (ele.address.address) {
622
- return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
623
- } else {
624
- return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
625
- }
626
- });
627
-
628
- if (device) {
629
- app.nodeService.setDeviceDisplayName(device, displayName).then(function (result) {
630
- if (result) {
631
- slotProps.node.label = displayName;
632
- }
633
- });
634
- }
635
-
636
- app.showDeviceNameDialog = false;
637
- },
638
- setPointName() {
639
- 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
+ });
640
161
 
641
- const slotProps = app.rightClickedPoint;
642
- const pointDisplayName = app.pointDisplayNameValue;
643
- 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
+ }
644
210
 
645
- let device = app.deviceList.find((ele) => {
646
- return ele.deviceName == slotProps.node.parentDevice;
647
- });
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
+ });
648
276
 
649
- if (device) {
650
- let deviceAddress = app.getDeviceAddress(device.address);
651
- let deviceKey = `${deviceAddress}-${device.deviceId}`;
277
+ if (indexMap.deviceIndex !== -1 && indexMap.mstpNetorkIndex !== -1) {
278
+ childDevice = parentDevice.children[indexMap.mstpNetorkIndex].children[indexMap.deviceIndex];
279
+ }
280
+ }
652
281
 
653
- app.nodeService.setPointDisplayName(deviceKey, pointName, pointDisplayName).then(function (result) {
654
- if (result) {
655
- slotProps.node.label = pointDisplayName;
656
- }
657
- });
658
- }
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
+ }
659
313
 
660
- app.showPointNameDialog = false;
661
- },
662
- settingDeviceName(slotProps) {
663
- let app = this;
664
- if (slotProps.node.settingDisplayName) {
665
- return true;
666
- }
667
- return false;
668
- },
669
- cancelDisplayNameDialog() {
670
- let app = this;
671
- app.deviceDisplayNameValue = "";
672
- app.showDeviceNameDialog = false;
673
- },
674
- cancelPointNameDialog() {
675
- let app = this;
676
- app.pointDisplayNameValue = "";
677
- app.showPointNameDialog = false;
678
- },
679
- exportReadList() {
680
- let app = this;
681
- let exportJson = {};
682
- let deviceIndex = 0;
683
- const devicesToExport = Object.keys(app.pointsToRead);
684
-
685
- doDevice(deviceIndex);
686
-
687
- function doDevice(deviceIndex) {
688
- const key = devicesToExport[deviceIndex];
689
- const device = app.pointsToRead[key];
690
-
691
- let readDevice = app.readDevices.find(ele => ele.ipAddr == key.split("-")[0] && ele.deviceId == key.split("-")[1]);
692
- let deviceName;
693
-
694
- if (readDevice) {
695
- deviceName = readDevice.label
696
- }
314
+ //set show added to true
315
+ slotProps.node.showAdded = true;
316
+ this.$forceUpdate();
697
317
 
698
- exportJson[key] = {};
699
- if (deviceName) {
700
- exportJson[key]["deviceName"] = deviceName;
701
- }
318
+ //update node-red data structure
319
+ if (!this.pointsToRead[key]) {
320
+ this.pointsToRead[key] = {};
321
+ }
702
322
 
703
- const devicePoints = Object.keys(device);
704
-
705
- for (let pointIndex = 0; pointIndex <= devicePoints.length; pointIndex++) {
706
- let pointName = devicePoints[pointIndex];
707
- let pointObject = device[pointName];
708
-
709
- //formatting json payload, still in progress
710
-
711
- if (pointObject) {
712
- exportJson[key][pointName] = {
713
- meta: pointObject.meta,
714
- objectName: pointObject.objectName,
715
- displayName: pointObject.displayName,
716
- };
717
- }
718
-
719
- if (pointIndex == devicePoints.length - 1) {
720
- //all points have been iterated
721
-
722
- if (deviceIndex < devicesToExport.length - 1) {
723
- //more work to do
724
- deviceIndex++;
725
- doDevice(deviceIndex);
726
- } else if (deviceIndex == devicesToExport.length - 1) {
727
- //all read devices complete
728
- let data = "text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(exportJson));
729
- let aEle = document.getElementById("exportJSON");
730
- aEle.setAttribute("href", "data:" + data);
731
- aEle.setAttribute("download", "bacnet-read-list.json");
732
- aEle.click();
733
- }
734
- }
735
- }
736
- }
737
- },
738
- importReadList() {
739
- let app = this;
740
- $("#readlist-file-upload").click();
741
- },
742
- addToReadDevices(pointsToRead) {
743
- let app = this;
744
-
745
- for (let key in pointsToRead) {
746
- let ip = key.split("-")[0];
747
- let id = key.split("-")[1];
748
- const importedDevice = pointsToRead[key];
749
- let foundIndex = app.devices.findIndex((ele) => ele.ipAddr == ip);
750
-
751
- if (foundIndex !== -1) {
752
- // match ip, check id
753
- if (app.devices[foundIndex].deviceId == id) {
754
- //found device
755
- let treeDevice = app.devices[foundIndex];
756
- let device = app.deviceList.find((ele) => {
757
- if (ele.address.address) {
758
- return ele.address.address == ip && ele.deviceId == id;
759
- } else {
760
- return ele.address == ip && ele.deviceId == id;
761
- }
762
- });
763
-
764
- for (let pointName in importedDevice) {
765
- let point = importedDevice[pointName];
766
- if (pointName == "deviceName") {
767
- app.nodeService.setDeviceDisplayName(device, point);
768
- treeDevice.label = point;
769
- } else {
770
- let pointInTree = treeDevice.children[0].children.find(
771
- (ele) => ele.bacnetInstance == point.meta.objectId.instance && ele.bacnetType == point.meta.objectId.type
772
- );
773
-
774
- if (pointInTree) {
775
- pointInTree.label = point.displayName;
776
-
777
- const isDeviceInReadList = app.readDevices
778
- ? app.readDevices.findIndex((ele) => ele.deviceId == treeDevice.deviceId)
779
- : -1;
780
-
781
- if (isDeviceInReadList == -1) {
782
- //no read devices present, add new
783
- let newReadParent = JSON.parse(JSON.stringify(treeDevice));
784
- newReadParent.children[0].children = [];
785
- newReadParent.children[0].children.push(pointInTree);
786
- if (app.readDevices) {
787
- app.readDevices.push(newReadParent);
788
- } else {
789
- app.readDevices = [newReadParent];
790
- }
791
- } else {
792
- // read device found, add point to existing
793
- let pointIndex = app.readDevices[isDeviceInReadList].children[0].children.findIndex(
794
- (ele) => ele.data == point.objectName
795
- );
796
- if (pointIndex == -1) {
797
- app.readDevices[isDeviceInReadList].children[0].children.push(pointInTree);
798
- } else {
799
- app.readDevices[isDeviceInReadList].children[0].children[pointIndex] = pointInTree;
800
- }
801
- }
802
- }
803
- }
804
- }
805
- } else {
806
- //search mstp devices
807
- let mstpIndex = -1;
808
- let folderIndex = -1;
809
-
810
- app.devices[foundIndex].children.forEach(function (child, index) {
811
- let temporaryIndex = -1;
812
- if (child.label.includes("MSTP")) {
813
- temporaryIndex = child.children.findIndex((ele) => ele.deviceId == id);
814
- }
815
- if (temporaryIndex !== -1) {
816
- mstpIndex = temporaryIndex;
817
- folderIndex = index;
818
- }
819
- });
820
-
821
- if (mstpIndex !== -1 && folderIndex !== -1) {
822
- let mstpDevice = app.devices[foundIndex].children[folderIndex].children[mstpIndex];
823
- let device = app.deviceList.find((ele) => {
824
- if (ele.address.address) {
825
- return ele.address.address == ip && ele.deviceId == id;
826
- } else {
827
- return ele.address == ip && ele.deviceId == id;
828
- }
829
- });
830
-
831
- for (let pointName in importedDevice) {
832
- let point = importedDevice[pointName];
833
- if (pointName == "deviceName") {
834
- app.nodeService.setDeviceDisplayName(device, point);
835
- mstpDevice.label = point;
836
- } else {
837
- let pointInTree = mstpDevice.children[0].children.find(
838
- (ele) => ele.bacnetInstance == point.meta.objectId.instance && ele.bacnetType == point.meta.objectId.type
839
- );
840
-
841
- if (pointInTree) {
842
- pointInTree.label = point.displayName;
843
-
844
- const isDeviceInReadList = app.readDevices
845
- ? app.readDevices.findIndex((ele) => ele.deviceId == mstpDevice.deviceId)
846
- : -1;
847
-
848
- if (isDeviceInReadList == -1) {
849
- //no read devices present, add new
850
- let newReadParent = JSON.parse(JSON.stringify(mstpDevice));
851
- newReadParent.children[0].children = [];
852
- newReadParent.children[0].children.push(pointInTree);
853
- if (app.readDevices) {
854
- app.readDevices.push(newReadParent);
855
- } else {
856
- app.readDevices = [newReadParent];
857
- }
858
- } else {
859
- // read device found, add point to existing
860
- let pointIndex = app.readDevices[isDeviceInReadList].children[0].children.findIndex(
861
- (ele) => ele.data == point.objectName
862
- );
863
- if (pointIndex == -1) {
864
- app.readDevices[isDeviceInReadList].children[0].children.push(pointInTree);
865
- } else {
866
- app.readDevices[isDeviceInReadList].children[0].children[pointIndex] = pointInTree;
867
- }
868
- }
869
- }
870
- }
871
- }
872
- } else {
873
- // not part of device list at all, notify user
874
- }
875
- }
876
- }
877
- }
323
+ let point = this.pointList[key][slotProps.node.pointName];
324
+ this.pointsToRead[key][point.objectName] = point;
878
325
 
879
- app.$forceUpdate();
880
- },
881
- refreshReadListTree() {
882
- this.addToReadDevices(this.pointsToRead);
883
- },
884
- calculateMstpCount(slotProps) {
885
- let count = 0;
886
- slotProps.node.children.forEach(function (child) {
887
- if (child.label.includes("MSTP")) {
888
- count += child.children.length;
889
- }
890
- });
891
-
892
- return count;
893
- },
894
- calculatePointCount(slotProps) {
895
- let count = 0;
896
- return count;
897
- },
898
- },
899
- components: {
900
- "p-tree": primevue.tree,
901
- "p-button": primevue.button,
902
- "p-timeline": primevue.timeline,
903
- "p-progressbar": primevue.progressbar,
904
- "p-dialog": primevue.dialog,
905
- "p-input-text": primevue.inputtext,
906
- },
907
- };
326
+ //force a deploy state
327
+ node.hiddenDeployToggle = !node.prevHiddenToggleState;
908
328
 
909
- let vueapp = createApp(App);
910
- vueapp.use(primevue.config.default);
911
- vueapp.use(primevue.confirmationservice);
912
- 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
+ });
913
337
 
914
- //reinstate device data
915
- if (node.readDevices) {
916
- 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
917
382
  }
918
383
 
919
- if (node.pointsToRead) {
920
- 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
+ }
921
406
  }
922
407
 
923
- //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
+ });
924
644
 
925
- document.getElementById("node-input-object_property_simplePayload").checked = node.object_property_simplePayload;
926
- document.getElementById("node-input-object_property_simplePayload").onclick = handleCheckboxClick;
927
- document.getElementById("node-input-object_property_simpleWithStatus").checked = node.object_property_simpleWithStatus;
928
- document.getElementById("node-input-object_property_simpleWithStatus").onclick = handleCheckboxClick;
929
- document.getElementById("node-input-object_property_fullObject").checked = node.object_property_fullObject;
930
- 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
+ }
931
652
 
932
- document.getElementById("node-input-roundDecimal").value = node.roundDecimal;
933
- document.getElementById("node-input-json").checked = node.json;
934
- document.getElementById("node-input-json").onclick = handleMsgTypeClick;
935
- document.getElementById("node-input-mqtt").checked = node.mqtt;
936
- document.getElementById("node-input-mqtt").onclick = handleMsgTypeClick;
937
- document.getElementById("node-input-pointJson").checked = node.pointJson;
938
- document.getElementById("node-input-pointJson").onclick = handleMsgTypeClick;
653
+ app.showDeviceNameDialog = false;
654
+ },
655
+ setPointName() {
656
+ let app = this;
939
657
 
940
- document.getElementById("node-input-useDeviceName").checked = node.useDeviceName;
658
+ const slotProps = app.rightClickedPoint;
659
+ const pointDisplayName = app.pointDisplayNameValue;
660
+ const pointName = slotProps.node.pointName;
941
661
 
942
- var menu = document.querySelector(".context-menu");
943
- window.addEventListener("click", (event) => {
944
- menu.style.display = "none";
662
+ let device = app.deviceList.find((ele) => {
663
+ return ele.deviceName == slotProps.node.parentDevice;
945
664
  });
946
665
 
947
- var pointMenu = document.querySelector(".point-context-menu");
948
- window.addEventListener("click", (event) => {
949
- pointMenu.style.display = "none";
950
- });
666
+ if (device) {
667
+ let deviceAddress = app.getDeviceAddress(device.address);
668
+ let deviceKey = `${deviceAddress}-${device.deviceId}`;
951
669
 
952
- function handleCheckboxClick() {
953
- if (this.id == "node-input-object_property_simplePayload") {
954
- document.getElementById("node-input-object_property_fullObject").checked = false;
955
- document.getElementById("node-input-object_property_simpleWithStatus").checked = false;
956
- }
957
- if (this.id == "node-input-object_property_simpleWithStatus") {
958
- document.getElementById("node-input-object_property_fullObject").checked = false;
959
- document.getElementById("node-input-object_property_simplePayload").checked = false;
960
- }
961
- if (this.id == "node-input-object_property_fullObject") {
962
- document.getElementById("node-input-object_property_simplePayload").checked = false;
963
- 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;
964
673
  }
674
+ });
965
675
  }
966
676
 
967
- function handleMsgTypeClick() {
968
- if (this.id == "node-input-json") {
969
- document.getElementById("node-input-mqtt").checked = false;
970
- document.getElementById("node-input-pointJson").checked = false;
971
- }
972
- if (this.id == "node-input-mqtt") {
973
- document.getElementById("node-input-json").checked = false;
974
- 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
+ };
975
736
  }
976
- if (this.id == "node-input-pointJson") {
977
- document.getElementById("node-input-json").checked = false;
978
- 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
+ }
979
753
  }
754
+ }
980
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
+ });
981
849
 
982
- //create tabs
983
- let tabs = RED.tabs.create({
984
- id: "node-input-read-tabs",
985
- onchange: function (tab) {
986
- $("#node-input-tabs-content").children().hide();
987
- $("#" + tab.id).show();
988
- },
989
- });
990
-
991
- tabs.addTab({
992
- id: "read-networkTree-tab",
993
- label: "Device List",
994
- });
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;
995
867
 
996
- tabs.addTab({
997
- id: "read-readList-tab",
998
- label: "Read List",
999
- });
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
+ }
1000
898
 
1001
- tabs.addTab({
1002
- id: "read-properties-tab",
1003
- 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
+ }
1004
910
  });
1005
911
 
1006
- //remove loading animation
1007
- let loadingGif = document.getElementById("loadingGif");
1008
- let loadingText = document.getElementById("loadingText");
1009
- let table = document.getElementById("read-networkTree-tab-content");
1010
- loadingGif.style.display = "none";
1011
- loadingText.style.display = "none";
1012
- table.style.display = "inherit";
912
+ return count;
913
+ },
914
+ calculatePointCount(slotProps) {
915
+ let count = 0;
916
+ return count;
917
+ },
1013
918
  },
1014
- oneditsave: function () {
1015
- let node = this;
1016
- if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
1017
- 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,
1018
928
  },
1019
- oneditcancel: function () {
1020
- let node = this;
1021
- if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
1022
- 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();
1023
1012
  },
1024
- });
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
+ });
1025
1049
  </script>
1026
1050
 
1027
1051
  <script type="text/html" data-template-name="Bacnet-Discovery">
@@ -1145,18 +1169,22 @@
1145
1169
 
1146
1170
  <div class="headerDiv">
1147
1171
  <a class="countStatus" style="margin-left: 15px;"> <span class="bp-deviceCount">{{deviceCount}}</span> Device(s)</a>
1148
- <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>
1149
1177
  <div class="buttonGroup">
1150
- <button @click="rebuildDataModel()" class="rebuildDataButton" title="Rebuild Data Model">
1178
+ <button @click="rebuildConfirm()" class="rebuildDataButton" title="Rebuild Data Model">
1151
1179
  <i class="pi pi-wrench" style="color: #969696;"></i>
1152
1180
  </button>
1153
-
1181
+
1154
1182
  <button @click="addAllDevices()" class="reloadButton" title="Add all devices">
1155
1183
  <i class="pi pi-plus" style="color: #62ABE9;"></i> <span>Add all devices</span>
1156
1184
  </button>
1157
1185
 
1158
1186
  <button @click="getData()" class="reloadButton" title="Reload Data">
1159
- <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>
1160
1188
  </button>
1161
1189
  </div>
1162
1190
  </div>
@@ -1265,14 +1293,12 @@
1265
1293
  <input type="file" id="readlist-file-upload" accept="application/JSON" class="inputStyle" style="display: none;" />
1266
1294
 
1267
1295
  <button @click="removeAllDevices()" class="removeAllDevicesButton" title="Remove all devices">
1268
- <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>
1269
1297
  </button>
1270
1298
 
1271
1299
  <button @click="refreshReadListTree()" class="reloadButton bp-read-list-refresh-button" title="Refresh tree">
1272
- <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>
1273
1301
  </button>
1274
-
1275
-
1276
1302
  </div>
1277
1303
 
1278
1304
  <p-tree :value="readDevices">
@@ -1307,9 +1333,7 @@
1307
1333
  >Object Properties</label
1308
1334
  >
1309
1335
 
1310
- <div
1311
- id="node-input-object_properties_group"
1312
- 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;">
1313
1337
  <div class="objectPropertiesLabel">
1314
1338
  <label
1315
1339
  for="node-input-object_property_simplePayload"
@@ -1359,27 +1383,17 @@
1359
1383
 
1360
1384
  <div class="form-row msgTypeDiv bp-prop-row" style="display: flex;">
1361
1385
  <label for="node-input-msgType" class="bp-prop-heading"> Message type </label>
1362
- <div
1363
- id="node-input-msgType"
1364
- 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;">
1365
1387
  <!-- class= checkbox-round -->
1366
1388
  <div style="display: flex; flex-direction: row; align-items: flex-start;">
1367
- <input
1368
- class="checkbox-round"
1369
- type="checkbox"
1370
- id="node-input-json"
1371
- 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
1372
1390
  for="node-input-json"
1373
1391
  style="padding-left: 20px; width: fit-content;"
1374
1392
  >Block per device</label
1375
1393
  >
1376
1394
  </div>
1377
1395
  <div style="display: flex; flex-direction: row; align-items: flex-start;">
1378
- <input
1379
- class="checkbox-round"
1380
- type="checkbox"
1381
- id="node-input-mqtt"
1382
- 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
1383
1397
  for="node-input-mqtt"
1384
1398
  style="padding-left: 20px; width: fit-content;"
1385
1399
  >Individual msgs</label
@@ -1400,13 +1414,10 @@
1400
1414
  </div>
1401
1415
 
1402
1416
  <div class="bp-checkbox-row bp-readnode-useDeviceName">
1403
- <label
1404
- for="node-input-useDeviceName"
1405
- style="padding-left: 4px; align-items: start;"
1406
- class="objectPropertiesLabel">
1407
- <span data-i18n="bitpool-bacnet.label.useDeviceName"></span>
1408
- <a style="white-space: nowrap;">Use device name in topic</a>
1409
- <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
1410
1421
  style="margin-left: 10px; bottom: 3px;"
1411
1422
  class=" objectProp bp-checkbox"
1412
1423
  type="checkbox"
@@ -1425,11 +1436,12 @@
1425
1436
  <input style="display: none !important;" type="checkbox" id="node-input-hiddenDeployToggle" />
1426
1437
  </label>
1427
1438
 
1428
- <hr>
1439
+ <hr />
1429
1440
 
1430
1441
  <div class="form-row bp-import-buttons">
1431
1442
  <label for="points-export" class="export-points-button" @click="exportPointListCsv()">
1432
- <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>
1433
1445
  </label>
1434
1446
  </div>
1435
1447
  </div>
@@ -1441,11 +1453,11 @@
1441
1453
  <h3><strong>Device List</strong></h3>
1442
1454
  <ol class="node-ports">
1443
1455
  <p>
1444
- This tab displays the devices and device points that are a result of a network Discover. The data is broken down and
1445
- listed as Devices, Points for the Device, and Point properties for the Points. On this tab the user may choose specific
1446
- 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
1447
- have been recieved by the bitpool BACnet node. Please note: Data can only be shown here once a Discover sucessfully
1448
- 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
1449
1461
  </p>
1450
1462
  </ol>
1451
1463
 
@@ -1457,16 +1469,15 @@
1457
1469
  <h3><strong>Properties</strong></h3>
1458
1470
  <ol class="node-ports">
1459
1471
  <p>
1460
- This tab shows all of the point properties the user may choose to read from the points detailed in the Read List tab.
1461
- Here the user may also choose the output format of the Read data, as MQTT compatible Individual msgs, or a JSON block
1462
- 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.
1463
1474
  </p>
1464
1475
  </ol>
1465
1476
 
1466
1477
  <h3><strong>Examples</strong></h3>
1467
1478
  <p>
1468
- For example flows, please use the examples section for this node. These examples can be found at: Node-red hamburger menu
1469
- 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
1470
1481
  </p>
1471
1482
  <p>
1472
1483
  To find captured examples of settings and flows, please go to our wiki