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