@bitpoolos/edge-bacnet 1.2.7 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/README.md +20 -2
- package/bacnet_client.js +1662 -1572
- package/bacnet_device.js +122 -60
- package/bacnet_gateway.html +115 -71
- package/bacnet_gateway.js +165 -48
- package/bacnet_read.html +1025 -596
- package/bacnet_read.js +68 -84
- package/bacnet_server.js +187 -186
- package/bacnet_write.html +971 -738
- package/common.js +40 -28
- package/package.json +1 -1
- package/resources/bitArray.js +167 -0
- package/resources/node-bacstack-ts/dist/lib/asn1.js +16 -5
- package/resources/node-bacstack-ts/dist/lib/client.js +5 -6
- package/resources/style.css +321 -0
- package/treeBuilder.js +533 -0
package/bacnet_write.html
CHANGED
|
@@ -3,767 +3,1000 @@
|
|
|
3
3
|
-->
|
|
4
4
|
|
|
5
5
|
<script type="text/javascript">
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
6
|
+
RED.nodes.registerType("Bacnet-Write", {
|
|
7
|
+
category: "Bitpool BACnet",
|
|
8
|
+
color: "#00aeef",
|
|
9
|
+
defaults: {
|
|
10
|
+
name: { value: "" },
|
|
11
|
+
applicationTag: { value: "4" },
|
|
12
|
+
priority: { value: "16" },
|
|
13
|
+
pointsToWrite: { value: [] },
|
|
14
|
+
writeDevices: { value: [] },
|
|
15
|
+
hiddenDeployToggle: { value: false },
|
|
16
|
+
prevHiddenToggleState: { value: false },
|
|
17
|
+
},
|
|
18
|
+
inputs: 1,
|
|
19
|
+
outputs: 1,
|
|
20
|
+
icon: "bitpool.svg",
|
|
21
|
+
label: function () {
|
|
22
|
+
return "write";
|
|
23
|
+
},
|
|
24
|
+
paletteLabel: function () {
|
|
25
|
+
return "write";
|
|
26
|
+
},
|
|
27
|
+
oneditprepare: function () {
|
|
28
|
+
let node = this;
|
|
29
|
+
|
|
30
|
+
node.prevHiddenToggleState = node.hiddenDeployToggle;
|
|
31
|
+
|
|
32
|
+
const { createApp, ref, onMounted } = Vue;
|
|
33
|
+
|
|
34
|
+
//prime vue app
|
|
35
|
+
const App = {
|
|
36
|
+
data() {
|
|
37
|
+
return {
|
|
38
|
+
devices: ref(),
|
|
39
|
+
writeDevices: ref(),
|
|
40
|
+
deviceList: ref(),
|
|
41
|
+
pointList: ref(),
|
|
42
|
+
pointsToWrite: ref([]),
|
|
43
|
+
nodeService: ref(new NodeService()),
|
|
44
|
+
deviceCount: ref(),
|
|
45
|
+
};
|
|
18
46
|
},
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
47
|
+
setup() {
|
|
48
|
+
let pointList;
|
|
49
|
+
let deviceList;
|
|
50
|
+
const selectedKeys = ref(null);
|
|
51
|
+
const nodes = ref();
|
|
52
|
+
const expandedKeys = ref({});
|
|
53
|
+
|
|
54
|
+
const expandAll = () => {
|
|
55
|
+
for (let node of devices.value) {
|
|
56
|
+
expandNode(node);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
expandedKeys.value = { ...expandedKeys.value };
|
|
60
|
+
};
|
|
61
|
+
const collapseAll = () => {
|
|
62
|
+
expandedKeys.value = {};
|
|
63
|
+
};
|
|
64
|
+
const expandNode = (node) => {
|
|
65
|
+
if (node.children && node.children.length) {
|
|
66
|
+
expandedKeys.value[node.key] = true;
|
|
67
|
+
|
|
68
|
+
for (let child of node.children) {
|
|
69
|
+
expandNode(child);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
nodes,
|
|
76
|
+
expandedKeys,
|
|
77
|
+
expandAll,
|
|
78
|
+
collapseAll,
|
|
79
|
+
expandNode,
|
|
80
|
+
};
|
|
24
81
|
},
|
|
25
|
-
|
|
26
|
-
|
|
82
|
+
mounted() {
|
|
83
|
+
this.getData();
|
|
27
84
|
},
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
let pointList;
|
|
51
|
-
let deviceList;
|
|
52
|
-
const selectedKeys = ref(null);
|
|
53
|
-
const nodes = ref();
|
|
54
|
-
const expandedKeys = ref({});
|
|
55
|
-
|
|
56
|
-
const expandAll = () => {
|
|
57
|
-
for (let node of devices.value) {
|
|
58
|
-
expandNode(node);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
expandedKeys.value = {...expandedKeys.value};
|
|
62
|
-
};
|
|
63
|
-
const collapseAll = () => {
|
|
64
|
-
expandedKeys.value = {};
|
|
65
|
-
};
|
|
66
|
-
const expandNode = (node) => {
|
|
67
|
-
if (node.children && node.children.length) {
|
|
68
|
-
expandedKeys.value[node.key] = true;
|
|
69
|
-
|
|
70
|
-
for (let child of node.children) {
|
|
71
|
-
expandNode(child);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
nodes,
|
|
78
|
-
expandedKeys,
|
|
79
|
-
expandAll,
|
|
80
|
-
collapseAll,
|
|
81
|
-
expandNode,
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
mounted() {
|
|
85
|
-
this.getData();
|
|
86
|
-
},
|
|
87
|
-
methods: {
|
|
88
|
-
getData() {
|
|
89
|
-
let app = this;
|
|
90
|
-
this.nodeService.getNetworkData().then(function (result) {
|
|
91
|
-
app.devices = result.renderList;
|
|
92
|
-
app.deviceList = result.deviceList;
|
|
93
|
-
app.pointList = result.pointList;
|
|
94
|
-
app.pollFrequency = parseInt(result.pollFrequency);
|
|
95
|
-
app.deviceCount = result.deviceList.length;
|
|
96
|
-
});
|
|
97
|
-
},
|
|
98
|
-
addAllClicked(slotProps) {
|
|
99
|
-
let app = this;
|
|
100
|
-
//update UI
|
|
101
|
-
if (this.writeDevices) {
|
|
102
|
-
let foundIndex = this.writeDevices.findIndex(ele => ele.key == slotProps.node.key && ele.label == slotProps.node.label);
|
|
103
|
-
if (foundIndex == -1) this.writeDevices.push(slotProps.node);
|
|
104
|
-
} else {
|
|
105
|
-
this.writeDevices = [slotProps.node];
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
this.$forceUpdate()
|
|
109
|
-
|
|
110
|
-
//update node-red data structure to forward to gateway
|
|
111
|
-
let device = this.deviceList.find(ele => {
|
|
112
|
-
if(ele.address.address) {
|
|
113
|
-
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
114
|
-
} else{
|
|
115
|
-
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
let deviceAddress = app.getDeviceAddress(device.address);
|
|
119
|
-
let key = `${deviceAddress}-${device.deviceId}`;
|
|
120
|
-
let points = this.pointList[key];
|
|
121
|
-
|
|
122
|
-
if (!this.pointsToWrite[key] || typeof this.pointsToWrite[key] == 'undefined') {
|
|
123
|
-
this.pointsToWrite[key] = {};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
for (let pointName in points) {
|
|
127
|
-
let point = this.pointList[key][pointName];
|
|
128
|
-
this.pointsToWrite[key][point.objectName] = point;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
//force a deploy state
|
|
132
|
-
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
133
|
-
},
|
|
134
|
-
removeAllClicked(slotProps) {
|
|
135
|
-
let app = this;
|
|
136
|
-
//update UI
|
|
137
|
-
if (this.writeDevices.length > 0) {
|
|
138
|
-
let foundIndex = this.writeDevices.findIndex(ele => ele.key == slotProps.node.key && ele.label == slotProps.node.label);
|
|
139
|
-
if (foundIndex !== -1) this.writeDevices.splice(foundIndex, 1);
|
|
140
|
-
}
|
|
141
|
-
this.$forceUpdate()
|
|
142
|
-
|
|
143
|
-
//update node-red data structure
|
|
144
|
-
let device = this.deviceList.find(ele => {
|
|
145
|
-
if(ele.address.address) {
|
|
146
|
-
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
147
|
-
} else{
|
|
148
|
-
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
149
|
-
}
|
|
150
|
-
});
|
|
151
|
-
let deviceAddress = app.getDeviceAddress(device.address);
|
|
152
|
-
let key = `${deviceAddress}-${device.deviceId}`;
|
|
153
|
-
if (this.pointsToWrite[key]) {
|
|
154
|
-
delete this.pointsToWrite[key];
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
//force a deploy state
|
|
158
|
-
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
159
|
-
},
|
|
160
|
-
addPointClicked(slotProps) {
|
|
161
|
-
let app = this;
|
|
162
|
-
//update UI
|
|
163
|
-
let parentDeviceName = slotProps.node.parentDevice;
|
|
164
|
-
let foundDeviceIndex = this.writeDevices ? this.writeDevices.findIndex(ele => ele.label == parentDeviceName) : -1;
|
|
165
|
-
let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
|
|
166
|
-
let deviceAddress = app.getDeviceAddress(device.address);
|
|
167
|
-
let key = `${deviceAddress}-${device.deviceId}`;
|
|
168
|
-
let parentDevice = this.devices.find(ele => ele.ipAddr == deviceAddress);
|
|
169
|
-
let childDevice;
|
|
170
|
-
if(device.isMstp) {
|
|
171
|
-
let foundChildIndex = parentDevice.children[1].children.findIndex(ele => ele.label == parentDeviceName);
|
|
172
|
-
if(foundChildIndex !== -1) {
|
|
173
|
-
childDevice = parentDevice.children[1].children[foundChildIndex];
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (foundDeviceIndex == -1) {
|
|
178
|
-
//no read devices present, add new
|
|
179
|
-
let newReadParent;
|
|
180
|
-
if(childDevice) {
|
|
181
|
-
newReadParent = {...childDevice};
|
|
182
|
-
} else {
|
|
183
|
-
newReadParent = {...parentDevice};
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
newReadParent.children = [];
|
|
187
|
-
newReadParent.children.push(slotProps.node);
|
|
188
|
-
|
|
189
|
-
if (this.writeDevices) {
|
|
190
|
-
this.writeDevices.push(newReadParent);
|
|
191
|
-
} else {
|
|
192
|
-
this.writeDevices = [newReadParent];
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
} else {
|
|
196
|
-
// read device found, add point to existing
|
|
197
|
-
this.writeDevices[foundDeviceIndex].children.push(slotProps.node);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
slotProps.node.showAdded = true;
|
|
201
|
-
|
|
202
|
-
console.log("write point added, slotProps.node: ", slotProps.node);
|
|
203
|
-
|
|
204
|
-
this.$forceUpdate();
|
|
205
|
-
|
|
206
|
-
//update node-red data structure
|
|
207
|
-
|
|
208
|
-
let point = this.pointList[key][slotProps.node.pointName];
|
|
209
|
-
point.deviceId = device.deviceId;
|
|
210
|
-
point.deviceAddress = device.address;
|
|
211
|
-
|
|
212
|
-
if (!this.pointsToWrite || this.pointsToWrite.length == 'undefined') {
|
|
213
|
-
this.pointsToWrite = [];
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
let found = this.pointsToWrite.find(ele =>
|
|
217
|
-
ele.deviceId == point.deviceId &&
|
|
218
|
-
ele.objectName == point.objectName &&
|
|
219
|
-
ele.meta.arrayIndex == point.meta.arrayIndex &&
|
|
220
|
-
ele.meta.objectId.instance == point.meta.objectId.instance &&
|
|
221
|
-
ele.meta.objectId.type == point.meta.objectId.type);
|
|
222
|
-
|
|
223
|
-
if (!found) this.pointsToWrite.push(point);
|
|
224
|
-
|
|
225
|
-
console.log("this.pointsToWrite: ", this.pointsToWrite);
|
|
226
|
-
|
|
227
|
-
//force a deploy state
|
|
228
|
-
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
229
|
-
},
|
|
230
|
-
removePointClicked(slotProps) {
|
|
231
|
-
let app = this;
|
|
232
|
-
//update UI
|
|
233
|
-
let parentDeviceName = slotProps.node.parentDevice;
|
|
234
|
-
let foundDeviceIndex = this.writeDevices ? this.writeDevices.findIndex(ele => ele.label == parentDeviceName) : -1;
|
|
235
|
-
let parentDevice = this.devices.find(ele => ele.label == parentDeviceName);
|
|
236
|
-
|
|
237
|
-
if (foundDeviceIndex !== -1) {
|
|
238
|
-
let foundIndex = this.writeDevices[foundDeviceIndex].children.findIndex(ele => ele.key == slotProps.node.key && ele.label == slotProps.node.label);
|
|
239
|
-
if (foundIndex !== -1) this.writeDevices[foundDeviceIndex].children.splice(foundIndex, 1);
|
|
240
|
-
if (this.writeDevices[foundDeviceIndex].children.length == 0) {
|
|
241
|
-
this.writeDevices.splice(foundDeviceIndex, 1);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
slotProps.node.showAdded = false;
|
|
246
|
-
|
|
247
|
-
this.$forceUpdate();
|
|
248
|
-
|
|
249
|
-
//update node-red data stucture
|
|
250
|
-
let device = this.deviceList.find(ele => {
|
|
251
|
-
if(ele.address.address) {
|
|
252
|
-
return ele.address.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
|
|
253
|
-
} else {
|
|
254
|
-
return ele.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
|
|
255
|
-
}
|
|
256
|
-
});
|
|
257
|
-
let deviceAddress = app.getDeviceAddress(device.address);
|
|
258
|
-
let key = `${deviceAddress}-${device.deviceId}`;
|
|
259
|
-
let point = this.pointList[key][slotProps.node.pointName];
|
|
260
|
-
point.deviceId = device.deviceId;
|
|
261
|
-
|
|
262
|
-
let foundIndex = this.pointsToWrite.findIndex(ele =>
|
|
263
|
-
ele.deviceId == point.deviceId &&
|
|
264
|
-
ele.objectName == point.objectName &&
|
|
265
|
-
ele.meta.arrayIndex == point.meta.arrayIndex &&
|
|
266
|
-
ele.meta.objectId.instance == point.meta.objectId.instance &&
|
|
267
|
-
ele.meta.objectId.type == point.meta.objectId.type);
|
|
268
|
-
|
|
269
|
-
if (foundIndex !== -1) {
|
|
270
|
-
this.pointsToWrite.splice(foundIndex, 1);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
//force a deploy state
|
|
274
|
-
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
275
|
-
},
|
|
276
|
-
getDeviceAddress(addr) {
|
|
277
|
-
switch(typeof addr) {
|
|
278
|
-
case "object":
|
|
279
|
-
return addr.address;
|
|
280
|
-
case "string":
|
|
281
|
-
return addr;
|
|
282
|
-
default:
|
|
283
|
-
return addr;
|
|
284
|
-
}
|
|
285
|
-
},
|
|
286
|
-
isDeviceActive(slotProps) {
|
|
287
|
-
let app = this;
|
|
288
|
-
if (((Date.now() - slotProps.node.lastSeen) / 1000) < app.pollFrequency) {
|
|
289
|
-
return true;
|
|
290
|
-
}
|
|
291
|
-
return false;
|
|
292
|
-
},
|
|
293
|
-
isSlotAdded(slotProps) {
|
|
294
|
-
if (slotProps.node.showAdded == true) {
|
|
295
|
-
return true;
|
|
296
|
-
} else {
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
hasData() {
|
|
301
|
-
if (this.devices && this.devices.length > 0) {
|
|
302
|
-
return true
|
|
303
|
-
} else {
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
},
|
|
308
|
-
components: {
|
|
309
|
-
"p-tree": primevue.tree,
|
|
310
|
-
"p-button": primevue.button,
|
|
311
|
-
"p-timeline": primevue.timeline
|
|
312
|
-
}
|
|
313
|
-
};
|
|
85
|
+
methods: {
|
|
86
|
+
getData() {
|
|
87
|
+
let app = this;
|
|
88
|
+
this.nodeService.getNetworkData().then(function (result) {
|
|
89
|
+
app.devices = result.renderList;
|
|
90
|
+
app.deviceList = result.deviceList;
|
|
91
|
+
app.pointList = result.pointList;
|
|
92
|
+
app.pollFrequency = parseInt(result.pollFrequency);
|
|
93
|
+
app.deviceCount = result.deviceList.length;
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
addAllClicked(slotProps) {
|
|
97
|
+
let app = this;
|
|
98
|
+
//update UI
|
|
99
|
+
if (this.writeDevices) {
|
|
100
|
+
let foundIndex = this.writeDevices.findIndex(
|
|
101
|
+
(ele) => ele.key == slotProps.node.key && ele.label == slotProps.node.label
|
|
102
|
+
);
|
|
103
|
+
if (foundIndex == -1) this.writeDevices.push(slotProps.node);
|
|
104
|
+
} else {
|
|
105
|
+
this.writeDevices = [slotProps.node];
|
|
106
|
+
}
|
|
314
107
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
node
|
|
108
|
+
this.$forceUpdate();
|
|
109
|
+
|
|
110
|
+
//update node-red data structure to forward to gateway
|
|
111
|
+
let device = this.deviceList.find((ele) => {
|
|
112
|
+
if (ele.address.address) {
|
|
113
|
+
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
114
|
+
} else {
|
|
115
|
+
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
let deviceAddress = app.getDeviceAddress(device.address);
|
|
119
|
+
let key = `${deviceAddress}-${device.deviceId}`;
|
|
120
|
+
let points = this.pointList[key];
|
|
121
|
+
|
|
122
|
+
if (!this.pointsToWrite[key] || typeof this.pointsToWrite[key] == "undefined") {
|
|
123
|
+
this.pointsToWrite[key] = {};
|
|
124
|
+
}
|
|
318
125
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
126
|
+
for (let pointName in points) {
|
|
127
|
+
let point = this.pointList[key][pointName];
|
|
128
|
+
this.pointsToWrite[key][point.objectName] = point;
|
|
322
129
|
}
|
|
323
|
-
|
|
324
|
-
|
|
130
|
+
|
|
131
|
+
//force a deploy state
|
|
132
|
+
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
133
|
+
},
|
|
134
|
+
removeAllClicked(slotProps) {
|
|
135
|
+
let app = this;
|
|
136
|
+
//update UI
|
|
137
|
+
if (this.writeDevices.length > 0) {
|
|
138
|
+
let foundIndex = this.writeDevices.findIndex(
|
|
139
|
+
(ele) => ele.key == slotProps.node.key && ele.label == slotProps.node.label
|
|
140
|
+
);
|
|
141
|
+
if (foundIndex !== -1) this.writeDevices.splice(foundIndex, 1);
|
|
142
|
+
}
|
|
143
|
+
this.$forceUpdate();
|
|
144
|
+
|
|
145
|
+
//update node-red data structure
|
|
146
|
+
let device = this.deviceList.find((ele) => {
|
|
147
|
+
if (ele.address.address) {
|
|
148
|
+
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
149
|
+
} else {
|
|
150
|
+
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
let deviceAddress = app.getDeviceAddress(device.address);
|
|
154
|
+
let key = `${deviceAddress}-${device.deviceId}`;
|
|
155
|
+
if (this.pointsToWrite[key]) {
|
|
156
|
+
delete this.pointsToWrite[key];
|
|
325
157
|
}
|
|
326
158
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
tabs.addTab(
|
|
350
|
-
{
|
|
351
|
-
id: "read-write-tab",
|
|
352
|
-
label: "Properties"
|
|
353
|
-
});
|
|
354
|
-
|
|
355
|
-
document.getElementById("node-input-applicationTag").value = node.applicationTag;
|
|
356
|
-
document.getElementById("node-input-priority").value = node.priority;
|
|
357
|
-
|
|
358
|
-
//remove loading animation
|
|
359
|
-
let loadingGif = document.getElementById("loadingGif");
|
|
360
|
-
let loadingText = document.getElementById("loadingText");
|
|
361
|
-
let table = document.getElementById("read-networkTree-tab-content");
|
|
362
|
-
loadingGif.style.display = "none";
|
|
363
|
-
loadingText.style.display = "none";
|
|
364
|
-
table.style.display = "inherit";
|
|
159
|
+
//force a deploy state
|
|
160
|
+
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
161
|
+
},
|
|
162
|
+
addPointClicked(slotProps) {
|
|
163
|
+
let app = this;
|
|
164
|
+
//update UI
|
|
165
|
+
let parentDeviceName = slotProps.node.parentDevice;
|
|
166
|
+
let foundDeviceIndex = this.writeDevices
|
|
167
|
+
? this.writeDevices.findIndex((ele) => ele.label == parentDeviceName)
|
|
168
|
+
: -1;
|
|
169
|
+
let device = this.deviceList.find((ele) => ele.deviceName == parentDeviceName);
|
|
170
|
+
let deviceAddress = app.getDeviceAddress(device.address);
|
|
171
|
+
let key = `${deviceAddress}-${device.deviceId}`;
|
|
172
|
+
let parentDevice = this.devices.find((ele) => ele.ipAddr == deviceAddress);
|
|
173
|
+
let childDevice;
|
|
174
|
+
if (device.isMstp) {
|
|
175
|
+
let foundChildIndex = parentDevice.children[1].children.findIndex((ele) => ele.label == parentDeviceName);
|
|
176
|
+
if (foundChildIndex !== -1) {
|
|
177
|
+
childDevice = parentDevice.children[1].children[foundChildIndex];
|
|
178
|
+
}
|
|
179
|
+
}
|
|
365
180
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
181
|
+
if (foundDeviceIndex == -1) {
|
|
182
|
+
//no read devices present, add new
|
|
183
|
+
let newReadParent;
|
|
184
|
+
if (childDevice) {
|
|
185
|
+
newReadParent = { ...childDevice };
|
|
186
|
+
} else {
|
|
187
|
+
newReadParent = { ...parentDevice };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
newReadParent.children = [];
|
|
191
|
+
newReadParent.children.push(slotProps.node);
|
|
192
|
+
|
|
193
|
+
if (this.writeDevices) {
|
|
194
|
+
this.writeDevices.push(newReadParent);
|
|
195
|
+
} else {
|
|
196
|
+
this.writeDevices = [newReadParent];
|
|
197
|
+
}
|
|
198
|
+
} else {
|
|
199
|
+
// read device found, add point to existing
|
|
200
|
+
this.writeDevices[foundDeviceIndex].children.push(slotProps.node);
|
|
201
|
+
}
|
|
374
202
|
|
|
375
|
-
|
|
203
|
+
slotProps.node.showAdded = true;
|
|
204
|
+
this.$forceUpdate();
|
|
376
205
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
}
|
|
383
|
-
.p-tree {
|
|
384
|
-
background: inherit !important;
|
|
385
|
-
border: inherit !important;
|
|
386
|
-
padding-right: 0px !important;
|
|
387
|
-
}
|
|
388
|
-
.p-button {
|
|
389
|
-
margin-right: .5rem;
|
|
390
|
-
}
|
|
391
|
-
.addPointButton {
|
|
392
|
-
float: right;
|
|
393
|
-
}
|
|
394
|
-
.minusPointButton {
|
|
395
|
-
float: right;
|
|
396
|
-
}
|
|
397
|
-
.addPointButton:hover, .minusPointButton:hover {
|
|
398
|
-
background: #d5d5d5 !important;
|
|
399
|
-
}
|
|
400
|
-
.pointLabel {
|
|
401
|
-
font-weight: 400;
|
|
402
|
-
}
|
|
403
|
-
.deviceLabel {
|
|
404
|
-
font-weight: 100;
|
|
405
|
-
}
|
|
406
|
-
.removeAllButton {
|
|
407
|
-
float: right;
|
|
408
|
-
}
|
|
409
|
-
.addAllButton {
|
|
410
|
-
float: right;
|
|
411
|
-
}
|
|
412
|
-
.bacnetbutton {
|
|
413
|
-
background: none;
|
|
414
|
-
border: none;
|
|
415
|
-
color: black;
|
|
416
|
-
font-weight: 400;
|
|
417
|
-
}
|
|
418
|
-
.bacnetbutton:hover {
|
|
419
|
-
background: #f0f0f0;
|
|
420
|
-
border-radius: 10px;
|
|
421
|
-
}
|
|
422
|
-
.allFunctionsText {
|
|
423
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
|
|
424
|
-
padding-left: 5px;
|
|
425
|
-
}
|
|
426
|
-
.p-treenode-children > li > .p-treenode-children > li {
|
|
427
|
-
font-size: 14px;
|
|
428
|
-
/* height: 35px; */
|
|
429
|
-
color: #b5b5b5 !important;
|
|
430
|
-
}
|
|
431
|
-
.p-treenode-children > li > .p-treenode-children > .p-treenode-label {
|
|
432
|
-
color: #b5b5b5 !important;
|
|
433
|
-
}
|
|
434
|
-
.p-tree-toggler:enabled:hover {
|
|
435
|
-
background: #d5d5d5 !important;
|
|
436
|
-
}
|
|
437
|
-
.p-tree-toggler:focus {
|
|
438
|
-
border: none !important;
|
|
439
|
-
box-shadow: none !important;
|
|
440
|
-
}
|
|
441
|
-
.deviceStatus {
|
|
442
|
-
font-size: 10px;
|
|
443
|
-
}
|
|
444
|
-
.statusOnline {
|
|
445
|
-
color: #11c511;
|
|
446
|
-
}
|
|
447
|
-
.statusOffline {
|
|
448
|
-
color: red;
|
|
449
|
-
}
|
|
450
|
-
/*
|
|
451
|
-
.deviceLabel {
|
|
452
|
-
position: absolute;
|
|
453
|
-
}
|
|
454
|
-
*/
|
|
455
|
-
.objectPropertiesLabel {
|
|
456
|
-
display: flex !important;
|
|
457
|
-
flex-direction: row;
|
|
458
|
-
align-items: center;
|
|
459
|
-
}
|
|
460
|
-
.p-tree .p-tree-container .p-treenode .p-treenode-content:focus {
|
|
461
|
-
outline: 0 none !important;
|
|
462
|
-
outline-offset: 0 !important;
|
|
463
|
-
box-shadow: inset 0 0 0 1px #bdbdbd !important;
|
|
464
|
-
}
|
|
465
|
-
.checkbox-round {
|
|
466
|
-
width: 13px !important;
|
|
467
|
-
height: 13px !important;
|
|
468
|
-
background-color: white;
|
|
469
|
-
border-radius: 50%;
|
|
470
|
-
vertical-align: middle;
|
|
471
|
-
border: 1px solid #ddd;
|
|
472
|
-
appearance: none;
|
|
473
|
-
-webkit-appearance: none;
|
|
474
|
-
outline: none;
|
|
475
|
-
cursor: pointer;
|
|
476
|
-
}
|
|
477
|
-
.checkbox-round:checked {
|
|
478
|
-
background-color: #00AEEF;
|
|
479
|
-
}
|
|
480
|
-
.checkbox-round:focus {
|
|
481
|
-
outline: none !important;
|
|
482
|
-
}
|
|
483
|
-
.p-tree-filter:focus, .p-tree-filter:focus-visible, .p-inputtext:enabled:hover {
|
|
484
|
-
box-shadow: inset 0 0 0 0.15rem #dfdcdc !important;
|
|
485
|
-
border-color: transparent !important;
|
|
486
|
-
}
|
|
487
|
-
.bacnetbutton > .pi {
|
|
488
|
-
display: flex;
|
|
489
|
-
}
|
|
490
|
-
.p-tree-container {
|
|
491
|
-
margin: 0 !important;
|
|
492
|
-
}
|
|
493
|
-
.reloadButtonIcon {
|
|
494
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
|
|
495
|
-
}
|
|
496
|
-
.removeAllDevicesButton {
|
|
497
|
-
border: none;
|
|
498
|
-
background: none;
|
|
499
|
-
font-size: 14px !important;
|
|
500
|
-
float: right;
|
|
501
|
-
display: flex;
|
|
502
|
-
align-items: center;
|
|
503
|
-
}
|
|
504
|
-
.removeAllDevicesButton:hover {
|
|
505
|
-
background-color: #d5d5d5;
|
|
506
|
-
border-radius: 10px;
|
|
507
|
-
}
|
|
508
|
-
.reloadButton {
|
|
509
|
-
border: none;
|
|
510
|
-
background: none;
|
|
511
|
-
font-size: 14px !important;
|
|
512
|
-
float: right;
|
|
513
|
-
}
|
|
514
|
-
.rebuildDataButton {
|
|
515
|
-
border: none;
|
|
516
|
-
background: none;
|
|
517
|
-
font-size: 14px !important;
|
|
518
|
-
float: right;
|
|
519
|
-
}
|
|
520
|
-
.reloadButton:hover {
|
|
521
|
-
background-color: #d5d5d5;
|
|
522
|
-
border-radius: 10px;
|
|
523
|
-
}
|
|
524
|
-
.rebuildDataButton:hover {
|
|
525
|
-
background-color: #d5d5d5;
|
|
526
|
-
border-radius: 10px;
|
|
527
|
-
}
|
|
528
|
-
.headerDiv {
|
|
529
|
-
display: flex;
|
|
530
|
-
flex-direction: row;
|
|
531
|
-
flex-wrap: nowrap;
|
|
532
|
-
justify-content: space-around;
|
|
533
|
-
height: 20px;
|
|
534
|
-
}
|
|
535
|
-
.msgTypeDiv {
|
|
536
|
-
display: flex;
|
|
537
|
-
align-items: flex-start;
|
|
538
|
-
flex-direction: column;
|
|
539
|
-
}
|
|
540
|
-
.p-progressbar .p-progressbar-value {
|
|
541
|
-
background: #00AEEF !important;
|
|
542
|
-
}
|
|
543
|
-
.p-treenode-label {
|
|
544
|
-
overflow: hidden;
|
|
545
|
-
white-space: nowrap;
|
|
546
|
-
text-overflow: ellipsis;
|
|
547
|
-
}
|
|
548
|
-
.buttonGroup {
|
|
549
|
-
padding-left: 7px;
|
|
550
|
-
}
|
|
551
|
-
#read-readList-tab {
|
|
552
|
-
display: flex;
|
|
553
|
-
flex-direction: column;
|
|
554
|
-
}
|
|
555
|
-
.removeAllDevicesDiv {
|
|
556
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
557
|
-
padding-right: 20px;
|
|
558
|
-
}
|
|
559
|
-
.p-tree .p-treenode-children {
|
|
560
|
-
padding: 0 !important;
|
|
561
|
-
}
|
|
562
|
-
.p-tree-toggler .p-link {
|
|
563
|
-
width: 25px !important;
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
</style>
|
|
567
|
-
|
|
568
|
-
<div class="form-row">
|
|
569
|
-
<label for="node-input-name"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.name"></span> Name</label>
|
|
570
|
-
<input type="text" id="node-input-name" placeholder="Name">
|
|
571
|
-
</div>
|
|
206
|
+
//update node-red data structure
|
|
207
|
+
let point = this.pointList[key][slotProps.node.pointName];
|
|
208
|
+
point.deviceId = device.deviceId;
|
|
209
|
+
point.deviceAddress = device.address;
|
|
210
|
+
point.key = slotProps.node.key;
|
|
572
211
|
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
212
|
+
if (!this.pointsToWrite || this.pointsToWrite.length == "undefined") {
|
|
213
|
+
this.pointsToWrite = [];
|
|
214
|
+
}
|
|
576
215
|
|
|
577
|
-
|
|
216
|
+
let found = this.pointsToWrite.find(
|
|
217
|
+
(ele) =>
|
|
218
|
+
ele.deviceId == point.deviceId &&
|
|
219
|
+
ele.objectName == point.objectName &&
|
|
220
|
+
ele.meta.arrayIndex == point.meta.arrayIndex &&
|
|
221
|
+
ele.meta.objectId.instance == point.meta.objectId.instance &&
|
|
222
|
+
ele.meta.objectId.type == point.meta.objectId.type
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
if (!found) this.pointsToWrite.push(point);
|
|
226
|
+
|
|
227
|
+
//force a deploy state
|
|
228
|
+
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
229
|
+
},
|
|
230
|
+
removePointClicked(slotProps) {
|
|
231
|
+
let app = this;
|
|
232
|
+
|
|
233
|
+
//update UI
|
|
234
|
+
let parentDeviceName = slotProps.node.parentDevice;
|
|
235
|
+
let foundDeviceIndex = this.writeDevices
|
|
236
|
+
? this.writeDevices.findIndex((ele) => ele.label == parentDeviceName)
|
|
237
|
+
: -1;
|
|
238
|
+
let parentDevice = this.devices.find((ele) => ele.label == parentDeviceName);
|
|
239
|
+
|
|
240
|
+
if (foundDeviceIndex !== -1) {
|
|
241
|
+
let foundIndex = this.writeDevices[foundDeviceIndex].children.findIndex(
|
|
242
|
+
(ele) => ele.key == slotProps.node.key && ele.label == slotProps.node.label
|
|
243
|
+
);
|
|
244
|
+
if (foundIndex !== -1) this.writeDevices[foundDeviceIndex].children.splice(foundIndex, 1);
|
|
245
|
+
if (this.writeDevices[foundDeviceIndex].children.length == 0) {
|
|
246
|
+
this.writeDevices.splice(foundDeviceIndex, 1);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
578
249
|
|
|
579
|
-
|
|
250
|
+
let foundIndex = this.pointsToWrite.findIndex((ele) => ele.key == slotProps.node.key);
|
|
580
251
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
<button @click="getData()" class="reloadButton">
|
|
585
|
-
<i class="pi pi-refresh" style="color: #00AEEF;"><a class="allFunctionsText">Reload data</a></i>
|
|
586
|
-
</button>
|
|
587
|
-
</div>
|
|
252
|
+
if (foundIndex !== -1) {
|
|
253
|
+
this.pointsToWrite.splice(foundIndex, 1);
|
|
254
|
+
}
|
|
588
255
|
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
256
|
+
slotProps.node.showAdded = false;
|
|
257
|
+
|
|
258
|
+
this.$forceUpdate();
|
|
259
|
+
|
|
260
|
+
//force a deploy state
|
|
261
|
+
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
262
|
+
},
|
|
263
|
+
getDeviceAddress(addr) {
|
|
264
|
+
switch (typeof addr) {
|
|
265
|
+
case "object":
|
|
266
|
+
return addr.address;
|
|
267
|
+
case "string":
|
|
268
|
+
return addr;
|
|
269
|
+
default:
|
|
270
|
+
return addr;
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
isDeviceActive(slotProps) {
|
|
274
|
+
let app = this;
|
|
275
|
+
if ((Date.now() - slotProps.node.lastSeen) / 1000 < app.pollFrequency) {
|
|
276
|
+
return true;
|
|
277
|
+
}
|
|
278
|
+
return false;
|
|
279
|
+
},
|
|
280
|
+
isSlotAdded(slotProps) {
|
|
281
|
+
if (slotProps.node.showAdded == true) {
|
|
282
|
+
return true;
|
|
283
|
+
} else {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
hasData() {
|
|
288
|
+
if (this.devices && this.devices.length > 0) {
|
|
289
|
+
return true;
|
|
290
|
+
} else {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
calculateMstpCount(slotProps) {
|
|
295
|
+
let count = 0;
|
|
296
|
+
slotProps.node.children.forEach(function (child) {
|
|
297
|
+
if (child.label.includes("MSTP")) {
|
|
298
|
+
count += child.children.length;
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
return count;
|
|
303
|
+
},
|
|
304
|
+
settingDeviceName(slotProps) {
|
|
305
|
+
let app = this;
|
|
306
|
+
if (slotProps.node.settingDisplayName) {
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
return false;
|
|
310
|
+
},
|
|
311
|
+
cancelDisplayNameDialog() {
|
|
312
|
+
let app = this;
|
|
313
|
+
app.deviceDisplayNameValue = "";
|
|
314
|
+
app.showDeviceNameDialog = false;
|
|
315
|
+
},
|
|
316
|
+
cancelPointNameDialog() {
|
|
317
|
+
let app = this;
|
|
318
|
+
app.pointDisplayNameValue = "";
|
|
319
|
+
app.showPointNameDialog = false;
|
|
320
|
+
},
|
|
321
|
+
onDeviceRightClick(slotProps, event) {
|
|
322
|
+
let app = this;
|
|
323
|
+
app.rightClickedDevice = slotProps;
|
|
324
|
+
event.preventDefault();
|
|
325
|
+
menu.style.setProperty("--mouse-x", event.clientX + "px");
|
|
326
|
+
menu.style.setProperty("--mouse-y", event.clientY + "px");
|
|
327
|
+
menu.style.display = "block";
|
|
328
|
+
},
|
|
329
|
+
onPointRightClick(slotProps, event) {
|
|
330
|
+
let app = this;
|
|
331
|
+
app.rightClickedPoint = slotProps;
|
|
332
|
+
event.preventDefault();
|
|
333
|
+
pointMenu.style.setProperty("--mouse-x", event.clientX + "px");
|
|
334
|
+
pointMenu.style.setProperty("--mouse-y", event.clientY + "px");
|
|
335
|
+
pointMenu.style.display = "block";
|
|
336
|
+
},
|
|
337
|
+
handleContextMenuClick(type) {
|
|
338
|
+
let app = this;
|
|
339
|
+
switch (type) {
|
|
340
|
+
case "purgeDevice":
|
|
341
|
+
app.purgeDevice(app.rightClickedDevice);
|
|
342
|
+
break;
|
|
343
|
+
case "updatePoints":
|
|
344
|
+
app.updatePointsForDevice(app.rightClickedDevice);
|
|
345
|
+
break;
|
|
346
|
+
case "addAllPoints":
|
|
347
|
+
app.addAllClicked(app.rightClickedDevice);
|
|
348
|
+
break;
|
|
349
|
+
case "removeAllPoints":
|
|
350
|
+
app.removeAllClicked(app.rightClickedDevice);
|
|
351
|
+
break;
|
|
352
|
+
case "setDeviceName":
|
|
353
|
+
app.showDeviceNameDialog = true;
|
|
354
|
+
app.deviceDisplayNameValue = app.rightClickedDevice.node.label;
|
|
355
|
+
break;
|
|
356
|
+
default:
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
},
|
|
360
|
+
handlePointContextMenuClick(type) {
|
|
361
|
+
let app = this;
|
|
362
|
+
switch (type) {
|
|
363
|
+
case "setPointName":
|
|
364
|
+
app.showPointNameDialog = true;
|
|
365
|
+
app.pointDisplayNameValue = app.rightClickedPoint.node.label;
|
|
366
|
+
break;
|
|
367
|
+
case "updatePoint":
|
|
368
|
+
app.updatePoint(app.rightClickedDevice);
|
|
369
|
+
break;
|
|
370
|
+
default:
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
},
|
|
374
|
+
purgeDevice(slotProps) {
|
|
375
|
+
let app = this;
|
|
376
|
+
let device = app.deviceList.find((ele) => {
|
|
377
|
+
if (ele.address.address) {
|
|
378
|
+
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
379
|
+
} else {
|
|
380
|
+
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
if (device) {
|
|
384
|
+
app.nodeService.purgeDevice(device).then(function (result) { });
|
|
385
|
+
}
|
|
386
|
+
},
|
|
387
|
+
updatePointsForDevice(slotProps) {
|
|
388
|
+
let app = this;
|
|
389
|
+
let device = app.deviceList.find((ele) => {
|
|
390
|
+
if (ele.address.address) {
|
|
391
|
+
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
392
|
+
} else {
|
|
393
|
+
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
if (device) {
|
|
397
|
+
app.nodeService.updatePointsForDevice(device).then(function (result) { });
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
updatePoint(slotProps) {
|
|
401
|
+
let app = this;
|
|
402
|
+
let device = app.deviceList.find((ele) => {
|
|
403
|
+
if (ele.address.address) {
|
|
404
|
+
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
405
|
+
} else {
|
|
406
|
+
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
if (device) {
|
|
410
|
+
app.nodeService.updatePoint(device).then(function (result) { });
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
setDeviceName() {
|
|
414
|
+
let app = this;
|
|
415
|
+
const slotProps = app.rightClickedDevice;
|
|
416
|
+
const displayName = app.deviceDisplayNameValue;
|
|
417
|
+
let device = app.deviceList.find((ele) => {
|
|
418
|
+
if (ele.address.address) {
|
|
419
|
+
return ele.address.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
420
|
+
} else {
|
|
421
|
+
return ele.address == slotProps.node.ipAddr && ele.deviceId == slotProps.node.deviceId;
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
if (device) {
|
|
426
|
+
app.nodeService.setDeviceDisplayName(device, displayName).then(function (result) {
|
|
427
|
+
if (result) {
|
|
428
|
+
slotProps.node.label = displayName;
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
app.showDeviceNameDialog = false;
|
|
434
|
+
},
|
|
435
|
+
setPointName() {
|
|
436
|
+
let app = this;
|
|
437
|
+
|
|
438
|
+
const slotProps = app.rightClickedPoint;
|
|
439
|
+
const pointDisplayName = app.pointDisplayNameValue;
|
|
440
|
+
const pointName = slotProps.node.pointName;
|
|
441
|
+
|
|
442
|
+
let device = app.deviceList.find((ele) => {
|
|
443
|
+
return ele.deviceName == slotProps.node.parentDevice;
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
if (device) {
|
|
447
|
+
let deviceAddress = app.getDeviceAddress(device.address);
|
|
448
|
+
let deviceKey = `${deviceAddress}-${device.deviceId}`;
|
|
449
|
+
|
|
450
|
+
app.nodeService.setPointDisplayName(deviceKey, pointName, pointDisplayName).then(function (result) {
|
|
451
|
+
if (result) {
|
|
452
|
+
slotProps.node.label = pointDisplayName;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
app.showPointNameDialog = false;
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
components: {
|
|
461
|
+
"p-tree": primevue.tree,
|
|
462
|
+
"p-button": primevue.button,
|
|
463
|
+
"p-timeline": primevue.timeline,
|
|
464
|
+
},
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
let vueapp = createApp(App);
|
|
468
|
+
vueapp.use(primevue.config.default);
|
|
469
|
+
node.vm = vueapp.mount("#node-input-tabs-content");
|
|
470
|
+
|
|
471
|
+
//reinstate device data
|
|
472
|
+
if (node.writeDevices) {
|
|
473
|
+
node.vm.$data.writeDevices = node.writeDevices;
|
|
474
|
+
}
|
|
475
|
+
if (node.pointsToWrite) {
|
|
476
|
+
node.vm.$data.pointsToWrite = node.pointsToWrite;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
let tabs = RED.tabs.create({
|
|
480
|
+
id: "node-input-read-tabs",
|
|
481
|
+
onchange: function (tab) {
|
|
482
|
+
$("#node-input-tabs-content").children().hide();
|
|
483
|
+
$("#" + tab.id).show();
|
|
484
|
+
},
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
tabs.addTab({
|
|
488
|
+
id: "read-networkTree-tab",
|
|
489
|
+
label: "Device List",
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
tabs.addTab({
|
|
493
|
+
id: "read-writeList-tab",
|
|
494
|
+
label: "Write List",
|
|
495
|
+
});
|
|
496
|
+
|
|
497
|
+
tabs.addTab({
|
|
498
|
+
id: "read-write-tab",
|
|
499
|
+
label: "Properties",
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
document.getElementById("node-input-applicationTag").value = node.applicationTag;
|
|
503
|
+
document.getElementById("node-input-priority").value = node.priority;
|
|
504
|
+
|
|
505
|
+
var menu = document.querySelector(".context-menu");
|
|
506
|
+
window.addEventListener("click", (event) => {
|
|
507
|
+
menu.style.display = "none";
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
var pointMenu = document.querySelector(".point-context-menu");
|
|
511
|
+
window.addEventListener("click", (event) => {
|
|
512
|
+
pointMenu.style.display = "none";
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
//remove loading animation
|
|
516
|
+
let loadingGif = document.getElementById("loadingGif");
|
|
517
|
+
let loadingText = document.getElementById("loadingText");
|
|
518
|
+
let table = document.getElementById("read-networkTree-tab-content");
|
|
519
|
+
loadingGif.style.display = "none";
|
|
520
|
+
loadingText.style.display = "none";
|
|
521
|
+
table.style.display = "inherit";
|
|
522
|
+
},
|
|
523
|
+
oneditsave: function () {
|
|
524
|
+
let node = this;
|
|
525
|
+
if (node.vm.$data.devices && node.vm.$data.devices.length > 0) node.devices = node.vm.$data.devices;
|
|
526
|
+
if (node.vm.$data.writeDevices && node.vm.$data.writeDevices.length > 0)
|
|
527
|
+
node.writeDevices = node.vm.$data.writeDevices;
|
|
528
|
+
if (node.vm.$data.pointsToWrite && node.vm.$data.pointsToWrite.length > 0)
|
|
529
|
+
node.pointsToWrite = node.vm.$data.pointsToWrite;
|
|
530
|
+
},
|
|
531
|
+
});
|
|
532
|
+
</script>
|
|
623
533
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
534
|
+
<script type="text/html" data-template-name="Bacnet-Write">
|
|
535
|
+
<style>
|
|
536
|
+
.p-treenode-label {
|
|
537
|
+
color: black;
|
|
538
|
+
width: 100%;
|
|
539
|
+
}
|
|
540
|
+
.p-tree {
|
|
541
|
+
background: inherit !important;
|
|
542
|
+
border: inherit !important;
|
|
543
|
+
padding-right: 0px !important;
|
|
544
|
+
}
|
|
545
|
+
.p-button {
|
|
546
|
+
margin-right: 0.5rem;
|
|
547
|
+
}
|
|
548
|
+
.addPointButton {
|
|
549
|
+
float: right;
|
|
550
|
+
}
|
|
551
|
+
.minusPointButton {
|
|
552
|
+
float: right;
|
|
553
|
+
}
|
|
554
|
+
.addPointButton:hover,
|
|
555
|
+
.minusPointButton:hover {
|
|
556
|
+
background: #d5d5d5 !important;
|
|
557
|
+
}
|
|
558
|
+
.pointLabel {
|
|
559
|
+
font-weight: 400;
|
|
560
|
+
}
|
|
561
|
+
.deviceLabel {
|
|
562
|
+
font-weight: 100;
|
|
563
|
+
}
|
|
564
|
+
.removeAllButton {
|
|
565
|
+
float: right;
|
|
566
|
+
}
|
|
567
|
+
.addAllButton {
|
|
568
|
+
float: right;
|
|
569
|
+
}
|
|
570
|
+
.bacnetbutton {
|
|
571
|
+
background: none;
|
|
572
|
+
border: none;
|
|
573
|
+
color: black;
|
|
574
|
+
font-weight: 400;
|
|
575
|
+
}
|
|
576
|
+
.bacnetbutton:hover {
|
|
577
|
+
background: #f0f0f0;
|
|
578
|
+
border-radius: 10px;
|
|
579
|
+
}
|
|
580
|
+
.allFunctionsText {
|
|
581
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
|
|
582
|
+
"Segoe UI Emoji", "Segoe UI Symbol" !important;
|
|
583
|
+
padding-left: 5px;
|
|
584
|
+
}
|
|
585
|
+
.p-treenode-children > li > .p-treenode-children > li {
|
|
586
|
+
font-size: 14px;
|
|
587
|
+
/* height: 35px; */
|
|
588
|
+
color: #b5b5b5 !important;
|
|
589
|
+
}
|
|
590
|
+
.p-treenode-children > li > .p-treenode-children > .p-treenode-label {
|
|
591
|
+
color: #b5b5b5 !important;
|
|
592
|
+
}
|
|
593
|
+
.p-tree-toggler:enabled:hover {
|
|
594
|
+
background: #d5d5d5 !important;
|
|
595
|
+
}
|
|
596
|
+
.p-tree-toggler:focus {
|
|
597
|
+
border: none !important;
|
|
598
|
+
box-shadow: none !important;
|
|
599
|
+
}
|
|
600
|
+
.deviceStatus {
|
|
601
|
+
font-size: 10px;
|
|
602
|
+
}
|
|
603
|
+
.statusOnline {
|
|
604
|
+
color: #11c511;
|
|
605
|
+
}
|
|
606
|
+
.statusOffline {
|
|
607
|
+
color: red;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
.objectPropertiesLabel {
|
|
611
|
+
display: flex !important;
|
|
612
|
+
flex-direction: row;
|
|
613
|
+
align-items: center;
|
|
614
|
+
}
|
|
615
|
+
.p-tree .p-tree-container .p-treenode .p-treenode-content:focus {
|
|
616
|
+
outline: 0 none !important;
|
|
617
|
+
outline-offset: 0 !important;
|
|
618
|
+
box-shadow: inset 0 0 0 1px #bdbdbd !important;
|
|
619
|
+
}
|
|
620
|
+
.checkbox-round {
|
|
621
|
+
width: 13px !important;
|
|
622
|
+
height: 13px !important;
|
|
623
|
+
background-color: white;
|
|
624
|
+
border-radius: 50%;
|
|
625
|
+
vertical-align: middle;
|
|
626
|
+
border: 1px solid #ddd;
|
|
627
|
+
appearance: none;
|
|
628
|
+
-webkit-appearance: none;
|
|
629
|
+
outline: none;
|
|
630
|
+
cursor: pointer;
|
|
631
|
+
}
|
|
632
|
+
.checkbox-round:checked {
|
|
633
|
+
background-color: #00aeef;
|
|
634
|
+
}
|
|
635
|
+
.checkbox-round:focus {
|
|
636
|
+
outline: none !important;
|
|
637
|
+
}
|
|
638
|
+
.p-tree-filter:focus,
|
|
639
|
+
.p-tree-filter:focus-visible,
|
|
640
|
+
.p-inputtext:enabled:hover {
|
|
641
|
+
box-shadow: inset 0 0 0 0.15rem #dfdcdc !important;
|
|
642
|
+
border-color: transparent !important;
|
|
643
|
+
}
|
|
644
|
+
.bacnetbutton > .pi {
|
|
645
|
+
display: flex;
|
|
646
|
+
}
|
|
647
|
+
.p-tree-container {
|
|
648
|
+
margin: 0 !important;
|
|
649
|
+
}
|
|
650
|
+
.reloadButtonIcon {
|
|
651
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
|
|
652
|
+
"Segoe UI Emoji", "Segoe UI Symbol" !important;
|
|
653
|
+
}
|
|
654
|
+
.removeAllDevicesButton {
|
|
655
|
+
border: none;
|
|
656
|
+
background: none;
|
|
657
|
+
font-size: 14px !important;
|
|
658
|
+
float: right;
|
|
659
|
+
display: flex;
|
|
660
|
+
align-items: center;
|
|
661
|
+
}
|
|
662
|
+
.removeAllDevicesButton:hover {
|
|
663
|
+
background-color: #d5d5d5;
|
|
664
|
+
border-radius: 10px;
|
|
665
|
+
}
|
|
666
|
+
.reloadButton {
|
|
667
|
+
border: none;
|
|
668
|
+
background: none;
|
|
669
|
+
font-size: 14px !important;
|
|
670
|
+
float: right;
|
|
671
|
+
}
|
|
672
|
+
.rebuildDataButton {
|
|
673
|
+
border: none;
|
|
674
|
+
background: none;
|
|
675
|
+
font-size: 14px !important;
|
|
676
|
+
float: right;
|
|
677
|
+
}
|
|
678
|
+
.reloadButton:hover {
|
|
679
|
+
background-color: #d5d5d5;
|
|
680
|
+
border-radius: 10px;
|
|
681
|
+
}
|
|
682
|
+
.rebuildDataButton:hover {
|
|
683
|
+
background-color: #d5d5d5;
|
|
684
|
+
border-radius: 10px;
|
|
685
|
+
}
|
|
686
|
+
.headerDiv {
|
|
687
|
+
display: flex;
|
|
688
|
+
flex-direction: row;
|
|
689
|
+
flex-wrap: nowrap;
|
|
690
|
+
justify-content: space-around;
|
|
691
|
+
height: 20px;
|
|
692
|
+
}
|
|
693
|
+
.msgTypeDiv {
|
|
694
|
+
display: flex;
|
|
695
|
+
align-items: flex-start;
|
|
696
|
+
flex-direction: column;
|
|
697
|
+
}
|
|
698
|
+
.p-progressbar .p-progressbar-value {
|
|
699
|
+
background: #00aeef !important;
|
|
700
|
+
}
|
|
701
|
+
.p-treenode-label {
|
|
702
|
+
overflow: hidden;
|
|
703
|
+
white-space: nowrap;
|
|
704
|
+
text-overflow: ellipsis;
|
|
705
|
+
}
|
|
706
|
+
.buttonGroup {
|
|
707
|
+
padding-left: 7px;
|
|
708
|
+
}
|
|
709
|
+
#read-readList-tab {
|
|
710
|
+
display: flex;
|
|
711
|
+
flex-direction: column;
|
|
712
|
+
}
|
|
713
|
+
.removeAllDevicesDiv {
|
|
714
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
|
|
715
|
+
"Segoe UI Emoji", "Segoe UI Symbol";
|
|
716
|
+
padding-right: 20px;
|
|
717
|
+
}
|
|
718
|
+
.p-tree .p-treenode-children {
|
|
719
|
+
padding: 0 !important;
|
|
720
|
+
}
|
|
721
|
+
.p-tree-toggler .p-link {
|
|
722
|
+
width: 25px !important;
|
|
723
|
+
}
|
|
724
|
+
</style>
|
|
725
|
+
|
|
726
|
+
<div class="form-row">
|
|
727
|
+
<label for="node-input-name"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.name"></span> Name</label>
|
|
728
|
+
<input type="text" id="node-input-name" placeholder="Name" />
|
|
729
|
+
</div>
|
|
730
|
+
|
|
731
|
+
<div class="form-row node-input-read-tabs-row">
|
|
732
|
+
<ul style="min-width:600px;margin-bottom:20px" id="node-input-read-tabs"></ul>
|
|
733
|
+
</div>
|
|
734
|
+
|
|
735
|
+
<div id="node-input-tabs-content">
|
|
736
|
+
|
|
737
|
+
<!-- Start Device Context Menu -->
|
|
738
|
+
<ul
|
|
739
|
+
class="red-ui-menu red-ui-menu-dropdown red-ui-menu-dropdown-direction-right red-ui-menu-dropdown-noicons red-ui-menu-dropdown-submenus context-menu">
|
|
740
|
+
<li class="context-menu-item" @click="handleContextMenuClick('purgeDevice')">
|
|
741
|
+
<a class="red-ui-menu-label">
|
|
742
|
+
<i class="pi pi-wrench context-menu-icon"></i>
|
|
743
|
+
<span class="context-menu-item-text">Purge Device</span>
|
|
744
|
+
</a>
|
|
745
|
+
</li>
|
|
746
|
+
<li class="context-menu-item" @click="handleContextMenuClick('updatePoints')">
|
|
747
|
+
<a class="red-ui-menu-label">
|
|
748
|
+
<i class="pi pi-refresh context-menu-icon"></i>
|
|
749
|
+
<span class="context-menu-item-text">Update Points</span>
|
|
750
|
+
</a>
|
|
751
|
+
</li>
|
|
752
|
+
<li class="red-ui-menu-divider"></li>
|
|
753
|
+
<li class="context-menu-item" @click="handleContextMenuClick('addAllPoints')">
|
|
754
|
+
<a class="red-ui-menu-label">
|
|
755
|
+
<i class="pi pi-plus-circle context-menu-icon"></i>
|
|
756
|
+
<span class="context-menu-item-text">Add All Points </span>
|
|
757
|
+
</a>
|
|
758
|
+
</li>
|
|
759
|
+
<li class="context-menu-item" @click="handleContextMenuClick('removeAllPoints')">
|
|
760
|
+
<a class="red-ui-menu-label">
|
|
761
|
+
<i class="pi pi-minus-circle context-menu-icon"></i>
|
|
762
|
+
<span class="context-menu-item-text">Remove All Points</span>
|
|
763
|
+
</a>
|
|
764
|
+
</li>
|
|
765
|
+
<li class="red-ui-menu-divider"></li>
|
|
766
|
+
<li class="context-menu-item" @click="handleContextMenuClick('setDeviceName')">
|
|
767
|
+
<a class="red-ui-menu-label">
|
|
768
|
+
<i class="pi pi-pencil context-menu-icon"></i>
|
|
769
|
+
<span class="context-menu-item-text">Set Device Name</span>
|
|
770
|
+
</a>
|
|
771
|
+
</li>
|
|
772
|
+
</ul>
|
|
773
|
+
<!-- End Device Context Menu -->
|
|
774
|
+
|
|
775
|
+
<!-- Start Point Context Menu -->
|
|
776
|
+
<ul
|
|
777
|
+
class="red-ui-menu red-ui-menu-dropdown red-ui-menu-dropdown-direction-right red-ui-menu-dropdown-noicons red-ui-menu-dropdown-submenus point-context-menu">
|
|
778
|
+
<li class="context-menu-item" @click="handlePointContextMenuClick('setPointName')">
|
|
779
|
+
<a class="red-ui-menu-label">
|
|
780
|
+
<i class="pi pi-pencil context-menu-icon"></i>
|
|
781
|
+
<span class="context-menu-item-text">Set Point Name</span>
|
|
782
|
+
</a>
|
|
783
|
+
</li>
|
|
784
|
+
<li class="red-ui-menu-divider"></li>
|
|
785
|
+
<li class="context-menu-item" @click="handlePointContextMenuClick('updatePoint')">
|
|
786
|
+
<a class="red-ui-menu-label">
|
|
787
|
+
<i class="pi pi-refresh context-menu-icon"></i>
|
|
788
|
+
<span class="context-menu-item-text">Update Point</span>
|
|
789
|
+
</a>
|
|
790
|
+
</li>
|
|
791
|
+
</ul>
|
|
792
|
+
<!-- End Point Context Menu -->
|
|
793
|
+
|
|
794
|
+
|
|
795
|
+
<div id="read-networkTree-tab" style="display:none">
|
|
796
|
+
<div id="read-networkTree-tab-content" class="networkTreeContent" style="display:none">
|
|
797
|
+
<div>
|
|
798
|
+
<a class="countStatus" style="margin-left: 15px;">Count: {{deviceCount}} device(s)</a>
|
|
799
|
+
<button @click="getData()" class="reloadButton">
|
|
800
|
+
<i class="pi pi-refresh" style="color: #00AEEF;"><a class="allFunctionsText">Reload data</a></i>
|
|
801
|
+
</button>
|
|
628
802
|
</div>
|
|
629
803
|
|
|
630
|
-
<div id=
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
804
|
+
<div id="deviceListApp">
|
|
805
|
+
<p-tree :value="devices" selectable="false" :filter="true" filterMode="lenient" v-if="hasData()">
|
|
806
|
+
<template #device="slotProps">
|
|
807
|
+
<div @contextmenu="onDeviceRightClick(slotProps, $event)" class="p-treenode-label">
|
|
808
|
+
|
|
809
|
+
<div v-if="isDeviceActive(slotProps)" class="deviceLabelParent">
|
|
810
|
+
<b class="deviceLabel">
|
|
811
|
+
<span class="statusOnline deviceStatus dotOnline dot"></span>
|
|
812
|
+
{{slotProps.node.label}}
|
|
813
|
+
</b>
|
|
814
|
+
</div>
|
|
815
|
+
<div v-else>
|
|
816
|
+
<b class="deviceLabel">
|
|
817
|
+
<span class="statusOffline deviceStatus dotOffline dot"></span>
|
|
818
|
+
{{slotProps.node.label}}
|
|
819
|
+
</b>
|
|
820
|
+
</div>
|
|
821
|
+
|
|
822
|
+
</div>
|
|
823
|
+
</template>
|
|
824
|
+
|
|
825
|
+
<template #point="slotProps" v-model:class="pointContent">
|
|
826
|
+
<div @contextmenu="onDeviceRightClick(slotProps, $event)" class="p-treenode-label">
|
|
635
827
|
|
|
636
|
-
<
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
828
|
+
<b class="pointLabel">{{slotProps.node.label}}</b>
|
|
829
|
+
<template v-if="isSlotAdded(slotProps)">
|
|
830
|
+
<button class="addPointButton bacnetbutton">
|
|
831
|
+
<i class="pi pi-check-circle " style="color: #00AEEF;"></i>
|
|
832
|
+
</button>
|
|
833
|
+
</template>
|
|
834
|
+
<template v-else>
|
|
835
|
+
<button @click="addPointClicked(slotProps, this)" class="addPointButton bacnetbutton">
|
|
836
|
+
<i class="pi pi-plus-circle "></i>
|
|
837
|
+
</button>
|
|
641
838
|
</template>
|
|
642
|
-
</p-tree>
|
|
643
|
-
</div>
|
|
644
839
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
<option value="6">OCTET_STRING</option>
|
|
656
|
-
<option value="7">CHARACTER_STRING</option>
|
|
657
|
-
<option value="8">BIT_STRING</option>
|
|
658
|
-
<option value="9">ENUMERATED</option>
|
|
659
|
-
<option value="10">DATE</option>
|
|
660
|
-
<option value="11">TIME</option>
|
|
661
|
-
<option value="12">OBJECT_ID</option>
|
|
662
|
-
<option value="13">RESERVE1</option>
|
|
663
|
-
<option value="14">RESERVE2</option>
|
|
664
|
-
<option value="15">RESERVE3</option>
|
|
665
|
-
<option value="16">MAX_BACNET_APPLICATION_TAG</option>
|
|
666
|
-
<option value="100">EMPTYLIST</option>
|
|
667
|
-
<option value="101">WEEKNDAY</option>
|
|
668
|
-
<option value="102">DATERANGE</option>
|
|
669
|
-
<option value="103">DATETIME</option>
|
|
670
|
-
<option value="104">TIMESTAMP</option>
|
|
671
|
-
<option value="105">ERROR</option>
|
|
672
|
-
<option value="106">DEVICE_OBJECT_PROPERTY_REFERENCE</option>
|
|
673
|
-
<option value="107">DEVICE_OBJECT_REFERENCE</option>
|
|
674
|
-
<option value="108">OBJECT_PROPERTY_REFERENCE</option>
|
|
675
|
-
<option value="109">DESTINATION</option>
|
|
676
|
-
<option value="110">RECIPIENT</option>
|
|
677
|
-
<option value="111">COV_SUBSCRIPTION</option>
|
|
678
|
-
<option value="112">CALENDAR_ENTRY</option>
|
|
679
|
-
<option value="113">WEEKLY_SCHEDULE</option>
|
|
680
|
-
<option value="114">SPECIAL_EVENT</option>
|
|
681
|
-
<option value="115">READ_ACCESS_SPECIFICATION</option>
|
|
682
|
-
<option value="116">READ_ACCESS_RESULT</option>
|
|
683
|
-
<option value="117">LIGHTING_COMMAND</option>
|
|
684
|
-
<option value="118">CONTEXT_SPECIFIC_DECODED</option>
|
|
685
|
-
<option value="119">CONTEXT_SPECIFIC_ENCODED</option>
|
|
686
|
-
<option value="120">LOG_RECORD</option>
|
|
687
|
-
</select>
|
|
688
|
-
</div>
|
|
689
|
-
|
|
690
|
-
<div class="form-row">
|
|
691
|
-
<label for="node-input-priority"><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.priority"></span> Priority</label>
|
|
692
|
-
<select id="node-input-priority">
|
|
693
|
-
<option value="1">1 - Manual-Life Safety</option>
|
|
694
|
-
<option value="2">2 - Automatic-Life Safety</option>
|
|
695
|
-
<option value="3">3 - Available</option>
|
|
696
|
-
<option value="4">4 - Available</option>
|
|
697
|
-
<option value="5">5 - Critical Equipment Control</option>
|
|
698
|
-
<option value="6">6 - Minimum On/Off</option>
|
|
699
|
-
<option value="7">7 - Available</option>
|
|
700
|
-
<option value="8">8 - Manual Operator</option>
|
|
701
|
-
<option value="9">9 - Available</option>
|
|
702
|
-
<option value="10">10 - Available</option>
|
|
703
|
-
<option value="11">11 - Available</option>
|
|
704
|
-
<option value="12">12 - Available</option>
|
|
705
|
-
<option value="13">13 - Available</option>
|
|
706
|
-
<option value="14">14 - Available</option>
|
|
707
|
-
<option value="15">15 - Available</option>
|
|
708
|
-
<option value="16">16 - Available</option>
|
|
709
|
-
</select>
|
|
710
|
-
</div>
|
|
711
|
-
|
|
712
|
-
<label for="node-input-hiddenDeployToggle" style="display: none !important;" >
|
|
713
|
-
<i class="icon-tag" style="display: none !important;"></i> <span data-i18n="bitpool-bacnet.label.hiddenDeployToggle" style="display: none !important;"></span>
|
|
714
|
-
<input style="display: none !important;" type="checkbox" id="node-input-hiddenDeployToggle">
|
|
715
|
-
</label>
|
|
840
|
+
<button @click="removePointClicked(slotProps, this)" class="minusPointButton bacnetbutton">
|
|
841
|
+
<i class="pi pi-minus-circle "></i>
|
|
842
|
+
</button>
|
|
843
|
+
</div>
|
|
844
|
+
|
|
845
|
+
</template>
|
|
846
|
+
</p-tree>
|
|
847
|
+
<div v-else style="text-align: center; padding-top: 20px;">
|
|
848
|
+
<a>No devices found.</a>
|
|
849
|
+
</div>
|
|
716
850
|
</div>
|
|
851
|
+
</div>
|
|
852
|
+
|
|
853
|
+
<img
|
|
854
|
+
id="loadingGif"
|
|
855
|
+
src="resources/@bitpoolos/edge-bacnet/BitpoolCube_Blue_350.gif"
|
|
856
|
+
style="width: 70px; display: block; margin-left: auto; margin-right: auto;" />
|
|
857
|
+
<p id="loadingText" style="display: block; margin-left: auto; margin-right: auto; text-align: center; color: #505050;">
|
|
858
|
+
Loading current network info
|
|
859
|
+
</p>
|
|
860
|
+
</div>
|
|
717
861
|
|
|
862
|
+
<div id="read-writeList-tab" style="display:none">
|
|
863
|
+
<p-tree :value="writeDevices">
|
|
864
|
+
<template #device="slotProps">
|
|
865
|
+
<b class="deviceLabel">{{slotProps.node.label}} </b>
|
|
866
|
+
</template>
|
|
867
|
+
|
|
868
|
+
<template #point="slotProps" v-model:class="pointContent">
|
|
869
|
+
<b class="pointLabel">{{slotProps.node.label}}</b>
|
|
870
|
+
<button @click="removePointClicked(slotProps, this)" class="minusPointButton bacnetbutton">
|
|
871
|
+
<i class="pi pi-minus-circle "></i>
|
|
872
|
+
</button>
|
|
873
|
+
</template>
|
|
874
|
+
</p-tree>
|
|
718
875
|
</div>
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
<
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
876
|
+
|
|
877
|
+
<div id="read-write-tab" style="display:none">
|
|
878
|
+
<div class="form-row">
|
|
879
|
+
<label for="node-input-applicationTag"
|
|
880
|
+
><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.applicationTag"></span> Application Tag</label
|
|
881
|
+
>
|
|
882
|
+
<select id="node-input-applicationTag">
|
|
883
|
+
<option value="0">NULL</option>
|
|
884
|
+
<option value="1">BOOLEAN</option>
|
|
885
|
+
<option value="2">UNSIGNED_INT</option>
|
|
886
|
+
<option value="3">SIGNED_INT</option>
|
|
887
|
+
<option value="4">REAL</option>
|
|
888
|
+
<option value="5">DOUBLE</option>
|
|
889
|
+
<option value="6">OCTET_STRING</option>
|
|
890
|
+
<option value="7">CHARACTER_STRING</option>
|
|
891
|
+
<option value="8">BIT_STRING</option>
|
|
892
|
+
<option value="9">ENUMERATED</option>
|
|
893
|
+
<option value="10">DATE</option>
|
|
894
|
+
<option value="11">TIME</option>
|
|
895
|
+
<option value="12">OBJECT_ID</option>
|
|
896
|
+
<option value="13">RESERVE1</option>
|
|
897
|
+
<option value="14">RESERVE2</option>
|
|
898
|
+
<option value="15">RESERVE3</option>
|
|
899
|
+
<option value="16">MAX_BACNET_APPLICATION_TAG</option>
|
|
900
|
+
<option value="100">EMPTYLIST</option>
|
|
901
|
+
<option value="101">WEEKNDAY</option>
|
|
902
|
+
<option value="102">DATERANGE</option>
|
|
903
|
+
<option value="103">DATETIME</option>
|
|
904
|
+
<option value="104">TIMESTAMP</option>
|
|
905
|
+
<option value="105">ERROR</option>
|
|
906
|
+
<option value="106">DEVICE_OBJECT_PROPERTY_REFERENCE</option>
|
|
907
|
+
<option value="107">DEVICE_OBJECT_REFERENCE</option>
|
|
908
|
+
<option value="108">OBJECT_PROPERTY_REFERENCE</option>
|
|
909
|
+
<option value="109">DESTINATION</option>
|
|
910
|
+
<option value="110">RECIPIENT</option>
|
|
911
|
+
<option value="111">COV_SUBSCRIPTION</option>
|
|
912
|
+
<option value="112">CALENDAR_ENTRY</option>
|
|
913
|
+
<option value="113">WEEKLY_SCHEDULE</option>
|
|
914
|
+
<option value="114">SPECIAL_EVENT</option>
|
|
915
|
+
<option value="115">READ_ACCESS_SPECIFICATION</option>
|
|
916
|
+
<option value="116">READ_ACCESS_RESULT</option>
|
|
917
|
+
<option value="117">LIGHTING_COMMAND</option>
|
|
918
|
+
<option value="118">CONTEXT_SPECIFIC_DECODED</option>
|
|
919
|
+
<option value="119">CONTEXT_SPECIFIC_ENCODED</option>
|
|
920
|
+
<option value="120">LOG_RECORD</option>
|
|
921
|
+
</select>
|
|
922
|
+
</div>
|
|
923
|
+
|
|
924
|
+
<div class="form-row">
|
|
925
|
+
<label for="node-input-priority"
|
|
926
|
+
><i class="icon-tag"></i><span data-i18n="bitpool-bacnet.label.priority"></span> Priority</label
|
|
927
|
+
>
|
|
928
|
+
<select id="node-input-priority">
|
|
929
|
+
<option value="1">1 - Manual-Life Safety</option>
|
|
930
|
+
<option value="2">2 - Automatic-Life Safety</option>
|
|
931
|
+
<option value="3">3 - Available</option>
|
|
932
|
+
<option value="4">4 - Available</option>
|
|
933
|
+
<option value="5">5 - Critical Equipment Control</option>
|
|
934
|
+
<option value="6">6 - Minimum On/Off</option>
|
|
935
|
+
<option value="7">7 - Available</option>
|
|
936
|
+
<option value="8">8 - Manual Operator</option>
|
|
937
|
+
<option value="9">9 - Available</option>
|
|
938
|
+
<option value="10">10 - Available</option>
|
|
939
|
+
<option value="11">11 - Available</option>
|
|
940
|
+
<option value="12">12 - Available</option>
|
|
941
|
+
<option value="13">13 - Available</option>
|
|
942
|
+
<option value="14">14 - Available</option>
|
|
943
|
+
<option value="15">15 - Available</option>
|
|
944
|
+
<option value="16">16 - Available</option>
|
|
945
|
+
</select>
|
|
946
|
+
</div>
|
|
947
|
+
|
|
948
|
+
<label for="node-input-hiddenDeployToggle" style="display: none !important;">
|
|
949
|
+
<i class="icon-tag" style="display: none !important;"></i>
|
|
950
|
+
<span data-i18n="bitpool-bacnet.label.hiddenDeployToggle" style="display: none !important;"></span>
|
|
951
|
+
<input style="display: none !important;" type="checkbox" id="node-input-hiddenDeployToggle" />
|
|
952
|
+
</label>
|
|
953
|
+
</div>
|
|
954
|
+
</div>
|
|
955
|
+
</script>
|
|
956
|
+
<script type="text/html" data-help-name="Bacnet-Write">
|
|
957
|
+
<p>A node used to view, select devices, device points, and point properties to add to the Write polling list.</p>
|
|
958
|
+
|
|
959
|
+
<h3><strong>Device List</strong></h3>
|
|
960
|
+
<ol class="node-ports">
|
|
961
|
+
<p>
|
|
962
|
+
This tab displays the devices and device points that are a result of a network Discover. The data is broken down and
|
|
963
|
+
listed as Devices, Points for the Device, and Point properties for the Points. On this tab the user may choose specific
|
|
964
|
+
points to Write values to. The reload button may be used to show any new data that may have been recieved by the
|
|
965
|
+
bitpool BACnet node. Please note: Data can only be shown here once a Discover sucessfully recieves a response from
|
|
966
|
+
online devices on the network
|
|
967
|
+
</p>
|
|
968
|
+
</ol>
|
|
969
|
+
|
|
970
|
+
<h3><strong>Write List</strong></h3>
|
|
971
|
+
<ol class="node-ports">
|
|
972
|
+
<p>This tab shows all of the devices and points that have been chosen to write.</p>
|
|
973
|
+
</ol>
|
|
974
|
+
|
|
975
|
+
<h3><strong>Properties</strong></h3>
|
|
976
|
+
<ol class="node-ports">
|
|
977
|
+
<p>
|
|
978
|
+
This tab allows the user to choose the Application Tag and Priority to be used in a Write function. Please make sure
|
|
979
|
+
the device / controller is configured correctly to accept the write command.
|
|
980
|
+
</p>
|
|
981
|
+
</ol>
|
|
982
|
+
|
|
983
|
+
<h3><strong>Examples</strong></h3>
|
|
984
|
+
<p>
|
|
985
|
+
For example flows, please use the examples section for this node. These examples can be found at: Node-red hamburger menu
|
|
986
|
+
on top right -> Import -> Examples -> @bitpoolos/edge-bacnet
|
|
987
|
+
</p>
|
|
988
|
+
<p>
|
|
989
|
+
To find captured examples of settings and flows, please go to our wiki
|
|
990
|
+
<a href="https://wiki.bitpool.com/en/edge/apps/bitpool-edge/nr-bacnet">here</a>
|
|
991
|
+
</p>
|
|
992
|
+
|
|
993
|
+
<h3>Resources:</h3>
|
|
994
|
+
<p><a href="https://youtu.be/4K7mVxfvfbc">Video Walk-through </a></p>
|
|
995
|
+
<h4><strong>Online Docs:</strong></h4>
|
|
996
|
+
<ul type="1">
|
|
997
|
+
<li><a href="https://www.bitpool.com/">bitpool.com</a> - check us out here.</li>
|
|
998
|
+
<li><a href="https://app.bitpool.com/">app.bitpool.com</a> - set up your account.</li>
|
|
999
|
+
<li><a href="https://wiki.bitpool.com/">wiki.bitpool.com</a> - find more documentation.</li>
|
|
1000
|
+
<li><a href="https://bacnet.org/">BACnet</a> - find more about the protocol.</li>
|
|
1001
|
+
</ul>
|
|
769
1002
|
</script>
|