@bitpoolos/edge-bacnet 1.0.6 → 1.1.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/bacnet_client.js +650 -233
- package/bacnet_device.js +65 -16
- package/bacnet_gateway.html +242 -99
- package/bacnet_gateway.js +211 -27
- package/bacnet_object.js +1 -1
- package/bacnet_read.html +211 -133
- package/bacnet_read.js +24 -24
- package/bacnet_server.js +321 -0
- package/bacnet_write.html +24 -15
- package/bacnet_write.js +0 -2
- package/common.js +95 -9
- package/edge-bacnet-datastore.cfg +0 -0
- package/package.json +6 -4
- package/resources/confirmationservice.min.js +1 -0
- package/resources/confirmdialog.min.js +1 -0
- package/resources/fonts/primeicons.woff2 +0 -0
- package/resources/node-bacnet/CHANGELOG.md +481 -0
- package/resources/{bacstack → node-bacnet}/LICENSE.md +3 -1
- package/resources/node-bacnet/README.md +91 -0
- package/resources/node-bacnet/docs/Client.html +4422 -0
- package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
- package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
- package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
- package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
- package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
- package/resources/node-bacnet/docs/bacnet.html +7032 -0
- package/resources/node-bacnet/docs/client.js.html +1759 -0
- package/resources/node-bacnet/docs/enum.js.html +2530 -0
- package/resources/node-bacnet/docs/global.html +2068 -0
- package/resources/node-bacnet/docs/images/mocha-logo.svg +65 -0
- package/resources/node-bacnet/docs/index.html +283 -0
- package/resources/node-bacnet/docs/scripts/collapse.js +11 -0
- package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +4 -0
- package/resources/node-bacnet/docs/scripts/linenumber.js +26 -0
- package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
- package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +2 -0
- package/resources/node-bacnet/docs/scripts/prettify/prettify.js +28 -0
- package/resources/node-bacnet/docs/scripts/search.js +47 -0
- package/resources/node-bacnet/docs/services_i-am.js.html +157 -0
- package/resources/node-bacnet/docs/services_time-sync.js.html +118 -0
- package/resources/node-bacnet/docs/services_who-is.js.html +138 -0
- package/resources/node-bacnet/docs/styles/jsdoc.css +683 -0
- package/resources/node-bacnet/docs/styles/prettify.css +82 -0
- package/resources/node-bacnet/examples/discover-devices.js +66 -0
- package/resources/node-bacnet/examples/read-device.js +510 -0
- package/resources/node-bacnet/examples/subscribe-cov.js +75 -0
- package/resources/{bacstack → node-bacnet}/index.js +3 -0
- package/resources/{bacstack → node-bacnet}/lib/apdu.js +56 -39
- package/resources/{bacstack → node-bacnet}/lib/asn1.js +550 -532
- package/resources/node-bacnet/lib/bvlc.js +90 -0
- package/resources/node-bacnet/lib/client.js +1695 -0
- package/resources/node-bacnet/lib/enum.js +2463 -0
- package/resources/node-bacnet/lib/npdu.js +123 -0
- package/resources/{bacstack → node-bacnet}/lib/services/add-list-element.js +12 -6
- package/resources/{bacstack → node-bacnet}/lib/services/alarm-acknowledge.js +3 -3
- package/resources/{bacstack → node-bacnet}/lib/services/alarm-summary.js +5 -4
- package/resources/{bacstack → node-bacnet}/lib/services/atomic-read-file.js +49 -26
- package/resources/{bacstack → node-bacnet}/lib/services/atomic-write-file.js +40 -23
- package/resources/{bacstack → node-bacnet}/lib/services/cov-notify.js +33 -17
- package/resources/{bacstack → node-bacnet}/lib/services/create-object.js +23 -13
- package/resources/{bacstack → node-bacnet}/lib/services/delete-object.js +7 -2
- package/resources/{bacstack → node-bacnet}/lib/services/device-communication-control.js +8 -3
- package/resources/{bacstack → node-bacnet}/lib/services/error.js +7 -0
- package/resources/{bacstack → node-bacnet}/lib/services/event-information.js +10 -9
- package/resources/{bacstack → node-bacnet}/lib/services/event-notify-data.js +38 -16
- package/resources/{bacstack → node-bacnet}/lib/services/get-enrollment-summary.js +24 -11
- package/resources/{bacstack → node-bacnet}/lib/services/get-event-information.js +28 -13
- package/resources/node-bacnet/lib/services/i-am.js +90 -0
- package/resources/{bacstack/lib/services/i-have-broadcast.js → node-bacnet/lib/services/i-have.js} +3 -2
- package/resources/{bacstack → node-bacnet}/lib/services/index.js +7 -4
- package/resources/{bacstack → node-bacnet}/lib/services/life-safety-operation.js +3 -2
- package/resources/{bacstack → node-bacnet}/lib/services/private-transfer.js +3 -2
- package/resources/{bacstack → node-bacnet}/lib/services/read-property-multiple.js +11 -6
- package/resources/{bacstack → node-bacnet}/lib/services/read-property.js +42 -24
- package/resources/{bacstack → node-bacnet}/lib/services/read-range.js +37 -27
- package/resources/node-bacnet/lib/services/register-foreign-device.js +18 -0
- package/resources/{bacstack → node-bacnet}/lib/services/reinitialize-device.js +9 -4
- package/resources/{bacstack → node-bacnet}/lib/services/subscribe-cov.js +9 -4
- package/resources/{bacstack → node-bacnet}/lib/services/subscribe-property.js +18 -8
- package/resources/{bacstack → node-bacnet}/lib/services/time-sync.js +28 -5
- package/resources/{bacstack → node-bacnet}/lib/services/who-has.js +3 -3
- package/resources/{bacstack → node-bacnet}/lib/services/who-is.js +42 -9
- package/resources/{bacstack → node-bacnet}/lib/services/write-property-multiple.js +33 -16
- package/resources/{bacstack → node-bacnet}/lib/services/write-property.js +23 -13
- package/resources/node-bacnet/lib/transport.js +82 -0
- package/resources/node-bacnet/package.json +92 -0
- package/resources/primeicons.css +90 -2
- package/resources/bacstack/.codeclimate.yml +0 -15
- package/resources/bacstack/.dockerignore +0 -5
- package/resources/bacstack/.editorconfig +0 -13
- package/resources/bacstack/.eslintrc.yml +0 -13
- package/resources/bacstack/.github/ISSUE_TEMPLATE.md +0 -26
- package/resources/bacstack/.github/PULL_REQUEST_TEMPLATE.md +0 -14
- package/resources/bacstack/.github/workflows/ci.yml +0 -39
- package/resources/bacstack/.jscsrc +0 -8
- package/resources/bacstack/.jshintrc +0 -50
- package/resources/bacstack/.travis.yml +0 -27
- package/resources/bacstack/CHANGELOG.md +0 -232
- package/resources/bacstack/CODE_OF_CONDUCT.md +0 -74
- package/resources/bacstack/CONTRIBUTING.md +0 -77
- package/resources/bacstack/Dockerfile +0 -15
- package/resources/bacstack/FAQ.md +0 -64
- package/resources/bacstack/README.md +0 -157
- package/resources/bacstack/docker-compose.yml +0 -9
- package/resources/bacstack/lib/adpu.js +0 -190
- package/resources/bacstack/lib/bvlc.js +0 -43
- package/resources/bacstack/lib/client.js +0 -1028
- package/resources/bacstack/lib/enum.js +0 -1314
- package/resources/bacstack/lib/npdu.js +0 -119
- package/resources/bacstack/lib/services/i-am-broadcast.js +0 -51
- package/resources/bacstack/lib/services.js +0 -1963
- package/resources/bacstack/lib/transport.js +0 -52
- package/resources/bacstack/package-lock.json +0 -7974
- package/resources/bacstack/package.json +0 -84
- package/resources/bacstack/test/compliance/who-is.spec.js +0 -37
- package/resources/bacstack/test/integration/acknowledge-alarm.spec.js +0 -14
- package/resources/bacstack/test/integration/add-list-element.spec.js +0 -16
- package/resources/bacstack/test/integration/confirmed-event-notification.spec.js +0 -30
- package/resources/bacstack/test/integration/confirmed-private-transfer.spec.js +0 -15
- package/resources/bacstack/test/integration/create-object.spec.js +0 -16
- package/resources/bacstack/test/integration/delete-object.spec.js +0 -14
- package/resources/bacstack/test/integration/device-communication-control.spec.js +0 -14
- package/resources/bacstack/test/integration/get-alarm-summary.spec.js +0 -14
- package/resources/bacstack/test/integration/get-enrollment-summary.spec.js +0 -15
- package/resources/bacstack/test/integration/get-event-information.spec.js +0 -14
- package/resources/bacstack/test/integration/read-file.spec.js +0 -14
- package/resources/bacstack/test/integration/read-property-multiple.spec.js +0 -110
- package/resources/bacstack/test/integration/read-property.spec.js +0 -14
- package/resources/bacstack/test/integration/read-range.spec.js +0 -14
- package/resources/bacstack/test/integration/reinitialize-sevice.spec.js +0 -14
- package/resources/bacstack/test/integration/remove-list-element.spec.js +0 -16
- package/resources/bacstack/test/integration/subscribe-cov.spec.js +0 -14
- package/resources/bacstack/test/integration/subscribe-property.spec.js +0 -14
- package/resources/bacstack/test/integration/time-sync-utc.spec.js +0 -10
- package/resources/bacstack/test/integration/time-sync.spec.js +0 -10
- package/resources/bacstack/test/integration/unconfirmed-event-notification.spec.js +0 -28
- package/resources/bacstack/test/integration/unconfirmed-private-transfer.spec.js +0 -11
- package/resources/bacstack/test/integration/utils.js +0 -30
- package/resources/bacstack/test/integration/who-is.spec.js +0 -17
- package/resources/bacstack/test/integration/write-file.spec.js +0 -14
- package/resources/bacstack/test/integration/write-property-multiple.spec.js +0 -19
- package/resources/bacstack/test/integration/write-property.spec.js +0 -14
- package/resources/bacstack/test/unit/apdu.spec.js +0 -162
- package/resources/bacstack/test/unit/asn1.spec.js +0 -39
- package/resources/bacstack/test/unit/bacnet-apdu.spec.js +0 -161
- package/resources/bacstack/test/unit/bacnet-asn1.spec.js +0 -32
- package/resources/bacstack/test/unit/bacnet-bvlc.spec.js +0 -57
- package/resources/bacstack/test/unit/bacnet-npdu.spec.js +0 -118
- package/resources/bacstack/test/unit/bacnet-services.spec.js +0 -2052
- package/resources/bacstack/test/unit/bvlc.spec.js +0 -58
- package/resources/bacstack/test/unit/npdu.spec.js +0 -119
- package/resources/bacstack/test/unit/service-add-list-element.spec.js +0 -24
- package/resources/bacstack/test/unit/service-alarm-acknowledge.spec.js +0 -71
- package/resources/bacstack/test/unit/service-alarm-summary.spec.js +0 -22
- package/resources/bacstack/test/unit/service-atomic-read-file.spec.js +0 -54
- package/resources/bacstack/test/unit/service-atomic-write-file.spec.js +0 -56
- package/resources/bacstack/test/unit/service-cov-notify.spec.js +0 -98
- package/resources/bacstack/test/unit/service-create-object.spec.js +0 -90
- package/resources/bacstack/test/unit/service-delete-object.spec.js +0 -17
- package/resources/bacstack/test/unit/service-device-communication-control.spec.js +0 -29
- package/resources/bacstack/test/unit/service-error.spec.js +0 -17
- package/resources/bacstack/test/unit/service-event-information.spec.js +0 -48
- package/resources/bacstack/test/unit/service-event-notify-data.spec.js +0 -310
- package/resources/bacstack/test/unit/service-get-enrollment-summary.spec.js +0 -45
- package/resources/bacstack/test/unit/service-get-event-information.spec.js +0 -62
- package/resources/bacstack/test/unit/service-i-am.spec.js +0 -19
- package/resources/bacstack/test/unit/service-i-have-broadcast.spec.js +0 -18
- package/resources/bacstack/test/unit/service-life-safety-operation.spec.js +0 -19
- package/resources/bacstack/test/unit/service-private-transfer.spec.js +0 -18
- package/resources/bacstack/test/unit/service-read-property-multiple.spec.js +0 -131
- package/resources/bacstack/test/unit/service-read-property.spec.js +0 -541
- package/resources/bacstack/test/unit/service-read-range.spec.js +0 -97
- package/resources/bacstack/test/unit/service-reinitialize-device.spec.js +0 -27
- package/resources/bacstack/test/unit/service-subscribe-cov.spec.js +0 -32
- package/resources/bacstack/test/unit/service-subscribe-property.spec.js +0 -50
- package/resources/bacstack/test/unit/service-time-sync.spec.js +0 -18
- package/resources/bacstack/test/unit/service-who-has.spec.js +0 -33
- package/resources/bacstack/test/unit/service-who-is.spec.js +0 -17
- package/resources/bacstack/test/unit/service-write-property-multiple.spec.js +0 -143
- package/resources/bacstack/test/unit/service-write-property.spec.js +0 -198
- package/resources/bacstack/test/unit/utils.js +0 -6
package/bacnet_client.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
/*
|
|
2
2
|
MIT License Copyright 2021, 2022 - Bitpool Pty Ltd
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
const baEnum =
|
|
7
|
-
const
|
|
8
|
-
const { EventEmitter } = require('events');
|
|
9
|
-
const { DeviceObjectId, DeviceObject, logger, getUnit, roundDecimalPlaces } = require('./common');
|
|
10
|
-
const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler')
|
|
4
|
+
const bacnet = require('./resources/node-bacnet/index.js');
|
|
5
|
+
const { BacnetServer } = require("./bacnet_server.js");
|
|
6
|
+
const baEnum = bacnet.enum;
|
|
7
|
+
const bacnetIdMax = baEnum.ASN1_MAX_PROPERTY_ID;
|
|
8
|
+
const { EventEmitter, captureRejectionSymbol } = require('events');
|
|
9
|
+
const { DeviceObjectId, DeviceObject, logger, getUnit, roundDecimalPlaces, Store_Config, Read_Config_Sync } = require('./common');
|
|
10
|
+
const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler');
|
|
11
11
|
const { BacnetDevice } = require('./bacnet_device');
|
|
12
12
|
const {Mutex, Semaphore, withTimeout} = require("async-mutex");
|
|
13
|
+
|
|
13
14
|
class BacnetClient extends EventEmitter {
|
|
14
15
|
|
|
15
16
|
//client constructor
|
|
16
17
|
constructor(config) {
|
|
17
18
|
super();
|
|
18
19
|
let that = this;
|
|
20
|
+
|
|
21
|
+
let cachedData = JSON.parse(Read_Config_Sync());
|
|
22
|
+
|
|
19
23
|
that.deviceList = [];
|
|
20
|
-
that.pointReferenceList = [];
|
|
21
24
|
that.networkTree = {};
|
|
22
25
|
that.lastWhoIs = null;
|
|
23
26
|
that.client = null;
|
|
@@ -25,6 +28,17 @@ class BacnetClient extends EventEmitter {
|
|
|
25
28
|
that.scheduler = new ToadScheduler();
|
|
26
29
|
that.mutex = new Mutex();
|
|
27
30
|
|
|
31
|
+
if(typeof cachedData == "object") {
|
|
32
|
+
if(cachedData.renderList) that.renderList = cachedData.renderList;
|
|
33
|
+
if(cachedData.deviceList) {
|
|
34
|
+
cachedData.deviceList.forEach(function(device) {
|
|
35
|
+
let newBacnetDevice = new BacnetDevice(true, device);
|
|
36
|
+
that.deviceList.push(newBacnetDevice);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
if(cachedData.pointList) that.networkTree = cachedData.pointList;
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
try {
|
|
29
43
|
that.config = config;
|
|
30
44
|
that.roundDecimal = config.roundDecimal;
|
|
@@ -34,10 +48,16 @@ class BacnetClient extends EventEmitter {
|
|
|
34
48
|
that.device_id_range_enabled = config.device_id_range_enabled;
|
|
35
49
|
that.device_id_range_start = config.device_id_range_start;
|
|
36
50
|
that.device_id_range_end = config.device_id_range_end;
|
|
51
|
+
that.deviceId = config.deviceId;
|
|
52
|
+
that.broadCastAddr = config.broadCastAddr;
|
|
53
|
+
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
54
|
+
that.manual_instance_range_start = config.manual_instance_range_start;
|
|
55
|
+
that.manual_instance_range_end = config.manual_instance_range_end;
|
|
56
|
+
that.bacnetServerEnabled = config.bacnetServerEnabled;
|
|
37
57
|
|
|
38
58
|
that.readPropertyMultipleOptions = {
|
|
39
59
|
maxSegments: that.maxSegments,
|
|
40
|
-
|
|
60
|
+
maxApdu: that.apduSize
|
|
41
61
|
};
|
|
42
62
|
|
|
43
63
|
try {
|
|
@@ -51,11 +71,12 @@ class BacnetClient extends EventEmitter {
|
|
|
51
71
|
|
|
52
72
|
const job = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, task)
|
|
53
73
|
|
|
54
|
-
that.scheduler.addSimpleIntervalJob(job)
|
|
74
|
+
that.scheduler.addSimpleIntervalJob(job);
|
|
55
75
|
|
|
56
76
|
//query device task
|
|
57
|
-
const queryDevices = new Task('simple task', () => {
|
|
77
|
+
const queryDevices = new Task('simple task', () => {
|
|
58
78
|
that.queryDevices();
|
|
79
|
+
that.sanitizeDeviceList();
|
|
59
80
|
});
|
|
60
81
|
|
|
61
82
|
const queryJob = new SimpleIntervalJob({ seconds: parseInt(that.discover_polling_schedule), }, queryDevices)
|
|
@@ -63,7 +84,7 @@ class BacnetClient extends EventEmitter {
|
|
|
63
84
|
that.scheduler.addSimpleIntervalJob(queryJob);
|
|
64
85
|
|
|
65
86
|
//buildNetworkTreeData task
|
|
66
|
-
const buildNetworkTree = new Task('simple task', () => {
|
|
87
|
+
const buildNetworkTree = new Task('simple task', () => {
|
|
67
88
|
that.buildNetworkTreeData();
|
|
68
89
|
});
|
|
69
90
|
|
|
@@ -77,45 +98,88 @@ class BacnetClient extends EventEmitter {
|
|
|
77
98
|
that.queryDevices();
|
|
78
99
|
}, "5000")
|
|
79
100
|
|
|
80
|
-
} catch(e){
|
|
81
|
-
|
|
101
|
+
} catch(e) {
|
|
102
|
+
that.logOut("Issue initializing client: ", e)
|
|
82
103
|
}
|
|
83
104
|
|
|
84
105
|
//who is callback
|
|
85
106
|
that.client.on('iAm', (device) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
107
|
+
if(device.header.sender.address !== that.config.localIpAdrress) {
|
|
108
|
+
if(that.device_id_range_enabled) {
|
|
109
|
+
if(device.payload.deviceId >= that.device_id_range_start && device.payload.deviceId <= that.device_id_range_end) {
|
|
110
|
+
//only add unique device to array
|
|
111
|
+
let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
|
|
112
|
+
if(foundIndex == -1) {
|
|
113
|
+
let newBacnetDevice = new BacnetDevice(false, device);
|
|
114
|
+
newBacnetDevice.setLastSeen(Date.now());
|
|
115
|
+
that.updateDeviceName(newBacnetDevice);
|
|
116
|
+
that.deviceList.push(newBacnetDevice);
|
|
117
|
+
|
|
118
|
+
} else if(foundIndex !== -1) {
|
|
119
|
+
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
120
|
+
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
121
|
+
that.updateDeviceName(that.deviceList[foundIndex]);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//emit event for node-red to log
|
|
125
|
+
that.emit('deviceFound', device);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
//only add unique device to array
|
|
129
|
+
let foundIndex = that.deviceList.findIndex(ele => ele.getDeviceId() == device.payload.deviceId);
|
|
130
|
+
if(foundIndex == -1) {
|
|
131
|
+
let newBacnetDevice = new BacnetDevice(false, device);
|
|
132
|
+
newBacnetDevice.setLastSeen(Date.now());
|
|
133
|
+
that.updateDeviceName(newBacnetDevice);
|
|
134
|
+
that.deviceList.push(newBacnetDevice);
|
|
135
|
+
|
|
136
|
+
} else if(foundIndex !== -1) {
|
|
137
|
+
that.deviceList[foundIndex].updateDeviceConfig(device);
|
|
138
|
+
that.deviceList[foundIndex].setLastSeen(Date.now());
|
|
139
|
+
that.updateDeviceName(that.deviceList[foundIndex]);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
//emit event for node-red to log
|
|
143
|
+
that.emit('deviceFound', device);
|
|
144
|
+
}
|
|
98
145
|
}
|
|
99
|
-
|
|
100
|
-
//emit event for node-red to log
|
|
101
|
-
that.emit('deviceFound', device);
|
|
102
146
|
});
|
|
103
|
-
|
|
104
|
-
|
|
147
|
+
|
|
148
|
+
} catch(e) {
|
|
149
|
+
that.logOut("Issue with creating bacnet client, see error: ", e);
|
|
105
150
|
}
|
|
106
151
|
|
|
107
152
|
that.client.on('error', (err) => {
|
|
108
|
-
|
|
153
|
+
that.logOut('Error occurred: ', err);
|
|
109
154
|
|
|
110
155
|
if(err.errno == -4090){
|
|
111
|
-
|
|
156
|
+
that.logOut("Invalid Client information or incorrect IP address provided");
|
|
112
157
|
} else if(err.errno == -49) {
|
|
113
|
-
|
|
158
|
+
that.logOut("Invalid IP address provided");
|
|
114
159
|
} else {
|
|
115
160
|
that.reinitializeClient(that.config);
|
|
116
161
|
}
|
|
117
162
|
});
|
|
163
|
+
}
|
|
118
164
|
|
|
165
|
+
logOut(param1, param2) {
|
|
166
|
+
let that = this;
|
|
167
|
+
that.emit('bacnetErrorLog', param1, param2);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
rebuildDataModel() {
|
|
171
|
+
let that = this;
|
|
172
|
+
return new Promise((resolve, reject) => {
|
|
173
|
+
try {
|
|
174
|
+
that.deviceList = [];
|
|
175
|
+
that.renderList = [];
|
|
176
|
+
that.networkTree = {};
|
|
177
|
+
resolve(true);
|
|
178
|
+
} catch(e) {
|
|
179
|
+
that.logOut("Error clearing BACnet data model: ", e);
|
|
180
|
+
reject(e);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
119
183
|
}
|
|
120
184
|
|
|
121
185
|
queryDevices() {
|
|
@@ -125,26 +189,60 @@ class BacnetClient extends EventEmitter {
|
|
|
125
189
|
.acquire()
|
|
126
190
|
.then(function(release) {
|
|
127
191
|
try {
|
|
192
|
+
|
|
128
193
|
that.getDevicePointList(device).then(function() {
|
|
129
194
|
that.buildJsonObject(device).then(function() {
|
|
130
195
|
release();
|
|
131
196
|
}).catch(function(e) {
|
|
132
197
|
release();
|
|
133
198
|
});
|
|
134
|
-
}).catch(function(e){
|
|
199
|
+
}).catch(function(e) {
|
|
200
|
+
that.getDevicePointListWithoutObjectList(device).then(function() {
|
|
201
|
+
that.buildJsonObject(device).then(function() {
|
|
202
|
+
release();
|
|
203
|
+
}).catch(function(e) {
|
|
204
|
+
release();
|
|
205
|
+
});
|
|
206
|
+
}).catch(function(e) {
|
|
207
|
+
release();
|
|
208
|
+
});
|
|
135
209
|
release();
|
|
136
210
|
});
|
|
211
|
+
|
|
137
212
|
} catch(e) {
|
|
138
|
-
|
|
213
|
+
that.logOut("Error while querying devices: ", e);
|
|
139
214
|
release();
|
|
140
215
|
}
|
|
141
216
|
});
|
|
142
217
|
});
|
|
218
|
+
Store_Config(JSON.stringify({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree}));
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
sanitizeDeviceList() {
|
|
222
|
+
let that = this;
|
|
223
|
+
|
|
224
|
+
that.deviceList.forEach(function(device, index) {
|
|
225
|
+
if(((Date.now() - device.getLastSeen()) / 1000) > 3600) {
|
|
226
|
+
//device hasnt responded to whoIs for over an hour
|
|
227
|
+
|
|
228
|
+
let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
|
|
229
|
+
delete that.networkTree[deviceKey];
|
|
230
|
+
|
|
231
|
+
if(that.renderList){
|
|
232
|
+
let foundIndex = that.renderList.findIndex(ele => ele.ipAddr == device.getAddress() && ele.deviceId == device.getDeviceId());
|
|
233
|
+
if(foundIndex !== -1) {
|
|
234
|
+
that.renderList.splice(foundIndex, 1);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
that.deviceList.splice(index, 1);
|
|
239
|
+
}
|
|
240
|
+
});
|
|
143
241
|
}
|
|
144
242
|
|
|
145
243
|
updateDeviceName(device) {
|
|
146
244
|
let that = this;
|
|
147
|
-
that._getDeviceName(device.
|
|
245
|
+
that._getDeviceName(device.getAddress(), device.getDeviceId()).then(function(deviceName) {
|
|
148
246
|
device.setDeviceName(deviceName);
|
|
149
247
|
});
|
|
150
248
|
}
|
|
@@ -152,21 +250,34 @@ class BacnetClient extends EventEmitter {
|
|
|
152
250
|
reinitializeClient(config) {
|
|
153
251
|
let that = this;
|
|
154
252
|
|
|
253
|
+
that.config = config;
|
|
254
|
+
that.roundDecimal = config.roundDecimal;
|
|
255
|
+
that.apduSize = config.apduSize;
|
|
256
|
+
that.maxSegments = config.maxSegments;
|
|
257
|
+
that.discover_polling_schedule = config.discover_polling_schedule;
|
|
155
258
|
that.device_id_range_enabled = config.device_id_range_enabled;
|
|
156
259
|
that.device_id_range_start = config.device_id_range_start;
|
|
157
260
|
that.device_id_range_end = config.device_id_range_end;
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
261
|
+
that.deviceId = config.deviceId;
|
|
262
|
+
that.broadCastAddr = config.broadCastAddr;
|
|
263
|
+
that.manual_instance_range_enabled = config.manual_instance_range_enabled;
|
|
264
|
+
that.manual_instance_range_start = config.manual_instance_range_start;
|
|
265
|
+
that.manual_instance_range_end = config.manual_instance_range_end;
|
|
266
|
+
that.bacnetServerEnabled = config.bacnetServerEnabled;
|
|
163
267
|
|
|
164
268
|
if(that.scheduler !== null) {
|
|
165
269
|
that.scheduler.stop();
|
|
166
270
|
}
|
|
167
271
|
|
|
168
|
-
try{
|
|
169
|
-
that.client =
|
|
272
|
+
try {
|
|
273
|
+
that.client._settings.apduTimeout = config.apduTimeout;
|
|
274
|
+
that.client._settings.interface = config.localIpAdrress;
|
|
275
|
+
that.client._settings.port = config.port;
|
|
276
|
+
that.client._settings.broadcastAddress = config.broadCastAddr;
|
|
277
|
+
|
|
278
|
+
that.client._transport.interface = config.localIpAdrress;
|
|
279
|
+
that.client._transport.port = config.port;
|
|
280
|
+
that.client._transport.broadcastAddress = config.broadCastAddr;
|
|
170
281
|
|
|
171
282
|
const task = new Task('simple task', () => {
|
|
172
283
|
that.globalWhoIs();
|
|
@@ -179,26 +290,12 @@ class BacnetClient extends EventEmitter {
|
|
|
179
290
|
that.globalWhoIs();
|
|
180
291
|
|
|
181
292
|
} catch(e){
|
|
182
|
-
|
|
293
|
+
that.logOut("Error reinitializing bacnet client: ", e)
|
|
183
294
|
}
|
|
184
295
|
};
|
|
185
296
|
|
|
186
|
-
|
|
297
|
+
getValidPointProperties(point, requestedProps) {
|
|
187
298
|
let that = this;
|
|
188
|
-
|
|
189
|
-
let points = promiseArray.map(function(element){return element.point})
|
|
190
|
-
let promises = promiseArray.map(function(element){return element.promise})
|
|
191
|
-
promiseArray.forEach(function(element){
|
|
192
|
-
let point = element.point;
|
|
193
|
-
|
|
194
|
-
Promise.resolve(element.promise).then(function(result){
|
|
195
|
-
that.pointReferenceList.push({})
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
getValidPointProperties(point, requestedProps){
|
|
202
299
|
let availableProps = point.propertyList;
|
|
203
300
|
let newProps = [];
|
|
204
301
|
|
|
@@ -208,43 +305,46 @@ class BacnetClient extends EventEmitter {
|
|
|
208
305
|
if(foundInAvailable) newProps.push(prop);
|
|
209
306
|
});
|
|
210
307
|
//add object name for use in formatting
|
|
211
|
-
newProps.push({id: baEnum.
|
|
308
|
+
newProps.push({id: baEnum.PropertyIdentifier.OBJECT_NAME});
|
|
212
309
|
} catch(e){
|
|
213
|
-
|
|
310
|
+
that.logOut("Issue finding valid object properties, see error: ", e);
|
|
214
311
|
}
|
|
215
312
|
|
|
216
313
|
return newProps;
|
|
217
314
|
}
|
|
218
315
|
|
|
219
|
-
doRead(readConfig, outputType, msgId) {
|
|
316
|
+
doRead(readConfig, outputType, objectPropertyType, msgId) {
|
|
220
317
|
let that = this;
|
|
221
|
-
|
|
222
318
|
that.roundDecimal = readConfig.precision;
|
|
223
319
|
let devicesToRead = Object.keys(readConfig.pointsToRead);
|
|
224
|
-
let propertiesToRead = readConfig.objectProperties;
|
|
225
320
|
|
|
226
321
|
try {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
let
|
|
230
|
-
let
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
let point = readConfig.pointsToRead[deviceAddress][pointName];
|
|
234
|
-
readPromiseArray.push(that._readObjectFull(deviceAddress, point.meta.objectId.type, point.meta.objectId.instance));
|
|
235
|
-
});
|
|
236
|
-
that.readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, msgId);
|
|
322
|
+
let bacnetResults = {};
|
|
323
|
+
devicesToRead.forEach(function(key, index) {
|
|
324
|
+
let device = that.deviceList.find(ele => `${that.getDeviceAddress(ele)}-${ele.getDeviceId()}` == key);
|
|
325
|
+
let deviceName = device.getDeviceName();
|
|
326
|
+
bacnetResults[deviceName] = readConfig.pointsToRead[key];
|
|
327
|
+
if(index == devicesToRead.length - 1) that.emit('values', bacnetResults, outputType, objectPropertyType);
|
|
237
328
|
});
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
console.log("Issue doing read, see error: ", e);
|
|
329
|
+
} catch(e) {
|
|
330
|
+
that.logOut("Issue doing read, see error: ", e);
|
|
241
331
|
}
|
|
332
|
+
}
|
|
242
333
|
|
|
334
|
+
getDeviceAddress(device){
|
|
335
|
+
switch(typeof device.getAddress()) {
|
|
336
|
+
case "object":
|
|
337
|
+
return device.getAddress().address;
|
|
338
|
+
case "string":
|
|
339
|
+
return device.getAddress();
|
|
340
|
+
default:
|
|
341
|
+
return device.getAddress();
|
|
342
|
+
}
|
|
243
343
|
}
|
|
244
344
|
|
|
245
|
-
readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, msgId) {
|
|
345
|
+
readDeviceAndEmitJSON(readPromiseArray, device, outputType, propertiesToRead, objectPropertyType, msgId) {
|
|
246
346
|
let that = this;
|
|
247
|
-
let deviceName = device.
|
|
347
|
+
let deviceName = device.getDeviceName();
|
|
248
348
|
|
|
249
349
|
let bacnetResults = {
|
|
250
350
|
[deviceName]: []
|
|
@@ -261,45 +361,69 @@ class BacnetClient extends EventEmitter {
|
|
|
261
361
|
element.values.forEach(function(point){
|
|
262
362
|
point.values.forEach(function(object) {
|
|
263
363
|
let toReadProperty = propertiesToRead.findIndex(ele => ele.id == object.id);
|
|
364
|
+
let objectName = that._findValueById(point.values, baEnum.PropertyIdentifier.OBJECT_NAME);
|
|
264
365
|
//checks for error code json structure, returned for invalid bacnet requests
|
|
265
|
-
if(!object.value.value && toReadProperty !== -1) {
|
|
366
|
+
if(!object.value.value && toReadProperty !== -1 && objectName !== "") {
|
|
266
367
|
var currobjectId = point.objectId.type
|
|
267
368
|
let bac_obj = that.getObjectType(currobjectId);
|
|
268
|
-
let objectName = that._findValueById(point.values, baEnum.PropertyIds.PROP_OBJECT_NAME);
|
|
269
|
-
|
|
270
369
|
let objectId;
|
|
271
|
-
|
|
272
|
-
objectName = objectName.split(" ").join("_");
|
|
273
|
-
objectId = objectName + "_" + bac_obj + '_' + point.objectId.instance;
|
|
274
|
-
} else {
|
|
275
|
-
objectId = bac_obj + '_' + point.objectId.instance;
|
|
276
|
-
}
|
|
370
|
+
objectId = objectName;
|
|
277
371
|
|
|
278
372
|
//init json object
|
|
279
373
|
if(!values[objectId]) values[objectId] = {};
|
|
280
374
|
|
|
281
375
|
switch(object.id) {
|
|
282
|
-
case baEnum.
|
|
283
|
-
if(object.value[0] &&
|
|
376
|
+
case baEnum.PropertyIdentifier.PRESENT_VALUE:
|
|
377
|
+
if(object.value[0] &&
|
|
378
|
+
object.value[0].value !== "undefined" &&
|
|
379
|
+
object.value[0].value !== null &&
|
|
380
|
+
typeof object.value[0].value == "number") {
|
|
381
|
+
values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, that.roundDecimal);
|
|
382
|
+
} else if(object.value[0] &&
|
|
383
|
+
object.value[0].value !== "undefined" &&
|
|
384
|
+
object.value[0].value !== null &&
|
|
385
|
+
typeof object.value[0].value == "string") {
|
|
386
|
+
values[objectId].presentValue = object.value[0].value;
|
|
387
|
+
}
|
|
284
388
|
break;
|
|
285
|
-
case baEnum.
|
|
389
|
+
case baEnum.PropertyIdentifier.DESCRIPTION:
|
|
286
390
|
if(object.value[0]) values[objectId].description = object.value[0].value;
|
|
287
391
|
break;
|
|
288
|
-
case baEnum.
|
|
392
|
+
case baEnum.PropertyIdentifier.STATUS_FLAGS:
|
|
289
393
|
if(object.value[0] && object.value[0].value) values[objectId].statusFlags = that.getStatusFlags(object);
|
|
290
394
|
break;
|
|
291
|
-
case baEnum.
|
|
395
|
+
case baEnum.PropertyIdentifier.RELIABILITY:
|
|
292
396
|
if(object.value[0]) values[objectId].reliability = that.getPROP_RELIABILITY(object.value[0].value);
|
|
293
397
|
break;
|
|
294
|
-
case baEnum.
|
|
398
|
+
case baEnum.PropertyIdentifier.OUT_OF_SERVICE:
|
|
295
399
|
if(object.value[0]) values[objectId].outOfService = object.value[0].value;
|
|
296
400
|
break;
|
|
297
|
-
case baEnum.
|
|
401
|
+
case baEnum.PropertyIdentifier.UNITS:
|
|
298
402
|
if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
|
|
299
403
|
break;
|
|
300
|
-
case baEnum.
|
|
404
|
+
case baEnum.PropertyIdentifier.OBJECT_NAME:
|
|
301
405
|
if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
|
|
302
406
|
break;
|
|
407
|
+
case baEnum.PropertyIdentifier.SYSTEM_STATUS:
|
|
408
|
+
if(object.value[0]){
|
|
409
|
+
values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
|
|
410
|
+
}
|
|
411
|
+
break;
|
|
412
|
+
case baEnum.PropertyIdentifier.MODIFICATION_DATE:
|
|
413
|
+
if(object.value[0]) {
|
|
414
|
+
values[objectId].modificationDate = object.value[0].value;
|
|
415
|
+
}
|
|
416
|
+
break;
|
|
417
|
+
case baEnum.PropertyIdentifier.PROGRAM_STATE:
|
|
418
|
+
if(object.value[0]){
|
|
419
|
+
values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
|
|
420
|
+
}
|
|
421
|
+
break;
|
|
422
|
+
case baEnum.PropertyIdentifier.RECORD_COUNT:
|
|
423
|
+
if(object.value[0] ) {
|
|
424
|
+
values[objectId].recordCount = object.value[0].value;
|
|
425
|
+
}
|
|
426
|
+
break;
|
|
303
427
|
}
|
|
304
428
|
}
|
|
305
429
|
});
|
|
@@ -307,11 +431,11 @@ class BacnetClient extends EventEmitter {
|
|
|
307
431
|
bacnetResults[deviceName] = values;
|
|
308
432
|
|
|
309
433
|
} catch(e) {
|
|
310
|
-
|
|
434
|
+
that.logOut("issue resolving bacnet payload, see error: ", e);
|
|
311
435
|
}
|
|
312
436
|
});
|
|
313
437
|
if(Object.keys(bacnetResults[deviceName]).length !== 0) {
|
|
314
|
-
that.emit('values',
|
|
438
|
+
that.emit('values', bacnetResults, outputType, objectPropertyType);
|
|
315
439
|
}
|
|
316
440
|
|
|
317
441
|
}).catch(function (error) {
|
|
@@ -319,12 +443,10 @@ class BacnetClient extends EventEmitter {
|
|
|
319
443
|
});
|
|
320
444
|
|
|
321
445
|
} catch(e){
|
|
322
|
-
|
|
446
|
+
that.logOut("Issue reading from device, see error: ", e);
|
|
323
447
|
}
|
|
324
448
|
}
|
|
325
449
|
|
|
326
|
-
|
|
327
|
-
|
|
328
450
|
_getDeviceName(address, deviceId) {
|
|
329
451
|
let that = this;
|
|
330
452
|
return new Promise((resolve, reject) => {
|
|
@@ -335,10 +457,10 @@ class BacnetClient extends EventEmitter {
|
|
|
335
457
|
if(object.value[0]) {
|
|
336
458
|
resolve(object.value[0].value);
|
|
337
459
|
} else {
|
|
338
|
-
|
|
460
|
+
that.logOut("Issue with deviceName payload, see object: ", object);
|
|
339
461
|
}
|
|
340
462
|
} catch(e){
|
|
341
|
-
|
|
463
|
+
that.logOut("Unable to get device name: ", e);
|
|
342
464
|
}
|
|
343
465
|
});
|
|
344
466
|
}
|
|
@@ -347,9 +469,10 @@ class BacnetClient extends EventEmitter {
|
|
|
347
469
|
}
|
|
348
470
|
|
|
349
471
|
getPropertiesForType(props, type) {
|
|
472
|
+
let that = this;
|
|
350
473
|
let newProps = [];
|
|
351
474
|
props.forEach(function(prop) {
|
|
352
|
-
//
|
|
475
|
+
//that.logOut(prop);
|
|
353
476
|
switch(type){
|
|
354
477
|
case 0: //analog-input
|
|
355
478
|
newProps.push(prop);
|
|
@@ -370,13 +493,13 @@ class BacnetClient extends EventEmitter {
|
|
|
370
493
|
newProps.push(prop);
|
|
371
494
|
break;
|
|
372
495
|
case 13:
|
|
373
|
-
if(prop.id == baEnum.
|
|
496
|
+
if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
|
|
374
497
|
break;
|
|
375
498
|
case 14:
|
|
376
|
-
if(prop.id == baEnum.
|
|
499
|
+
if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
|
|
377
500
|
break;
|
|
378
501
|
case 19:
|
|
379
|
-
if(prop.id == baEnum.
|
|
502
|
+
if(prop.id == baEnum.PropertyIdentifier.PRESENT_VALUE || prop.id == baEnum.PropertyIdentifier.OBJECT_NAME) newProps.push(prop);
|
|
380
503
|
break;
|
|
381
504
|
}
|
|
382
505
|
});
|
|
@@ -387,21 +510,122 @@ class BacnetClient extends EventEmitter {
|
|
|
387
510
|
let that = this;
|
|
388
511
|
return new Promise(async function(resolve, reject) {
|
|
389
512
|
try {
|
|
513
|
+
device.setManualDiscoveryMode(false);
|
|
390
514
|
let result = await that.scanDevice(device);
|
|
391
515
|
device.setPointsList(result);
|
|
392
516
|
resolve(result);
|
|
517
|
+
} catch(e) {
|
|
518
|
+
that.logOut(`Error getting point list for ${device.getAddress()} - ${device.getDeviceId()}: `, e);
|
|
519
|
+
reject(e);
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
getDevicePointListWithoutObjectList(device) {
|
|
525
|
+
let that = this;
|
|
526
|
+
return new Promise(function(resolve, reject) {
|
|
527
|
+
try {
|
|
528
|
+
device.setManualDiscoveryMode(true);
|
|
529
|
+
that.scanDeviceManually(device).then(function(result) {
|
|
530
|
+
device.setPointsList(result);
|
|
531
|
+
resolve(result);
|
|
532
|
+
}).catch(function(error) {
|
|
533
|
+
reject(error);
|
|
534
|
+
});
|
|
535
|
+
|
|
393
536
|
|
|
394
537
|
} catch(e) {
|
|
395
|
-
|
|
538
|
+
that.logOut("Error getting point list: ", e);
|
|
396
539
|
reject(e);
|
|
397
540
|
}
|
|
398
541
|
|
|
399
542
|
});
|
|
400
543
|
}
|
|
401
544
|
|
|
402
|
-
|
|
545
|
+
scanDeviceManually(device) {
|
|
403
546
|
let that = this;
|
|
547
|
+
return new Promise(function(resolve, reject) {
|
|
548
|
+
let objectNameProperty = [{ id: baEnum.PropertyIdentifier.OBJECT_NAME }];
|
|
549
|
+
let address = device.getAddress();
|
|
550
|
+
let objectTypeList = [0, 1, 2, 3];
|
|
551
|
+
let instanceRange = {start: 0, end: 100};
|
|
552
|
+
let requestArray = [];
|
|
553
|
+
let maxRequestThreshold = 1000;
|
|
554
|
+
let requestRate = 20;
|
|
555
|
+
let requestBuffer = [];
|
|
556
|
+
let sendBuffer = [];
|
|
557
|
+
|
|
558
|
+
if(that.manual_instance_range_enabled == true) {
|
|
559
|
+
instanceRange.start = that.manual_instance_range_start;
|
|
560
|
+
maxRequestThreshold = that.manual_instance_range_end;
|
|
561
|
+
if(that.manual_instance_range_end < requestRate) {
|
|
562
|
+
requestRate = that.manual_instance_range_end;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
for(let typeListIndex = 0; typeListIndex < objectTypeList.length; typeListIndex++){
|
|
567
|
+
let objectType = objectTypeList[typeListIndex];
|
|
568
|
+
for(let i = instanceRange.start; i <= instanceRange.end; i++) {
|
|
569
|
+
|
|
570
|
+
requestArray.push({
|
|
571
|
+
objectId: { type: objectType, instance: i },
|
|
572
|
+
properties: objectNameProperty
|
|
573
|
+
})
|
|
574
|
+
|
|
575
|
+
if(requestArray.length == requestRate ) {
|
|
576
|
+
requestBuffer.push(that._readObjectWithRequestArray(address, requestArray));
|
|
577
|
+
instanceRange.end += requestRate;
|
|
578
|
+
requestArray = [];
|
|
579
|
+
if(i >= maxRequestThreshold) {
|
|
580
|
+
instanceRange.end = maxRequestThreshold;
|
|
581
|
+
if(typeListIndex == objectTypeList.length-1) {
|
|
582
|
+
send();
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
break;
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
404
589
|
|
|
590
|
+
instanceRange.end = 100;
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
function send() {
|
|
594
|
+
|
|
595
|
+
for(let index = 0; index < requestBuffer.length; index++) {
|
|
596
|
+
let promise = requestBuffer[index];
|
|
597
|
+
try {
|
|
598
|
+
Promise.resolve(promise).then(function(result) {
|
|
599
|
+
let keys = Object.keys(result);
|
|
600
|
+
for (const [key, value] of Object.entries(result)) {
|
|
601
|
+
if(key == "value" && typeof value == "object") {
|
|
602
|
+
for(let x = 0; x < value.values.length; x++) {
|
|
603
|
+
let ele = value.values[x];
|
|
604
|
+
let valueRoot = ele.values[0].value[0];
|
|
605
|
+
if(!valueRoot.value.errorClass && !valueRoot.value.errorCode) {
|
|
606
|
+
sendBuffer.push({"value": ele.objectId, "type": 12});
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
if(index == requestBuffer.length - 1) {
|
|
613
|
+
resolve(sendBuffer);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
}).catch(function(error) {
|
|
617
|
+
reject(error);
|
|
618
|
+
});
|
|
619
|
+
} catch(e) {
|
|
620
|
+
reject(e)
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
_readObjectWithRequestArray(deviceAddress, requestArray) {
|
|
628
|
+
let that = this;
|
|
405
629
|
return new Promise((resolve, reject) => {
|
|
406
630
|
this.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, (error, value) => {
|
|
407
631
|
resolve({
|
|
@@ -431,9 +655,9 @@ class BacnetClient extends EventEmitter {
|
|
|
431
655
|
_readDeviceName(deviceAddress, deviceId, callback){
|
|
432
656
|
let that = this;
|
|
433
657
|
const requestArray = [{
|
|
434
|
-
objectId: { type: baEnum.
|
|
658
|
+
objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
435
659
|
properties: [
|
|
436
|
-
{ id: baEnum.
|
|
660
|
+
{ id: baEnum.PropertyIdentifier.OBJECT_NAME }
|
|
437
661
|
]
|
|
438
662
|
}];
|
|
439
663
|
|
|
@@ -443,53 +667,45 @@ class BacnetClient extends EventEmitter {
|
|
|
443
667
|
_readObjectList(deviceAddress, deviceId, callback) {
|
|
444
668
|
let that = this;
|
|
445
669
|
const requestArray = [{
|
|
446
|
-
objectId: { type: baEnum.
|
|
447
|
-
properties: [{ id: baEnum.
|
|
670
|
+
objectId: { type: baEnum.ObjectType.DEVICE, instance: deviceId },
|
|
671
|
+
properties: [{ id: baEnum.PropertyIdentifier.OBJECT_LIST }
|
|
448
672
|
]
|
|
449
673
|
}];
|
|
450
674
|
|
|
451
675
|
try {
|
|
452
676
|
that.client.readPropertyMultiple(deviceAddress, requestArray, that.readPropertyMultipleOptions, callback);
|
|
453
677
|
} catch(e) {
|
|
454
|
-
|
|
678
|
+
that.logOut("Error reading object list: ", e);
|
|
455
679
|
}
|
|
456
680
|
}
|
|
457
681
|
|
|
458
682
|
_readObjectFull(deviceAddress, type, instance) {
|
|
459
683
|
|
|
460
684
|
return this._readObject(deviceAddress, type, instance, [
|
|
461
|
-
{ id: baEnum.
|
|
462
|
-
{ id: baEnum.PropertyIds.PROP_OBJECT_NAME },
|
|
463
|
-
{ id: baEnum.PropertyIds.PROP_OBJECT_TYPE },
|
|
464
|
-
{ id: baEnum.PropertyIds.PROP_DESCRIPTION },
|
|
465
|
-
{ id: baEnum.PropertyIds.PROP_UNITS },
|
|
466
|
-
{ id: baEnum.PropertyIds.PROP_PRESENT_VALUE },
|
|
467
|
-
{ id: baEnum.PropertyIds.PROP_PROPERTY_LIST },
|
|
468
|
-
{ id: baEnum.PropertyIds.PROP_STATUS_FLAGS },
|
|
469
|
-
{ id: baEnum.PropertyIds.PROP_RELIABILITY },
|
|
470
|
-
{ id: baEnum.PropertyIds.PROP_OUT_OF_SERVICE }
|
|
685
|
+
{ id: baEnum.PropertyIdentifier.ALL }
|
|
471
686
|
]);
|
|
687
|
+
|
|
472
688
|
};
|
|
473
689
|
|
|
474
690
|
_readObjectPropList(deviceAddress, type, instance) {
|
|
475
691
|
|
|
476
692
|
return this._readObject(deviceAddress, type, instance, [
|
|
477
|
-
{ id: baEnum.
|
|
693
|
+
{ id: baEnum.PropertyIdentifier.PROPERTY_LIST }
|
|
478
694
|
]);
|
|
479
695
|
};
|
|
480
696
|
|
|
481
697
|
_readObjectId(deviceAddress, type, instance) {
|
|
482
698
|
|
|
483
699
|
return this._readObject(deviceAddress, type, instance, [
|
|
484
|
-
{ id: baEnum.
|
|
700
|
+
{ id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER }
|
|
485
701
|
]);
|
|
486
702
|
}
|
|
487
703
|
|
|
488
704
|
_readObjectPresentValue(deviceAddress, type, instance) {
|
|
489
705
|
|
|
490
706
|
return this._readObject(deviceAddress, type, instance, [
|
|
491
|
-
{ id: baEnum.
|
|
492
|
-
{ id: baEnum.
|
|
707
|
+
{ id: baEnum.PropertyIdentifier.PRESENT_VALUE },
|
|
708
|
+
{ id: baEnum.PropertyIdentifier.OBJECT_NAME}
|
|
493
709
|
]);
|
|
494
710
|
}
|
|
495
711
|
|
|
@@ -500,7 +716,7 @@ class BacnetClient extends EventEmitter {
|
|
|
500
716
|
options.pointsToWrite.forEach(function(point){
|
|
501
717
|
|
|
502
718
|
let deviceAddress = point.deviceAddress;
|
|
503
|
-
|
|
719
|
+
|
|
504
720
|
if(valuesArray[deviceAddress] == null || valuesArray[deviceAddress] == undefined){
|
|
505
721
|
valuesArray[deviceAddress] = [];
|
|
506
722
|
}
|
|
@@ -546,11 +762,11 @@ class BacnetClient extends EventEmitter {
|
|
|
546
762
|
Promise.all(writePromises).then(function(result) {
|
|
547
763
|
resolve(result);
|
|
548
764
|
}).catch(function(e) {
|
|
549
|
-
|
|
765
|
+
that.logOut("Error writing: ", e);
|
|
550
766
|
});
|
|
551
767
|
});
|
|
552
768
|
} catch (error) {
|
|
553
|
-
|
|
769
|
+
that.logOut(error);
|
|
554
770
|
}
|
|
555
771
|
}
|
|
556
772
|
|
|
@@ -573,11 +789,11 @@ class BacnetClient extends EventEmitter {
|
|
|
573
789
|
const objectInfo = object.values[0].objectId;
|
|
574
790
|
const deviceObjectId = new DeviceObjectId(objectInfo.type, objectInfo.instance);
|
|
575
791
|
const objectProperties = object.values[0].values;
|
|
576
|
-
const name = this._findValueById(objectProperties, baEnum.
|
|
577
|
-
const PROP_DESCRIPTION = this._findValueById(objectProperties, baEnum.
|
|
578
|
-
const type = this._findValueById(objectProperties, baEnum.
|
|
579
|
-
const PROP_UNITS = this._findValueById(objectProperties, baEnum.
|
|
580
|
-
const presentValue = this._findValueById(objectProperties, baEnum.
|
|
792
|
+
const name = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_NAME);
|
|
793
|
+
const PROP_DESCRIPTION = this._findValueById(objectProperties, baEnum.PropertyIdentifier.DESCRIPTION);
|
|
794
|
+
const type = this._findValueById(objectProperties, baEnum.PropertyIdentifier.OBJECT_TYPE);
|
|
795
|
+
const PROP_UNITS = this._findValueById(objectProperties, baEnum.PropertyIdentifier.UNITS);
|
|
796
|
+
const presentValue = this._findValueById(objectProperties, baEnum.PropertyIdentifier.PRESENT_VALUE);
|
|
581
797
|
|
|
582
798
|
return new DeviceObject(deviceObjectId, name, PROP_DESCRIPTION, type, PROP_UNITS, presentValue);
|
|
583
799
|
}
|
|
@@ -612,16 +828,17 @@ class BacnetClient extends EventEmitter {
|
|
|
612
828
|
}
|
|
613
829
|
|
|
614
830
|
scanDevice(device) {
|
|
831
|
+
let that = this;
|
|
615
832
|
return new Promise((resolve, reject) => {
|
|
616
|
-
this._readObjectList(device.
|
|
833
|
+
this._readObjectList(device.getAddress(), device.getDeviceId(), (err, result) => {
|
|
617
834
|
if (!err) {
|
|
618
835
|
try {
|
|
619
836
|
resolve(result.values[0].values[0].value);
|
|
620
837
|
} catch(e) {
|
|
621
|
-
|
|
838
|
+
that.logOut("Issue with getting device point list, see error: ", e);
|
|
622
839
|
}
|
|
623
840
|
} else {
|
|
624
|
-
|
|
841
|
+
that.logOut(`Error while fetching objects: ${err}`);
|
|
625
842
|
reject(err);
|
|
626
843
|
}
|
|
627
844
|
});
|
|
@@ -632,7 +849,7 @@ class BacnetClient extends EventEmitter {
|
|
|
632
849
|
shutDownClient() {
|
|
633
850
|
let that = this;
|
|
634
851
|
if(that.client) that.client.close((err, result) => {
|
|
635
|
-
|
|
852
|
+
that.logOut(err, result);
|
|
636
853
|
});
|
|
637
854
|
};
|
|
638
855
|
|
|
@@ -640,7 +857,8 @@ class BacnetClient extends EventEmitter {
|
|
|
640
857
|
let that = this;
|
|
641
858
|
let options = {
|
|
642
859
|
lowLimit: 0,
|
|
643
|
-
highLimit:
|
|
860
|
+
highLimit: bacnetIdMax,
|
|
861
|
+
'net': 65535
|
|
644
862
|
};
|
|
645
863
|
|
|
646
864
|
if(that.device_id_range_enabled == true) {
|
|
@@ -649,7 +867,7 @@ class BacnetClient extends EventEmitter {
|
|
|
649
867
|
}
|
|
650
868
|
|
|
651
869
|
if(that.client) {
|
|
652
|
-
that.client.whoIs(
|
|
870
|
+
that.client.whoIs({'net': 65535});
|
|
653
871
|
} else {
|
|
654
872
|
that.reinitializeClient(that.config);
|
|
655
873
|
}
|
|
@@ -681,56 +899,95 @@ class BacnetClient extends EventEmitter {
|
|
|
681
899
|
}
|
|
682
900
|
|
|
683
901
|
buildNetworkTreeData() {
|
|
684
|
-
let that = this;
|
|
902
|
+
let that = this;
|
|
903
|
+
that.buildTreeMutex = new Mutex();
|
|
904
|
+
let displayNameCharThreshold = 40;
|
|
685
905
|
return new Promise(async function(resolve, reject) {
|
|
686
906
|
if(!that.renderList) that.renderList = [];
|
|
687
907
|
if(that.deviceList && that.networkTree) {
|
|
688
908
|
that.deviceList.forEach(function(deviceInfo, index) {
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
let
|
|
695
|
-
let
|
|
909
|
+
that.buildTreeMutex
|
|
910
|
+
.acquire()
|
|
911
|
+
.then(function(release) {
|
|
912
|
+
|
|
913
|
+
let ipAddr = typeof deviceInfo.getAddress() == "object" ? deviceInfo.getAddress().address : deviceInfo.getAddress();
|
|
914
|
+
let deviceId = deviceInfo.getDeviceId();
|
|
915
|
+
let deviceName = deviceInfo.getDeviceName() == null ? ipAddr : deviceInfo.getDeviceName();
|
|
916
|
+
let deviceKey = ipAddr + "-" + deviceInfo.getDeviceId();
|
|
917
|
+
let deviceObject = that.networkTree[deviceKey];
|
|
918
|
+
let isMstpDevice = deviceInfo.getIsMstpDevice();
|
|
919
|
+
let manualDiscoveryMode = deviceInfo.getManualDiscoveryMode();
|
|
920
|
+
|
|
921
|
+
if(deviceObject) {
|
|
922
|
+
let children = [];
|
|
923
|
+
let pointIndex = 0;
|
|
924
|
+
|
|
925
|
+
for(const pointName in deviceObject) {
|
|
926
|
+
let pointProperties = [];
|
|
927
|
+
let values = deviceObject[pointName];
|
|
928
|
+
let displayName = pointName;
|
|
929
|
+
if(pointName.length > displayNameCharThreshold) {
|
|
930
|
+
displayName = "";
|
|
931
|
+
let charArray = pointName.split("");
|
|
932
|
+
for(let i = 0; i < charArray.length; i++) {
|
|
933
|
+
if(i < displayNameCharThreshold){
|
|
934
|
+
displayName += charArray[i];
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
displayName += "...";
|
|
938
|
+
}
|
|
696
939
|
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
940
|
+
if(values.objectName){
|
|
941
|
+
pointProperties.push({"key": `${index}-${pointIndex}-0`, "label": `Name: ${values.objectName}`, "data": values.objectName, "icon": "pi pi-bolt", "children": null});
|
|
942
|
+
}
|
|
943
|
+
if(values.objectType){
|
|
944
|
+
pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-bolt", "children": null});
|
|
945
|
+
}
|
|
946
|
+
if(values.objectID && values.objectID.instance) {
|
|
947
|
+
pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-bolt", "children": null});
|
|
948
|
+
}
|
|
949
|
+
if(values.description){
|
|
950
|
+
pointProperties.push({"key": `${index}-${pointIndex}-3`, "label": `Description: ${values.description}`, "data": `${values.description}`, "icon": "pi pi-bolt", "children": null});
|
|
951
|
+
}
|
|
952
|
+
if(values.units){
|
|
953
|
+
pointProperties.push({"key": `${index}-${pointIndex}-4`, "label": `Units: ${values.units}`, "data": `${values.units}`, "icon": "pi pi-bolt", "children": null});
|
|
954
|
+
}
|
|
955
|
+
if(values.presentValue !== "undefined" && values.presentValue !== null && typeof values.presentValue !== "undefined") {
|
|
956
|
+
pointProperties.push({"key": `${index}-${pointIndex}-5`, "label": `Present Value: ${values.presentValue}`, "data": `${values.presentValue}`, "icon": "pi pi-bolt", "children": null});
|
|
957
|
+
}
|
|
958
|
+
if(values.systemStatus !== null && typeof values.systemStatus !== "undefined" && values.systemStatus !== ""){
|
|
959
|
+
pointProperties.push({"key": `${index}-${pointIndex}-6`, "label": `System Status: ${values.systemStatus}`, "data": `${values.systemStatus}`, "icon": "pi pi-bolt", "children": null});
|
|
960
|
+
}
|
|
961
|
+
if(values.modificationDate && !values.modificationDate.errorClass) {
|
|
962
|
+
pointProperties.push({"key": `${index}-${pointIndex}-7`, "label": `Modification Date: ${values.modificationDate}`, "data": `${values.modificationDate}`, "icon": "pi pi-bolt", "children": null});
|
|
963
|
+
}
|
|
964
|
+
if(values.programState){
|
|
965
|
+
pointProperties.push({"key": `${index}-${pointIndex}-8`, "label": `Program State: ${values.programState}`, "data": `${values.programState}`, "icon": "pi pi-bolt", "children": null});
|
|
966
|
+
}
|
|
967
|
+
if(values.recordCount && !values.recordCount.errorClass){
|
|
968
|
+
pointProperties.push({"key": `${index}-${pointIndex}-9`, "label": `Record Count: ${values.recordCount}`, "data": `${values.recordCount}`, "icon": "pi pi-bolt", "children": null});
|
|
969
|
+
}
|
|
700
970
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
}
|
|
704
|
-
if(values.objectType){
|
|
705
|
-
pointProperties.push({"key": `${index}-${pointIndex}-1`, "label": `Object Type: ${values.objectType}`, "data": values.objectType, "icon": "pi pi-bolt", "children": null});
|
|
706
|
-
}
|
|
707
|
-
if(values.objectID && values.objectID.instance) {
|
|
708
|
-
pointProperties.push({"key": `${index}-${pointIndex}-2`, "label": `Object Instance: ${values.objectID.instance}`, "data": values.objectID.instance, "icon": "pi pi-bolt", "children": null});
|
|
971
|
+
children.push({"key": `${index}-${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})
|
|
972
|
+
pointIndex++;
|
|
709
973
|
}
|
|
710
|
-
|
|
711
|
-
|
|
974
|
+
let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.deviceId == deviceId);
|
|
975
|
+
if(foundIndex !== -1) {
|
|
976
|
+
that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice};
|
|
977
|
+
} else if(foundIndex == -1) {
|
|
978
|
+
that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": that.getDeviceIcon(isMstpDevice, manualDiscoveryMode), "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr, "deviceId": deviceId, "isMstpDevice": isMstpDevice});
|
|
712
979
|
}
|
|
713
|
-
if(
|
|
714
|
-
|
|
980
|
+
if(index == that.deviceList.length - 1) {
|
|
981
|
+
resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
|
|
715
982
|
}
|
|
716
|
-
|
|
717
|
-
|
|
983
|
+
} else {
|
|
984
|
+
if(index == that.deviceList.length - 1) {
|
|
985
|
+
resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
|
|
718
986
|
}
|
|
719
|
-
children.push({"key": `${index}-${pointIndex}`, "label": pointName, "data": pointName, "icon": "", "children": pointProperties, "type": "point", "parentDevice": deviceName, "showAdded": false, "bacnetType": values.meta.objectId.type})
|
|
720
|
-
pointIndex++;
|
|
721
|
-
}
|
|
722
|
-
let foundIndex = that.renderList.findIndex(ele => ele.key == index && ele.ipAddr == ipAddr);
|
|
723
|
-
if(foundIndex !== -1) {
|
|
724
|
-
that.renderList[foundIndex] = {"key": index, "label": deviceName, "data": deviceName, "icon": "pi pi-box", "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr};
|
|
725
|
-
} else if(foundIndex == -1) {
|
|
726
|
-
that.renderList.push({"key": index, "label": deviceName, "data": deviceName, "icon": "pi pi-box", "children": children.sort(that.sortPoints), "type": "device", "lastSeen": deviceInfo.getLastSeen(), "showAdded": false, "ipAddr": ipAddr});
|
|
727
987
|
}
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
} else {
|
|
732
|
-
if(index == that.deviceList.length - 1) resolve({renderList: that.renderList, deviceList: that.deviceList, pointList: that.networkTree, pollFrequency: that.discover_polling_schedule});
|
|
733
|
-
}
|
|
988
|
+
|
|
989
|
+
release();
|
|
990
|
+
});
|
|
734
991
|
});
|
|
735
992
|
}
|
|
736
993
|
});
|
|
@@ -740,125 +997,171 @@ class BacnetClient extends EventEmitter {
|
|
|
740
997
|
let that = this;
|
|
741
998
|
let address = device.address;
|
|
742
999
|
let pointList = device.getPointsList();
|
|
1000
|
+
let requestMutex = new Mutex();
|
|
743
1001
|
|
|
744
|
-
return new Promise(function(resolve, reject) {
|
|
1002
|
+
return new Promise(function(resolve, reject) {
|
|
745
1003
|
let promiseArray = [];
|
|
746
|
-
pointList.
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
1004
|
+
if(typeof pointList !== "undefined" && pointList.length > 0) {
|
|
1005
|
+
pointList.forEach(function(point, pointListIndex) {
|
|
1006
|
+
requestMutex
|
|
1007
|
+
.acquire()
|
|
1008
|
+
.then(function(release) {
|
|
1009
|
+
that._readObjectFull(address, point.value.type, point.value.instance).then(function(result) {
|
|
1010
|
+
|
|
1011
|
+
if(!result.error) {
|
|
1012
|
+
promiseArray.push(result);
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
release();
|
|
1016
|
+
|
|
1017
|
+
if(pointListIndex == pointList.length - 1) {
|
|
1018
|
+
that.buildResponse(promiseArray, device).then(function() {
|
|
1019
|
+
that.lastNetworkPoll = Date.now();
|
|
1020
|
+
resolve({deviceList: that.deviceList, pointList: that.networkTree});
|
|
1021
|
+
}).catch(function(e){
|
|
1022
|
+
that.logOut("Error while building json object: ", e);
|
|
1023
|
+
reject(e);
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
}).catch(function(e) {
|
|
1028
|
+
release();
|
|
1029
|
+
that.logOut("_readObjectFull error: ", e);
|
|
1030
|
+
|
|
1031
|
+
if(pointListIndex == pointList.length - 1) {
|
|
1032
|
+
that.buildResponse(promiseArray, device).then(function() {
|
|
1033
|
+
that.lastNetworkPoll = Date.now();
|
|
1034
|
+
resolve({deviceList: that.deviceList, pointList: that.networkTree});
|
|
1035
|
+
}).catch(function(e){
|
|
1036
|
+
that.logOut("Error while building json object: ", e);
|
|
1037
|
+
reject(e);
|
|
1038
|
+
});
|
|
1039
|
+
}
|
|
1040
|
+
|
|
756
1041
|
});
|
|
757
|
-
}).catch(function(e) {
|
|
758
|
-
console.log("Error while building json object: ", e);
|
|
759
|
-
reject(e);
|
|
760
1042
|
});
|
|
761
|
-
}
|
|
762
|
-
}
|
|
1043
|
+
});
|
|
1044
|
+
} else {
|
|
1045
|
+
reject("Unable to build network tree, empty point list");
|
|
1046
|
+
}
|
|
763
1047
|
});
|
|
764
1048
|
}
|
|
765
1049
|
|
|
766
1050
|
// Builds response object for a fully qualified
|
|
767
1051
|
buildResponse(fullObjects, device) {
|
|
768
1052
|
let that = this;
|
|
769
|
-
let deviceName = device.getDeviceName();
|
|
770
|
-
let ipAddr = device.getAddress();
|
|
771
|
-
|
|
772
1053
|
return new Promise(function(resolve, reject) {
|
|
773
|
-
let
|
|
774
|
-
|
|
775
|
-
for(let i = 0; i < fullObjects.length; i++) {
|
|
776
|
-
|
|
1054
|
+
let deviceKey = (typeof device.getAddress() == "object") ? device.getAddress().address + "-" + device.getDeviceId() : device.getAddress() + "-" + device.getDeviceId();
|
|
1055
|
+
let values = that.networkTree[deviceKey] ? that.networkTree[deviceKey] : {};
|
|
1056
|
+
for(let i = 0; i < fullObjects.length; i++) {
|
|
777
1057
|
let obj = fullObjects[i];
|
|
778
1058
|
let successfulResult = !obj.error ? obj.value : null;
|
|
779
|
-
|
|
780
1059
|
if(successfulResult) {
|
|
781
1060
|
successfulResult.values.forEach(function(pointProperty, pointPropertyIndex) {
|
|
782
|
-
|
|
783
1061
|
let currobjectId = pointProperty.objectId.type
|
|
784
1062
|
let bac_obj = that.getObjectType(currobjectId);
|
|
785
|
-
|
|
786
|
-
let
|
|
787
|
-
let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIds.PROP_OBJECT_TYPE);
|
|
788
|
-
|
|
1063
|
+
let objectName = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_NAME);
|
|
1064
|
+
let objectType = that._findValueById(pointProperty.values, baEnum.PropertyIdentifier.OBJECT_TYPE);
|
|
789
1065
|
let objectId;
|
|
790
1066
|
if(objectName !== null) {
|
|
791
|
-
objectName = objectName.split(" ").join("_");
|
|
792
1067
|
objectId = objectName + "_" + bac_obj + '_' + pointProperty.objectId.instance;
|
|
793
1068
|
} else {
|
|
794
1069
|
objectId = bac_obj + '_' + pointProperty.objectId.instance;
|
|
795
1070
|
}
|
|
796
|
-
|
|
797
|
-
if(!values[objectId]) values[objectId] = {};
|
|
798
|
-
values[objectId].meta = {
|
|
799
|
-
objectId: pointProperty.objectId
|
|
800
|
-
};
|
|
801
|
-
|
|
802
1071
|
try {
|
|
803
1072
|
pointProperty.values.forEach(function(object, objectIndex) {
|
|
804
1073
|
//checks for error code json structure, returned for invalid bacnet requests
|
|
805
|
-
if(!object.value.value) {
|
|
1074
|
+
//if(!object.value.value && !object.value[0].value.errorClass && !object.value.errorClass) {
|
|
1075
|
+
if(object && object.value && !object.value.errorClass) {
|
|
1076
|
+
|
|
1077
|
+
|
|
1078
|
+
if(!values[objectId]) values[objectId] = {};
|
|
1079
|
+
values[objectId].meta = {
|
|
1080
|
+
objectId: pointProperty.objectId
|
|
1081
|
+
};
|
|
1082
|
+
|
|
806
1083
|
switch(object.id) {
|
|
807
|
-
case baEnum.
|
|
1084
|
+
case baEnum.PropertyIdentifier.PRESENT_VALUE:
|
|
808
1085
|
if(object.value[0] && object.value[0].value !== "undefined" && object.value[0].value !== null) {
|
|
809
1086
|
//check for binary object type
|
|
810
|
-
if(objectType == 3 || objectType == 4 || objectType == 5){
|
|
1087
|
+
if(objectType == 3 || objectType == 4 || objectType == 5) {
|
|
811
1088
|
if(object.value[0].value == 0) {
|
|
812
1089
|
values[objectId].presentValue = false;
|
|
813
1090
|
} else if(object.value[0].value == 1) {
|
|
814
1091
|
values[objectId].presentValue = true;
|
|
815
1092
|
}
|
|
1093
|
+
} else if(objectType == 40) {
|
|
1094
|
+
//character string
|
|
1095
|
+
values[objectId].presentValue = object.value[0].value;
|
|
816
1096
|
} else {
|
|
817
1097
|
values[objectId].presentValue = roundDecimalPlaces(object.value[0].value, 2);
|
|
818
1098
|
}
|
|
819
1099
|
}
|
|
820
1100
|
values[objectId].meta.arrayIndex = object.index;
|
|
821
1101
|
break;
|
|
822
|
-
case baEnum.
|
|
1102
|
+
case baEnum.PropertyIdentifier.DESCRIPTION:
|
|
823
1103
|
if(object.value[0]) values[objectId].description = object.value[0].value;
|
|
824
1104
|
break;
|
|
825
|
-
case baEnum.
|
|
1105
|
+
case baEnum.PropertyIdentifier.UNITS:
|
|
826
1106
|
if(object.value[0] && object.value[0].value) values[objectId].units = getUnit(object.value[0].value);
|
|
827
1107
|
break;
|
|
828
|
-
case baEnum.
|
|
1108
|
+
case baEnum.PropertyIdentifier.OBJECT_NAME:
|
|
829
1109
|
if(object.value[0] && object.value[0].value) values[objectId].objectName = object.value[0].value;
|
|
830
1110
|
break;
|
|
831
|
-
case baEnum.
|
|
1111
|
+
case baEnum.PropertyIdentifier.OBJECT_TYPE:
|
|
832
1112
|
if(object.value[0] && object.value[0].value) values[objectId].objectType = object.value[0].value;
|
|
833
1113
|
break;
|
|
834
|
-
case baEnum.
|
|
1114
|
+
case baEnum.PropertyIdentifier.OBJECT_IDENTIFIER:
|
|
835
1115
|
if(object.value[0] && object.value[0].value) values[objectId].objectID = object.value[0].value;
|
|
836
1116
|
break;
|
|
837
|
-
case baEnum.
|
|
1117
|
+
case baEnum.PropertyIdentifier.PROPERTY_LIST:
|
|
838
1118
|
if(object.value) values[objectId].propertyList = that.mapPropsToArray(object.value);
|
|
839
|
-
break;
|
|
1119
|
+
break;
|
|
1120
|
+
|
|
1121
|
+
case baEnum.PropertyIdentifier.SYSTEM_STATUS:
|
|
1122
|
+
if(object.value[0]){
|
|
1123
|
+
values[objectId].systemStatus = that.getPROP_SYSTEM_STATUS(object.value[0].value);
|
|
1124
|
+
}
|
|
1125
|
+
break;
|
|
1126
|
+
|
|
1127
|
+
case baEnum.PropertyIdentifier.MODIFICATION_DATE:
|
|
1128
|
+
if(object.value[0]) {
|
|
1129
|
+
values[objectId].modificationDate = object.value[0].value;
|
|
1130
|
+
}
|
|
1131
|
+
break;
|
|
1132
|
+
|
|
1133
|
+
case baEnum.PropertyIdentifier.PROGRAM_STATE:
|
|
1134
|
+
if(object.value[0]){
|
|
1135
|
+
values[objectId].programState = that.getPROP_PROGRAM_STATE(object.value[0].value);
|
|
1136
|
+
}
|
|
1137
|
+
break;
|
|
1138
|
+
|
|
1139
|
+
case baEnum.PropertyIdentifier.RECORD_COUNT:
|
|
1140
|
+
if(object.value[0] ) {
|
|
1141
|
+
values[objectId].recordCount = object.value[0].value;
|
|
1142
|
+
}
|
|
1143
|
+
break;
|
|
840
1144
|
}
|
|
841
1145
|
}
|
|
842
|
-
|
|
843
1146
|
if(pointPropertyIndex == successfulResult.values.length - 1 && objectIndex == pointProperty.values.length - 1 && i == fullObjects.length - 1) {
|
|
844
|
-
that.networkTree[
|
|
1147
|
+
that.networkTree[deviceKey] = values;
|
|
845
1148
|
resolve(that.networkTree);
|
|
846
1149
|
}
|
|
847
1150
|
});
|
|
848
1151
|
} catch(e) {
|
|
849
|
-
|
|
1152
|
+
that.logOut("issue resolving bacnet payload, see error: ", e);
|
|
850
1153
|
reject(e);
|
|
851
1154
|
}
|
|
852
1155
|
});
|
|
853
1156
|
} else {
|
|
854
1157
|
//error found in point property
|
|
855
1158
|
if(i == fullObjects.length - 1) {
|
|
856
|
-
that.networkTree[
|
|
1159
|
+
that.networkTree[deviceKey] = values;
|
|
857
1160
|
resolve(that.networkTree);
|
|
858
1161
|
}
|
|
859
1162
|
}
|
|
860
1163
|
}
|
|
861
|
-
reject("Unexpectedly found end of loop, line
|
|
1164
|
+
reject("Unexpectedly found end of loop, line 1170");
|
|
862
1165
|
});
|
|
863
1166
|
}
|
|
864
1167
|
|
|
@@ -870,6 +1173,104 @@ class BacnetClient extends EventEmitter {
|
|
|
870
1173
|
return uniquePropArray;
|
|
871
1174
|
}
|
|
872
1175
|
|
|
1176
|
+
getPROP_PROGRAM_STATE(value) {
|
|
1177
|
+
switch(value) {
|
|
1178
|
+
case 0:
|
|
1179
|
+
return "0 - Idle";
|
|
1180
|
+
case 1:
|
|
1181
|
+
return "1 - Loading";
|
|
1182
|
+
case 2:
|
|
1183
|
+
return "2 - Running";
|
|
1184
|
+
case 3:
|
|
1185
|
+
return "3 - Waiting";
|
|
1186
|
+
case 4:
|
|
1187
|
+
return "4 - Halted";
|
|
1188
|
+
case 5:
|
|
1189
|
+
return "5 - Unloading";
|
|
1190
|
+
default:
|
|
1191
|
+
return "";
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
getPROP_SYSTEM_STATUS(value) {
|
|
1196
|
+
switch(value) {
|
|
1197
|
+
case 0:
|
|
1198
|
+
return "0 - Operational";
|
|
1199
|
+
case 1:
|
|
1200
|
+
return "1 - Operational Readonly";
|
|
1201
|
+
case 2:
|
|
1202
|
+
return "2 - Download Required";
|
|
1203
|
+
case 3:
|
|
1204
|
+
return "3 - Download In Progress";
|
|
1205
|
+
case 4:
|
|
1206
|
+
return "4 - Non Operational";
|
|
1207
|
+
case 5:
|
|
1208
|
+
return "5 - Backup In Progress";
|
|
1209
|
+
default:
|
|
1210
|
+
return "";
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
getPointIcon(objectId) {
|
|
1215
|
+
switch(objectId) {
|
|
1216
|
+
case 0:
|
|
1217
|
+
//AI
|
|
1218
|
+
return "pi pi-tags";
|
|
1219
|
+
case 1:
|
|
1220
|
+
//AO
|
|
1221
|
+
return "pi pi-tags";
|
|
1222
|
+
case 2:
|
|
1223
|
+
//AV
|
|
1224
|
+
return "pi pi-tags";
|
|
1225
|
+
case 3:
|
|
1226
|
+
//BI
|
|
1227
|
+
return "pi pi-tags";
|
|
1228
|
+
case 4:
|
|
1229
|
+
//BO
|
|
1230
|
+
return "pi pi-tags";
|
|
1231
|
+
case 5:
|
|
1232
|
+
//BV
|
|
1233
|
+
return "pi pi-tags";
|
|
1234
|
+
case 8:
|
|
1235
|
+
//Device
|
|
1236
|
+
return "pi pi-box";
|
|
1237
|
+
case 13:
|
|
1238
|
+
//MI
|
|
1239
|
+
return "pi pi-tags";
|
|
1240
|
+
case 14:
|
|
1241
|
+
//MO
|
|
1242
|
+
return "pi pi-tags";
|
|
1243
|
+
case 19:
|
|
1244
|
+
//MV
|
|
1245
|
+
return "pi pi-tags";
|
|
1246
|
+
case 10:
|
|
1247
|
+
//File
|
|
1248
|
+
return "pi pi-file";
|
|
1249
|
+
case 16:
|
|
1250
|
+
//Program
|
|
1251
|
+
return "pi pi-database";
|
|
1252
|
+
case 20:
|
|
1253
|
+
//Trendlog
|
|
1254
|
+
return "pi pi-chart-line";
|
|
1255
|
+
case 15:
|
|
1256
|
+
//Notification Class
|
|
1257
|
+
return "pi pi-bell";
|
|
1258
|
+
case 56:
|
|
1259
|
+
return "pi pi-sitemap";
|
|
1260
|
+
case 178:
|
|
1261
|
+
return "pi pi-lock";
|
|
1262
|
+
case 20:
|
|
1263
|
+
return "pi pi-chart-line";
|
|
1264
|
+
case 17:
|
|
1265
|
+
return "pi pi-calendar";
|
|
1266
|
+
case 6:
|
|
1267
|
+
return "pi pi-calendar";
|
|
1268
|
+
default:
|
|
1269
|
+
//Return circle for all other types
|
|
1270
|
+
return "pi pi-tags";
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
|
|
873
1274
|
getObjectType(objectId) {
|
|
874
1275
|
switch(objectId) {
|
|
875
1276
|
case 0:
|
|
@@ -892,6 +1293,8 @@ class BacnetClient extends EventEmitter {
|
|
|
892
1293
|
return "MO";
|
|
893
1294
|
case 19:
|
|
894
1295
|
return "MV";
|
|
1296
|
+
case 40:
|
|
1297
|
+
return "CS";
|
|
895
1298
|
default:
|
|
896
1299
|
return "";
|
|
897
1300
|
}
|
|
@@ -935,6 +1338,20 @@ class BacnetClient extends EventEmitter {
|
|
|
935
1338
|
getStatusFlags(flags) {
|
|
936
1339
|
return flags.value[0].value;
|
|
937
1340
|
}
|
|
1341
|
+
|
|
1342
|
+
getDeviceIcon(isMstp, manualDiscoveryMode) {
|
|
1343
|
+
if(manualDiscoveryMode == true) {
|
|
1344
|
+
return "pi pi-exclamation-triangle"
|
|
1345
|
+
} else if(manualDiscoveryMode == false) {
|
|
1346
|
+
if(isMstp == true) {
|
|
1347
|
+
return "pi pi-share-alt"
|
|
1348
|
+
} else if(isMstp == false) {
|
|
1349
|
+
return "pi pi-server"
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
return "pi pi-server";
|
|
1354
|
+
};
|
|
938
1355
|
}
|
|
939
1356
|
|
|
940
1357
|
module.exports = { BacnetClient };
|