@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_client.js
CHANGED
|
@@ -2,1719 +2,1809 @@
|
|
|
2
2
|
MIT License Copyright 2021, 2024 - Bitpool Pty Ltd
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const bacnet = require(
|
|
5
|
+
const bacnet = require("./resources/node-bacstack-ts/dist/index.js");
|
|
6
6
|
const baEnum = bacnet.enum;
|
|
7
7
|
const bacnetIdMax = baEnum.ASN1_MAX_PROPERTY_ID;
|
|
8
|
-
const { EventEmitter } = require(
|
|
9
|
-
const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync, isNumber } = require(
|
|
10
|
-
const { ToadScheduler, SimpleIntervalJob, Task } = require(
|
|
11
|
-
const { BacnetDevice } = require(
|
|
12
|
-
const {Mutex} = require("async-mutex");
|
|
8
|
+
const { EventEmitter } = require("events");
|
|
9
|
+
const { getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync, isNumber, decodeBitArray } = require("./common");
|
|
10
|
+
const { ToadScheduler, SimpleIntervalJob, Task } = require("toad-scheduler");
|
|
11
|
+
const { BacnetDevice } = require("./bacnet_device");
|
|
12
|
+
const { Mutex } = require("async-mutex");
|
|
13
|
+
const { treeBuilder } = require("./treeBuilder.js");
|
|
13
14
|
|
|
14
15
|
class BacnetClient extends EventEmitter {
|
|
16
|
+
//client constructor
|
|
17
|
+
constructor(config) {
|
|
18
|
+
super();
|
|
19
|
+
let that = this;
|
|
20
|
+
that.config = config;
|
|
21
|
+
that.deviceList = [];
|
|
22
|
+
that.networkTree = {};
|
|
23
|
+
that.lastWhoIs = null;
|
|
24
|
+
that.client = null;
|
|
25
|
+
that.lastNetworkPoll = null;
|
|
26
|
+
that.scheduler = new ToadScheduler();
|
|
27
|
+
that.mutex = new Mutex();
|
|
28
|
+
that.manualMutex = new Mutex();
|
|
29
|
+
that.pollInProgress = false;
|
|
30
|
+
that.scanMatrix = [];
|
|
31
|
+
that.renderListCount = 0;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
if (that.config.cacheFileEnabled) {
|
|
35
|
+
let cachedData = JSON.parse(Read_Config_Sync());
|
|
36
|
+
if (cachedData && typeof cachedData == "object") {
|
|
37
|
+
if (cachedData.renderList) that.renderList = cachedData.renderList;
|
|
38
|
+
if (cachedData.deviceList) {
|
|
39
|
+
cachedData.deviceList.forEach(function (device) {
|
|
40
|
+
let newBacnetDevice = new BacnetDevice(true, device);
|
|
41
|
+
that.deviceList.push(newBacnetDevice);
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (cachedData.pointList) that.networkTree = cachedData.pointList;
|
|
45
|
+
if (cachedData.renderListCount) that.renderListCount = cachedData.renderListCount;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
that.roundDecimal = config.roundDecimal;
|
|
50
|
+
that.apduSize = config.apduSize;
|
|
51
|
+
that.maxSegments = config.maxSegments;
|
|
52
|
+
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
53
|
+
that.deviceId = config.deviceId;
|
|
54
|
+
that.broadCastAddr = config.broadCastAddr;
|
|
55
|
+
that.device_read_schedule = config.device_read_schedule;
|
|
56
|
+
that.deviceRetryCount = parseInt(config.retries);
|
|
57
|
+
that.sanitise_device_schedule = config.sanitise_device_schedule;
|
|
58
|
+
that.buildTreeException = false;
|
|
59
|
+
|
|
60
|
+
that.readPropertyMultipleOptions = {
|
|
61
|
+
maxSegments: 112,
|
|
62
|
+
maxApdu: 5,
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
that.client = new bacnet.Client({
|
|
67
|
+
apduTimeout: config.apduTimeout,
|
|
68
|
+
interface: config.localIpAdrress,
|
|
69
|
+
port: config.port,
|
|
70
|
+
broadcastAddress: config.broadCastAddr,
|
|
71
|
+
});
|
|
72
|
+
that.setMaxListeners(1);
|
|
15
73
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
let that = this;
|
|
20
|
-
that.deviceList = [];
|
|
21
|
-
that.manualDiscoverQueue = [];
|
|
22
|
-
that.networkTree = {};
|
|
23
|
-
that.lastWhoIs = null;
|
|
24
|
-
that.client = null;
|
|
25
|
-
that.lastNetworkPoll = null;
|
|
26
|
-
that.scheduler = new ToadScheduler();
|
|
27
|
-
that.mutex = new Mutex();
|
|
28
|
-
that.manualMutex = new Mutex();
|
|
29
|
-
that.pollInProgress = false;
|
|
30
|
-
that.scanMatrix = [];
|
|
31
|
-
that.renderListCount = 0;
|
|
32
|
-
|
|
33
|
-
try {
|
|
74
|
+
const task = new Task("simple task", () => {
|
|
75
|
+
that.globalWhoIs();
|
|
76
|
+
});
|
|
34
77
|
|
|
35
|
-
|
|
36
|
-
let cachedData = JSON.parse(Read_Config_Sync());
|
|
37
|
-
if(cachedData && typeof cachedData == "object") {
|
|
38
|
-
if(cachedData.renderList) that.renderList = cachedData.renderList;
|
|
39
|
-
if(cachedData.deviceList) {
|
|
40
|
-
cachedData.deviceList.forEach(function(device) {
|
|
41
|
-
let newBacnetDevice = new BacnetDevice(true, device);
|
|
42
|
-
that.deviceList.push(newBacnetDevice);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
if(cachedData.pointList) that.networkTree = cachedData.pointList;
|
|
46
|
-
if(cachedData.renderListCount) that.renderListCount = cachedData.renderListCount;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
78
|
+
const job = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule) }, task);
|
|
49
79
|
|
|
50
|
-
|
|
51
|
-
that.roundDecimal = config.roundDecimal;
|
|
52
|
-
that.apduSize = config.apduSize;
|
|
53
|
-
that.maxSegments = config.maxSegments;
|
|
54
|
-
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
55
|
-
that.deviceId = config.deviceId;
|
|
56
|
-
that.broadCastAddr = config.broadCastAddr;
|
|
57
|
-
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
58
|
-
that.manual_instance_range_start = config.manual_instance_range_start;
|
|
59
|
-
that.manual_instance_range_end = config.manual_instance_range_end;
|
|
60
|
-
that.device_read_schedule = config.device_read_schedule;
|
|
61
|
-
that.deviceRetryCount = parseInt(config.retries);
|
|
62
|
-
|
|
63
|
-
that.readPropertyMultipleOptions = {
|
|
64
|
-
maxSegments: 112,
|
|
65
|
-
maxApdu: 5
|
|
66
|
-
};
|
|
80
|
+
that.scheduler.addSimpleIntervalJob(job);
|
|
67
81
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
82
|
+
//query device task
|
|
83
|
+
const queryDevices = new Task("simple task", () => {
|
|
84
|
+
if (!that.pollInProgress) that.queryDevices();
|
|
85
|
+
});
|
|
72
86
|
|
|
73
|
-
|
|
74
|
-
that.globalWhoIs();
|
|
75
|
-
});
|
|
87
|
+
const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.device_read_schedule) }, queryDevices);
|
|
76
88
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
that.scheduler.addSimpleIntervalJob(job);
|
|
89
|
+
that.scheduler.addSimpleIntervalJob(queryJob);
|
|
80
90
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if(!that.pollInProgress) that.queryDevices();
|
|
84
|
-
that.sanitizeDeviceList();
|
|
85
|
-
});
|
|
91
|
+
//buildNetworkTreeData task
|
|
92
|
+
const buildNetworkTree = new Task("simple task", () => {
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
that.scheduler.addSimpleIntervalJob(queryJob);
|
|
94
|
+
that.doTreeBuilder();
|
|
95
|
+
that.countDevices();
|
|
90
96
|
|
|
91
|
-
|
|
92
|
-
const buildNetworkTree = new Task('simple task', () => {
|
|
93
|
-
that.buildNetworkTreeData().then(function() {
|
|
94
|
-
that.countDevices();
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
+
});
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 5 }, buildNetworkTree);
|
|
100
|
+
|
|
101
|
+
that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
|
|
102
|
+
|
|
103
|
+
that.globalWhoIs();
|
|
104
|
+
|
|
105
|
+
setTimeout(() => {
|
|
106
|
+
that.queryDevices();
|
|
107
|
+
}, "5000");
|
|
108
|
+
} catch (e) {
|
|
109
|
+
that.logOut("Issue initializing client: ", e);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
//who is callback
|
|
113
|
+
that.client.on("iAm", (device) => {
|
|
114
|
+
if (device.address !== that.config.localIpAdrress) {
|
|
115
|
+
if (that.scanMatrix.length > 0) {
|
|
116
|
+
let matrixMap = that.scanMatrix.filter((ele) => device.deviceId >= ele.start && device.deviceId <= ele.end);
|
|
117
|
+
if (matrixMap.length > 0) {
|
|
118
|
+
//only add unique device to array
|
|
119
|
+
let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
|
|
120
|
+
if (foundIndex == -1) {
|
|
121
|
+
let newBacnetDevice = new BacnetDevice(false, device);
|
|
122
|
+
newBacnetDevice.setLastSeen(Date.now());
|
|
123
|
+
if (newBacnetDevice.getIsMstpDevice()) {
|
|
124
|
+
that.addToParentMstpNetwork(newBacnetDevice);
|
|
125
|
+
}
|
|
126
|
+
that.deviceList.push(newBacnetDevice);
|
|
127
|
+
} else if (foundIndex !== -1) {
|
|
128
|
+
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
129
|
+
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
130
|
+
if (that.deviceList[foundIndex].getIsMstpDevice()) {
|
|
131
|
+
that.addToParentMstpNetwork(that.deviceList[foundIndex]);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
101
134
|
|
|
102
|
-
|
|
135
|
+
//emit event for node-red to log
|
|
136
|
+
that.emit("deviceFound", device);
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
//only add unique device to array
|
|
140
|
+
let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
|
|
141
|
+
if (foundIndex == -1) {
|
|
142
|
+
let newBacnetDevice = new BacnetDevice(false, device);
|
|
143
|
+
newBacnetDevice.setLastSeen(Date.now());
|
|
144
|
+
if (newBacnetDevice.getIsMstpDevice()) {
|
|
145
|
+
that.addToParentMstpNetwork(newBacnetDevice);
|
|
146
|
+
}
|
|
147
|
+
that.deviceList.push(newBacnetDevice);
|
|
148
|
+
} else if (foundIndex !== -1) {
|
|
149
|
+
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
150
|
+
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
151
|
+
if (that.deviceList[foundIndex].getIsMstpDevice()) {
|
|
152
|
+
that.addToParentMstpNetwork(that.deviceList[foundIndex]);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
103
155
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
156
|
+
//emit event for node-red to log
|
|
157
|
+
that.emit("deviceFound", device);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
} catch (e) {
|
|
162
|
+
that.logOut("Issue with creating bacnet client, see error: ", e);
|
|
163
|
+
}
|
|
111
164
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
165
|
+
that.client.on("error", (err) => {
|
|
166
|
+
that.logOut("Error occurred: ", err);
|
|
167
|
+
|
|
168
|
+
if (err.errno == -4090) {
|
|
169
|
+
that.logOut("Invalid Client information or incorrect IP address provided");
|
|
170
|
+
} else if (err.errno == -49) {
|
|
171
|
+
that.logOut("Invalid IP address provided");
|
|
172
|
+
} else {
|
|
173
|
+
that.reinitializeClient(that.config);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
testFunction(address, type, instance, property) {
|
|
179
|
+
let that = this;
|
|
180
|
+
|
|
181
|
+
console.log("test function ");
|
|
182
|
+
|
|
183
|
+
that.client.readProperty(
|
|
184
|
+
address,
|
|
185
|
+
{ type: type, instance: instance },
|
|
186
|
+
property,
|
|
187
|
+
that.readPropertyMultipleOptions,
|
|
188
|
+
(err, value) => {
|
|
189
|
+
if (err) {
|
|
190
|
+
console.log("err: ", err);
|
|
191
|
+
}
|
|
115
192
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
that.deviceList.push(newBacnetDevice);
|
|
158
|
-
} else if(foundIndex !== -1) {
|
|
159
|
-
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
160
|
-
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
161
|
-
that.updateDeviceName(that.deviceList[foundIndex]);
|
|
162
|
-
|
|
163
|
-
if(that.deviceList[foundIndex].getIsMstpDevice()) {
|
|
164
|
-
that.addToParentMstpNetwork(that.deviceList[foundIndex]);
|
|
165
|
-
}
|
|
193
|
+
if (value) {
|
|
194
|
+
console.log("value : ", value);
|
|
195
|
+
console.log("value1 : ", value.values[0].value);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
getProtocolSupported(device) {
|
|
202
|
+
//return protocols support for device
|
|
203
|
+
let that = this;
|
|
204
|
+
return new Promise((resolve, reject) => {
|
|
205
|
+
that.client.readProperty(
|
|
206
|
+
device.getAddress(),
|
|
207
|
+
{ type: baEnum.ObjectType.DEVICE, instance: device.getDeviceId() },
|
|
208
|
+
baEnum.PropertyIdentifier.PROTOCOL_SERVICES_SUPPORTED,
|
|
209
|
+
that.readPropertyMultipleOptions,
|
|
210
|
+
(err, value) => {
|
|
211
|
+
if (err) {
|
|
212
|
+
reject(err);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (value) {
|
|
216
|
+
resolve(value);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
addToParentMstpNetwork(device) {
|
|
225
|
+
let that = this;
|
|
226
|
+
let address = device.getAddress().address;
|
|
227
|
+
let deviceId = device.getDeviceId();
|
|
228
|
+
let foundParentIndex = that.deviceList.findIndex((ele) => ele.getAddress() == address);
|
|
229
|
+
if (foundParentIndex !== -1) {
|
|
230
|
+
that.deviceList[foundParentIndex].addChildDevice(deviceId);
|
|
231
|
+
device.setParentDeviceId(that.deviceList[foundParentIndex].getDeviceId());
|
|
232
|
+
}
|
|
233
|
+
}
|
|
166
234
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
});
|
|
235
|
+
logOut(param1, param2) {
|
|
236
|
+
let that = this;
|
|
237
|
+
that.emit("bacnetErrorLog", param1, param2);
|
|
238
|
+
}
|
|
174
239
|
|
|
175
|
-
|
|
176
|
-
|
|
240
|
+
rebuildDataModel() {
|
|
241
|
+
let that = this;
|
|
242
|
+
return new Promise((resolve, reject) => {
|
|
243
|
+
try {
|
|
244
|
+
that.deviceList = [];
|
|
245
|
+
that.renderList = [];
|
|
246
|
+
that.networkTree = {};
|
|
247
|
+
that.pollInProgress = false;
|
|
248
|
+
that.renderListCount = 0;
|
|
249
|
+
resolve(true);
|
|
250
|
+
} catch (e) {
|
|
251
|
+
that.logOut("Error clearing BACnet data model: ", e);
|
|
252
|
+
reject(e);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
purgeDevice(device) {
|
|
258
|
+
let that = this;
|
|
259
|
+
return new Promise((resolve, reject) => {
|
|
260
|
+
try {
|
|
261
|
+
let renderListIndex = that.renderList.findIndex(
|
|
262
|
+
(ele) => ele.deviceId == device.deviceId && ele.ipAddr == device.address
|
|
263
|
+
);
|
|
264
|
+
let deviceListIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
|
|
265
|
+
let deviceKey = device.address + "-" + device.deviceId;
|
|
266
|
+
delete that.networkTree[deviceKey];
|
|
267
|
+
that.renderList.splice(renderListIndex, 1);
|
|
268
|
+
that.deviceList.splice(deviceListIndex, 1);
|
|
269
|
+
|
|
270
|
+
that.countDevices();
|
|
271
|
+
|
|
272
|
+
resolve(true);
|
|
273
|
+
} catch (e) {
|
|
274
|
+
reject(e);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
updatePointsForDevice(deviceObject) {
|
|
280
|
+
let that = this;
|
|
281
|
+
return new Promise((resolve, reject) => {
|
|
282
|
+
try {
|
|
283
|
+
let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
|
|
284
|
+
that.updateDeviceName(device);
|
|
285
|
+
|
|
286
|
+
if (device.getIsProtocolServicesSet() == false) {
|
|
287
|
+
that.getProtocolSupported(device).then(function (result) {
|
|
288
|
+
let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
|
|
289
|
+
device.setProtocolServicesSupported(decodedValues);
|
|
290
|
+
}).catch(function (error) {
|
|
291
|
+
that.logOut("getProtocolSupported error: ", error);
|
|
292
|
+
});
|
|
177
293
|
}
|
|
178
294
|
|
|
179
|
-
that
|
|
180
|
-
|
|
295
|
+
that
|
|
296
|
+
.getDevicePointList(device)
|
|
297
|
+
.then(function () {
|
|
298
|
+
that
|
|
299
|
+
.buildJsonObject(device)
|
|
300
|
+
.then(function () {
|
|
301
|
+
// do nothing for now
|
|
302
|
+
resolve(true);
|
|
303
|
+
})
|
|
304
|
+
.catch(function (e) {
|
|
305
|
+
that.logOut(`Update points list error 1: ${device.getAddress()}`, e);
|
|
306
|
+
});
|
|
307
|
+
})
|
|
308
|
+
.catch(function (e) {
|
|
309
|
+
that.logOut(`Update points list error 2: ${device.getAddress()}`, e);
|
|
310
|
+
device.setManualDiscoveryMode(true);
|
|
311
|
+
that
|
|
312
|
+
.getDevicePointListWithoutObjectList(device)
|
|
313
|
+
.then(function () {
|
|
314
|
+
that
|
|
315
|
+
.buildJsonObject(device)
|
|
316
|
+
.then(function () {
|
|
317
|
+
// do nothing for now
|
|
318
|
+
resolve(true);
|
|
319
|
+
})
|
|
320
|
+
.catch(function (e) {
|
|
321
|
+
that.logOut(`Update points list error 3: ${device.getAddress()}`, e);
|
|
322
|
+
});
|
|
323
|
+
})
|
|
324
|
+
.catch(function (e) {
|
|
325
|
+
that.logOut(`Update points list error 4: ${device.getAddress()}`, e);
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
} catch (e) {
|
|
329
|
+
reject(e);
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
setDeviceDisplayName(deviceObject, displayName) {
|
|
335
|
+
let that = this;
|
|
336
|
+
return new Promise((resolve, reject) => {
|
|
337
|
+
try {
|
|
338
|
+
let device = that.deviceList.find((ele) => ele.getDeviceId() == deviceObject.deviceId);
|
|
339
|
+
|
|
340
|
+
device.setDisplayName(displayName);
|
|
341
|
+
|
|
342
|
+
that.buildTreeException = true;
|
|
343
|
+
|
|
344
|
+
resolve(true);
|
|
345
|
+
} catch (e) {
|
|
346
|
+
that.logOut("setDeviceDisplayName error: ", e);
|
|
347
|
+
|
|
348
|
+
reject(e);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
setPointDisplayName(deviceKey, pointName, pointDisplayName) {
|
|
354
|
+
let that = this;
|
|
355
|
+
return new Promise((resolve, reject) => {
|
|
356
|
+
try {
|
|
357
|
+
if (that.networkTree[deviceKey][pointName]) {
|
|
358
|
+
that.networkTree[deviceKey][pointName].displayName = pointDisplayName;
|
|
359
|
+
}
|
|
181
360
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
361
|
+
that.buildTreeException = true;
|
|
362
|
+
|
|
363
|
+
resolve(true);
|
|
364
|
+
} catch (e) {
|
|
365
|
+
that.logOut("setPointDisplayName error: ", e);
|
|
366
|
+
reject(e);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
importReadList(payload) {
|
|
372
|
+
let that = this;
|
|
373
|
+
|
|
374
|
+
return new Promise((resolve, reject) => {
|
|
375
|
+
try {
|
|
376
|
+
that.buildTreeException = true;
|
|
377
|
+
|
|
378
|
+
for (let key in payload) {
|
|
379
|
+
let device = payload[key];
|
|
380
|
+
for (let pointName in device) {
|
|
381
|
+
let pointObject = device[pointName]
|
|
382
|
+
if (that.networkTree[key][pointName]) {
|
|
383
|
+
that.networkTree[key][pointName] = pointObject;
|
|
188
384
|
}
|
|
189
|
-
|
|
190
|
-
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
resolve(true);
|
|
388
|
+
} catch (e) {
|
|
389
|
+
that.logOut("importReadList error: ", e);
|
|
390
|
+
reject(e);
|
|
391
|
+
}
|
|
392
|
+
});
|
|
393
|
+
}
|
|
191
394
|
|
|
192
|
-
|
|
193
|
-
|
|
395
|
+
queryDevices() {
|
|
396
|
+
let that = this;
|
|
194
397
|
|
|
398
|
+
that.pollInProgress = true;
|
|
195
399
|
|
|
400
|
+
let index = 0;
|
|
196
401
|
|
|
197
|
-
|
|
402
|
+
query(index);
|
|
198
403
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
let address = device.getAddress().address;
|
|
202
|
-
let deviceId = device.getDeviceId();
|
|
203
|
-
let foundParentIndex = that.deviceList.findIndex(ele => ele.getAddress() == address);
|
|
204
|
-
if(foundParentIndex !== -1) {
|
|
205
|
-
that.deviceList[foundParentIndex].addChildDevice(deviceId);
|
|
206
|
-
device.setParentDeviceId(that.deviceList[foundParentIndex].getDeviceId());
|
|
207
|
-
}
|
|
208
|
-
}
|
|
404
|
+
function query(index) {
|
|
405
|
+
let device = that.deviceList[index];
|
|
209
406
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
that.emit('bacnetErrorLog', param1, param2);
|
|
213
|
-
}
|
|
407
|
+
if (index < that.deviceList.length) {
|
|
408
|
+
index++;
|
|
214
409
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
410
|
+
if (typeof device == "object") {
|
|
411
|
+
if (device.getIsProtocolServicesSet() == false) {
|
|
412
|
+
that.getProtocolSupported(device).then(function (result) {
|
|
413
|
+
let decodedValues = decodeBitArray(8, result.values[0].originalBitString.value);
|
|
414
|
+
device.setProtocolServicesSupported(decodedValues);
|
|
415
|
+
}).catch(function (error) {
|
|
416
|
+
that.logOut("getProtocolSupported error: ", error);
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
if (!device.getManualDiscoveryMode()) {
|
|
218
421
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
422
|
+
that.updateDeviceName(device);
|
|
423
|
+
that
|
|
424
|
+
.getDevicePointList(device)
|
|
425
|
+
.then(function () {
|
|
426
|
+
that
|
|
427
|
+
.buildJsonObject(device)
|
|
428
|
+
.then(function () {
|
|
429
|
+
query(index);
|
|
430
|
+
})
|
|
431
|
+
.catch(function (e) {
|
|
432
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
433
|
+
query(index);
|
|
434
|
+
});
|
|
435
|
+
})
|
|
436
|
+
.catch(function (e) {
|
|
437
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
438
|
+
device.setManualDiscoveryMode(true);
|
|
439
|
+
that
|
|
440
|
+
.getDevicePointListWithoutObjectList(device)
|
|
441
|
+
.then(function () {
|
|
442
|
+
that
|
|
443
|
+
.buildJsonObject(device)
|
|
444
|
+
.then(function () {
|
|
445
|
+
query(index);
|
|
446
|
+
})
|
|
447
|
+
.catch(function (e) {
|
|
448
|
+
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
449
|
+
query(index);
|
|
450
|
+
});
|
|
451
|
+
})
|
|
452
|
+
.catch(function (e) {
|
|
453
|
+
query(index);
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
} catch (e) {
|
|
457
|
+
that.logOut("Error while querying devices: ", e);
|
|
458
|
+
query(index);
|
|
228
459
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
that.pollInProgress = true;
|
|
236
|
-
|
|
237
|
-
let index = 0;
|
|
238
|
-
|
|
239
|
-
query(index);
|
|
240
|
-
|
|
241
|
-
function query(index) {
|
|
242
|
-
|
|
243
|
-
that.queryPriorityDevices().then(function() {
|
|
244
|
-
|
|
245
|
-
let device = that.deviceList[index];
|
|
246
|
-
|
|
247
|
-
if(index < that.deviceList.length) {
|
|
248
|
-
index++;
|
|
249
|
-
|
|
250
|
-
if(typeof device == "object") {
|
|
251
|
-
if(!device.getManualDiscoveryMode()) {
|
|
252
|
-
try {
|
|
253
|
-
that.getDevicePointList(device).then(function() {
|
|
254
|
-
that.removeDeviceFromManualQueue(device);
|
|
255
|
-
that.buildJsonObject(device, null).then(function() {
|
|
256
|
-
query(index);
|
|
257
|
-
}).catch(function(e) {
|
|
258
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
259
|
-
query(index);
|
|
260
|
-
});
|
|
261
|
-
}).catch(function(e) {
|
|
262
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
263
|
-
device.setManualDiscoveryMode(true);
|
|
264
|
-
that.getDevicePointListWithoutObjectList(device).then(function() {
|
|
265
|
-
that.buildJsonObject(device, null).then(function() {
|
|
266
|
-
query(index);
|
|
267
|
-
}).catch(function(e) {
|
|
268
|
-
that.logOut(`getDevicePointList error: ${device.getAddress()}`, e);
|
|
269
|
-
query(index);
|
|
270
|
-
});
|
|
271
|
-
}).catch(function(e){
|
|
272
|
-
query(index);
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
} catch(e) {
|
|
276
|
-
that.logOut("Error while querying devices: ", e);
|
|
277
|
-
query(index);
|
|
278
|
-
}
|
|
279
|
-
} else {
|
|
280
|
-
query(index);
|
|
281
|
-
}
|
|
282
|
-
} else {
|
|
283
|
-
that.logOut("queryDevices: invalid device found: ", device);
|
|
284
|
-
query(index);
|
|
285
|
-
}
|
|
286
|
-
} else if(index == that.deviceList.length) {
|
|
287
|
-
|
|
288
|
-
if(that.manualDiscoverQueue.length > 0) {
|
|
289
|
-
that.queryDevicesManually();
|
|
290
|
-
} else {
|
|
291
|
-
that.pollInProgress = false;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
});
|
|
460
|
+
} else {
|
|
461
|
+
query(index);
|
|
462
|
+
}
|
|
463
|
+
} else {
|
|
464
|
+
that.logOut("queryDevices: invalid device found: ", device);
|
|
465
|
+
query(index);
|
|
295
466
|
}
|
|
296
|
-
|
|
467
|
+
} else if (index == that.deviceList.length) {
|
|
468
|
+
that.pollInProgress = false;
|
|
469
|
+
}
|
|
297
470
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
query(index);
|
|
325
|
-
}
|
|
326
|
-
} catch(e) {
|
|
327
|
-
query(index);
|
|
328
|
-
}
|
|
329
|
-
} else {
|
|
330
|
-
query(index);
|
|
331
|
-
}
|
|
332
|
-
} else if(index == that.manualDiscoverQueue.length) {
|
|
333
|
-
that.pollInProgress = false;
|
|
334
|
-
}
|
|
335
|
-
});
|
|
336
|
-
}
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
updateDeviceName(device) {
|
|
474
|
+
let that = this;
|
|
475
|
+
that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function (deviceObject) {
|
|
476
|
+
if (typeof deviceObject.name == "string") {
|
|
477
|
+
device.setDeviceName(deviceObject.name + " " + device.getDeviceId());
|
|
478
|
+
device.setPointsList(deviceObject.devicePointEntry);
|
|
479
|
+
}
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
reinitializeClient(config) {
|
|
484
|
+
let that = this;
|
|
485
|
+
|
|
486
|
+
that.config = config;
|
|
487
|
+
that.roundDecimal = config.roundDecimal;
|
|
488
|
+
that.apduSize = config.apduSize;
|
|
489
|
+
that.maxSegments = config.maxSegments;
|
|
490
|
+
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
491
|
+
that.deviceId = config.deviceId;
|
|
492
|
+
that.broadCastAddr = config.broadCastAddr;
|
|
493
|
+
that.device_read_schedule = config.device_read_schedule;
|
|
494
|
+
|
|
495
|
+
if (that.scheduler !== null) {
|
|
496
|
+
that.scheduler.stop();
|
|
337
497
|
}
|
|
338
498
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
if(priorityDevices.length > 0) {
|
|
345
|
-
let index = 0;
|
|
346
|
-
|
|
347
|
-
query(index);
|
|
348
|
-
|
|
349
|
-
function query(index) {
|
|
350
|
-
let device = priorityDevices[index];
|
|
351
|
-
|
|
352
|
-
if(index < priorityDevices.length) {
|
|
353
|
-
index++;
|
|
354
|
-
|
|
355
|
-
if(typeof device == "object" && ((Date.now() - device.getLastPriorityQueueTS()) / 1000) > parseInt(that.device_read_schedule) ) {
|
|
356
|
-
|
|
357
|
-
try {
|
|
358
|
-
let points = device.getPriorityQueue();
|
|
359
|
-
that.buildJsonObject(device, points).then(function() {
|
|
360
|
-
device.setLastPriorityQueueTS();
|
|
361
|
-
query(index);
|
|
362
|
-
}).catch(function(e) {
|
|
363
|
-
that.logOut(`queryPriorityDevices error: ${device.getAddress()}`, e);
|
|
364
|
-
query(index);
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
} catch(e) {
|
|
368
|
-
that.logOut("Error while querying priority devices: ", e);
|
|
369
|
-
query(index);
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
} else {
|
|
373
|
-
query(index);
|
|
374
|
-
}
|
|
375
|
-
} else if(index == priorityDevices.length) {
|
|
376
|
-
resolve()
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
} else if(priorityDevices.length == 0) {
|
|
380
|
-
resolve()
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
}
|
|
499
|
+
try {
|
|
500
|
+
that.client._settings.apduTimeout = config.apduTimeout;
|
|
501
|
+
that.client._settings.interface = config.localIpAdrress;
|
|
502
|
+
that.client._settings.port = config.port;
|
|
503
|
+
that.client._settings.broadcastAddress = config.broadCastAddr;
|
|
384
504
|
|
|
385
|
-
|
|
386
|
-
|
|
505
|
+
that.client._transport.interface = config.localIpAdrress;
|
|
506
|
+
that.client._transport.port = config.port;
|
|
507
|
+
that.client._transport.broadcastAddress = config.broadCastAddr;
|
|
387
508
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if(index == -1) {
|
|
392
|
-
that.manualDiscoverQueue.push(device);
|
|
393
|
-
}
|
|
394
|
-
} else {
|
|
395
|
-
device.incrementPointListRetryCount();
|
|
396
|
-
}
|
|
397
|
-
}
|
|
509
|
+
const task = new Task("simple task", () => {
|
|
510
|
+
that.globalWhoIs();
|
|
511
|
+
});
|
|
398
512
|
|
|
399
|
-
|
|
400
|
-
let that = this;
|
|
401
|
-
device.setManualDiscoveryMode(false);
|
|
402
|
-
device.clearPointListRetryCount()
|
|
403
|
-
let index = that.manualDiscoverQueue.findIndex(ele => ele.getDeviceId() == device.getDeviceId());
|
|
404
|
-
if(index !== -1) {
|
|
405
|
-
that.manualDiscoverQueue.splice(index, 1);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
513
|
+
const job = new SimpleIntervalJob({ seconds: parseInt(config.discover_polling_schedule) }, task);
|
|
408
514
|
|
|
409
|
-
|
|
410
|
-
let that = this;
|
|
411
|
-
|
|
412
|
-
//Discover frequencey x 2
|
|
413
|
-
let timeoutThreshold = parseInt(that.discover_polling_schedule) * 2;
|
|
515
|
+
that.scheduler.addSimpleIntervalJob(job);
|
|
414
516
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
517
|
+
// //query device task
|
|
518
|
+
const queryDevices = new Task("simple task", () => {
|
|
519
|
+
if (!that.pollInProgress) that.queryDevices();
|
|
520
|
+
});
|
|
418
521
|
|
|
419
|
-
|
|
522
|
+
const queryJob = new SimpleIntervalJob({ seconds: parseInt(config.device_read_schedule) }, queryDevices);
|
|
420
523
|
|
|
421
|
-
|
|
422
|
-
let deviceKey = ipAddr + "-" + device.getDeviceId();
|
|
524
|
+
that.scheduler.addSimpleIntervalJob(queryJob);
|
|
423
525
|
|
|
424
|
-
|
|
526
|
+
//buildNetworkTreeData task
|
|
527
|
+
const buildNetworkTree = new Task("simple task", () => {
|
|
528
|
+
that.doTreeBuilder();
|
|
529
|
+
that.countDevices();
|
|
530
|
+
});
|
|
425
531
|
|
|
426
|
-
|
|
532
|
+
const buildNetworkTreeJob = new SimpleIntervalJob({ seconds: 10 }, buildNetworkTree);
|
|
427
533
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
534
|
+
that.scheduler.addSimpleIntervalJob(buildNetworkTreeJob);
|
|
535
|
+
} catch (e) {
|
|
536
|
+
that.logOut("Error reinitializing bacnet client: ", e);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
getValidPointProperties(point, requestedProps) {
|
|
541
|
+
let that = this;
|
|
542
|
+
let availableProps = point.propertyList;
|
|
543
|
+
let newProps = [];
|
|
544
|
+
|
|
545
|
+
try {
|
|
546
|
+
requestedProps.forEach(function (prop) {
|
|
547
|
+
let foundInAvailable = availableProps.find((ele) => ele === prop.id);
|
|
548
|
+
if (foundInAvailable) newProps.push(prop);
|
|
549
|
+
});
|
|
550
|
+
//add object name for use in formatting
|
|
551
|
+
newProps.push({ id: baEnum.PropertyIdentifier.OBJECT_NAME });
|
|
552
|
+
} catch (e) {
|
|
553
|
+
that.logOut("Issue finding valid object properties, see error: ", e);
|
|
432
554
|
}
|
|
433
555
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
556
|
+
return newProps;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
findDeviceByKey(key, deviceList, that) {
|
|
560
|
+
return deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` === key);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
getObjectId(pointName, pointConfig, that) {
|
|
564
|
+
// Retrieve the object type based on the point configuration
|
|
565
|
+
const bacObjType = that.getObjectType(pointConfig.meta.objectId.type);
|
|
566
|
+
// Construct the object ID string
|
|
567
|
+
return `${pointName}_${bacObjType}_${pointConfig.meta.objectId.instance}`;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
createDeviceKey(device) {
|
|
571
|
+
// Create a device key by combining the address and device ID
|
|
572
|
+
const address = device.getAddress();
|
|
573
|
+
const deviceId = device.getDeviceId();
|
|
574
|
+
if (typeof address === "object") {
|
|
575
|
+
return `${address.address}-${deviceId}`;
|
|
576
|
+
} else {
|
|
577
|
+
return `${address}-${deviceId}`;
|
|
442
578
|
}
|
|
579
|
+
}
|
|
443
580
|
|
|
444
|
-
reinitializeClient(config) {
|
|
445
|
-
let that = this;
|
|
446
|
-
|
|
447
|
-
that.config = config;
|
|
448
|
-
that.roundDecimal = config.roundDecimal;
|
|
449
|
-
that.apduSize = config.apduSize;
|
|
450
|
-
that.maxSegments = config.maxSegments;
|
|
451
|
-
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
452
|
-
that.deviceId = config.deviceId;
|
|
453
|
-
that.broadCastAddr = config.broadCastAddr;
|
|
454
|
-
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
455
|
-
that.manual_instance_range_start = config.manual_instance_range_start;
|
|
456
|
-
that.manual_instance_range_end = config.manual_instance_range_end;
|
|
457
|
-
that.device_read_schedule = config.device_read_schedule;
|
|
458
|
-
|
|
459
|
-
if(that.scheduler !== null) {
|
|
460
|
-
that.scheduler.stop();
|
|
461
|
-
}
|
|
462
581
|
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
582
|
+
async doRead(readConfig, outputType, objectPropertyType, readNodeName) {
|
|
583
|
+
const that = this;
|
|
584
|
+
const roundDecimal = readConfig.precision;
|
|
585
|
+
const devicesToRead = Object.keys(readConfig.pointsToRead);
|
|
586
|
+
const bacnetResults = {};
|
|
587
|
+
let pendingRequests = 0;
|
|
468
588
|
|
|
469
|
-
|
|
470
|
-
that.client._transport.port = config.port;
|
|
471
|
-
that.client._transport.broadcastAddress = config.broadCastAddr;
|
|
589
|
+
try {
|
|
472
590
|
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
591
|
+
// Process all devices in sequence
|
|
592
|
+
for (let deviceIndex = 0; deviceIndex < devicesToRead.length; deviceIndex++) {
|
|
593
|
+
const key = devicesToRead[deviceIndex];
|
|
594
|
+
const device = that.findDeviceByKey(key, that.deviceList, that);
|
|
595
|
+
if (!device) continue;
|
|
476
596
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
597
|
+
const deviceName = that.computeDeviceName(device);
|
|
598
|
+
const deviceKey = that.createDeviceKey(device);
|
|
599
|
+
const deviceObject = that.networkTree[deviceKey];
|
|
600
|
+
const maxObjectCount = that.estimateMaxObjectSize(device.getMaxApdu());
|
|
480
601
|
|
|
602
|
+
if (!bacnetResults[deviceName]) {
|
|
603
|
+
bacnetResults[deviceName] = {};
|
|
604
|
+
}
|
|
481
605
|
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
606
|
+
// Process points for the current device
|
|
607
|
+
const pointsToRead = readConfig.pointsToRead[key];
|
|
608
|
+
const pointNames = Object.keys(pointsToRead);
|
|
609
|
+
const totalPoints = pointNames.length;
|
|
610
|
+
let requestArray = [];
|
|
611
|
+
let processedPoints = 0; // Counter for processed points
|
|
612
|
+
|
|
613
|
+
// Process each point for the device in batches
|
|
614
|
+
for (let i = 0; i < pointNames.length; i++) {
|
|
615
|
+
const pointName = pointNames[i];
|
|
616
|
+
if (pointName === "deviceName") continue;
|
|
617
|
+
|
|
618
|
+
const pointConfig = pointsToRead[pointName];
|
|
619
|
+
const objectId = that.getObjectId(pointName, pointConfig, that);
|
|
620
|
+
const point = deviceObject[objectId];
|
|
621
|
+
|
|
622
|
+
if (point) {
|
|
623
|
+
point.displayName = pointConfig.displayName;
|
|
624
|
+
|
|
625
|
+
// Prepare request array for batch processing
|
|
626
|
+
requestArray.push({
|
|
627
|
+
objectId: { type: point.meta.objectId.type, instance: point.meta.objectId.instance },
|
|
628
|
+
properties: [{ id: baEnum.PropertyIdentifier.PRESENT_VALUE }],
|
|
629
|
+
pointRef: point,
|
|
630
|
+
pointName: pointName
|
|
486
631
|
});
|
|
632
|
+
}
|
|
487
633
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
634
|
+
// Process the batch when the request array is full or the last point is reached
|
|
635
|
+
if (requestArray.length === maxObjectCount || i === pointNames.length - 1) {
|
|
636
|
+
if (device.getProtocolServiceSupport("ReadPropertyMultiple") == true) {
|
|
637
|
+
await that.processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
|
|
638
|
+
} else {
|
|
639
|
+
await that.processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal);
|
|
640
|
+
}
|
|
491
641
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
});
|
|
642
|
+
requestArray = [];
|
|
643
|
+
// Increment the processed points counter
|
|
644
|
+
processedPoints += maxObjectCount;
|
|
645
|
+
}
|
|
497
646
|
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
647
|
+
// Check if all points for the device have been processed
|
|
648
|
+
if (processedPoints >= totalPoints) {
|
|
649
|
+
pendingRequests++;
|
|
650
|
+
// Emit the `values` event for the current device
|
|
651
|
+
that.emit("values", bacnetResults, outputType, objectPropertyType, readNodeName, pendingRequests, devicesToRead.length);
|
|
652
|
+
delete bacnetResults[deviceName];
|
|
501
653
|
|
|
502
|
-
|
|
503
|
-
that.logOut("Error reinitializing bacnet client: ", e)
|
|
654
|
+
}
|
|
504
655
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
656
|
+
}
|
|
657
|
+
} catch (error) {
|
|
658
|
+
that.logOut("doRead error: ", error);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
async processBatch(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
|
|
663
|
+
try {
|
|
664
|
+
const results = await that.updateManyPoints(device, requestArray);
|
|
665
|
+
if (results.error) {
|
|
666
|
+
throw results.error;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// Process the results of the batch
|
|
670
|
+
results.value.values.forEach(pointResult => {
|
|
671
|
+
const cacheRef = requestArray.find(ele =>
|
|
672
|
+
ele.pointRef.meta.objectId.type === pointResult.objectId.type &&
|
|
673
|
+
ele.pointRef.meta.objectId.instance === pointResult.objectId.instance
|
|
674
|
+
);
|
|
675
|
+
|
|
676
|
+
if (cacheRef) {
|
|
677
|
+
const pointRef = cacheRef.pointRef;
|
|
678
|
+
const pointNameRef = cacheRef.pointName;
|
|
679
|
+
const val = pointResult.values[0].value[0].value;
|
|
680
|
+
|
|
681
|
+
if (isNumber(val)) {
|
|
682
|
+
pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
|
|
683
|
+
if (pointRef.meta.objectId.type == 19 || pointRef.meta.objectId.type == 13 || pointRef.meta.objectId.type == 14) {
|
|
684
|
+
if (val != 0) {
|
|
685
|
+
pointRef.presentValue = pointRef.stateTextArray[val - 1].value;
|
|
686
|
+
} else {
|
|
687
|
+
pointRef.presentValue = pointRef.stateTextArray[val].value;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
} else {
|
|
691
|
+
if (typeof val !== "object") {
|
|
692
|
+
pointRef.presentValue = val;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
511
695
|
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
let foundInAvailable = availableProps.find(ele => ele === prop.id);
|
|
515
|
-
if(foundInAvailable) newProps.push(prop);
|
|
516
|
-
});
|
|
517
|
-
//add object name for use in formatting
|
|
518
|
-
newProps.push({id: baEnum.PropertyIdentifier.OBJECT_NAME});
|
|
519
|
-
} catch(e){
|
|
520
|
-
that.logOut("Issue finding valid object properties, see error: ", e);
|
|
696
|
+
// Store the point data in results
|
|
697
|
+
bacnetResults[deviceName][pointNameRef] = pointRef;
|
|
521
698
|
}
|
|
522
|
-
|
|
523
|
-
|
|
699
|
+
});
|
|
700
|
+
} catch (err) {
|
|
701
|
+
that.logOut("Error processing batch:", err);
|
|
524
702
|
}
|
|
703
|
+
}
|
|
525
704
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
devicesToRead.forEach(function(key, index) {
|
|
533
|
-
let device = that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
|
|
534
|
-
if(device) {
|
|
535
|
-
let deviceName = device.getDeviceName();
|
|
536
|
-
let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
|
|
537
|
-
let deviceObject = that.networkTree[deviceKey];
|
|
538
|
-
if(!bacnetResults[deviceName]) bacnetResults[deviceName] = {};
|
|
539
|
-
if(deviceObject) {
|
|
540
|
-
for(const pointName in readConfig.pointsToRead[key]) {
|
|
541
|
-
let bac_obj = that.getObjectType(readConfig.pointsToRead[key][pointName].meta.objectId.type);
|
|
542
|
-
let objectId = pointName + "_" + bac_obj + '_' + readConfig.pointsToRead[key][pointName].meta.objectId.instance;
|
|
543
|
-
let point = deviceObject[objectId];
|
|
544
|
-
|
|
545
|
-
that.updatePoint(device, point).then(function(result) {
|
|
546
|
-
if(isNumber(result.values[0].value)) {
|
|
547
|
-
point.presentValue = roundDecimalPlaces(result.values[0].value, that.roundDecimal);
|
|
548
|
-
} else {
|
|
549
|
-
point.presentValue = result.values[0].value;
|
|
550
|
-
}
|
|
551
|
-
bacnetResults[deviceName][pointName] = point;
|
|
552
|
-
}).catch(function(err) {
|
|
553
|
-
//do nothing for now
|
|
554
|
-
});
|
|
705
|
+
async processIndividualPoints(device, requestArray, deviceName, bacnetResults, that, roundDecimal) {
|
|
706
|
+
for (const request of requestArray) {
|
|
707
|
+
const { objectId, pointRef, pointName } = request;
|
|
708
|
+
try {
|
|
709
|
+
const result = await that.updatePoint(device, pointRef);
|
|
710
|
+
const val = result.values[0].value;
|
|
555
711
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
setTimeout(() => {
|
|
561
|
-
if(index == devicesToRead.length - 1 && Object.keys(readConfig.pointsToRead).length > 0) that.emit('values', bacnetResults, outputType, objectPropertyType, readNodeName);
|
|
562
|
-
}, 3000);
|
|
563
|
-
});
|
|
564
|
-
} catch(e) {
|
|
565
|
-
that.logOut("Issue doing read, see error: ", e);
|
|
712
|
+
if (isNumber(val)) {
|
|
713
|
+
pointRef.presentValue = roundDecimalPlaces(val, roundDecimal);
|
|
714
|
+
} else {
|
|
715
|
+
pointRef.presentValue = val;
|
|
566
716
|
}
|
|
567
|
-
}
|
|
568
717
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
device.getAddress(),
|
|
575
|
-
{type: point.objectID.type, instance: point.objectID.instance },
|
|
576
|
-
baEnum.PropertyIdentifier.PRESENT_VALUE,
|
|
577
|
-
{},
|
|
578
|
-
(err, value) => {
|
|
579
|
-
if(err) {
|
|
580
|
-
//console.log("err ", err);
|
|
581
|
-
reject(err);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if(value) {
|
|
585
|
-
resolve(value);
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
);
|
|
589
|
-
});
|
|
718
|
+
// Store the point data in results
|
|
719
|
+
bacnetResults[deviceName][pointName] = pointRef;
|
|
720
|
+
} catch (err) {
|
|
721
|
+
that.logOut(`Error updating point ${pointName}:`, err);
|
|
722
|
+
}
|
|
590
723
|
}
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
updateManyPoints(device, points) {
|
|
727
|
+
let that = this;
|
|
728
|
+
return new Promise((resolve, reject) => {
|
|
729
|
+
that._readObjectWithRequestArray(device.getAddress(), points, that.readPropertyMultipleOptions).then(function (results) {
|
|
730
|
+
resolve(results);
|
|
731
|
+
}).catch(function (err) {
|
|
732
|
+
reject(err);
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
updatePoint(device, point) {
|
|
738
|
+
let that = this;
|
|
739
|
+
return new Promise((resolve, reject) => {
|
|
740
|
+
that.client.readProperty(
|
|
741
|
+
device.getAddress(),
|
|
742
|
+
{ type: point.meta.objectId.type, instance: point.meta.objectId.instance },
|
|
743
|
+
baEnum.PropertyIdentifier.PRESENT_VALUE,
|
|
744
|
+
that.readPropertyMultipleOptions,
|
|
745
|
+
(err, value) => {
|
|
746
|
+
if (err) {
|
|
747
|
+
reject(err);
|
|
748
|
+
}
|
|
749
|
+
if (value) {
|
|
750
|
+
resolve(value);
|
|
751
|
+
}
|
|
600
752
|
}
|
|
753
|
+
);
|
|
754
|
+
});
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
estimateMaxObjectSize(apduSize) {
|
|
758
|
+
if (apduSize < 500) {
|
|
759
|
+
return 20;
|
|
760
|
+
} else if (apduSize > 500 && apduSize < 1000) {
|
|
761
|
+
//return Math.round(((apduSize - 30) / 7));
|
|
762
|
+
return 50;
|
|
763
|
+
} else if (apduSize > 1000) {
|
|
764
|
+
//return Math.round(((apduSize - 30) / 7));
|
|
765
|
+
return 100;
|
|
601
766
|
}
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
devicePointEntry: [{ value: { type: 8, instance: deviceId }, type: 12 }]
|
|
613
|
-
};
|
|
614
|
-
resolve(deviceObject);
|
|
615
|
-
} else {
|
|
616
|
-
that.logOut("Issue with deviceName payload, see object: ", object);
|
|
617
|
-
}
|
|
618
|
-
} catch(e){
|
|
619
|
-
that.logOut("Unable to get device name: ", e);
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
});
|
|
623
|
-
});
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
getDeviceAddress(device) {
|
|
770
|
+
switch (typeof device.getAddress()) {
|
|
771
|
+
case "object":
|
|
772
|
+
return device.getAddress().address;
|
|
773
|
+
case "string":
|
|
774
|
+
return device.getAddress();
|
|
775
|
+
default:
|
|
776
|
+
return device.getAddress();
|
|
624
777
|
}
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
case 3: //binary-input
|
|
642
|
-
newProps.push(prop);
|
|
643
|
-
break;
|
|
644
|
-
case 4: //binary-output
|
|
645
|
-
newProps.push(prop);
|
|
646
|
-
break;
|
|
647
|
-
case 5: //binary-value
|
|
648
|
-
newProps.push(prop);
|
|
649
|
-
break;
|
|
650
|
-
case 13:
|
|
651
|
-
if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
|
|
652
|
-
break;
|
|
653
|
-
case 14:
|
|
654
|
-
if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
|
|
655
|
-
break;
|
|
656
|
-
case 19:
|
|
657
|
-
if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
|
|
658
|
-
break;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
_getDeviceName(address, deviceId) {
|
|
781
|
+
let that = this;
|
|
782
|
+
return new Promise((resolve, reject) => {
|
|
783
|
+
that._readDeviceName(address, deviceId, (err, result) => {
|
|
784
|
+
if (result) {
|
|
785
|
+
try {
|
|
786
|
+
if (result.values[0].value) {
|
|
787
|
+
const deviceObject = {
|
|
788
|
+
name: result.values[0].value,
|
|
789
|
+
devicePointEntry: [{ value: { type: 8, instance: deviceId }, type: 12 }],
|
|
790
|
+
};
|
|
791
|
+
resolve(deviceObject);
|
|
792
|
+
} else {
|
|
793
|
+
that.logOut("Issue with deviceName payload, see object: ", object);
|
|
659
794
|
}
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
795
|
+
} catch (e) {
|
|
796
|
+
that.logOut("Unable to get device name: ", e);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
getPropertiesForType(props, type) {
|
|
804
|
+
let that = this;
|
|
805
|
+
let newProps = [];
|
|
806
|
+
props.forEach(function (prop) {
|
|
807
|
+
//that.logOut(prop);
|
|
808
|
+
switch (type) {
|
|
809
|
+
case 0: //analog-input
|
|
810
|
+
newProps.push(prop);
|
|
811
|
+
break;
|
|
812
|
+
case 1: //analog-output
|
|
813
|
+
newProps.push(prop);
|
|
814
|
+
break;
|
|
815
|
+
case 2: //analog-value
|
|
816
|
+
newProps.push(prop);
|
|
817
|
+
break;
|
|
818
|
+
case 3: //binary-input
|
|
819
|
+
newProps.push(prop);
|
|
820
|
+
break;
|
|
821
|
+
case 4: //binary-output
|
|
822
|
+
newProps.push(prop);
|
|
823
|
+
break;
|
|
824
|
+
case 5: //binary-value
|
|
825
|
+
newProps.push(prop);
|
|
826
|
+
break;
|
|
827
|
+
case 13:
|
|
828
|
+
if (prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME)
|
|
829
|
+
newProps.push(prop);
|
|
830
|
+
break;
|
|
831
|
+
case 14:
|
|
832
|
+
if (prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME)
|
|
833
|
+
newProps.push(prop);
|
|
834
|
+
break;
|
|
835
|
+
case 19:
|
|
836
|
+
if (prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME)
|
|
837
|
+
newProps.push(prop);
|
|
838
|
+
break;
|
|
839
|
+
}
|
|
840
|
+
});
|
|
841
|
+
return newProps;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
getDevicePointList(device) {
|
|
845
|
+
let that = this;
|
|
846
|
+
return new Promise(async function (resolve, reject) {
|
|
847
|
+
try {
|
|
848
|
+
device.setManualDiscoveryMode(false);
|
|
849
|
+
let result = await that.scanDevice(device);
|
|
850
|
+
device.setPointsList(result);
|
|
851
|
+
resolve(result);
|
|
852
|
+
} catch (e) {
|
|
853
|
+
that.logOut(`Error getting point list for ${device.getAddress().toString()} - ${device.getDeviceId()}: `, e);
|
|
854
|
+
reject(e);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
getDevicePointListWithoutObjectList(device) {
|
|
860
|
+
let that = this;
|
|
861
|
+
return new Promise(function (resolve, reject) {
|
|
862
|
+
try {
|
|
863
|
+
that
|
|
864
|
+
.scanDeviceManually(device)
|
|
865
|
+
.then(function (result) {
|
|
866
|
+
device.setPointsList(result);
|
|
867
|
+
resolve(result);
|
|
868
|
+
})
|
|
869
|
+
.catch(function (error) {
|
|
870
|
+
reject(error);
|
|
871
|
+
});
|
|
872
|
+
} catch (e) {
|
|
873
|
+
that.logOut("Error getting point list: ", e);
|
|
874
|
+
reject(e);
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
scanDeviceManually(device) {
|
|
880
|
+
let that = this;
|
|
881
|
+
|
|
882
|
+
return new Promise(function (resolve, reject) {
|
|
883
|
+
let address = device.getAddress();
|
|
884
|
+
let deviceId = device.getDeviceId();
|
|
885
|
+
let discoveredPointList = [];
|
|
886
|
+
|
|
887
|
+
let index = 1;
|
|
888
|
+
|
|
889
|
+
send(index);
|
|
890
|
+
|
|
891
|
+
function send(index) {
|
|
892
|
+
let readOptions = {
|
|
893
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
894
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
895
|
+
arrayIndex: index,
|
|
896
|
+
};
|
|
663
897
|
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
} catch(e) {
|
|
673
|
-
that.logOut(`Error getting point list for ${device.getAddress().toString()} - ${device.getDeviceId()}: `, e);
|
|
674
|
-
reject(e);
|
|
898
|
+
that.client.readProperty(
|
|
899
|
+
address,
|
|
900
|
+
{ type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
901
|
+
baEnum.PropertyIdentifier.OBJECT_LIST,
|
|
902
|
+
readOptions,
|
|
903
|
+
(err, value) => {
|
|
904
|
+
if (err) {
|
|
905
|
+
resolve(discoveredPointList);
|
|
675
906
|
}
|
|
676
|
-
});
|
|
677
|
-
}
|
|
678
907
|
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
that.scanDeviceManually(device).then(function(result) {
|
|
684
|
-
device.setPointsList(result);
|
|
685
|
-
resolve(result);
|
|
686
|
-
}).catch(function(error) {
|
|
687
|
-
reject(error);
|
|
688
|
-
});
|
|
689
|
-
|
|
690
|
-
} catch(e) {
|
|
691
|
-
that.logOut("Error getting point list: ", e);
|
|
692
|
-
reject(e);
|
|
908
|
+
if (value) {
|
|
909
|
+
discoveredPointList.push(value.values[0]);
|
|
910
|
+
index++;
|
|
911
|
+
send(index);
|
|
693
912
|
}
|
|
694
|
-
|
|
913
|
+
}
|
|
914
|
+
);
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
_readObjectWithRequestArray(deviceAddress, requestArray, readOptions) {
|
|
920
|
+
let that = this;
|
|
921
|
+
return new Promise((resolve, reject) => {
|
|
922
|
+
this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
|
|
923
|
+
resolve({
|
|
924
|
+
error: error,
|
|
925
|
+
value: value,
|
|
695
926
|
});
|
|
927
|
+
});
|
|
928
|
+
});
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
_readDeviceName(deviceAddress, deviceId, callback) {
|
|
932
|
+
let that = this;
|
|
933
|
+
that.client.readProperty(
|
|
934
|
+
deviceAddress,
|
|
935
|
+
{ type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
936
|
+
baEnum.PropertyIdentifier.OBJECT_NAME,
|
|
937
|
+
that.readPropertyMultipleOptions,
|
|
938
|
+
callback
|
|
939
|
+
);
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
_readObjectList(deviceAddress, deviceId, readOptions, callback) {
|
|
943
|
+
let that = this;
|
|
944
|
+
|
|
945
|
+
try {
|
|
946
|
+
that.client.readProperty(
|
|
947
|
+
deviceAddress,
|
|
948
|
+
{ type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
949
|
+
baEnum.PropertyIdentifier.OBJECT_LIST,
|
|
950
|
+
readOptions,
|
|
951
|
+
callback
|
|
952
|
+
);
|
|
953
|
+
} catch (e) {
|
|
954
|
+
that.logOut("Error reading object list: ", e);
|
|
696
955
|
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
_readObject(deviceAddress, type, instance, properties, readOptions) {
|
|
959
|
+
let that = this;
|
|
960
|
+
return new Promise((resolve, reject) => {
|
|
961
|
+
const requestArray = [
|
|
962
|
+
{
|
|
963
|
+
objectId: { type: type, instance: instance },
|
|
964
|
+
properties: properties,
|
|
965
|
+
},
|
|
966
|
+
];
|
|
967
|
+
this.client.readPropertyMultiple(deviceAddress, requestArray, readOptions, (error, value) => {
|
|
968
|
+
resolve({
|
|
969
|
+
error: error,
|
|
970
|
+
value: value,
|
|
971
|
+
});
|
|
972
|
+
});
|
|
973
|
+
});
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
_readObjectFull(device, deviceAddress, type, instance) {
|
|
977
|
+
const that = this;
|
|
978
|
+
const readOptions = {
|
|
979
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
980
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
981
|
+
};
|
|
697
982
|
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
if(value) {
|
|
731
|
-
discoveredPointList.push(value.values[0]);
|
|
732
|
-
index++;
|
|
733
|
-
send(index);
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
);
|
|
737
|
-
}
|
|
983
|
+
// Define all properties to be read
|
|
984
|
+
const allProperties = [
|
|
985
|
+
{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
|
|
986
|
+
{ id: baEnum.PropertyIdentifier.DESCRIPTION },
|
|
987
|
+
{ id: baEnum.PropertyIdentifier.UNITS },
|
|
988
|
+
{ id: baEnum.PropertyIdentifier.OBJECT_NAME },
|
|
989
|
+
{ id: baEnum.PropertyIdentifier.OBJECT_TYPE },
|
|
990
|
+
{ id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
|
|
991
|
+
{ id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
|
|
992
|
+
{ id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
|
|
993
|
+
{ id: baEnum.PropertyIdentifier.STATE_TEXT },
|
|
994
|
+
{ id: baEnum.PropertyIdentifier.RECORD_COUNT },
|
|
995
|
+
{ id: baEnum.PropertyIdentifier.PRIORITY_ARRAY },
|
|
996
|
+
{ id: baEnum.PropertyIdentifier.VENDOR_NAME },
|
|
997
|
+
];
|
|
998
|
+
|
|
999
|
+
return new Promise((resolve, reject) => {
|
|
1000
|
+
// Try to read all properties at once
|
|
1001
|
+
that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions)
|
|
1002
|
+
.then(result => {
|
|
1003
|
+
if (result.value) {
|
|
1004
|
+
// If the result has value, resolve the promise
|
|
1005
|
+
resolve(result);
|
|
1006
|
+
} else {
|
|
1007
|
+
// If not, proceed to read individual properties
|
|
1008
|
+
readPropertiesIndividually();
|
|
1009
|
+
}
|
|
1010
|
+
})
|
|
1011
|
+
.catch(() => {
|
|
1012
|
+
// On error, proceed to read individual properties
|
|
1013
|
+
readPropertiesIndividually();
|
|
738
1014
|
});
|
|
739
|
-
}
|
|
740
1015
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
1016
|
+
// Function to read properties individually
|
|
1017
|
+
const readPropertiesIndividually = () => {
|
|
1018
|
+
const promises = allProperties.map((property, index) => new Promise((propertyResolve) => {
|
|
1019
|
+
that.client.readProperty(
|
|
1020
|
+
deviceAddress,
|
|
1021
|
+
{ type: type, instance: instance },
|
|
1022
|
+
property.id,
|
|
1023
|
+
readOptions,
|
|
1024
|
+
(err, value) => {
|
|
1025
|
+
if (err) {
|
|
1026
|
+
propertyResolve(null);
|
|
1027
|
+
} else {
|
|
1028
|
+
propertyResolve({
|
|
1029
|
+
id: property.id,
|
|
1030
|
+
index: value.property.index,
|
|
1031
|
+
value: value.values,
|
|
748
1032
|
});
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
);
|
|
1036
|
+
}));
|
|
1037
|
+
|
|
1038
|
+
Promise.all(promises)
|
|
1039
|
+
.then(resultArray => {
|
|
1040
|
+
// Filter out null results
|
|
1041
|
+
const validResults = resultArray.filter(result => result !== null);
|
|
1042
|
+
|
|
1043
|
+
resolve({
|
|
1044
|
+
error: null,
|
|
1045
|
+
value: {
|
|
1046
|
+
values: [
|
|
1047
|
+
{
|
|
1048
|
+
objectId: {
|
|
1049
|
+
type: type,
|
|
1050
|
+
instance: instance,
|
|
1051
|
+
},
|
|
1052
|
+
values: validResults,
|
|
1053
|
+
},
|
|
1054
|
+
],
|
|
1055
|
+
},
|
|
749
1056
|
});
|
|
750
|
-
|
|
1057
|
+
})
|
|
1058
|
+
.catch(reject);
|
|
1059
|
+
};
|
|
1060
|
+
});
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
_readObjectPropList(deviceAddress, type, instance) {
|
|
1065
|
+
return this._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.PROPERTY_LIST }]);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
_readObjectId(deviceAddress, type, instance) {
|
|
1069
|
+
return this._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER }]);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
_readObjectPresentValue(deviceAddress, type, instance) {
|
|
1073
|
+
return this._readObject(deviceAddress, type, instance, [
|
|
1074
|
+
{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
|
|
1075
|
+
{ id: baEnum.PropertyIdentifier.OBJECT_NAME },
|
|
1076
|
+
]);
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
doWrite(value, options) {
|
|
1080
|
+
let that = this;
|
|
1081
|
+
let valuesArray = [];
|
|
1082
|
+
options.pointsToWrite.forEach(function (point) {
|
|
1083
|
+
let deviceAddress = point.deviceAddress;
|
|
1084
|
+
let writeObject = {
|
|
1085
|
+
address: deviceAddress,
|
|
1086
|
+
objectId: {
|
|
1087
|
+
type: point.meta.objectId.type,
|
|
1088
|
+
instance: point.meta.objectId.instance,
|
|
1089
|
+
},
|
|
1090
|
+
values: {
|
|
1091
|
+
property: {
|
|
1092
|
+
id: 85,
|
|
1093
|
+
index: point.meta.arrayIndex,
|
|
1094
|
+
},
|
|
1095
|
+
value: [
|
|
1096
|
+
{
|
|
1097
|
+
type: options.appTag,
|
|
1098
|
+
value: value,
|
|
1099
|
+
},
|
|
1100
|
+
],
|
|
1101
|
+
},
|
|
1102
|
+
options: {
|
|
1103
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
1104
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
1105
|
+
arrayIndex: point.meta.arrayIndex,
|
|
1106
|
+
priority: options.priority,
|
|
1107
|
+
},
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
valuesArray.push(writeObject);
|
|
1111
|
+
});
|
|
1112
|
+
|
|
1113
|
+
return that._writePropertyMultiple(valuesArray);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
_writePropertyMultiple(values) {
|
|
1117
|
+
let that = this;
|
|
1118
|
+
try {
|
|
1119
|
+
values.forEach(function (point) {
|
|
1120
|
+
that.client.writeProperty(
|
|
1121
|
+
point.address,
|
|
1122
|
+
point.objectId,
|
|
1123
|
+
baEnum.PropertyIdentifier.PRESENT_VALUE,
|
|
1124
|
+
point.values.value,
|
|
1125
|
+
point.options,
|
|
1126
|
+
(err, value) => {
|
|
1127
|
+
if (err) {
|
|
1128
|
+
that.logOut(err);
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
);
|
|
1132
|
+
});
|
|
1133
|
+
} catch (error) {
|
|
1134
|
+
that.logOut(error);
|
|
751
1135
|
}
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
_findValueById(properties, id) {
|
|
1139
|
+
const property = properties.find(function (element) {
|
|
1140
|
+
return element.id === id;
|
|
1141
|
+
});
|
|
1142
|
+
if (property && property.value && property.value.length > 0) {
|
|
1143
|
+
return property.value[0].value;
|
|
1144
|
+
} else {
|
|
1145
|
+
return null;
|
|
762
1146
|
}
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
that.logOut("
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
scanDevice(device) {
|
|
1150
|
+
let that = this;
|
|
1151
|
+
return new Promise((resolve, reject) => {
|
|
1152
|
+
const readOptions = {
|
|
1153
|
+
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
1154
|
+
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
1155
|
+
};
|
|
1156
|
+
this._readObjectList(device.getAddress(), device.getDeviceId(), readOptions, (err, result) => {
|
|
1157
|
+
if (!err) {
|
|
1158
|
+
try {
|
|
1159
|
+
resolve(result.values);
|
|
1160
|
+
} catch (e) {
|
|
1161
|
+
that.logOut("Issue with getting device point list, see error: ", e);
|
|
1162
|
+
}
|
|
1163
|
+
} else {
|
|
1164
|
+
that.logOut(`Error while fetching objects: ${err}`);
|
|
1165
|
+
reject(err);
|
|
778
1166
|
}
|
|
1167
|
+
});
|
|
1168
|
+
});
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
//closes bacnet client
|
|
1172
|
+
shutDownClient() {
|
|
1173
|
+
let that = this;
|
|
1174
|
+
if (that.client)
|
|
1175
|
+
that.client.close((err, result) => {
|
|
1176
|
+
that.logOut(err, result);
|
|
1177
|
+
});
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
globalWhoIs() {
|
|
1181
|
+
let that = this;
|
|
1182
|
+
if (that.client) {
|
|
1183
|
+
that.client.whoIs({ net: 65535 });
|
|
1184
|
+
} else {
|
|
1185
|
+
that.reinitializeClient(that.config);
|
|
779
1186
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
error: error,
|
|
791
|
-
value: value
|
|
792
|
-
});
|
|
793
|
-
});
|
|
1187
|
+
that.lastWhoIs = Date.now();
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
getNetworkTreeData() {
|
|
1191
|
+
let that = this;
|
|
1192
|
+
return new Promise(async function (resolve, reject) {
|
|
1193
|
+
try {
|
|
1194
|
+
const reducedDeviceList = JSON.parse(JSON.stringify(that.deviceList));
|
|
1195
|
+
reducedDeviceList.forEach((device) => {
|
|
1196
|
+
delete device["pointsList"];
|
|
794
1197
|
});
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
_readObjectFull(device, deviceAddress, type, instance) {
|
|
798
|
-
let that = this;
|
|
799
|
-
const readOptions = {
|
|
800
|
-
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
801
|
-
maxApdu: that.readPropertyMultipleOptions.maxApdu
|
|
802
|
-
};
|
|
803
|
-
|
|
804
|
-
const allProperties = [
|
|
805
|
-
{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
|
|
806
|
-
{ id: baEnum.PropertyIdentifier.DESCRIPTION },
|
|
807
|
-
{ id: baEnum.PropertyIdentifier.UNITS },
|
|
808
|
-
{ id: baEnum.PropertyIdentifier.OBJECT_NAME },
|
|
809
|
-
{ id: baEnum.PropertyIdentifier.OBJECT_TYPE },
|
|
810
|
-
{ id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
|
|
811
|
-
{ id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
|
|
812
|
-
{ id: baEnum.PropertyIdentifier.MODIFICATION_DATE },
|
|
813
|
-
{ id: baEnum.PropertyIdentifier.PROGRAM_STATE },
|
|
814
|
-
{ id: baEnum.PropertyIdentifier.RECORD_COUNT }
|
|
815
|
-
];
|
|
816
|
-
|
|
817
|
-
return new Promise((resolve, reject) => {
|
|
818
|
-
that._readObject(deviceAddress, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions).then(function(result) {
|
|
819
|
-
|
|
820
|
-
if(result.value) {
|
|
821
|
-
resolve(result);
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
if(result.error) {
|
|
825
|
-
let i = 0;
|
|
826
|
-
readIndividualProperties(i);
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
}).catch(function(error) {
|
|
830
|
-
let i = 0;
|
|
831
|
-
readIndividualProperties(i);
|
|
832
|
-
});
|
|
833
1198
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
// reject(errorArray);
|
|
874
|
-
// }
|
|
875
|
-
} else if( index < allProperties.length - 1) {
|
|
876
|
-
index++;
|
|
877
|
-
readIndividualProperties(index);
|
|
878
|
-
}
|
|
879
|
-
}
|
|
880
|
-
);
|
|
881
|
-
};
|
|
1199
|
+
resolve({
|
|
1200
|
+
renderList: that.renderList,
|
|
1201
|
+
deviceList: reducedDeviceList,
|
|
1202
|
+
pointList: that.networkTree,
|
|
1203
|
+
pollFrequency: that.discover_polling_schedule,
|
|
1204
|
+
renderListCount: that.renderListCount,
|
|
1205
|
+
});
|
|
1206
|
+
} catch (e) {
|
|
1207
|
+
reject(e);
|
|
1208
|
+
}
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
getDeviceList() {
|
|
1213
|
+
let that = this;
|
|
1214
|
+
return new Promise(async function (resolve, reject) {
|
|
1215
|
+
try {
|
|
1216
|
+
resolve({ deviceList: that.deviceList });
|
|
1217
|
+
} catch (e) {
|
|
1218
|
+
reject(e);
|
|
1219
|
+
}
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
updateDeviceList(json) {
|
|
1224
|
+
let that = this;
|
|
1225
|
+
return new Promise(async function (resolve, reject) {
|
|
1226
|
+
try {
|
|
1227
|
+
let deviceL = json.body.deviceList;
|
|
1228
|
+
deviceL.forEach(function (device) {
|
|
1229
|
+
let foundIndex = that.deviceList.findIndex((ele) => ele.getDeviceId() == device.deviceId);
|
|
1230
|
+
if (foundIndex == -1) {
|
|
1231
|
+
let newBacnetDevice = new BacnetDevice(true, device);
|
|
1232
|
+
newBacnetDevice.setLastSeen(Date.now());
|
|
1233
|
+
that.deviceList.push(newBacnetDevice);
|
|
1234
|
+
} else if (foundIndex !== -1) {
|
|
1235
|
+
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
1236
|
+
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
1237
|
+
}
|
|
882
1238
|
});
|
|
883
|
-
};
|
|
884
|
-
|
|
885
|
-
_readObjectPropList(deviceAddress, type, instance) {
|
|
886
|
-
|
|
887
|
-
return this._readObject(deviceAddress, type, instance, [
|
|
888
|
-
{ id: baEnum.PropertyIdentifier.PROPERTY_LIST }
|
|
889
|
-
]);
|
|
890
|
-
};
|
|
891
|
-
|
|
892
|
-
_readObjectId(deviceAddress, type, instance) {
|
|
893
1239
|
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1240
|
+
resolve(true);
|
|
1241
|
+
} catch (e) {
|
|
1242
|
+
reject(e);
|
|
1243
|
+
}
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
sortDevices(a, b) {
|
|
1248
|
+
if (a.deviceId < b.deviceId) {
|
|
1249
|
+
return -1;
|
|
1250
|
+
} else if (a.deviceId > b.deviceId) {
|
|
1251
|
+
return 1;
|
|
897
1252
|
}
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
1253
|
+
return 0; // deviceIds are equal
|
|
1254
|
+
}
|
|
1255
|
+
|
|
1256
|
+
sortPoints(a, b) {
|
|
1257
|
+
if (a.bacnetType > b.bacnetType) {
|
|
1258
|
+
return 1;
|
|
1259
|
+
} else if (a.bacnetType < b.bacnetType) {
|
|
1260
|
+
return -1;
|
|
1261
|
+
} else if (a.bacnetType == b.bacnetType) {
|
|
1262
|
+
return 0;
|
|
905
1263
|
}
|
|
906
1264
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
let valuesArray = [];
|
|
910
|
-
options.pointsToWrite.forEach(function(point){
|
|
911
|
-
let deviceAddress = point.deviceAddress;
|
|
912
|
-
let writeObject = {
|
|
913
|
-
address: deviceAddress,
|
|
914
|
-
objectId: {
|
|
915
|
-
type: point.meta.objectId.type,
|
|
916
|
-
instance: point.meta.objectId.instance
|
|
917
|
-
},
|
|
918
|
-
values: {
|
|
919
|
-
property: {
|
|
920
|
-
id: 85,
|
|
921
|
-
index: point.meta.arrayIndex
|
|
922
|
-
},
|
|
923
|
-
value: [{
|
|
924
|
-
type: options.appTag,
|
|
925
|
-
value: value
|
|
926
|
-
}],
|
|
927
|
-
|
|
928
|
-
},
|
|
929
|
-
options: {
|
|
930
|
-
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
931
|
-
maxApdu: that.readPropertyMultipleOptions.maxApdu,
|
|
932
|
-
arrayIndex: point.meta.arrayIndex,
|
|
933
|
-
priority: options.priority
|
|
934
|
-
}
|
|
935
|
-
};
|
|
936
|
-
|
|
937
|
-
valuesArray.push(writeObject);
|
|
938
|
-
});
|
|
1265
|
+
return a.label.localeCompare(b.label);
|
|
1266
|
+
}
|
|
939
1267
|
|
|
940
|
-
|
|
1268
|
+
computeDeviceName(device) {
|
|
1269
|
+
if (device.getDisplayName() !== null && device.getDisplayName() !== "" && device.getDisplayName() !== undefined) {
|
|
1270
|
+
return device.getDisplayName();
|
|
941
1271
|
}
|
|
1272
|
+
return device.getDeviceName();
|
|
1273
|
+
}
|
|
942
1274
|
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
values.forEach(function(point) {
|
|
947
|
-
|
|
948
|
-
that.client.writeProperty(
|
|
949
|
-
point.address,
|
|
950
|
-
point.objectId,
|
|
951
|
-
baEnum.PropertyIdentifier.PRESENT_VALUE,
|
|
952
|
-
point.values.value,
|
|
953
|
-
point.options,
|
|
954
|
-
(err, value) => {
|
|
955
|
-
if(err) {
|
|
956
|
-
that.logOut(err);
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
);
|
|
960
|
-
});
|
|
1275
|
+
checkInterruptFlag() {
|
|
1276
|
+
let that = this;
|
|
1277
|
+
let BreakException = {};
|
|
961
1278
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
}
|
|
1279
|
+
if (that.buildTreeException) {
|
|
1280
|
+
throw BreakException;
|
|
965
1281
|
}
|
|
1282
|
+
}
|
|
966
1283
|
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
});
|
|
971
|
-
if (property && property.value && property.value.length > 0) {
|
|
972
|
-
return property.value[0].value;
|
|
973
|
-
} else {
|
|
974
|
-
return null;
|
|
975
|
-
}
|
|
976
|
-
};
|
|
977
|
-
|
|
978
|
-
scanDevice(device) {
|
|
979
|
-
let that = this;
|
|
980
|
-
return new Promise((resolve, reject) => {
|
|
981
|
-
const readOptions = {
|
|
982
|
-
maxSegments: that.readPropertyMultipleOptions.maxSegments,
|
|
983
|
-
maxApdu: that.readPropertyMultipleOptions.maxApdu
|
|
984
|
-
};
|
|
985
|
-
this._readObjectList(device.getAddress(), device.getDeviceId(), readOptions, (err, result) => {
|
|
986
|
-
if (!err) {
|
|
987
|
-
try {
|
|
988
|
-
resolve(result.values);
|
|
989
|
-
} catch(e) {
|
|
990
|
-
that.logOut("Issue with getting device point list, see error: ", e);
|
|
991
|
-
}
|
|
992
|
-
} else {
|
|
993
|
-
that.logOut(`Error while fetching objects: ${err}`);
|
|
994
|
-
reject(err);
|
|
995
|
-
}
|
|
996
|
-
});
|
|
997
|
-
});
|
|
1284
|
+
getPointName(object, pointName) {
|
|
1285
|
+
if (object.displayName) {
|
|
1286
|
+
return object.displayName;
|
|
998
1287
|
}
|
|
1288
|
+
return pointName;
|
|
1289
|
+
}
|
|
999
1290
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
that.logOut(err, result);
|
|
1005
|
-
});
|
|
1006
|
-
};
|
|
1007
|
-
|
|
1008
|
-
globalWhoIs() {
|
|
1009
|
-
let that = this;
|
|
1010
|
-
if(that.client) {
|
|
1011
|
-
that.client.whoIs({'net': 65535});
|
|
1012
|
-
} else {
|
|
1013
|
-
that.reinitializeClient(that.config);
|
|
1014
|
-
}
|
|
1015
|
-
that.lastWhoIs = Date.now();
|
|
1291
|
+
addUniqueToArray(device, array) {
|
|
1292
|
+
const foundIndex = array.findIndex(ele => ele.getDeviceId() === device.getDeviceId());
|
|
1293
|
+
if (foundIndex === -1) {
|
|
1294
|
+
array.push(device);
|
|
1016
1295
|
}
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
async getDevicesNotRenderedYet() {
|
|
1299
|
+
let that = this;
|
|
1300
|
+
let missingDevices = [];
|
|
1301
|
+
for (let i = 0; i < that.deviceList.length; i++) {
|
|
1302
|
+
const device = that.deviceList[i];
|
|
1303
|
+
if (!device.getIsMstpDevice()) {
|
|
1304
|
+
//ip device
|
|
1305
|
+
const foundIndex = that.renderList.findIndex(ele => ele.deviceId == device.getDeviceId());
|
|
1306
|
+
if (foundIndex == -1) {
|
|
1307
|
+
that.addUniqueToArray(device, missingDevices);
|
|
1308
|
+
}
|
|
1309
|
+
} else {
|
|
1310
|
+
//mstp device
|
|
1311
|
+
const foundParentIndex = that.renderList.findIndex(ele => ele.deviceId == device.getParentDeviceId());
|
|
1312
|
+
if (foundParentIndex == -1) {
|
|
1313
|
+
//parent not existent in tree
|
|
1314
|
+
const parentDeviceIndex = that.deviceList.findIndex(ele => ele.getDeviceId() === device.getParentDeviceId());
|
|
1315
|
+
if (parentDeviceIndex !== -1) {
|
|
1316
|
+
that.addUniqueToArray(that.deviceList[parentDeviceIndex], missingDevices);
|
|
1317
|
+
}
|
|
1318
|
+
that.addUniqueToArray(device, missingDevices);
|
|
1319
|
+
} else {
|
|
1320
|
+
const parentTreeDevice = that.renderList[foundParentIndex];
|
|
1321
|
+
let mstpIndex = -1;
|
|
1322
|
+
parentTreeDevice.children.forEach(child => {
|
|
1323
|
+
if (child.label.includes("MSTP")) {
|
|
1324
|
+
const tempIndex = child.children.findIndex(ele => ele.deviceId == device.getDeviceId());
|
|
1325
|
+
if (tempIndex !== -1) {
|
|
1326
|
+
mstpIndex = tempIndex;
|
|
1327
|
+
}
|
|
1030
1328
|
}
|
|
1031
|
-
|
|
1329
|
+
});
|
|
1330
|
+
if (mstpIndex == -1) {
|
|
1331
|
+
that.addUniqueToArray(device, missingDevices);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1032
1335
|
}
|
|
1336
|
+
return missingDevices;
|
|
1337
|
+
}
|
|
1033
1338
|
|
|
1034
|
-
|
|
1035
|
-
let that = this;
|
|
1036
|
-
return new Promise(async function(resolve, reject) {
|
|
1037
|
-
try {
|
|
1038
|
-
resolve({"deviceList": that.deviceList});
|
|
1039
|
-
} catch(e){
|
|
1040
|
-
reject(e);
|
|
1041
|
-
}
|
|
1042
|
-
});
|
|
1043
|
-
}
|
|
1339
|
+
initialTreeBuild = true;
|
|
1044
1340
|
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
return new Promise(async function(resolve, reject) {
|
|
1048
|
-
try {
|
|
1049
|
-
let deviceL = json.body.deviceList;
|
|
1050
|
-
deviceL.forEach(function(device) {
|
|
1051
|
-
let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.deviceId);
|
|
1052
|
-
if(foundIndex == -1) {
|
|
1053
|
-
let newBacnetDevice = new BacnetDevice(true, device);
|
|
1054
|
-
newBacnetDevice.setLastSeen(Date.now());
|
|
1055
|
-
that.deviceList.push(newBacnetDevice);
|
|
1056
|
-
|
|
1057
|
-
} else if(foundIndex !== -1) {
|
|
1058
|
-
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
1059
|
-
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
1060
|
-
}
|
|
1061
|
-
});
|
|
1341
|
+
async doTreeBuilder() {
|
|
1342
|
+
let that = this;
|
|
1062
1343
|
|
|
1063
|
-
|
|
1064
|
-
} catch(e) {
|
|
1065
|
-
reject(e);
|
|
1066
|
-
}
|
|
1067
|
-
});
|
|
1068
|
-
}
|
|
1344
|
+
const treeWorker = new treeBuilder(that.deviceList, that.networkTree, that.renderList, that.renderListCount, that.initialTreeBuild);
|
|
1069
1345
|
|
|
1070
|
-
|
|
1071
|
-
let that = this;
|
|
1072
|
-
return new Promise(async function(resolve, reject) {
|
|
1073
|
-
try {
|
|
1074
|
-
let keys = Object.keys(priorityDevices);
|
|
1075
|
-
if(keys.length > 0) {
|
|
1076
|
-
keys.forEach(function(key) {
|
|
1077
|
-
let device = that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
|
|
1078
|
-
let points = priorityDevices[key];
|
|
1079
|
-
if(device) {
|
|
1080
|
-
device.setPriorityQueue(points);
|
|
1081
|
-
}
|
|
1082
|
-
});
|
|
1083
|
-
} else if(keys.length == 0) {
|
|
1084
|
-
that.clearPriorityQueues();
|
|
1085
|
-
}
|
|
1086
|
-
resolve(true);
|
|
1087
|
-
} catch(e){
|
|
1088
|
-
reject(e);
|
|
1089
|
-
}
|
|
1090
|
-
});
|
|
1091
|
-
}
|
|
1346
|
+
treeWorker.cacheData();
|
|
1092
1347
|
|
|
1093
|
-
|
|
1094
|
-
let that = this;
|
|
1095
|
-
that.deviceList.forEach(function(device) {
|
|
1096
|
-
device.clearPriorityQueue();
|
|
1097
|
-
});
|
|
1098
|
-
}
|
|
1348
|
+
//const missingDevices = await that.getDevicesNotRenderedYet();
|
|
1099
1349
|
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
return priorityDevices;
|
|
1350
|
+
for (let i = 0; i < that.deviceList.length; i++) {
|
|
1351
|
+
let device = that.deviceList[i];
|
|
1352
|
+
await treeWorker.processDevice(device, i);
|
|
1104
1353
|
}
|
|
1105
1354
|
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1355
|
+
that.deviceList = treeWorker.deviceList;
|
|
1356
|
+
that.networkTree = treeWorker.networkTree;
|
|
1357
|
+
that.renderList = treeWorker.renderList;
|
|
1358
|
+
|
|
1359
|
+
that.initialTreeBuild = false;
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
countDevices() {
|
|
1363
|
+
let that = this;
|
|
1364
|
+
let deviceCount = 0;
|
|
1365
|
+
|
|
1366
|
+
if (that.renderList && that.renderList.length > 0) {
|
|
1367
|
+
that.renderList.forEach(function (device, index) {
|
|
1368
|
+
if (device && device.children.length > 0) {
|
|
1369
|
+
device.children.forEach(function (folder) {
|
|
1370
|
+
if (folder.label == "Points") {
|
|
1371
|
+
//increment for parent device / mstp router
|
|
1372
|
+
deviceCount++;
|
|
1373
|
+
} else if (folder.label.includes("MSTP")) {
|
|
1374
|
+
//increment for mstp device list
|
|
1375
|
+
deviceCount += folder.children.length;
|
|
1376
|
+
}
|
|
1377
|
+
});
|
|
1111
1378
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
sortPoints(a, b) {
|
|
1116
|
-
if(a.bacnetType > b.bacnetType) {
|
|
1117
|
-
return 1;
|
|
1118
|
-
} else if(a.bacnetType < b.bacnetType) {
|
|
1119
|
-
return -1;
|
|
1120
|
-
} else if(a.bacnetType == b.bacnetType) {
|
|
1121
|
-
return 0;
|
|
1379
|
+
if (index == that.renderList.length - 1) {
|
|
1380
|
+
that.renderListCount = deviceCount;
|
|
1122
1381
|
}
|
|
1123
|
-
|
|
1124
|
-
return a.label.localeCompare(b.label)
|
|
1382
|
+
});
|
|
1125
1383
|
}
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
buildJsonObject(device) {
|
|
1387
|
+
let that = this;
|
|
1388
|
+
let address = device.address;
|
|
1389
|
+
let pointList = device.getPointsList();
|
|
1390
|
+
let requestMutex = new Mutex();
|
|
1391
|
+
|
|
1392
|
+
return new Promise(function (resolve, reject) {
|
|
1393
|
+
let promiseArray = [];
|
|
1394
|
+
if (typeof pointList !== "undefined" && pointList.length > 0) {
|
|
1395
|
+
pointList.forEach(function (point, pointListIndex) {
|
|
1396
|
+
requestMutex.acquire().then(function (release) {
|
|
1397
|
+
that
|
|
1398
|
+
._readObjectFull(device, address, point.value.type, point.value.instance)
|
|
1399
|
+
.then(function (result) {
|
|
1400
|
+
if (!result.error) {
|
|
1401
|
+
if (result.length > 0 && Array.isArray(result)) {
|
|
1402
|
+
promiseArray = result;
|
|
1403
|
+
} else {
|
|
1404
|
+
promiseArray.push(result);
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1126
1407
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
.acquire()
|
|
1140
|
-
.then(function(release) {
|
|
1141
|
-
|
|
1142
|
-
let ipAddr = typeof deviceInfo.getAddress() == "object" ? deviceInfo.getAddress().address : deviceInfo.getAddress();
|
|
1143
|
-
let deviceId = deviceInfo.getDeviceId();
|
|
1144
|
-
let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
|
|
1145
|
-
let deviceKey = ipAddr + "-" + deviceInfo.getDeviceId();
|
|
1146
|
-
let deviceObject = that.networkTree[deviceKey];
|
|
1147
|
-
let isMstpDevice = deviceInfo.getIsMstpDevice();
|
|
1148
|
-
let manualDiscoveryMode = deviceInfo.getManualDiscoveryMode();
|
|
1149
|
-
|
|
1150
|
-
if(deviceObject && typeof deviceName !== "object") {
|
|
1151
|
-
let children = [];
|
|
1152
|
-
let pointIndex = 0;
|
|
1153
|
-
|
|
1154
|
-
for(const pointName in deviceObject) {
|
|
1155
|
-
let pointProperties = [];
|
|
1156
|
-
let values = deviceObject[pointName];
|
|
1157
|
-
|
|
1158
|
-
let displayName = pointName;
|
|
1159
|
-
if(pointName.length > displayNameCharThreshold) {
|
|
1160
|
-
displayName = "";
|
|
1161
|
-
let charArray = pointName.split("");
|
|
1162
|
-
for(let i = 0; i < charArray.length; i++) {
|
|
1163
|
-
if(i < displayNameCharThreshold){
|
|
1164
|
-
displayName += charArray[i];
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
displayName += "...";
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
if(values.objectName){
|
|
1171
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-cog", "children": null});
|
|
1172
|
-
}
|
|
1173
|
-
if(values.objectType && values.objectID.type !== 8){
|
|
1174
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-cog", "children": null});
|
|
1175
|
-
}
|
|
1176
|
-
if(values.objectID && values.objectID.instance) {
|
|
1177
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-cog", "children": null});
|
|
1178
|
-
}
|
|
1179
|
-
if(values.description){
|
|
1180
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-cog", "children": null});
|
|
1181
|
-
}
|
|
1182
|
-
if(values.units){
|
|
1183
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-cog", "children": null});
|
|
1184
|
-
}
|
|
1185
|
-
if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
|
|
1186
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-cog", "children": null});
|
|
1187
|
-
}
|
|
1188
|
-
if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
|
|
1189
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-cog", "children": null});
|
|
1190
|
-
}
|
|
1191
|
-
if(values.modificationDate && !values.modificationDate.errorClass) {
|
|
1192
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-cog", "children": null});
|
|
1193
|
-
}
|
|
1194
|
-
if(values.programState){
|
|
1195
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-cog", "children": null});
|
|
1196
|
-
}
|
|
1197
|
-
if(values.recordCount && !values.recordCount.errorClass){
|
|
1198
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-cog", "children": null});
|
|
1199
|
-
}
|
|
1200
|
-
if(values.objectID && values.objectID.type == 8) {
|
|
1201
|
-
//device point, add segmentation supported, and apdu size
|
|
1202
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-10`, "label": `Segmentation Supported: ${deviceInfo.getSegmentation()}`, "data": `${deviceInfo.getSegmentation()}`, "icon": "pi pi-cog", "children": null});
|
|
1203
|
-
pointProperties.push({"key": `${index}-0-${pointIndex}-11`, "label": `APDU Size: ${deviceInfo.getMaxApdu()}`, "data": `${deviceInfo.getMaxApdu()}`, "icon": "pi pi-cog", "children": null});
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
children.push({"key": `${index}-0-${pointIndex}`, "label": displayName, "data": displayName, "pointName": pointName, "icon": that.getPointIcon(values.meta.objectId.type), "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
|
|
1207
|
-
pointIndex++;
|
|
1208
|
-
}
|
|
1209
|
-
let foundIndex = that.renderList.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
|
|
1210
|
-
if(foundIndex !== -1) {
|
|
1211
|
-
let folderJson = [];
|
|
1212
|
-
if(deviceInfo.hasChildDevices()) {
|
|
1213
|
-
folderJson = [
|
|
1214
|
-
{
|
|
1215
|
-
key: `${index}-0`,
|
|
1216
|
-
label: "Points",
|
|
1217
|
-
data: "Points Folder",
|
|
1218
|
-
icon: "pi pi-circle-fill",
|
|
1219
|
-
type: "pointFolder",
|
|
1220
|
-
children: children.sort(that.sortPoints)
|
|
1221
|
-
},
|
|
1222
|
-
{
|
|
1223
|
-
key: `${index}-1`,
|
|
1224
|
-
label: "MSTP Network",
|
|
1225
|
-
data: "Devices Folder",
|
|
1226
|
-
icon: "pi pi-database",
|
|
1227
|
-
type: "deviceFolder",
|
|
1228
|
-
children: []
|
|
1229
|
-
}
|
|
1230
|
-
];
|
|
1231
|
-
} else {
|
|
1232
|
-
folderJson = [
|
|
1233
|
-
{
|
|
1234
|
-
key: `${index}-0`,
|
|
1235
|
-
label: "Points",
|
|
1236
|
-
data: "Points Folder",
|
|
1237
|
-
icon: "pi pi-circle-fill",
|
|
1238
|
-
type: "pointFolder",
|
|
1239
|
-
children: children.sort(that.sortPoints)
|
|
1240
|
-
}
|
|
1241
|
-
];
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
if(!isMstpDevice) {
|
|
1245
|
-
that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": that.renderList[foundIndex].children, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
|
|
1246
|
-
} else if(isMstpDevice) {
|
|
1247
|
-
let parentDeviceId = deviceInfo.getParentDeviceId();
|
|
1248
|
-
let parentDeviceIndex = that.renderList.findIndex(ele => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr);
|
|
1249
|
-
|
|
1250
|
-
if(parentDeviceIndex !== -1 && that.renderList[parentDeviceIndex].children[1].children) {
|
|
1251
|
-
let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
|
|
1252
|
-
if(mstpDeviceIndex == -1) {
|
|
1253
|
-
//that.renderListCount++;
|
|
1254
|
-
that.renderList[parentDeviceIndex].children[1].children.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
|
|
1255
|
-
} else {
|
|
1256
|
-
that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
} else if(foundIndex == -1) {
|
|
1262
|
-
let folderJson = [];
|
|
1263
|
-
if(deviceInfo.hasChildDevices()) {
|
|
1264
|
-
folderJson = [
|
|
1265
|
-
{
|
|
1266
|
-
key: `${index}-0`,
|
|
1267
|
-
label: "Points",
|
|
1268
|
-
data: "Points Folder",
|
|
1269
|
-
icon: "pi pi-circle-fill",
|
|
1270
|
-
type: "pointFolder",
|
|
1271
|
-
children: children.sort(that.sortPoints)
|
|
1272
|
-
},
|
|
1273
|
-
{
|
|
1274
|
-
key: `${index}-1`,
|
|
1275
|
-
label: "MSTP Network",
|
|
1276
|
-
data: "Devices Folder",
|
|
1277
|
-
icon: "pi pi-database",
|
|
1278
|
-
type: "deviceFolder",
|
|
1279
|
-
children: []
|
|
1280
|
-
}
|
|
1281
|
-
];
|
|
1282
|
-
} else {
|
|
1283
|
-
folderJson = [
|
|
1284
|
-
{
|
|
1285
|
-
key: `${index}-0`,
|
|
1286
|
-
label: "Points",
|
|
1287
|
-
data: "Points Folder",
|
|
1288
|
-
icon: "pi pi-circle-fill",
|
|
1289
|
-
type: "pointFolder",
|
|
1290
|
-
children: children.sort(that.sortPoints)
|
|
1291
|
-
}
|
|
1292
|
-
];
|
|
1293
|
-
}
|
|
1294
|
-
|
|
1295
|
-
if(!isMstpDevice) {
|
|
1296
|
-
//that.renderListCount++;
|
|
1297
|
-
that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
|
|
1298
|
-
} else if(isMstpDevice) {
|
|
1299
|
-
let parentDeviceId = deviceInfo.getParentDeviceId();
|
|
1300
|
-
let parentDeviceIndex = that.renderList.findIndex(ele => ele.deviceId == parentDeviceId && ele.ipAddr == ipAddr);
|
|
1301
|
-
|
|
1302
|
-
if(parentDeviceIndex !== -1 && that.renderList[parentDeviceIndex].children && that.renderList[parentDeviceIndex].children[1].children) {
|
|
1303
|
-
let mstpDeviceIndex = that.renderList[parentDeviceIndex].children[1].children.findIndex(ele => ele.deviceId == deviceId && ele.ipAddr == ipAddr);
|
|
1304
|
-
|
|
1305
|
-
if(mstpDeviceIndex == -1) {
|
|
1306
|
-
// that.renderListCount++;
|
|
1307
|
-
that.renderList[parentDeviceIndex].children[1].children.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
|
|
1308
|
-
} else {
|
|
1309
|
-
that.renderList[parentDeviceIndex].children[1].children[mstpDeviceIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": folderJson, "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
|
|
1315
|
-
if(index == that.deviceList.length - 1) {
|
|
1316
|
-
that.renderList.sort(that.sortDevices);
|
|
1317
|
-
resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
|
|
1318
|
-
}
|
|
1319
|
-
} else {
|
|
1320
|
-
if(index == that.deviceList.length - 1) {
|
|
1321
|
-
that.renderList.sort(that.sortDevices);
|
|
1322
|
-
resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
release();
|
|
1408
|
+
release();
|
|
1409
|
+
|
|
1410
|
+
if (pointListIndex == pointList.length - 1) {
|
|
1411
|
+
that
|
|
1412
|
+
.buildResponse(promiseArray, device)
|
|
1413
|
+
.then(function () {
|
|
1414
|
+
that.lastNetworkPoll = Date.now();
|
|
1415
|
+
resolve({ deviceList: that.deviceList, pointList: that.networkTree });
|
|
1416
|
+
})
|
|
1417
|
+
.catch(function (e) {
|
|
1418
|
+
that.logOut("Error while building json object: ", e);
|
|
1419
|
+
reject(e);
|
|
1327
1420
|
});
|
|
1328
|
-
});
|
|
1329
|
-
}
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
countDevices() {
|
|
1334
|
-
let that = this;
|
|
1335
|
-
|
|
1336
|
-
let deviceCount = 0;
|
|
1337
|
-
|
|
1338
|
-
that.renderList.forEach(function(device, index) {
|
|
1339
|
-
if(device) {
|
|
1340
|
-
if(device.children[1] && device.children[1].label == 'MSTP Network' && device.children[1].children && device.children[1].children.length > 0) {
|
|
1341
|
-
//increment for parent device / mstp router
|
|
1342
|
-
deviceCount++;
|
|
1343
|
-
//increment for mstp device list
|
|
1344
|
-
deviceCount += device.children[1].children.length;
|
|
1345
|
-
} else {
|
|
1346
|
-
deviceCount++;
|
|
1347
1421
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1422
|
+
})
|
|
1423
|
+
.catch(function (e) {
|
|
1424
|
+
release();
|
|
1425
|
+
that.logOut("_readObjectFull error: ", e);
|
|
1426
|
+
|
|
1427
|
+
if (pointListIndex == pointList.length - 1) {
|
|
1428
|
+
that
|
|
1429
|
+
.buildResponse(promiseArray, device)
|
|
1430
|
+
.then(function () {
|
|
1431
|
+
that.lastNetworkPoll = Date.now();
|
|
1432
|
+
resolve({ deviceList: that.deviceList, pointList: that.networkTree });
|
|
1433
|
+
})
|
|
1434
|
+
.catch(function (e) {
|
|
1435
|
+
that.logOut("Error while building json object: ", e);
|
|
1436
|
+
reject(e);
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
});
|
|
1440
|
+
});
|
|
1352
1441
|
});
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
release();
|
|
1442
|
+
} else {
|
|
1443
|
+
reject("Unable to build network tree, empty point list");
|
|
1444
|
+
}
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// Builds response object for a fully qualified
|
|
1449
|
+
buildResponse(fullObjects, device) {
|
|
1450
|
+
let that = this;
|
|
1451
|
+
const reg = /[$#\/\\+]/gi;
|
|
1452
|
+
return new Promise(function (resolve, reject) {
|
|
1453
|
+
let deviceKey =
|
|
1454
|
+
typeof device.getAddress() == "object"
|
|
1455
|
+
? device.getAddress().address + "-" + device.getDeviceId()
|
|
1456
|
+
: device.getAddress() + "-" + device.getDeviceId();
|
|
1457
|
+
let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
|
|
1458
|
+
for (let i = 0; i < fullObjects.length; i++) {
|
|
1459
|
+
let obj = fullObjects[i];
|
|
1460
|
+
let successfulResult = !obj.error ? obj.value : null;
|
|
1461
|
+
if (successfulResult) {
|
|
1462
|
+
successfulResult.values.forEach(function (pointProperty, pointPropertyIndex) {
|
|
1463
|
+
if (!pointProperty.objectId && successfulResult.objectId && !pointProperty.values && successfulResult.values) {
|
|
1464
|
+
pointProperty = successfulResult;
|
|
1465
|
+
}
|
|
1379
1466
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1467
|
+
let currobjectId = pointProperty.objectId.type;
|
|
1468
|
+
let bac_obj = that.getObjectType(currobjectId);
|
|
1469
|
+
let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
|
|
1470
|
+
let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
|
|
1471
|
+
let objectId;
|
|
1472
|
+
if (objectName !== null && typeof objectName == "string") {
|
|
1473
|
+
objectName = objectName.replace(reg, '');
|
|
1474
|
+
objectId = objectName + "_" + bac_obj + "_" + pointProperty.objectId.instance;
|
|
1475
|
+
|
|
1476
|
+
try {
|
|
1477
|
+
pointProperty.values.forEach(function (object, objectIndex) {
|
|
1478
|
+
//checks for error code json structure, returned for invalid bacnet requests
|
|
1479
|
+
if (object && object.value && !object.value.errorClass) {
|
|
1480
|
+
if (!values[objectId]) values[objectId] = {};
|
|
1481
|
+
values[objectId].meta = {
|
|
1482
|
+
objectId: pointProperty.objectId,
|
|
1483
|
+
};
|
|
1484
|
+
|
|
1485
|
+
switch (object.id) {
|
|
1486
|
+
case baEnum.PropertyIdentifier.PRESENT_VALUE:
|
|
1487
|
+
if (object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
|
|
1488
|
+
//check for binary object type
|
|
1489
|
+
if (objectType == 3 || objectType == 4 || objectType == 5) {
|
|
1490
|
+
if (object.value[0].value == 0) {
|
|
1491
|
+
values[objectId].presentValue = false;
|
|
1492
|
+
} else if (object.value[0].value == 1) {
|
|
1493
|
+
values[objectId].presentValue = true;
|
|
1388
1494
|
}
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
if(
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
reject(e);
|
|
1401
|
-
});
|
|
1495
|
+
} else if (objectType == 40) {
|
|
1496
|
+
//character string
|
|
1497
|
+
values[objectId].presentValue = object.value[0].value;
|
|
1498
|
+
} else if (objectType == 13 || objectType == 14 || objectType == 19) {
|
|
1499
|
+
//check for MSV MSI MSO - for enum state text
|
|
1500
|
+
if (values[objectId].stateTextArray && values[objectId].stateTextArray.length > 0) {
|
|
1501
|
+
if (object.value[0].value == 0) {
|
|
1502
|
+
values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value].value;
|
|
1503
|
+
} else if (object.value[0].value !== 0) {
|
|
1504
|
+
values[objectId].presentValue = values[objectId].stateTextArray[object.value[0].value - 1].value;
|
|
1505
|
+
}
|
|
1402
1506
|
}
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1507
|
+
} else {
|
|
1508
|
+
values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
values[objectId].meta.arrayIndex = object.index;
|
|
1512
|
+
break;
|
|
1513
|
+
case baEnum.PropertyIdentifier.DESCRIPTION:
|
|
1514
|
+
if (object.value[0]) values[objectId].description = object.value[0].value;
|
|
1515
|
+
break;
|
|
1516
|
+
case baEnum.PropertyIdentifier.UNITS:
|
|
1517
|
+
if (object.value[0] && object.value[0].value)
|
|
1518
|
+
values[objectId].units = getUnit(object.value[0].value);
|
|
1519
|
+
break;
|
|
1520
|
+
case baEnum.PropertyIdentifier.OBJECT_NAME:
|
|
1521
|
+
if (object.value[0] && object.value[0].value) {
|
|
1522
|
+
values[objectId].objectName = object.value[0].value.replace(reg, '');
|
|
1523
|
+
if (!values[objectId].displayName) {
|
|
1524
|
+
values[objectId].displayName = object.value[0].value.replace(reg, '');
|
|
1525
|
+
}
|
|
1526
|
+
}
|
|
1527
|
+
break;
|
|
1528
|
+
case baEnum.PropertyIdentifier.OBJECT_TYPE:
|
|
1529
|
+
if (object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
|
|
1530
|
+
break;
|
|
1531
|
+
case baEnum.PropertyIdentifier.OBJECT_IDENTIFIER:
|
|
1532
|
+
if (object.value[0] && object.value[0].value) values[objectId].objectID = object.value[0].value;
|
|
1533
|
+
break;
|
|
1534
|
+
case baEnum.PropertyIdentifier.PROPERTY_LIST:
|
|
1535
|
+
if (object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
|
|
1536
|
+
break;
|
|
1537
|
+
case baEnum.PropertyIdentifier.SYSTEM_STATUS:
|
|
1538
|
+
if (object.value[0]) {
|
|
1539
|
+
values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
|
|
1540
|
+
}
|
|
1541
|
+
break;
|
|
1542
|
+
case baEnum.PropertyIdentifier.MODIFICATION_DATE:
|
|
1543
|
+
if (object.value[0]) {
|
|
1544
|
+
values[objectId].modificationDate = object.value[0].value;
|
|
1545
|
+
}
|
|
1546
|
+
break;
|
|
1547
|
+
|
|
1548
|
+
case baEnum.PropertyIdentifier.PROGRAM_STATE:
|
|
1549
|
+
if (object.value[0]) {
|
|
1550
|
+
values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
|
|
1551
|
+
}
|
|
1552
|
+
break;
|
|
1411
1553
|
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
let objectId;
|
|
1434
|
-
if(objectName !== null && typeof objectName == "string") {
|
|
1435
|
-
objectId = objectName + "_" + bac_obj + '_' + pointProperty.objectId.instance;
|
|
1436
|
-
|
|
1437
|
-
try {
|
|
1438
|
-
pointProperty.values.forEach(function(object, objectIndex) {
|
|
1439
|
-
//checks for error code json structure, returned for invalid bacnet requests
|
|
1440
|
-
if(object && object.value && !object.value.errorClass) {
|
|
1441
|
-
|
|
1442
|
-
if(!values[objectId]) values[objectId] = {};
|
|
1443
|
-
values[objectId].meta = {
|
|
1444
|
-
objectId: pointProperty.objectId
|
|
1445
|
-
};
|
|
1446
|
-
|
|
1447
|
-
switch(object.id) {
|
|
1448
|
-
case baEnum.PropertyIdentifier.PRESENT_VALUE:
|
|
1449
|
-
if(object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
|
|
1450
|
-
//check for binary object type
|
|
1451
|
-
if(objectType == 3 || objectType == 4 || objectType == 5) {
|
|
1452
|
-
if(object.value[0].value == 0) {
|
|
1453
|
-
values[objectId].presentValue = false;
|
|
1454
|
-
} else if(object.value[0].value == 1) {
|
|
1455
|
-
values[objectId].presentValue = true;
|
|
1456
|
-
}
|
|
1457
|
-
} else if(objectType == 40) {
|
|
1458
|
-
//character string
|
|
1459
|
-
values[objectId].presentValue = object.value[0].value;
|
|
1460
|
-
} else {
|
|
1461
|
-
values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
values[objectId].meta.arrayIndex = object.index;
|
|
1465
|
-
break;
|
|
1466
|
-
case baEnum.PropertyIdentifier.DESCRIPTION:
|
|
1467
|
-
if(object.value[0]) values[objectId].description = object.value[0].value;
|
|
1468
|
-
break;
|
|
1469
|
-
case baEnum.PropertyIdentifier.UNITS:
|
|
1470
|
-
if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
|
|
1471
|
-
break;
|
|
1472
|
-
case baEnum.PropertyIdentifier.OBJECT_NAME:
|
|
1473
|
-
if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
|
|
1474
|
-
break;
|
|
1475
|
-
case baEnum.PropertyIdentifier.OBJECT_TYPE:
|
|
1476
|
-
if(object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
|
|
1477
|
-
break;
|
|
1478
|
-
case baEnum.PropertyIdentifier.OBJECT_IDENTIFIER:
|
|
1479
|
-
if(object.value[0] && object.value[0].value) values[objectId].objectID = object.value[0].value;
|
|
1480
|
-
break;
|
|
1481
|
-
case baEnum.PropertyIdentifier.PROPERTY_LIST:
|
|
1482
|
-
if(object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
|
|
1483
|
-
break;
|
|
1484
|
-
|
|
1485
|
-
case baEnum.PropertyIdentifier.SYSTEM_STATUS:
|
|
1486
|
-
if(object.value[0]){
|
|
1487
|
-
values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
|
|
1488
|
-
}
|
|
1489
|
-
break;
|
|
1490
|
-
|
|
1491
|
-
case baEnum.PropertyIdentifier.MODIFICATION_DATE:
|
|
1492
|
-
if(object.value[0]) {
|
|
1493
|
-
values[objectId].modificationDate = object.value[0].value;
|
|
1494
|
-
}
|
|
1495
|
-
break;
|
|
1496
|
-
|
|
1497
|
-
case baEnum.PropertyIdentifier.PROGRAM_STATE:
|
|
1498
|
-
if(object.value[0]){
|
|
1499
|
-
values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
|
|
1500
|
-
}
|
|
1501
|
-
break;
|
|
1502
|
-
|
|
1503
|
-
case baEnum.PropertyIdentifier.RECORD_COUNT:
|
|
1504
|
-
if(object.value[0] ) {
|
|
1505
|
-
values[objectId].recordCount = object.value[0].value;
|
|
1506
|
-
}
|
|
1507
|
-
break;
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
if(pointPropertyIndex == successfulResult.values.length - 1 && objectIndex == pointProperty.values.length - 1 && i == fullObjects.length - 1) {
|
|
1511
|
-
that.networkTree[deviceKey] = values;
|
|
1512
|
-
resolve(that.networkTree);
|
|
1513
|
-
}
|
|
1514
|
-
});
|
|
1515
|
-
} catch(e) {
|
|
1516
|
-
that.logOut("issue resolving bacnet payload, see error: ", e);
|
|
1517
|
-
reject(e);
|
|
1554
|
+
case baEnum.PropertyIdentifier.RECORD_COUNT:
|
|
1555
|
+
if (object.value[0]) {
|
|
1556
|
+
values[objectId].recordCount = object.value[0].value;
|
|
1557
|
+
}
|
|
1558
|
+
break;
|
|
1559
|
+
case baEnum.PropertyIdentifier.PRIORITY_ARRAY:
|
|
1560
|
+
if (object.value.length > 0) {
|
|
1561
|
+
values[objectId].hasPriorityArray = true;
|
|
1562
|
+
}
|
|
1563
|
+
break;
|
|
1564
|
+
case baEnum.PropertyIdentifier.STATE_TEXT:
|
|
1565
|
+
if (object.value) {
|
|
1566
|
+
values[objectId].stateTextArray = object.value;
|
|
1567
|
+
if (typeof values[objectId].presentValue == "number" &&
|
|
1568
|
+
values[objectId].presentValue !== null &&
|
|
1569
|
+
values[objectId].presentValue !== undefined) {
|
|
1570
|
+
const tempIndex = values[objectId].presentValue;
|
|
1571
|
+
if (tempIndex == 0) {
|
|
1572
|
+
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex].value;
|
|
1573
|
+
} else if (tempIndex !== 0) {
|
|
1574
|
+
values[objectId].presentValue = values[objectId].stateTextArray[tempIndex - 1].value;
|
|
1518
1575
|
}
|
|
1576
|
+
}
|
|
1519
1577
|
}
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1578
|
+
break;
|
|
1579
|
+
case baEnum.PropertyIdentifier.VENDOR_NAME:
|
|
1580
|
+
if (object.value) {
|
|
1581
|
+
if (object.value[0].value && typeof object.value[0].value == "string") {
|
|
1582
|
+
values[objectId].vendorName = object.value[0].value;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
break;
|
|
1526
1586
|
}
|
|
1527
|
-
|
|
1587
|
+
}
|
|
1588
|
+
if (
|
|
1589
|
+
pointPropertyIndex == successfulResult.values.length - 1 &&
|
|
1590
|
+
objectIndex == pointProperty.values.length - 1 &&
|
|
1591
|
+
i == fullObjects.length - 1
|
|
1592
|
+
) {
|
|
1593
|
+
that.networkTree[deviceKey] = values;
|
|
1594
|
+
resolve(that.networkTree);
|
|
1595
|
+
}
|
|
1596
|
+
});
|
|
1597
|
+
} catch (e) {
|
|
1598
|
+
that.logOut("issue resolving bacnet payload, see error: ", e);
|
|
1599
|
+
reject(e);
|
|
1600
|
+
}
|
|
1528
1601
|
}
|
|
1602
|
+
});
|
|
1603
|
+
} else {
|
|
1604
|
+
//error found in point property
|
|
1605
|
+
if (i == fullObjects.length - 1) {
|
|
1529
1606
|
that.networkTree[deviceKey] = values;
|
|
1530
1607
|
resolve(that.networkTree);
|
|
1531
|
-
|
|
1532
|
-
}
|
|
1533
|
-
|
|
1534
|
-
mapPropsToArray(propertyList) {
|
|
1535
|
-
let uniquePropArray = [];
|
|
1536
|
-
for(let i = 0; i < propertyList.length; i++) {
|
|
1537
|
-
if(uniquePropArray.indexOf(propertyList[i].value) === -1) uniquePropArray.push(propertyList[i].value);
|
|
1608
|
+
}
|
|
1538
1609
|
}
|
|
1539
|
-
|
|
1610
|
+
}
|
|
1611
|
+
that.networkTree[deviceKey] = values;
|
|
1612
|
+
resolve(that.networkTree);
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
mapPropsToArray(propertyList) {
|
|
1617
|
+
let uniquePropArray = [];
|
|
1618
|
+
for (let i = 0; i < propertyList.length; i++) {
|
|
1619
|
+
if (uniquePropArray.indexOf(propertyList[i].value) === -1) uniquePropArray.push(propertyList[i].value);
|
|
1540
1620
|
}
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1621
|
+
return uniquePropArray;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
getPROP_PROGRAM_STATE(value) {
|
|
1625
|
+
switch (value) {
|
|
1626
|
+
case 0:
|
|
1627
|
+
return "0 - Idle";
|
|
1628
|
+
case 1:
|
|
1629
|
+
return "1 - Loading";
|
|
1630
|
+
case 2:
|
|
1631
|
+
return "2 - Running";
|
|
1632
|
+
case 3:
|
|
1633
|
+
return "3 - Waiting";
|
|
1634
|
+
case 4:
|
|
1635
|
+
return "4 - Halted";
|
|
1636
|
+
case 5:
|
|
1637
|
+
return "5 - Unloading";
|
|
1638
|
+
default:
|
|
1639
|
+
return "";
|
|
1559
1640
|
}
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
getPROP_SYSTEM_STATUS(value) {
|
|
1644
|
+
switch (value) {
|
|
1645
|
+
case 0:
|
|
1646
|
+
return "0 - Operational";
|
|
1647
|
+
case 1:
|
|
1648
|
+
return "1 - Operational Readonly";
|
|
1649
|
+
case 2:
|
|
1650
|
+
return "2 - Download Required";
|
|
1651
|
+
case 3:
|
|
1652
|
+
return "3 - Download In Progress";
|
|
1653
|
+
case 4:
|
|
1654
|
+
return "4 - Non Operational";
|
|
1655
|
+
case 5:
|
|
1656
|
+
return "5 - Backup In Progress";
|
|
1657
|
+
default:
|
|
1658
|
+
return "";
|
|
1578
1659
|
}
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
getPointIcon(values) {
|
|
1663
|
+
const objectId = values.meta.objectId.type;
|
|
1664
|
+
const hasPriorityArray =
|
|
1665
|
+
values.hasPriorityArray && values.hasOwnProperty("hasPriorityArray") ? values.hasPriorityArray : false;
|
|
1666
|
+
|
|
1667
|
+
if (hasPriorityArray) {
|
|
1668
|
+
return "pi writePointIcon";
|
|
1669
|
+
} else {
|
|
1670
|
+
switch (objectId) {
|
|
1671
|
+
case 0:
|
|
1672
|
+
//AI
|
|
1673
|
+
return "pi readPointIcon";
|
|
1674
|
+
case 1:
|
|
1675
|
+
//AO
|
|
1676
|
+
return "pi readPointIcon";
|
|
1677
|
+
case 2:
|
|
1678
|
+
//AV
|
|
1679
|
+
return "pi readPointIcon";
|
|
1680
|
+
case 3:
|
|
1681
|
+
//BI
|
|
1682
|
+
return "pi readPointIcon";
|
|
1683
|
+
case 4:
|
|
1684
|
+
//BO
|
|
1685
|
+
return "pi readPointIcon";
|
|
1686
|
+
case 5:
|
|
1687
|
+
//BV
|
|
1688
|
+
return "pi readPointIcon";
|
|
1689
|
+
case 8:
|
|
1690
|
+
//Device
|
|
1691
|
+
return "pi pi-box";
|
|
1692
|
+
case 13:
|
|
1693
|
+
//MI
|
|
1694
|
+
return "pi readPointIcon";
|
|
1695
|
+
case 14:
|
|
1696
|
+
//MO
|
|
1697
|
+
return "pi readPointIcon";
|
|
1698
|
+
case 19:
|
|
1699
|
+
//MV
|
|
1700
|
+
return "pi readPointIcon";
|
|
1701
|
+
case 10:
|
|
1702
|
+
//File
|
|
1703
|
+
return "pi pi-file";
|
|
1704
|
+
case 16:
|
|
1705
|
+
//Program
|
|
1706
|
+
return "pi pi-database";
|
|
1707
|
+
case 20:
|
|
1708
|
+
//Trendlog
|
|
1709
|
+
return "pi pi-chart-line";
|
|
1710
|
+
case 15:
|
|
1711
|
+
//Notification Class
|
|
1712
|
+
return "pi pi-bell";
|
|
1713
|
+
case 56:
|
|
1714
|
+
return "pi pi-sitemap";
|
|
1715
|
+
case 178:
|
|
1716
|
+
return "pi pi-lock";
|
|
1717
|
+
case 17:
|
|
1718
|
+
return "pi pi-calendar";
|
|
1719
|
+
case 6:
|
|
1720
|
+
return "pi pi-calendar";
|
|
1721
|
+
default:
|
|
1722
|
+
//Return circle for all other types
|
|
1723
|
+
return "pi readPointIcon";
|
|
1724
|
+
}
|
|
1636
1725
|
}
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
getObjectType(objectId) {
|
|
1729
|
+
switch (objectId) {
|
|
1730
|
+
case 0:
|
|
1731
|
+
return "AI";
|
|
1732
|
+
case 1:
|
|
1733
|
+
return "AO";
|
|
1734
|
+
case 2:
|
|
1735
|
+
return "AV";
|
|
1736
|
+
case 3:
|
|
1737
|
+
return "BI";
|
|
1738
|
+
case 4:
|
|
1739
|
+
return "BO";
|
|
1740
|
+
case 5:
|
|
1741
|
+
return "BV";
|
|
1742
|
+
case 8:
|
|
1743
|
+
return "Device";
|
|
1744
|
+
case 13:
|
|
1745
|
+
return "MI";
|
|
1746
|
+
case 14:
|
|
1747
|
+
return "MO";
|
|
1748
|
+
case 19:
|
|
1749
|
+
return "MV";
|
|
1750
|
+
case 40:
|
|
1751
|
+
return "CS";
|
|
1752
|
+
default:
|
|
1753
|
+
return "";
|
|
1665
1754
|
}
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
getPROP_RELIABILITY(value) {
|
|
1758
|
+
switch (value) {
|
|
1759
|
+
case 0:
|
|
1760
|
+
return "No Fault Detected";
|
|
1761
|
+
case 1:
|
|
1762
|
+
return "No Sensor";
|
|
1763
|
+
case 2:
|
|
1764
|
+
return "Over Range";
|
|
1765
|
+
case 3:
|
|
1766
|
+
return "Under Range";
|
|
1767
|
+
case 4:
|
|
1768
|
+
return "Open Loop";
|
|
1769
|
+
case 5:
|
|
1770
|
+
return "Shorted Loop";
|
|
1771
|
+
case 6:
|
|
1772
|
+
return "No Output";
|
|
1773
|
+
case 7:
|
|
1774
|
+
return "Unreliable Other";
|
|
1775
|
+
case 8:
|
|
1776
|
+
return "Process Error";
|
|
1777
|
+
case 9:
|
|
1778
|
+
return "Multi State Fault";
|
|
1779
|
+
case 10:
|
|
1780
|
+
return "Configuration Error";
|
|
1781
|
+
case 11:
|
|
1782
|
+
return "Member Fault";
|
|
1783
|
+
case 12:
|
|
1784
|
+
return "Communication Failure";
|
|
1785
|
+
case 13:
|
|
1786
|
+
return "Tripped";
|
|
1787
|
+
default:
|
|
1788
|
+
return "";
|
|
1700
1789
|
}
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
}
|
|
1715
|
-
}
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
getStatusFlags(flags) {
|
|
1793
|
+
return flags.value[0].value;
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
getDeviceIcon(isMstp, manualDiscoveryMode) {
|
|
1797
|
+
if (manualDiscoveryMode == true) {
|
|
1798
|
+
return "pi pi-question-circle";
|
|
1799
|
+
} else if (manualDiscoveryMode == false) {
|
|
1800
|
+
if (isMstp == true) {
|
|
1801
|
+
return "pi pi-box";
|
|
1802
|
+
} else if (isMstp == false) {
|
|
1716
1803
|
return "pi pi-server";
|
|
1717
|
-
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
return "pi pi-server";
|
|
1807
|
+
}
|
|
1718
1808
|
}
|
|
1719
1809
|
|
|
1720
1810
|
module.exports = { BacnetClient };
|