@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/CHANGELOG.md +93 -81
- package/bacnet_client.js +141 -60
- package/bacnet_gateway.html +24 -38
- package/bacnet_gateway.js +2 -0
- package/bacnet_read.html +1032 -1021
- package/package.json +2 -2
- package/resources/style.css +5 -0
package/bacnet_read.html
CHANGED
|
@@ -3,1025 +3,1049 @@
|
|
|
3
3
|
-->
|
|
4
4
|
|
|
5
5
|
<script type="text/javascript">
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
-
|
|
360
|
-
|
|
361
|
-
|
|
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
|
-
|
|
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
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
|
|
642
|
-
|
|
643
|
-
|
|
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
|
-
|
|
646
|
-
|
|
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
|
-
|
|
650
|
-
|
|
651
|
-
|
|
277
|
+
if (indexMap.deviceIndex !== -1 && indexMap.mstpNetorkIndex !== -1) {
|
|
278
|
+
childDevice = parentDevice.children[indexMap.mstpNetorkIndex].children[indexMap.deviceIndex];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
652
281
|
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
-
|
|
661
|
-
|
|
662
|
-
|
|
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
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
318
|
+
//update node-red data structure
|
|
319
|
+
if (!this.pointsToRead[key]) {
|
|
320
|
+
this.pointsToRead[key] = {};
|
|
321
|
+
}
|
|
702
322
|
|
|
703
|
-
|
|
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
|
-
|
|
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
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
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
|
-
|
|
915
|
-
|
|
916
|
-
|
|
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
|
-
|
|
920
|
-
|
|
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
|
|
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
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
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
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
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
|
-
|
|
658
|
+
const slotProps = app.rightClickedPoint;
|
|
659
|
+
const pointDisplayName = app.pointDisplayNameValue;
|
|
660
|
+
const pointName = slotProps.node.pointName;
|
|
941
661
|
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
menu.style.display = "none";
|
|
662
|
+
let device = app.deviceList.find((ele) => {
|
|
663
|
+
return ele.deviceName == slotProps.node.parentDevice;
|
|
945
664
|
});
|
|
946
665
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
});
|
|
666
|
+
if (device) {
|
|
667
|
+
let deviceAddress = app.getDeviceAddress(device.address);
|
|
668
|
+
let deviceKey = `${deviceAddress}-${device.deviceId}`;
|
|
951
669
|
|
|
952
|
-
|
|
953
|
-
if (
|
|
954
|
-
|
|
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
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
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
|
-
|
|
977
|
-
|
|
978
|
-
|
|
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
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
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
|
-
|
|
997
|
-
|
|
998
|
-
|
|
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
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
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
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
let
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
table.style.display = "inherit";
|
|
912
|
+
return count;
|
|
913
|
+
},
|
|
914
|
+
calculatePointCount(slotProps) {
|
|
915
|
+
let count = 0;
|
|
916
|
+
return count;
|
|
917
|
+
},
|
|
1013
918
|
},
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
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
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
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
|
|
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="
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
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>
|
|
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
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|