@bitpoolos/edge-bacnet 1.2.5 → 1.2.7
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/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
- package/bacnet_client.js +414 -200
- package/bacnet_device.js +52 -0
- package/bacnet_gateway.html +836 -602
- package/bacnet_gateway.js +223 -128
- package/bacnet_read.html +64 -34
- package/bacnet_read.js +8 -3
- package/bacnet_server.js +193 -40
- package/bacnet_write.html +125 -33
- package/bacnet_write.js +1 -1
- package/common.js +152 -131
- package/package.json +2 -3
- package/resources/icons/icon-read.svg +19 -0
- package/resources/icons/icon-write.svg +16 -0
- package/resources/node-bacstack-ts/dist/lib/client.js +3 -3
- package/resources/style.css +11 -0
package/bacnet_read.html
CHANGED
|
@@ -106,7 +106,7 @@
|
|
|
106
106
|
app.pollFrequency = parseInt(result.pollFrequency);
|
|
107
107
|
app.deviceCount = result.deviceList.length;
|
|
108
108
|
//progress bar percentage
|
|
109
|
-
let progressVal = parseInt((result.
|
|
109
|
+
let progressVal = parseInt((result.renderListCount / result.deviceList.length) * 100);
|
|
110
110
|
if(typeof progressVal == "number" && !isNaN(progressVal)) {
|
|
111
111
|
app.progressBarValue = progressVal;
|
|
112
112
|
} else {
|
|
@@ -231,7 +231,7 @@
|
|
|
231
231
|
node.hiddenDeployToggle = !node.prevHiddenToggleState;
|
|
232
232
|
|
|
233
233
|
} catch(e) {
|
|
234
|
-
|
|
234
|
+
//do nothing
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
app.$forceUpdate();
|
|
@@ -241,11 +241,26 @@
|
|
|
241
241
|
//update UI
|
|
242
242
|
let parentDeviceName = slotProps.node.parentDevice;
|
|
243
243
|
let foundDeviceIndex = this.readDevices ? this.readDevices.findIndex(ele => ele.label == parentDeviceName) : -1;
|
|
244
|
-
let
|
|
244
|
+
let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
|
|
245
|
+
let deviceAddress = app.getDeviceAddress(device.address);
|
|
246
|
+
let key = `${deviceAddress}-${device.deviceId}`;
|
|
247
|
+
let parentDevice = this.devices.find(ele => ele.ipAddr == deviceAddress);
|
|
248
|
+
let childDevice;
|
|
249
|
+
if(device.isMstp){
|
|
250
|
+
let foundChildIndex = parentDevice.children[1].children.findIndex(ele => ele.label == parentDeviceName);
|
|
251
|
+
if(foundChildIndex !== -1) {
|
|
252
|
+
childDevice = parentDevice.children[1].children[foundChildIndex];
|
|
253
|
+
}
|
|
254
|
+
}
|
|
245
255
|
|
|
246
256
|
if (foundDeviceIndex == -1) {
|
|
247
257
|
//no read devices present, add new
|
|
248
|
-
let newReadParent
|
|
258
|
+
let newReadParent;
|
|
259
|
+
if(childDevice) {
|
|
260
|
+
newReadParent = {...childDevice};
|
|
261
|
+
} else{
|
|
262
|
+
newReadParent = {...parentDevice};
|
|
263
|
+
}
|
|
249
264
|
newReadParent.children = [];
|
|
250
265
|
newReadParent.children.push(slotProps.node);
|
|
251
266
|
|
|
@@ -260,22 +275,10 @@
|
|
|
260
275
|
}
|
|
261
276
|
|
|
262
277
|
//set show added to true
|
|
263
|
-
|
|
264
|
-
slot.showAdded = true;
|
|
265
|
-
|
|
278
|
+
slotProps.node.showAdded = true;
|
|
266
279
|
this.$forceUpdate();
|
|
267
280
|
|
|
268
281
|
//update node-red data structure
|
|
269
|
-
let device = this.deviceList.find(ele => {
|
|
270
|
-
if(ele.address.address) {
|
|
271
|
-
return ele.address.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
|
|
272
|
-
} else {
|
|
273
|
-
return ele.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
|
|
274
|
-
}
|
|
275
|
-
});
|
|
276
|
-
let deviceAddress = app.getDeviceAddress(device.address);
|
|
277
|
-
let key = `${deviceAddress}-${device.deviceId}`;
|
|
278
|
-
|
|
279
282
|
if (!this.pointsToRead[key]) {
|
|
280
283
|
this.pointsToRead[key] = {};
|
|
281
284
|
}
|
|
@@ -294,6 +297,9 @@
|
|
|
294
297
|
let parentDeviceName = slotProps.node.parentDevice;
|
|
295
298
|
let foundDeviceIndex = this.readDevices ? this.readDevices.findIndex(ele => ele.label == parentDeviceName) : -1;
|
|
296
299
|
let parentDevice = this.devices.find(ele => ele.label == parentDeviceName);
|
|
300
|
+
let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
|
|
301
|
+
let deviceAddress = app.getDeviceAddress(device.address);
|
|
302
|
+
let key = `${deviceAddress}-${device.deviceId}`;
|
|
297
303
|
|
|
298
304
|
if (foundDeviceIndex !== -1) {
|
|
299
305
|
let foundIndex = this.readDevices[foundDeviceIndex].children.findIndex(ele => ele.key == slotProps.node.key && ele.pointName == slotProps.node.pointName);
|
|
@@ -304,21 +310,10 @@
|
|
|
304
310
|
}
|
|
305
311
|
|
|
306
312
|
//set show added to true
|
|
307
|
-
let slot = parentDevice.showAdded ? slotProps.node : parentDevice.children.find(ele => ele.pointName == slotProps.node.pointName);
|
|
308
|
-
slot.showAdded = false;
|
|
309
313
|
slotProps.node.showAdded = false;
|
|
310
314
|
this.$forceUpdate();
|
|
311
315
|
|
|
312
316
|
//update node-red data stucture
|
|
313
|
-
let device = this.deviceList.find(ele => {
|
|
314
|
-
if(ele.address.address) {
|
|
315
|
-
return ele.address.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
|
|
316
|
-
} else {
|
|
317
|
-
return ele.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
let deviceAddress = app.getDeviceAddress(device.address);
|
|
321
|
-
let key = `${deviceAddress}-${device.deviceId}`;
|
|
322
317
|
let point = this.pointList[key][slotProps.node.pointName];
|
|
323
318
|
if (this.pointsToRead[key][point.objectName]) delete this.pointsToRead[key][point.objectName];
|
|
324
319
|
//if last point is removed, deleted whole entry
|
|
@@ -460,12 +455,22 @@
|
|
|
460
455
|
if (node.vm.$data.devices) node.devices = node.vm.$data.devices;
|
|
461
456
|
if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
|
|
462
457
|
if (node.vm.$data.pointsToRead) node.pointsToRead = node.vm.$data.pointsToRead;
|
|
458
|
+
//clear reload data function
|
|
459
|
+
if(node.reloadTimer) {
|
|
460
|
+
clearInterval(node.reloadTimer);
|
|
461
|
+
node.reloadTimer = null;
|
|
462
|
+
}
|
|
463
463
|
},
|
|
464
464
|
oneditcancel: function () {
|
|
465
465
|
let node = this;
|
|
466
466
|
if (node.vm.$data.devices) node.devices = node.vm.$data.devices;
|
|
467
467
|
if (node.vm.$data.readDevices) node.readDevices = node.vm.$data.readDevices;
|
|
468
468
|
if (node.vm.$data.pointsToRead) node.pointsToRead = node.vm.$data.pointsToRead;
|
|
469
|
+
//clear reload data function
|
|
470
|
+
if(node.reloadTimer) {
|
|
471
|
+
clearInterval(node.reloadTimer);
|
|
472
|
+
node.reloadTimer = null;
|
|
473
|
+
}
|
|
469
474
|
}
|
|
470
475
|
});
|
|
471
476
|
|
|
@@ -498,9 +503,6 @@
|
|
|
498
503
|
.pointLabel {
|
|
499
504
|
font-weight: 400;
|
|
500
505
|
}
|
|
501
|
-
/* .p-treenode-children {
|
|
502
|
-
background-color: #f0f0f0;
|
|
503
|
-
} */
|
|
504
506
|
.deviceLabel {
|
|
505
507
|
font-weight: 100;
|
|
506
508
|
}
|
|
@@ -526,15 +528,17 @@
|
|
|
526
528
|
}
|
|
527
529
|
.p-treenode-children > li > .p-treenode-children > li {
|
|
528
530
|
font-size: 14px;
|
|
529
|
-
height:
|
|
531
|
+
/* height: 35px; */
|
|
530
532
|
color: #b5b5b5 !important;
|
|
531
533
|
}
|
|
532
534
|
.p-treenode-children > li > .p-treenode-children > .p-treenode-label {
|
|
533
535
|
color: #b5b5b5 !important;
|
|
534
536
|
}
|
|
537
|
+
/*
|
|
535
538
|
.p-treenode-children > li > .p-treenode-children > li:last-child {
|
|
536
|
-
padding-bottom: 30px;
|
|
539
|
+
padding-bottom: 30px;
|
|
537
540
|
}
|
|
541
|
+
*/
|
|
538
542
|
.p-tree-toggler:enabled:hover {
|
|
539
543
|
background: #d5d5d5 !important;
|
|
540
544
|
}
|
|
@@ -551,6 +555,7 @@
|
|
|
551
555
|
.statusOffline {
|
|
552
556
|
color: red;
|
|
553
557
|
}
|
|
558
|
+
|
|
554
559
|
.deviceLabel {
|
|
555
560
|
position: absolute;
|
|
556
561
|
}
|
|
@@ -659,6 +664,22 @@
|
|
|
659
664
|
padding-right: 20px;
|
|
660
665
|
}
|
|
661
666
|
|
|
667
|
+
.p-tree .p-treenode-children {
|
|
668
|
+
padding: 0 !important;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
.p-tree-toggler .p-link {
|
|
672
|
+
width: 25px !important;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
|
|
676
|
+
/*
|
|
677
|
+
.p-treenode-content {
|
|
678
|
+
height: 15px;
|
|
679
|
+
}
|
|
680
|
+
*/
|
|
681
|
+
|
|
682
|
+
|
|
662
683
|
</style>
|
|
663
684
|
|
|
664
685
|
<div class="form-row">
|
|
@@ -701,7 +722,7 @@
|
|
|
701
722
|
|
|
702
723
|
|
|
703
724
|
<div id="deviceListApp">
|
|
704
|
-
<p-tree :value="devices" selectable="false" :filter="true" filterMode="lenient" filterPlaceholder="No results found." v-if="hasData()">
|
|
725
|
+
<p-tree :value="devices" selectable="false" :filter="true" filterMode="lenient" filterPlaceholder="No results found." v-if="hasData()">
|
|
705
726
|
<template #device="slotProps">
|
|
706
727
|
<div v-if="isDeviceActive(slotProps)" class="deviceLabelParent">
|
|
707
728
|
<b class="deviceLabel">{{slotProps.node.label}} <b class="statusOnline deviceStatus">Online</b></b>
|
|
@@ -726,6 +747,15 @@
|
|
|
726
747
|
</button>
|
|
727
748
|
</template>
|
|
728
749
|
|
|
750
|
+
<!-- <template #pointFolder="slotProps">
|
|
751
|
+
|
|
752
|
+
</template>
|
|
753
|
+
|
|
754
|
+
|
|
755
|
+
<template #deviceFolder="slotProps">
|
|
756
|
+
|
|
757
|
+
</template> -->
|
|
758
|
+
|
|
729
759
|
<template #point="slotProps" v-model:class="pointContent">
|
|
730
760
|
<b class="pointLabel">{{slotProps.node.label}}</b>
|
|
731
761
|
|
package/bacnet_read.js
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
module.exports = function (RED) {
|
|
8
|
-
const fetch = require('node-fetch');
|
|
9
8
|
const http = require("http");
|
|
10
9
|
const { ReadCommandConfig } = require('./common');
|
|
11
10
|
const baEnum = require('./resources/node-bacstack-ts/dist/index.js').enum;
|
|
@@ -20,6 +19,7 @@ module.exports = function (RED) {
|
|
|
20
19
|
this.pointsToRead = config.pointsToRead;
|
|
21
20
|
this.readDevices = config.readDevices;
|
|
22
21
|
this.id = config.id;
|
|
22
|
+
this.nodeName = config.name;
|
|
23
23
|
|
|
24
24
|
this.object_property_simplePayload = config.object_property_simplePayload;
|
|
25
25
|
this.object_property_fullObject = config.object_property_fullObject;
|
|
@@ -68,12 +68,13 @@ module.exports = function (RED) {
|
|
|
68
68
|
node.send(priorityDevicesMsg);
|
|
69
69
|
|
|
70
70
|
node.on('input', function(msg) {
|
|
71
|
+
node.status({ fill: "blue", shape: "dot", text: "Reading values" });
|
|
71
72
|
|
|
72
73
|
let readConfig = new ReadCommandConfig(node.pointsToRead, node.object_props, node.roundDecimal);
|
|
73
|
-
|
|
74
74
|
let output = {
|
|
75
75
|
type: "Read",
|
|
76
76
|
id: node.id,
|
|
77
|
+
readNodeName: node.nodeName,
|
|
77
78
|
options: readConfig,
|
|
78
79
|
objectPropertyType: {
|
|
79
80
|
simplePayload: node.object_property_simplePayload,
|
|
@@ -84,9 +85,13 @@ module.exports = function (RED) {
|
|
|
84
85
|
mqtt: node.mqtt
|
|
85
86
|
}
|
|
86
87
|
};
|
|
87
|
-
|
|
88
|
+
|
|
88
89
|
node.send(output);
|
|
89
90
|
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
node.status({});
|
|
93
|
+
}, 3000);
|
|
94
|
+
|
|
90
95
|
});
|
|
91
96
|
|
|
92
97
|
};
|
package/bacnet_server.js
CHANGED
|
@@ -8,7 +8,13 @@ class BacnetServer {
|
|
|
8
8
|
constructor(client, deviceId, nodeRedVersion) {
|
|
9
9
|
let that = this;
|
|
10
10
|
that.bacnetClient = client;
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
// object identifier init
|
|
13
|
+
that.objectIdNumber = {};
|
|
14
|
+
that.objectIdNumber[baEnum.ObjectType.ANALOG_VALUE] = 0;
|
|
15
|
+
that.objectIdNumber[baEnum.ObjectType.CHARACTERSTRING_VALUE] = 0;
|
|
16
|
+
that.objectIdNumber[baEnum.ObjectType.BINARY_VALUE] = 0;
|
|
17
|
+
|
|
12
18
|
that.nodeRedVersion = nodeRedVersion;
|
|
13
19
|
that.deviceId = deviceId;
|
|
14
20
|
that.vendorId = 1401;
|
|
@@ -63,7 +69,8 @@ class BacnetServer {
|
|
|
63
69
|
],
|
|
64
70
|
},
|
|
65
71
|
[baEnum.ObjectType.ANALOG_VALUE]: [],
|
|
66
|
-
[baEnum.ObjectType.CHARACTERSTRING_VALUE]: []
|
|
72
|
+
[baEnum.ObjectType.CHARACTERSTRING_VALUE]: [],
|
|
73
|
+
[baEnum.ObjectType.BINARY_VALUE]: []
|
|
67
74
|
};
|
|
68
75
|
|
|
69
76
|
try {
|
|
@@ -74,6 +81,7 @@ class BacnetServer {
|
|
|
74
81
|
if(cachedData.objectStore) {
|
|
75
82
|
that.objectStore[baEnum.ObjectType.ANALOG_VALUE] = cachedData.objectStore[baEnum.ObjectType.ANALOG_VALUE];
|
|
76
83
|
that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] = cachedData.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE];
|
|
84
|
+
that.objectStore[baEnum.ObjectType.BINARY_VALUE] = cachedData.objectStore[baEnum.ObjectType.BINARY_VALUE];
|
|
77
85
|
}
|
|
78
86
|
}
|
|
79
87
|
} catch (error) {
|
|
@@ -121,8 +129,6 @@ class BacnetServer {
|
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
} catch(e) {
|
|
124
|
-
console.log("Bacnet server readPropertyMultiple error: ", e);
|
|
125
|
-
|
|
126
132
|
that.bacnetClient.client.errorResponse(
|
|
127
133
|
data.address,
|
|
128
134
|
baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE,
|
|
@@ -160,7 +166,7 @@ class BacnetServer {
|
|
|
160
166
|
);
|
|
161
167
|
}
|
|
162
168
|
} catch(e) {
|
|
163
|
-
console.log("Local BACnet device readProperty error: ", e);
|
|
169
|
+
//console.log("Local BACnet device readProperty error: ", e);
|
|
164
170
|
}
|
|
165
171
|
|
|
166
172
|
});
|
|
@@ -180,55 +186,87 @@ class BacnetServer {
|
|
|
180
186
|
let that = this;
|
|
181
187
|
let objectType = that.getBacnetObjectType(value);
|
|
182
188
|
if(name && objectType) {
|
|
189
|
+
let instanceNumber;
|
|
190
|
+
if (name.includes('|')) {
|
|
191
|
+
// split name, assign last part to instanceNumber and the rest to name
|
|
192
|
+
let nameParts = name.split('|');
|
|
193
|
+
instanceNumber = nameParts[nameParts.length - 1];
|
|
194
|
+
nameParts.pop();
|
|
195
|
+
name = nameParts.join('|');
|
|
196
|
+
}
|
|
183
197
|
let formattedName = name.replaceAll('.', '_');
|
|
184
198
|
formattedName = formattedName.replaceAll('/', '_');
|
|
185
199
|
if(objectType == "number") {
|
|
186
200
|
let foundIndex = that.objectStore[baEnum.ObjectType.ANALOG_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
|
|
187
201
|
if(foundIndex == -1) {
|
|
188
|
-
|
|
189
|
-
|
|
202
|
+
let objectId = that.getObjectIdentifier(baEnum.ObjectType.ANALOG_VALUE, instanceNumber);
|
|
203
|
+
that.objectStore[baEnum.ObjectType.ANALOG_VALUE].push({
|
|
204
|
+
[baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
|
|
205
|
+
[baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.ANALOG_VALUE, type: 9}],
|
|
206
|
+
[baEnum.PropertyIdentifier.DESCRIPTION]: [{value: '', type: 7}],
|
|
207
|
+
[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId}, type: 12}],
|
|
208
|
+
[baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type: 4}],
|
|
209
|
+
[baEnum.PropertyIdentifier.STATUS_FLAGS]: [{value: 0, type: 8}],
|
|
210
|
+
[baEnum.PropertyIdentifier.EVENT_STATE]: [{value: 0, type: 9}],
|
|
211
|
+
[baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{value: 0, type: 9}],
|
|
212
|
+
[baEnum.PropertyIdentifier.UNITS]: [{value: 95, type: 9}],
|
|
213
|
+
[baEnum.PropertyIdentifier.PRIORITY_ARRAY]: [{value: 0, type: 9}],
|
|
214
|
+
[baEnum.PropertyIdentifier.MAX_PRES_VALUE]: [{value: value, type: 4}],
|
|
215
|
+
[baEnum.PropertyIdentifier.MIN_PRES_VALUE]: [{value: value, type: 4}],
|
|
216
|
+
[baEnum.PropertyIdentifier.RESOLUTION]: [{value: 0, type: 4}],
|
|
217
|
+
[baEnum.PropertyIdentifier.PROPERTY_LIST]:
|
|
218
|
+
[
|
|
219
|
+
{value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
|
|
220
|
+
{value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
|
|
221
|
+
{value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
|
|
222
|
+
{value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
|
|
223
|
+
{value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 },
|
|
224
|
+
{value: baEnum.PropertyIdentifier.STATUS_FLAGS, type: 9 },
|
|
225
|
+
{value: baEnum.PropertyIdentifier.EVENT_STATE, type: 9 },
|
|
226
|
+
{value: baEnum.PropertyIdentifier.OUT_OF_SERVICE, type: 9 },
|
|
227
|
+
{value: baEnum.PropertyIdentifier.UNITS, type: 9 },
|
|
228
|
+
{value: baEnum.PropertyIdentifier.PRIORITY_ARRAY, type: 9 },
|
|
229
|
+
{value: baEnum.PropertyIdentifier.MAX_PRES_VALUE, type: 9 },
|
|
230
|
+
{value: baEnum.PropertyIdentifier.MIN_PRES_VALUE, type: 9 },
|
|
231
|
+
{value: baEnum.PropertyIdentifier.RESOLUTION, type: 9 },
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
that.objectList.push({value: {type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId}, type: 12})
|
|
236
|
+
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
237
|
+
} else if(foundIndex !== -1) {
|
|
238
|
+
let foundObject = that.objectStore[baEnum.ObjectType.ANALOG_VALUE][foundIndex];
|
|
239
|
+
foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
|
|
240
|
+
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
241
|
+
}
|
|
242
|
+
} else if (objectType == "boolean") {
|
|
243
|
+
let foundIndex = that.objectStore[baEnum.ObjectType.BINARY_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
|
|
244
|
+
if(foundIndex == -1) {
|
|
245
|
+
let objectId = that.getObjectIdentifier(baEnum.ObjectType.BINARY_VALUE);
|
|
246
|
+
that.objectStore[baEnum.ObjectType.BINARY_VALUE].push({
|
|
190
247
|
[baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
|
|
191
|
-
[baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.
|
|
248
|
+
[baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.BINARY_VALUE, type: 9}],
|
|
192
249
|
[baEnum.PropertyIdentifier.DESCRIPTION]: [{value: '', type: 7}],
|
|
193
|
-
[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.
|
|
194
|
-
[baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type:
|
|
250
|
+
[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.BINARY_VALUE, instance: objectId}, type: 12}],
|
|
251
|
+
[baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type: 1}],
|
|
195
252
|
[baEnum.PropertyIdentifier.STATUS_FLAGS]: [{value: 0, type: 8}],
|
|
196
253
|
[baEnum.PropertyIdentifier.EVENT_STATE]: [{value: 0, type: 9}],
|
|
197
254
|
[baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{value: 0, type: 9}],
|
|
198
|
-
[baEnum.PropertyIdentifier.
|
|
199
|
-
[baEnum.PropertyIdentifier.
|
|
200
|
-
[baEnum.PropertyIdentifier.MAX_PRES_VALUE]: [{value: value, type: 4}],
|
|
201
|
-
[baEnum.PropertyIdentifier.MIN_PRES_VALUE]: [{value: value, type: 4}],
|
|
202
|
-
[baEnum.PropertyIdentifier.RESOLUTION]: [{value: 0, type: 4}],
|
|
203
|
-
[baEnum.PropertyIdentifier.PROPERTY_LIST]:
|
|
204
|
-
[
|
|
205
|
-
{value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
|
|
206
|
-
{value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
|
|
207
|
-
{value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
|
|
208
|
-
{value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
|
|
209
|
-
{value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 },
|
|
210
|
-
{value: baEnum.PropertyIdentifier.STATUS_FLAGS, type: 9 },
|
|
211
|
-
{value: baEnum.PropertyIdentifier.EVENT_STATE, type: 9 },
|
|
212
|
-
{value: baEnum.PropertyIdentifier.OUT_OF_SERVICE, type: 9 },
|
|
213
|
-
{value: baEnum.PropertyIdentifier.UNITS, type: 9 },
|
|
214
|
-
{value: baEnum.PropertyIdentifier.PRIORITY_ARRAY, type: 9 },
|
|
215
|
-
{value: baEnum.PropertyIdentifier.MAX_PRES_VALUE, type: 9 },
|
|
216
|
-
{value: baEnum.PropertyIdentifier.MIN_PRES_VALUE, type: 9 },
|
|
217
|
-
{value: baEnum.PropertyIdentifier.RESOLUTION, type: 9 },
|
|
218
|
-
],
|
|
255
|
+
[baEnum.PropertyIdentifier.ACTIVE_TEXT]: [{value: 'ACTIVE', type: 7}],
|
|
256
|
+
[baEnum.PropertyIdentifier.INACTIVE_TEXT]: [{value: 'INACTIVE', type: 7}],
|
|
219
257
|
});
|
|
220
258
|
|
|
221
|
-
that.objectList.push({value: {type: baEnum.ObjectType.
|
|
259
|
+
that.objectList.push({value: {type: baEnum.ObjectType.BINARY_VALUE, instance: objectId}, type: 12})
|
|
222
260
|
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
223
261
|
} else if(foundIndex !== -1) {
|
|
224
|
-
let foundObject = that.objectStore[baEnum.ObjectType.
|
|
262
|
+
let foundObject = that.objectStore[baEnum.ObjectType.BINARY_VALUE][foundIndex];
|
|
225
263
|
foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
|
|
226
264
|
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
227
265
|
}
|
|
228
266
|
} else if(objectType == "string") {
|
|
229
267
|
let foundIndex = that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
|
|
230
268
|
if(foundIndex == -1) {
|
|
231
|
-
let objectId = that.getObjectIdentifier();
|
|
269
|
+
let objectId = that.getObjectIdentifier(baEnum.ObjectType.CHARACTERSTRING_VALUE);
|
|
232
270
|
that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].push({
|
|
233
271
|
[baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
|
|
234
272
|
[baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.CHARACTERSTRING_VALUE, type: 9}],
|
|
@@ -350,11 +388,119 @@ class BacnetServer {
|
|
|
350
388
|
that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] = [];
|
|
351
389
|
that.objectStore[baEnum.ObjectType.ANALOG_VALUE] = [];
|
|
352
390
|
|
|
353
|
-
that.objectIdNumber =
|
|
391
|
+
that.objectIdNumber = {};
|
|
392
|
+
that.objectIdNumber[baEnum.ObjectType.ANALOG_VALUE] = 0;
|
|
393
|
+
that.objectIdNumber[baEnum.ObjectType.CHARACTERSTRING_VALUE] = 0;
|
|
394
|
+
that.objectIdNumber[baEnum.ObjectType.BINARY_VALUE] = 0;
|
|
354
395
|
|
|
355
396
|
Store_Config_Server(JSON.stringify({objectList: that.objectList, objectStore: that.objectStore}));
|
|
356
397
|
}
|
|
357
398
|
|
|
399
|
+
clearServerPoint(json) {
|
|
400
|
+
let that = this;
|
|
401
|
+
return new Promise(async function (resolve, reject) {
|
|
402
|
+
try {
|
|
403
|
+
let type;
|
|
404
|
+
switch (json.body.type) {
|
|
405
|
+
case 'SV':
|
|
406
|
+
type = baEnum.ObjectType.CHARACTERSTRING_VALUE;
|
|
407
|
+
break;
|
|
408
|
+
case 'BV':
|
|
409
|
+
type = baEnum.ObjectType.BINARY_VALUE;
|
|
410
|
+
break;
|
|
411
|
+
default:
|
|
412
|
+
type = baEnum.ObjectType.ANALOG_VALUE;
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// remove object from objectStore
|
|
417
|
+
let objectGroup = that.objectStore[type];
|
|
418
|
+
if (Array.isArray(objectGroup)) {
|
|
419
|
+
for (let i = 0; i < objectGroup.length; i++) {
|
|
420
|
+
let object = objectGroup[i];
|
|
421
|
+
if (object[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance == json.body.instance) {
|
|
422
|
+
that.objectStore[type].splice(i, 1);
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
} else {
|
|
427
|
+
delete that.objectStore[type];
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// remove object from objectList
|
|
431
|
+
let objectIndex = that.objectList.findIndex(ele =>
|
|
432
|
+
ele.value.instance == json.body.instance && ele.value.type == type);
|
|
433
|
+
if (objectIndex !== -1) {
|
|
434
|
+
that.objectList.splice(objectIndex, 1);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
// update objectList in device object
|
|
438
|
+
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
439
|
+
|
|
440
|
+
Store_Config_Server(JSON.stringify({ objectList: that.objectList, objectStore: that.objectStore }));
|
|
441
|
+
|
|
442
|
+
resolve(true);
|
|
443
|
+
} catch (e) {
|
|
444
|
+
reject(e);
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
getServerPoints() {
|
|
450
|
+
let that = this;
|
|
451
|
+
let points = [];
|
|
452
|
+
|
|
453
|
+
return new Promise(async function (resolve, reject) {
|
|
454
|
+
try {
|
|
455
|
+
// iterate analog value objects
|
|
456
|
+
if(that.objectStore[baEnum.ObjectType.ANALOG_VALUE] && that.objectStore[baEnum.ObjectType.ANALOG_VALUE].length > 0) {
|
|
457
|
+
that.objectStore[baEnum.ObjectType.ANALOG_VALUE].forEach((point) => {
|
|
458
|
+
let instance = point[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance;
|
|
459
|
+
let objectName = point[baEnum.PropertyIdentifier.OBJECT_NAME][0].value;
|
|
460
|
+
|
|
461
|
+
points.push({
|
|
462
|
+
name: objectName,
|
|
463
|
+
type: "AV",
|
|
464
|
+
instance
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// iterate character string value objects
|
|
470
|
+
if(that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] && that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].length > 0) {
|
|
471
|
+
that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].forEach((point) => {
|
|
472
|
+
let instance = point[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance;
|
|
473
|
+
let objectName = point[baEnum.PropertyIdentifier.OBJECT_NAME][0].value;
|
|
474
|
+
|
|
475
|
+
points.push({
|
|
476
|
+
name: objectName,
|
|
477
|
+
type: "SV",
|
|
478
|
+
instance
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// iterate binary value objects
|
|
484
|
+
if(that.objectStore[baEnum.ObjectType.BINARY_VALUE] && that.objectStore[baEnum.ObjectType.BINARY_VALUE].length > 0) {
|
|
485
|
+
that.objectStore[baEnum.ObjectType.BINARY_VALUE].forEach((point) => {
|
|
486
|
+
let instance = point[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance;
|
|
487
|
+
let objectName = point[baEnum.PropertyIdentifier.OBJECT_NAME][0].value;
|
|
488
|
+
|
|
489
|
+
points.push({
|
|
490
|
+
name: objectName,
|
|
491
|
+
type: "BV",
|
|
492
|
+
instance
|
|
493
|
+
});
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
resolve(points.sort((a, b) => (a.instance > b.instance) ? 1 : -1));
|
|
498
|
+
} catch (e) {
|
|
499
|
+
reject(e);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
|
|
358
504
|
getRandomArbitrary(min, max) {
|
|
359
505
|
return Math.random() * (max - min) + min;
|
|
360
506
|
}
|
|
@@ -367,16 +513,23 @@ class BacnetServer {
|
|
|
367
513
|
return "string"
|
|
368
514
|
case "number":
|
|
369
515
|
return "number"
|
|
516
|
+
case "boolean":
|
|
517
|
+
return "boolean"
|
|
370
518
|
default:
|
|
371
519
|
return null
|
|
372
520
|
}
|
|
373
521
|
}
|
|
374
522
|
|
|
375
|
-
getObjectIdentifier() {
|
|
376
|
-
let that = this;
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
523
|
+
getObjectIdentifier(type, instanceNumber) {
|
|
524
|
+
let that = this;
|
|
525
|
+
// manual instance numbering
|
|
526
|
+
if (instanceNumber) {
|
|
527
|
+
that.objectIdNumber[type] = instanceNumber + 1;
|
|
528
|
+
return instanceNumber;
|
|
529
|
+
}
|
|
530
|
+
// auto instance numbering
|
|
531
|
+
let objectId = that.objectIdNumber[type];
|
|
532
|
+
that.objectIdNumber[type]++;
|
|
380
533
|
return objectId;
|
|
381
534
|
}
|
|
382
535
|
|