@bitpoolos/edge-bacnet 1.1.7 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/README.md +2 -2
  2. package/bacnet_client.js +331 -168
  3. package/bacnet_device.js +50 -16
  4. package/bacnet_gateway.html +119 -15
  5. package/bacnet_gateway.js +388 -395
  6. package/bacnet_read.html +32 -11
  7. package/bacnet_read.js +1 -1
  8. package/bacnet_server.js +86 -24
  9. package/common.js +26 -19
  10. package/examples/1-Discover-Read.json +1 -1
  11. package/examples/2-Discover-Write.json +1 -1
  12. package/examples/3-Discover-Read-Write.json +1 -1
  13. package/package.json +3 -3
  14. package/resources/{node-bacnet/LICENSE.md → node-bacstack-ts/LICENSE} +3 -4
  15. package/resources/node-bacstack-ts/README.md +75 -0
  16. package/resources/{node-bacnet → node-bacstack-ts/dist}/index.js +0 -2
  17. package/resources/node-bacstack-ts/dist/lib/apdu.js +193 -0
  18. package/resources/node-bacstack-ts/dist/lib/asn1.js +1660 -0
  19. package/resources/node-bacstack-ts/dist/lib/bvlc.js +47 -0
  20. package/resources/node-bacstack-ts/dist/lib/client.js +1454 -0
  21. package/resources/node-bacstack-ts/dist/lib/enum.js +2114 -0
  22. package/resources/node-bacstack-ts/dist/lib/npdu.js +112 -0
  23. package/resources/node-bacstack-ts/dist/lib/services/add-list-element.js +58 -0
  24. package/resources/node-bacstack-ts/dist/lib/services/alarm-acknowledge.js +93 -0
  25. package/resources/node-bacstack-ts/dist/lib/services/alarm-summary.js +42 -0
  26. package/resources/node-bacstack-ts/dist/lib/services/atomic-read-file.js +157 -0
  27. package/resources/node-bacstack-ts/dist/lib/services/atomic-write-file.js +136 -0
  28. package/resources/node-bacstack-ts/dist/lib/services/cov-notify.js +119 -0
  29. package/resources/node-bacstack-ts/dist/lib/services/create-object.js +104 -0
  30. package/resources/node-bacstack-ts/dist/lib/services/delete-object.js +21 -0
  31. package/resources/node-bacstack-ts/dist/lib/services/device-communication-control.js +46 -0
  32. package/resources/node-bacstack-ts/dist/lib/services/error.js +27 -0
  33. package/resources/node-bacstack-ts/dist/lib/services/event-information.js +100 -0
  34. package/resources/node-bacstack-ts/dist/lib/services/event-notify-data.js +219 -0
  35. package/resources/node-bacstack-ts/dist/lib/services/get-enrollment-summary.js +172 -0
  36. package/resources/node-bacstack-ts/dist/lib/services/get-event-information.js +135 -0
  37. package/resources/node-bacstack-ts/dist/lib/services/i-am-broadcast.js +59 -0
  38. package/resources/node-bacstack-ts/dist/lib/services/i-have-broadcast.js +34 -0
  39. package/resources/node-bacstack-ts/dist/lib/services/index.js +32 -0
  40. package/resources/node-bacstack-ts/dist/lib/services/life-safety-operation.js +40 -0
  41. package/resources/node-bacstack-ts/dist/lib/services/private-transfer.js +43 -0
  42. package/resources/node-bacstack-ts/dist/lib/services/read-property-multiple.js +44 -0
  43. package/resources/node-bacstack-ts/dist/lib/services/read-property.js +122 -0
  44. package/resources/node-bacstack-ts/dist/lib/services/read-range.js +201 -0
  45. package/resources/node-bacstack-ts/dist/lib/services/reinitialize-device.js +35 -0
  46. package/resources/node-bacstack-ts/dist/lib/services/subscribe-cov.js +55 -0
  47. package/resources/node-bacstack-ts/dist/lib/services/subscribe-property.js +93 -0
  48. package/resources/node-bacstack-ts/dist/lib/services/time-sync.js +31 -0
  49. package/resources/node-bacstack-ts/dist/lib/services/who-has.js +56 -0
  50. package/resources/node-bacstack-ts/dist/lib/services/who-is.js +45 -0
  51. package/resources/node-bacstack-ts/dist/lib/services/write-property-multiple.js +105 -0
  52. package/resources/node-bacstack-ts/dist/lib/services/write-property.js +90 -0
  53. package/resources/node-bacstack-ts/dist/lib/transport.js +49 -0
  54. package/resources/node-bacstack-ts/dist/lib/types.js +2 -0
  55. package/resources/node-bacstack-ts/package.json +94 -0
  56. package/resources/node-bacnet/CHANGELOG.md +0 -481
  57. package/resources/node-bacnet/README.md +0 -91
  58. package/resources/node-bacnet/docs/Client.html +0 -4422
  59. package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
  60. package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
  61. package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
  62. package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
  63. package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
  64. package/resources/node-bacnet/docs/bacnet.html +0 -7032
  65. package/resources/node-bacnet/docs/client.js.html +0 -1759
  66. package/resources/node-bacnet/docs/enum.js.html +0 -2530
  67. package/resources/node-bacnet/docs/global.html +0 -2068
  68. package/resources/node-bacnet/docs/images/mocha-logo.svg +0 -65
  69. package/resources/node-bacnet/docs/index.html +0 -283
  70. package/resources/node-bacnet/docs/scripts/collapse.js +0 -11
  71. package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +0 -4
  72. package/resources/node-bacnet/docs/scripts/linenumber.js +0 -26
  73. package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
  74. package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +0 -2
  75. package/resources/node-bacnet/docs/scripts/prettify/prettify.js +0 -28
  76. package/resources/node-bacnet/docs/scripts/search.js +0 -47
  77. package/resources/node-bacnet/docs/services_i-am.js.html +0 -157
  78. package/resources/node-bacnet/docs/services_time-sync.js.html +0 -118
  79. package/resources/node-bacnet/docs/services_who-is.js.html +0 -138
  80. package/resources/node-bacnet/docs/styles/jsdoc.css +0 -683
  81. package/resources/node-bacnet/docs/styles/prettify.css +0 -82
  82. package/resources/node-bacnet/examples/discover-devices.js +0 -66
  83. package/resources/node-bacnet/examples/read-device.js +0 -510
  84. package/resources/node-bacnet/examples/subscribe-cov.js +0 -75
  85. package/resources/node-bacnet/lib/apdu.js +0 -209
  86. package/resources/node-bacnet/lib/asn1.js +0 -1733
  87. package/resources/node-bacnet/lib/bvlc.js +0 -90
  88. package/resources/node-bacnet/lib/client.js +0 -1695
  89. package/resources/node-bacnet/lib/enum.js +0 -2463
  90. package/resources/node-bacnet/lib/npdu.js +0 -123
  91. package/resources/node-bacnet/lib/services/add-list-element.js +0 -64
  92. package/resources/node-bacnet/lib/services/alarm-acknowledge.js +0 -90
  93. package/resources/node-bacnet/lib/services/alarm-summary.js +0 -42
  94. package/resources/node-bacnet/lib/services/atomic-read-file.js +0 -162
  95. package/resources/node-bacnet/lib/services/atomic-write-file.js +0 -138
  96. package/resources/node-bacnet/lib/services/cov-notify.js +0 -126
  97. package/resources/node-bacnet/lib/services/create-object.js +0 -106
  98. package/resources/node-bacnet/lib/services/delete-object.js +0 -23
  99. package/resources/node-bacnet/lib/services/device-communication-control.js +0 -48
  100. package/resources/node-bacnet/lib/services/error.js +0 -33
  101. package/resources/node-bacnet/lib/services/event-information.js +0 -99
  102. package/resources/node-bacnet/lib/services/event-notify-data.js +0 -229
  103. package/resources/node-bacnet/lib/services/get-enrollment-summary.js +0 -178
  104. package/resources/node-bacnet/lib/services/get-event-information.js +0 -144
  105. package/resources/node-bacnet/lib/services/i-am.js +0 -90
  106. package/resources/node-bacnet/lib/services/i-have.js +0 -34
  107. package/resources/node-bacnet/lib/services/index.js +0 -34
  108. package/resources/node-bacnet/lib/services/life-safety-operation.js +0 -40
  109. package/resources/node-bacnet/lib/services/private-transfer.js +0 -43
  110. package/resources/node-bacnet/lib/services/read-property-multiple.js +0 -50
  111. package/resources/node-bacnet/lib/services/read-property.js +0 -130
  112. package/resources/node-bacnet/lib/services/read-range.js +0 -201
  113. package/resources/node-bacnet/lib/services/register-foreign-device.js +0 -18
  114. package/resources/node-bacnet/lib/services/reinitialize-device.js +0 -37
  115. package/resources/node-bacnet/lib/services/subscribe-cov.js +0 -57
  116. package/resources/node-bacnet/lib/services/subscribe-property.js +0 -97
  117. package/resources/node-bacnet/lib/services/time-sync.js +0 -51
  118. package/resources/node-bacnet/lib/services/who-has.js +0 -54
  119. package/resources/node-bacnet/lib/services/who-is.js +0 -71
  120. package/resources/node-bacnet/lib/services/write-property-multiple.js +0 -117
  121. package/resources/node-bacnet/lib/services/write-property.js +0 -94
  122. package/resources/node-bacnet/lib/transport.js +0 -82
  123. package/resources/node-bacnet/package.json +0 -92
@@ -0,0 +1,1454 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Client = void 0;
4
+ // Util Modules
5
+ const events_1 = require("events");
6
+ const debug_1 = require("debug");
7
+ const debug = (0, debug_1.default)('bacstack');
8
+ // Local Modules
9
+ const transport_1 = require("./transport");
10
+ const baServices = require("./services");
11
+ const baAsn1 = require("./asn1");
12
+ const baApdu = require("./apdu");
13
+ const baNpdu = require("./npdu");
14
+ const baBvlc = require("./bvlc");
15
+ const baEnum = require("./enum");
16
+ const DEFAULT_HOP_COUNT = 0xFF;
17
+ const BVLC_HEADER_LENGTH = 4;
18
+ /**
19
+ * To be able to communicate to BACNET devices, you have to initialize a new bacstack instance.
20
+ * @class bacstack
21
+ * @param {object=} this._settings - The options object used for parameterizing the bacstack.
22
+ * @param {number=} [options.port=47808] - BACNET communication port for listening and sending.
23
+ * @param {string=} options.interface - Specific BACNET communication interface if different from primary one.
24
+ * @param {string=} [options.broadcastAddress=255.255.255.255] - The address used for broadcast messages.
25
+ * @param {number=} [options.apduTimeout=3000] - The timeout in milliseconds until a transaction should be interpreted as error.
26
+ * @example
27
+ * const bacnet = require('bacstack');
28
+ *
29
+ * const client = new bacnet({
30
+ * port: 47809, // Use BAC1 as communication port
31
+ * interface: '192.168.251.10', // Listen on a specific interface
32
+ * broadcastAddress: '192.168.251.255', // Use the subnet broadcast address
33
+ * apduTimeout: 6000 // Wait twice as long for response
34
+ * });
35
+ */
36
+ class Client extends events_1.EventEmitter {
37
+ constructor(options) {
38
+ super();
39
+ this._invokeCounter = 1;
40
+ this._invokeStore = {};
41
+ this._lastSequenceNumber = 0;
42
+ this._segmentStore = [];
43
+ options = options || {};
44
+ this._settings = {
45
+ port: options.port || 47808,
46
+ interface: options.interface,
47
+ transport: options.transport,
48
+ broadcastAddress: options.broadcastAddress || '255.255.255.255',
49
+ apduTimeout: options.apduTimeout || 3000
50
+ };
51
+ this._transport = this._settings.transport || new transport_1.Transport({
52
+ port: this._settings.port,
53
+ interface: this._settings.interface,
54
+ broadcastAddress: this._settings.broadcastAddress
55
+ });
56
+ // Setup code
57
+ this._transport.on('message', this._receiveData.bind(this));
58
+ this._transport.on('error', this._receiveError.bind(this));
59
+ this._transport.open();
60
+ }
61
+ // Helper utils
62
+ _getInvokeId() {
63
+ const id = this._invokeCounter++;
64
+ if (id >= 256)
65
+ this._invokeCounter = 1;
66
+ return id - 1;
67
+ }
68
+ _invokeCallback(id, err, result) {
69
+ const callback = this._invokeStore[id];
70
+ if (callback)
71
+ return callback(err, result);
72
+ debug('InvokeId ', id, ' not found -> drop package');
73
+ }
74
+ _addCallback(id, callback) {
75
+ const timeout = setTimeout(() => {
76
+ delete this._invokeStore[id];
77
+ callback(new Error('ERR_TIMEOUT'));
78
+ }, this._settings.apduTimeout);
79
+ this._invokeStore[id] = (err, data) => {
80
+ clearTimeout(timeout);
81
+ delete this._invokeStore[id];
82
+ callback(err, data);
83
+ };
84
+ }
85
+ _getBuffer() {
86
+ return {
87
+ buffer: Buffer.alloc(this._transport.getMaxPayload()),
88
+ offset: BVLC_HEADER_LENGTH
89
+ };
90
+ }
91
+ // Service Handlers
92
+ _processError(invokeId, buffer, offset, length) {
93
+ try {
94
+ const result = baServices.error.decode(buffer, offset);
95
+ if (!result)
96
+ return debug('Couldn`t decode Error');
97
+ this._invokeCallback(invokeId, new Error('BacnetError - Class:' + result.class + ' - Code:' + result.code));
98
+ } catch(e){
99
+ }
100
+ }
101
+ _processAbort(invokeId, reason) {
102
+ this._invokeCallback(invokeId, new Error('BacnetAbort - Reason:' + reason));
103
+ }
104
+ _segmentAckResponse(receiver, negative, server, originalInvokeId, sequencenumber, actualWindowSize) {
105
+ const buffer = this._getBuffer();
106
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
107
+ baApdu.encodeSegmentAck(buffer, baEnum.PduTypes.SEGMENT_ACK | (negative ? baEnum.PduSegAckBits.NEGATIVE_ACK : 0) | (server ? baEnum.PduSegAckBits.SERVER : 0), originalInvokeId, sequencenumber, actualWindowSize);
108
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
109
+ var sendAddress = typeof (receiver) != 'string' ? receiver.ip : receiver;
110
+ this.sendBvlc(sendAddress, buffer);
111
+ }
112
+ _performDefaultSegmentHandling(sender, adr, type, service, invokeId, maxSegments, maxApdu, sequencenumber, first, moreFollows, buffer, offset, length) {
113
+ if (first) {
114
+ this._segmentStore = [];
115
+ type &= ~baEnum.PduConReqBits.SEGMENTED_MESSAGE;
116
+ let apduHeaderLen = 3;
117
+ if ((type & baEnum.PDU_TYPE_MASK) === baEnum.PduTypes.CONFIRMED_REQUEST) {
118
+ apduHeaderLen = 4;
119
+ }
120
+ const apdubuffer = this._getBuffer();
121
+ apdubuffer.offset = 0;
122
+ buffer.copy(apdubuffer.buffer, apduHeaderLen, offset, offset + length);
123
+ if ((type & baEnum.PDU_TYPE_MASK) === baEnum.PduTypes.CONFIRMED_REQUEST) {
124
+ baApdu.encodeConfirmedServiceRequest(apdubuffer, type, service, maxSegments, maxApdu, invokeId, 0, 0);
125
+ }
126
+ else {
127
+ baApdu.encodeComplexAck(apdubuffer, type, service, invokeId, 0, 0);
128
+ }
129
+ this._segmentStore.push(apdubuffer.buffer.slice(0, length + apduHeaderLen));
130
+ }
131
+ else {
132
+ this._segmentStore.push(buffer.slice(offset, offset + length));
133
+ }
134
+ if (!moreFollows) {
135
+ const apduBuffer = Buffer.concat(this._segmentStore);
136
+ this._segmentStore = [];
137
+ type &= ~baEnum.PduConReqBits.SEGMENTED_MESSAGE;
138
+ this._handlePdu(adr, type, apduBuffer, 0, apduBuffer.length);
139
+ }
140
+ }
141
+ _handleSequenceTimeout(invokeId) {
142
+ if (this._sequenceTimeout) {
143
+ clearInterval(this._sequenceTimeout);
144
+ }
145
+ this._sequenceTimeout = setTimeout(() => { this._lastSequenceNumber = 0 }, this._settings.apduTimeout);
146
+ }
147
+
148
+ _processSegment(receiver, type, service, invokeId, maxSegments, maxApdu, server, sequencenumber, proposedWindowNumber, buffer, offset, length) {
149
+ let first = false;
150
+ if (sequencenumber === 0 && this._lastSequenceNumber === 0) {
151
+ first = true;
152
+ } else {
153
+ if (sequencenumber !== this._lastSequenceNumber + 1) {
154
+ return this._segmentAckResponse(receiver, true, server, invokeId, this._lastSequenceNumber, proposedWindowNumber);
155
+ }
156
+ }
157
+ this._lastSequenceNumber = sequencenumber;
158
+ this._handleSequenceTimeout();
159
+ const moreFollows = type & baEnum.PduConReqBits.MORE_FOLLOWS;
160
+ if (!moreFollows) {
161
+ this._lastSequenceNumber = 0;
162
+ }
163
+ if ((sequencenumber % proposedWindowNumber) === 0 || !moreFollows) {
164
+ this._segmentAckResponse(receiver, false, server, invokeId, sequencenumber, proposedWindowNumber);
165
+ }
166
+ this._performDefaultSegmentHandling(this, receiver, type, service, invokeId, maxSegments, maxApdu, sequencenumber, first, moreFollows, buffer, offset, length);
167
+ }
168
+
169
+ _processConfirmedServiceRequest(address, type, service, maxSegments, maxApdu, invokeId, buffer, offset, length, srcAddress, destAddress) {
170
+ let result;
171
+ debug('Handle this._processConfirmedServiceRequest');
172
+ if (service === baEnum.ConfirmedServiceChoice.READ_PROPERTY) {
173
+ result = baServices.readProperty.decode(buffer, offset, length);
174
+ if (!result) return debug('Received invalid readProperty message');
175
+ this.emit('readProperty', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress, destAddress: destAddress });
176
+ } else if (service === baEnum.ConfirmedServiceChoice.WRITE_PROPERTY) {
177
+ result = baServices.writeProperty.decode(buffer, offset, length);
178
+ if (!result) return debug('Received invalid writeProperty message');
179
+ this.emit('writeProperty', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress, destAddress: destAddress });
180
+ } else if (service === baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE) {
181
+ result = baServices.readPropertyMultiple.decode(buffer, offset, length);
182
+ if (!result) return debug('Received invalid readPropertyMultiple message');
183
+ this.emit('readPropertyMultiple', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress, destAddress: destAddress });
184
+ } else if (service === baEnum.ConfirmedServiceChoice.WRITE_PROPERTY_MULTIPLE) {
185
+ result = baServices.writePropertyMultiple.decode(buffer, offset, length);
186
+ if (!result) return debug('Received invalid writePropertyMultiple message');
187
+ this.emit('writePropertyMultiple', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress, destAddress: destAddress });
188
+ } else if (service === baEnum.ConfirmedServiceChoice.CONFIRMED_COV_NOTIFICATION) {
189
+ result = baServices.covNotify.decode(buffer, offset, length);
190
+ if (!result) return debug('Received invalid covNotify message');
191
+ this.emit('covNotify', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
192
+ } else if (service === baEnum.ConfirmedServiceChoice.ATOMIC_WRITE_FILE) {
193
+ result = baServices.atomicWriteFile.decode(buffer, offset, length);
194
+ if (!result) return debug('Received invalid atomicWriteFile message');
195
+ this.emit('atomicWriteFile', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
196
+ } else if (service === baEnum.ConfirmedServiceChoice.ATOMIC_READ_FILE) {
197
+ result = baServices.atomicReadFile.decode(buffer, offset, length);
198
+ if (!result) return debug('Received invalid atomicReadFile message');
199
+ this.emit('atomicReadFile', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
200
+ } else if (service === baEnum.ConfirmedServiceChoice.SUBSCRIBE_COV) {
201
+ result = baServices.subscribeCov.decode(buffer, offset, length);
202
+ if (!result) return debug('Received invalid subscribeCOV message');
203
+ this.emit('subscribeCOV', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
204
+ } else if (service === baEnum.ConfirmedServiceChoice.SUBSCRIBE_COV_PROPERTY) {
205
+ result = baServices.subscribeProperty.decode(buffer, offset, length);
206
+ if (!result) return debug('Received invalid subscribeProperty message');
207
+ this.emit('subscribeProperty', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
208
+ } else if (service === baEnum.ConfirmedServiceChoice.DEVICE_COMMUNICATION_CONTROL) {
209
+ result = baServices.deviceCommunicationControl.decode(buffer, offset, length);
210
+ if (!result) return debug('Received invalid deviceCommunicationControl message');
211
+ this.emit('deviceCommunicationControl', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
212
+ } else if (service === baEnum.ConfirmedServiceChoice.REINITIALIZE_DEVICE) {
213
+ result = baServices.reinitializeDevice.decode(buffer, offset, length);
214
+ if (!result) return debug('Received invalid reinitializeDevice message');
215
+ this.emit('reinitializeDevice', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
216
+ } else if (service === baEnum.ConfirmedServiceChoice.CONFIRMED_EVENT_NOTIFICATION) {
217
+ result = baServices.eventNotifyData.decode(buffer, offset, length);
218
+ if (!result) return debug('Received invalid eventNotifyData message');
219
+ this.emit('eventNotifyData', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
220
+ } else if (service === baEnum.ConfirmedServiceChoice.READ_RANGE) {
221
+ result = baServices.readRange.decode(buffer, offset, length);
222
+ if (!result) return debug('Received invalid readRange message');
223
+ this.emit('readRange', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
224
+ } else if (service === baEnum.ConfirmedServiceChoice.CREATE_OBJECT) {
225
+ result = baServices.createObject.decode(buffer, offset, length);
226
+ if (!result) return debug('Received invalid createObject message');
227
+ this.emit('createObject', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
228
+ } else if (service === baEnum.ConfirmedServiceChoice.DELETE_OBJECT) {
229
+ result = baServices.deleteObject.decode(buffer, offset, length);
230
+ if (!result) return debug('Received invalid deleteObject message');
231
+ this.emit('deleteObject', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
232
+ } else if (service === baEnum.ConfirmedServiceChoice.ACKNOWLEDGE_ALARM) {
233
+ result = baServices.alarmAcknowledge.decode(buffer, offset, length);
234
+ if (!result) return debug('Received invalid alarmAcknowledge message');
235
+ this.emit('alarmAcknowledge', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
236
+ } else if (service === baEnum.ConfirmedServiceChoice.GET_ALARM_SUMMARY) {
237
+ this.emit('getAlarmSummary', { address: address, invokeId: invokeId });
238
+ } else if (service === baEnum.ConfirmedServiceChoice.GET_ENROLLMENT_SUMMARY) {
239
+ result = baServices.getEnrollmentSummary.decode(buffer, offset, length);
240
+ if (!result) return debug('Received invalid getEntrollmentSummary message');
241
+ this.emit('getEntrollmentSummary', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
242
+ } else if (service === baEnum.ConfirmedServiceChoice.GET_EVENT_INFORMATION) {
243
+ result = baServices.getEventInformation.decode(buffer, offset, length);
244
+ if (!result) return debug('Received invalid getEventInformation message');
245
+ this.emit('getEventInformation', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
246
+ } else if (service === baEnum.ConfirmedServiceChoice.LIFE_SAFETY_OPERATION) {
247
+ result = baServices.lifeSafetyOperation.decode(buffer, offset, length);
248
+ if (!result) return debug('Received invalid lifeSafetyOperation message');
249
+ this.emit('lifeSafetyOperation', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
250
+ } else if (service === baEnum.ConfirmedServiceChoice.ADD_LIST_ELEMENT) {
251
+ result = baServices.addListElement.decode(buffer, offset, length);
252
+ if (!result) return debug('Received invalid addListElement message');
253
+ this.emit('addListElement', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
254
+ } else if (service === baEnum.ConfirmedServiceChoice.REMOVE_LIST_ELEMENT) {
255
+ result = baServices.addListElement.decode(buffer, offset, length);
256
+ if (!result) return debug('Received invalid removeListElement message');
257
+ this.emit('removeListElement', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
258
+ } else if (service === baEnum.ConfirmedServiceChoice.CONFIRMED_PRIVATE_TRANSFER) {
259
+ result = baServices.privateTransfer.decode(buffer, offset, length);
260
+ if (!result) return debug('Received invalid privateTransfer message');
261
+ this.emit('privateTransfer', { address: address, invokeId: invokeId, request: result, srcAddress: srcAddress });
262
+ } else {
263
+ debug('Received unsupported confirmed service request');
264
+ }
265
+ }
266
+
267
+ _processUnconfirmedServiceRequest(address, type, service, buffer, offset, length, addressObject) {
268
+ let result;
269
+ debug('Handle this._processUnconfirmedServiceRequest');
270
+ if (service === baEnum.UnconfirmedServiceChoice.I_AM) {
271
+ result = baServices.iAmBroadcast.decode(buffer, offset);
272
+ if (!result) return debug('Received invalid iAm message');
273
+
274
+ /**
275
+ * The iAm event represents the response to a whoIs request to detect all devices in a BACNET network.
276
+ * @event bacstack.iAm
277
+ * @param {object} device - An object representing the detected device.
278
+ * @param {string} device.address - The IP address of the detected device.
279
+ * @param {number} device.deviceId - The BACNET device-id of the detected device.
280
+ * @param {number} device.maxApdu - The max APDU size the detected device is supporting.
281
+ * @param {number} device.segmentation - The type of segmentation the detected device is supporting.
282
+ * @param {number} device.vendorId - The BACNET vendor-id of the detected device.
283
+ * @example
284
+ * const bacnet = require('bacstack');
285
+ * const client = new bacnet();
286
+ *
287
+ * client.on('iAm', (device) => {
288
+ * console.log('address: ', device.address, ' - deviceId: ', device.deviceId, ' - maxApdu: ', device.maxApdu, ' - segmentation: ', device.segmentation, ' - vendorId: ', device.vendorId);
289
+ * });
290
+ */
291
+ var net = typeof (addressObject) == 'object' ? addressObject.net : undefined;
292
+ var adr = typeof (addressObject) == 'object' ? addressObject.adr : undefined;
293
+ this.emit('iAm', { address: address, deviceId: result.deviceId, maxApdu: result.maxApdu, segmentation: result.segmentation, vendorId: result.vendorId, 'net': net, 'adr': adr });
294
+ } else if (service === baEnum.UnconfirmedServiceChoice.WHO_IS) {
295
+ result = baServices.whoIs.decode(buffer, offset, length);
296
+ if (!result) return debug('Received invalid WhoIs message');
297
+
298
+ /**
299
+ * The whoIs event represents the request for an IAm reponse to detect all devices in a BACNET network.
300
+ * @event bacstack.whoIs
301
+ * @param {object} request - An object representing the received request.
302
+ * @param {string} request.address - The IP address of the device sending the request.
303
+ * @param {number=} request.lowLimit - The lower limit of the BACNET device-id.
304
+ * @param {number=} request.highLimit - The higher limit of the BACNET device-id.
305
+ * @example
306
+ * const bacnet = require('bacstack');
307
+ * const client = new bacnet();
308
+ *
309
+ * client.on('whoIs', (request) => {
310
+ * console.log('address: ', device.address, ' - lowLimit: ', device.lowLimit, ' - highLimit: ', device.highLimit);
311
+ * });
312
+ */
313
+ this.emit('whoIs', { address: address, lowLimit: result.lowLimit, highLimit: result.highLimit });
314
+ } else if (service === baEnum.UnconfirmedServiceChoice.WHO_HAS) {
315
+ result = baServices.whoHas.decode(buffer, offset, length);
316
+ if (!result) return debug('Received invalid WhoHas message');
317
+ this.emit('whoHas', { address: address, lowLimit: result.lowLimit, highLimit: result.highLimit, objectId: result.objectId, objectName: result.objectName });
318
+ } else if (service === baEnum.UnconfirmedServiceChoice.UNCONFIRMED_COV_NOTIFICATION) {
319
+ result = baServices.covNotify.decode(buffer, offset, length);
320
+ if (!result) return debug('Received invalid covNotifyUnconfirmed message');
321
+ this.emit('covNotifyUnconfirmed', { address: address, request: result });
322
+ } else if (service === baEnum.UnconfirmedServiceChoice.TIME_SYNCHRONIZATION) {
323
+ result = baServices.timeSync.decode(buffer, offset, length);
324
+ if (!result) return debug('Received invalid TimeSync message');
325
+
326
+ /**
327
+ * The timeSync event represents the request to synchronize the local time to the received time.
328
+ * @event bacstack.timeSync
329
+ * @param {object} request - An object representing the received request.
330
+ * @param {string} request.address - The IP address of the device sending the request.
331
+ * @param {date} request.dateTime - The time to be synchronized to.
332
+ * @example
333
+ * const bacnet = require('bacstack');
334
+ * const client = new bacnet();
335
+ *
336
+ * client.on('timeSync', (request) => {
337
+ * console.log('address: ', device.address, ' - dateTime: ', device.dateTime);
338
+ * });
339
+ */
340
+ this.emit('timeSync', { address: address, dateTime: result.dateTime });
341
+ } else if (service === baEnum.UnconfirmedServiceChoice.UTC_TIME_SYNCHRONIZATION) {
342
+ result = baServices.timeSync.decode(buffer, offset, length);
343
+ if (!result) return debug('Received invalid TimeSyncUTC message');
344
+
345
+ /**
346
+ * The timeSyncUTC event represents the request to synchronize the local time to the received UTC time.
347
+ * @event bacstack.timeSyncUTC
348
+ * @param {object} request - An object representing the received request.
349
+ * @param {string} request.address - The IP address of the device sending the request.
350
+ * @param {date} request.dateTime - The time to be synchronized to.
351
+ * @example
352
+ * const bacnet = require('bacstack');
353
+ * const client = new bacnet();
354
+ *
355
+ * client.on('timeSyncUTC', (request) => {
356
+ * console.log('address: ', device.address, ' - dateTime: ', device.dateTime);
357
+ * });
358
+ */
359
+ this.emit('timeSyncUTC', { address: address, dateTime: result.dateTime });
360
+ } else if (service === baEnum.UnconfirmedServiceChoice.UNCONFIRMED_EVENT_NOTIFICATION) {
361
+ result = baServices.eventNotifyData.decode(buffer, offset, length);
362
+ if (!result) return debug('Received invalid EventNotify message');
363
+ this.emit('eventNotify', { address: address, eventData: result.eventData });
364
+ } else if (service === baEnum.UnconfirmedServiceChoice.I_HAVE) {
365
+ result = baServices.iHaveBroadcast.decode(buffer, offset, length);
366
+ if (!result) return debug('Received invalid ihaveBroadcast message');
367
+ this.emit('ihaveBroadcast', { address: address, eventData: result.eventData });
368
+ } else if (service === baEnum.UnconfirmedServiceChoice.UNCONFIRMED_PRIVATE_TRANSFER) {
369
+ result = baServices.privateTransfer.decode(buffer, offset, length);
370
+ if (!result) return debug('Received invalid privateTransfer message');
371
+ this.emit('privateTransfer', { address: address, eventData: result.eventData });
372
+ } else {
373
+ debug('Received unsupported unconfirmed service request');
374
+ }
375
+ }
376
+
377
+ _handlePdu(address, type, buffer, offset, length, addressObject, destAddressObject) {
378
+ let result;
379
+ // Handle different PDU types
380
+ switch (type & baEnum.PDU_TYPE_MASK) {
381
+ case baEnum.PduTypes.UNCONFIRMED_REQUEST:
382
+ result = baApdu.decodeUnconfirmedServiceRequest(buffer, offset);
383
+ this._processUnconfirmedServiceRequest(address, result.type, result.service, buffer, offset + result.len, length - result.len, addressObject);
384
+ break;
385
+ case baEnum.PduTypes.SIMPLE_ACK:
386
+ result = baApdu.decodeSimpleAck(buffer, offset);
387
+ offset += result.len;
388
+ length -= result.len;
389
+ this._invokeCallback(result.invokeId, null, { result: result, buffer: buffer, offset: offset + result.len, length: length - result.len });
390
+ break;
391
+ case baEnum.PduTypes.COMPLEX_ACK:
392
+ result = baApdu.decodeComplexAck(buffer, offset);
393
+ if ((type & baEnum.PduConReqBits.SEGMENTED_MESSAGE) === 0) {
394
+ this._invokeCallback(result.invokeId, null, { result: result, buffer: buffer, offset: offset + result.len, length: length - result.len });
395
+ } else {
396
+ this._processSegment(addressObject, result.type, result.service, result.invokeId, baEnum.MaxSegmentsAccepted.SEGMENTS_0, baEnum.MaxApduLengthAccepted.OCTETS_50, false, result.sequencenumber, result.proposedWindowNumber, buffer, offset + result.len, length - result.len);
397
+ }
398
+ break;
399
+ case baEnum.PduTypes.SEGMENT_ACK:
400
+ result = baApdu.decodeSegmentAck(buffer, offset);
401
+ //m_last_segment_ack.Set(address, result.originalInvokeId, result.sequencenumber, result.actualWindowSize);
402
+ //this._processSegmentAck(address, result.type, result.originalInvokeId, result.sequencenumber, result.actualWindowSize, buffer, offset + result.len, length - result.len);
403
+ break;
404
+ case baEnum.PduTypes.ERROR:
405
+ result = baApdu.decodeError(buffer, offset);
406
+ this._processError(result.invokeId, buffer, offset + result.len, length - result.len);
407
+ break;
408
+ case baEnum.PduTypes.REJECT:
409
+ case baEnum.PduTypes.ABORT:
410
+ result = baApdu.decodeAbort(buffer, offset);
411
+ this._processAbort(result.invokeId, result.reason);
412
+ break;
413
+ case baEnum.PduTypes.CONFIRMED_REQUEST:
414
+ result = baApdu.decodeConfirmedServiceRequest(buffer, offset);
415
+ if ((type & baEnum.PduConReqBits.SEGMENTED_MESSAGE) === 0) {
416
+ this._processConfirmedServiceRequest(address, result.type, result.service, result.maxSegments, result.maxApdu, result.invokeId, buffer, offset + result.len, length - result.len, addressObject, destAddressObject);
417
+ } else {
418
+ this._processSegment(address, result.type, result.service, result.invokeId, result.maxSegments, result.maxApdu, true, result.sequencenumber, result.proposedWindowNumber, buffer, offset + result.len, length - result.len);
419
+ }
420
+ break;
421
+ default:
422
+ debug('Received unknown PDU type -> Drop package');
423
+ break;
424
+ }
425
+ }
426
+ _handleNpdu(buffer, offset, msgLength, remoteAddress) {
427
+ // Check data length
428
+ if (msgLength <= 0) return debug('No NPDU data -> Drop package');
429
+ // Parse baNpdu header
430
+ const result = baNpdu.decode(buffer, offset);
431
+ var addressObject, destAddress;
432
+ // @todo a MSTP Dest & Source could occur. this case is not handled.
433
+ if (typeof (result.source) != 'undefined') {
434
+ addressObject = result.source;
435
+ addressObject.ip = remoteAddress;
436
+ } else {
437
+ addressObject = remoteAddress;
438
+ }
439
+
440
+ if (typeof (result.destination) != 'undefined') {
441
+ destAddress = result.destination;
442
+ destAddress.ip = remoteAddress;
443
+ } else {
444
+ destAddress = remoteAddress;
445
+ }
446
+
447
+ if (!result) return debug('Received invalid NPDU header -> Drop package');
448
+ if (result.funct & baEnum.NpduControlBits.NETWORK_LAYER_MESSAGE) {
449
+ return debug('Received network layer message -> Drop package');
450
+ }
451
+ offset += result.len;
452
+ msgLength -= result.len;
453
+ if (msgLength <= 0) return debug('No APDU data -> Drop package');
454
+ const apduType = baApdu.getDecodedType(buffer, offset);
455
+ this._handlePdu(remoteAddress, apduType, buffer, offset, msgLength, addressObject, destAddress);
456
+ }
457
+ _receiveData(buffer, remoteAddress) {
458
+ // Check data length
459
+ if (buffer.length < baEnum.BVLC_HEADER_LENGTH)
460
+ return debug('Received invalid data -> Drop package');
461
+ // Parse BVLC header
462
+ const result = baBvlc.decode(buffer, 0);
463
+ if (!result)
464
+ return debug('Received invalid BVLC header -> Drop package');
465
+ // Check BVLC function
466
+ if (result.func === baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU || result.func === baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU || result.func === baEnum.BvlcResultPurpose.FORWARDED_NPDU) {
467
+ this._handleNpdu(buffer, result.len, buffer.length - result.len, remoteAddress);
468
+ }
469
+ else {
470
+ debug('Received unknown BVLC function -> Drop package');
471
+ }
472
+ }
473
+ _receiveError(err) {
474
+ /**
475
+ * @event bacstack.error
476
+ * @param {error} err - The error object thrown by the underlying transport layer.
477
+ * @example
478
+ * const bacnet = require('bacstack');
479
+ * const client = new bacnet();
480
+ *
481
+ * client.on('error', (err) => {
482
+ * console.log('Error occurred: ', err);
483
+ * client.close();
484
+ * });
485
+ */
486
+ this.emit('error', err);
487
+ }
488
+ /**
489
+ * The whoIs command discovers all BACNET devices in a network.
490
+ * @function bacstack.whoIs
491
+ * @param {object=} options
492
+ * @param {number=} options.lowLimit - Minimal device instance number to search for.
493
+ * @param {number=} options.highLimit - Maximal device instance number to search for.
494
+ * @param {string=} options.address - Unicast address if command should address a device directly.
495
+ * @fires bacstack.iAm
496
+ * @example
497
+ * const bacnet = require('bacstack');
498
+ * const client = new bacnet();
499
+ *
500
+ * client.whoIs();
501
+
502
+ whoIs(options) {
503
+ options = options || {};
504
+ const settings = {
505
+ lowLimit: options.lowLimit,
506
+ highLimit: options.highLimit,
507
+ address: options.address || this._transport.getBroadcastAddress()
508
+ };
509
+ const buffer = this._getBuffer();
510
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, this._settings.address, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
511
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.WHO_IS);
512
+ baServices.whoIs.encode(buffer, settings.lowLimit, settings.highLimit);
513
+ const npduType = (this._settings.address !== this._transport.getBroadcastAddress()) ? baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU : baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU;
514
+ baBvlc.encode(buffer.buffer, npduType, buffer.offset);
515
+ this._transport.send(buffer.buffer, buffer.offset, settings.address);
516
+ }
517
+ */
518
+ whoIs(receiver, options) {
519
+ if (!options) {
520
+ if (
521
+ receiver &&
522
+ typeof receiver === 'object' &&
523
+ receiver.address === undefined &&
524
+ receiver.forwardedFrom === undefined &&
525
+ (receiver.lowLimit !== undefined || receiver.highLimit !== undefined)
526
+ ) {
527
+ // receiver seems to be an options object
528
+ options = receiver;
529
+ receiver = undefined;
530
+ }
531
+ }
532
+ options = options || {};
533
+
534
+ const settings = {
535
+ lowLimit: options.lowLimit,
536
+ highLimit: options.highLimit,
537
+ };
538
+ const buffer = this._getBuffer(receiver && receiver.forwardedFrom);
539
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
540
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.WHO_IS);
541
+ baServices.whoIs.encode(buffer, settings.lowLimit, settings.highLimit);
542
+ this.sendBvlc(receiver, buffer);
543
+ }
544
+ /**
545
+ * The timeSync command sets the time of a target device.
546
+ * @function bacstack.timeSync
547
+ * @param {string} address - IP address of the target device.
548
+ * @param {date} dateTime - The date and time to set on the target device.
549
+ * @example
550
+ * const bacnet = require('bacstack');
551
+ * const client = new bacnet();
552
+ *
553
+ * client.timeSync('192.168.1.43', new Date());
554
+ */
555
+ timeSync(address, dateTime) {
556
+ const buffer = this._getBuffer();
557
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, address);
558
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.TIME_SYNCHRONIZATION);
559
+ baServices.timeSync.encode(buffer, dateTime);
560
+ const npduType = (address !== this._transport.getBroadcastAddress()) ? baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU : baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU;
561
+ //baBvlc.encode(buffer.buffer, npduType, buffer.offset);
562
+ this.sendBvlc(address, buffer);
563
+ }
564
+ /**
565
+ * The timeSyncUTC command sets the UTC time of a target device.
566
+ * @function bacstack.timeSyncUTC
567
+ * @param {string} address - IP address of the target device.
568
+ * @param {date} dateTime - The date and time to set on the target device.
569
+ * @example
570
+ * const bacnet = require('bacstack');
571
+ * const client = new bacnet();
572
+ *
573
+ * client.timeSyncUTC('192.168.1.43', new Date());
574
+ */
575
+ timeSyncUTC(address, dateTime) {
576
+ const buffer = this._getBuffer();
577
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, address);
578
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.UTC_TIME_SYNCHRONIZATION);
579
+ baServices.timeSync.encode(buffer, dateTime);
580
+ const npduType = (address !== this._transport.getBroadcastAddress()) ? baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU : baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU;
581
+ //baBvlc.encode(buffer.buffer, npduType, buffer.offset);
582
+ this.sendBvlc(address, buffer);
583
+ }
584
+ /**
585
+ * The readProperty command reads a single property of an object from a device.
586
+ * @function bacstack.readProperty
587
+ * @param {string} address - IP address of the target device.
588
+ * @param {object} objectId - The BACNET object ID to read.
589
+ * @param {number} objectId.type - The BACNET object type to read.
590
+ * @param {number} objectId.instance - The BACNET object instance to read.
591
+ * @param {number} propertyId - The BACNET property id in the specified object to read.
592
+ * @param {object=} options
593
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
594
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
595
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
596
+ * @param {number=} options.arrayIndex - The array index of the property to be read.
597
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
598
+ * @example
599
+ * const bacnet = require('bacstack');
600
+ * const client = new bacnet();
601
+ *
602
+ * client.readProperty('192.168.1.43', {type: 8, instance: 44301}, 28, (err, value) => {
603
+ * console.log('value: ', value);
604
+ * });
605
+ */
606
+ readProperty(address, objectId, propertyId, options, next) {
607
+ next = next || options;
608
+ const settings = {
609
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
610
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
611
+ invokeId: options.invokeId || this._getInvokeId(),
612
+ arrayIndex: options.arrayIndex || baEnum.ASN1_ARRAY_ALL
613
+ };
614
+ const buffer = this._getBuffer();
615
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
616
+ const type = baEnum.PduTypes.CONFIRMED_REQUEST | (settings.maxSegments !== baEnum.MaxSegmentsAccepted.SEGMENTS_0 ? baEnum.PduConReqBits.SEGMENTED_RESPONSE_ACCEPTED : 0);
617
+ baApdu.encodeConfirmedServiceRequest(buffer, type, baEnum.ConfirmedServiceChoice.READ_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
618
+ baServices.readProperty.encode(buffer, objectId.type, objectId.instance, propertyId, settings.arrayIndex);
619
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
620
+ this.sendBvlc(address, buffer);
621
+ this._addCallback(settings.invokeId, (err, data) => {
622
+ try{
623
+ if (err)
624
+ return next(err);
625
+ const result = baServices.readProperty.decodeAcknowledge(data.buffer, data.offset, data.length);
626
+ if (!result)
627
+ return next(new Error('INVALID_DECODING'));
628
+ next(null, result);
629
+ } catch(e){
630
+ return next(e);
631
+ }
632
+ });
633
+ }
634
+ /**
635
+ * The writeProperty command writes a single property of an object to a device.
636
+ * @function bacstack.writeProperty
637
+ * @param {string} address - IP address of the target device.
638
+ * @param {object} objectId - The BACNET object ID to write.
639
+ * @param {number} objectId.type - The BACNET object type to write.
640
+ * @param {number} objectId.instance - The BACNET object instance to write.
641
+ * @param {number} propertyId - The BACNET property id in the specified object to write.
642
+ * @param {object[]} values - A list of values to be written to the specified property.
643
+ * @param {ApplicationTags} values.tag - The data-type of the value to be written.
644
+ * @param {number} values.value - The actual value to be written.
645
+ * @param {object=} options
646
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
647
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
648
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
649
+ * @param {number=} options.arrayIndex - The array index of the property to be read.
650
+ * @param {number=} options.priority - The priority of the value to be written.
651
+ * @param {function} next - The callback containing an error, in case of a failure.
652
+ * @example
653
+ * const bacnet = require('bacstack');
654
+ * const client = new bacnet();
655
+ *
656
+ * client.writeProperty('192.168.1.43', {type: 8, instance: 44301}, 28, [
657
+ * {type: bacnet.enum.ApplicationTags.REAL, value: 100}
658
+ * ], (err) => {
659
+ * console.log('error: ', err);
660
+ * });
661
+ */
662
+ writeProperty(address, objectId, propertyId, values, options, next) {
663
+ next = next || options;
664
+ const settings = {
665
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
666
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
667
+ invokeId: options.invokeId || this._getInvokeId(),
668
+ arrayIndex: options.arrayIndex || baEnum.ASN1_ARRAY_ALL,
669
+ priority: options.priority
670
+ };
671
+ const buffer = this._getBuffer();
672
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
673
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.WRITE_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
674
+ baServices.writeProperty.encode(buffer, objectId.type, objectId.instance, propertyId, settings.arrayIndex, settings.priority, values);
675
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
676
+ this.sendBvlc(address, buffer);
677
+ this._addCallback(settings.invokeId, (err) => next(err));
678
+ }
679
+ /**
680
+ * The readPropertyMultiple command reads multiple properties in multiple objects from a device.
681
+ * @function bacstack.readPropertyMultiple
682
+ * @param {string} address - IP address of the target device.
683
+ * @param {object[]} propertiesArray - List of object and property specifications to be read.
684
+ * @param {object} propertiesArray.objectId - Specifies which object to read.
685
+ * @param {number} propertiesArray.objectId.type - The BACNET object type to read.
686
+ * @param {number} propertiesArray.objectId.instance - The BACNET object instance to read.
687
+ * @param {object[]} propertiesArray.properties - List of properties to be read.
688
+ * @param {number} propertiesArray.properties.id - The BACNET property id in the specified object to read. Also supports 8 for all properties.
689
+ * @param {object=} options
690
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
691
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
692
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
693
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
694
+ * @example
695
+ * const bacnet = require('bacstack');
696
+ * const client = new bacnet();
697
+ *
698
+ * const propertiesArray = [
699
+ * {objectId: {type: 8, instance: 4194303}, properties: [{id: 8}]}
700
+ * ];
701
+ * client.readPropertyMultiple('192.168.1.43', propertiesArray, (err, value) => {
702
+ * console.log('value: ', value);
703
+ * });
704
+ */
705
+ readPropertyMultiple(address, propertiesArray, options, next) {
706
+ next = next || options;
707
+ const settings = {
708
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
709
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
710
+ invokeId: options.invokeId || this._getInvokeId()
711
+ };
712
+ const buffer = this._getBuffer();
713
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
714
+ const type = baEnum.PduTypes.CONFIRMED_REQUEST | (settings.maxSegments !== baEnum.MaxSegmentsAccepted.SEGMENTS_0 ? baEnum.PduConReqBits.SEGMENTED_RESPONSE_ACCEPTED : 0);
715
+ baApdu.encodeConfirmedServiceRequest(buffer, type, baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
716
+ baServices.readPropertyMultiple.encode(buffer, propertiesArray);
717
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
718
+ this.sendBvlc(address, buffer);
719
+ //this.sendBvlc(address, buffer);
720
+ this._addCallback(settings.invokeId, (err, data) => {
721
+ try {
722
+ if (err)
723
+ return next(err);
724
+ const result = baServices.readPropertyMultiple.decodeAcknowledge(data.buffer, data.offset, data.length);
725
+ if (!result)
726
+ return next(new Error('INVALID_DECODING'));
727
+ next(null, result);
728
+ } catch(e){
729
+ return next(e);
730
+ }
731
+ });
732
+ }
733
+ /**
734
+ * The writePropertyMultiple command writes multiple properties in multiple objects to a device.
735
+ * @function bacstack.writePropertyMultiple
736
+ * @param {string} address - IP address of the target device.
737
+ * @param {object[]} values - List of object and property specifications to be written.
738
+ * @param {object} values.objectId - Specifies which object to read.
739
+ * @param {number} values.objectId.type - The BACNET object type to read.
740
+ * @param {number} values.objectId.instance - The BACNET object instance to read.
741
+ * @param {object[]} values.values - List of properties to be written.
742
+ * @param {object} values.values.property - Property specifications to be written.
743
+ * @param {number} values.values.property.id - The BACNET property id in the specified object to write.
744
+ * @param {number} values.values.property.index - The array index of the property to be written.
745
+ * @param {object[]} values.values.value - A list of values to be written to the specified property.
746
+ * @param {ApplicationTags} values.values.value.tag - The data-type of the value to be written.
747
+ * @param {object} values.values.value.value - The actual value to be written.
748
+ * @param {number} values.values.priority - The priority to be used for writing to the property.
749
+ * @param {object=} options
750
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
751
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
752
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
753
+ * @param {function} next - The callback containing an error, in case of a failure.
754
+ * @example
755
+ * const bacnet = require('bacstack');
756
+ * const client = new bacnet();
757
+ *
758
+ * const values = [
759
+ * {objectId: {type: 8, instance: 44301}, values: [
760
+ * {property: {id: 28, index: 12}, value: [{type: bacnet.enum.ApplicationTags.BOOLEAN, value: true}], priority: 8}
761
+ * ]}
762
+ * ];
763
+ * client.writePropertyMultiple('192.168.1.43', values, (err) => {
764
+ * console.log('error: ', err);
765
+ * });
766
+ */
767
+ writePropertyMultiple(address, values, options, next) {
768
+ next = next || options;
769
+ const settings = {
770
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
771
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
772
+ invokeId: options.invokeId || this._getInvokeId()
773
+ };
774
+ const buffer = this._getBuffer();
775
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
776
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.WRITE_PROPERTY_MULTIPLE, settings.maxSegments, settings.maxApdu, settings.invokeId);
777
+ baServices.writePropertyMultiple.encodeObject(buffer, values);
778
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
779
+ this.sendBvlc(address, buffer);
780
+ this._addCallback(settings.invokeId, (err) => next(err));
781
+ }
782
+ /**
783
+ * The deviceCommunicationControl command enables or disables network communication of the target device.
784
+ * @function bacstack.deviceCommunicationControl
785
+ * @param {string} address - IP address of the target device.
786
+ * @param {number} timeDuration - The time to hold the network communication state in seconds. 0 for infinite.
787
+ * @param {EnableDisable} enableDisable - The network communication state to set.
788
+ * @param {object=} options
789
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
790
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
791
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
792
+ * @param {string=} options.password - The optional password used to set the network communication state.
793
+ * @param {function} next - The callback containing an error, in case of a failure.
794
+ * @example
795
+ * const bacnet = require('bacstack');
796
+ * const client = new bacnet();
797
+ *
798
+ * client.deviceCommunicationControl('192.168.1.43', 0, bacnet.enum.EnableDisable.DISABLE, (err) => {
799
+ * console.log('error: ', err);
800
+ * });
801
+ */
802
+ deviceCommunicationControl(address, timeDuration, enableDisable, options, next) {
803
+ next = next || options;
804
+ const settings = {
805
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
806
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
807
+ invokeId: options.invokeId || this._getInvokeId(),
808
+ password: options.password
809
+ };
810
+ const buffer = this._getBuffer();
811
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
812
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.DEVICE_COMMUNICATION_CONTROL, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
813
+ baServices.deviceCommunicationControl.encode(buffer, timeDuration, enableDisable, settings.password);
814
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
815
+ this.sendBvlc(address, buffer);
816
+ this._addCallback(settings.invokeId, (err) => next(err));
817
+ }
818
+ /**
819
+ * The reinitializeDevice command initiates a restart of the target device.
820
+ * @function bacstack.reinitializeDevice
821
+ * @param {string} address - IP address of the target device.
822
+ * @param {ReinitializedState} state - The type of restart to be initiated.
823
+ * @param {object=} options
824
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
825
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
826
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
827
+ * @param {string=} options.password - The optional password used to restart the device.
828
+ * @param {function} next - The callback containing an error, in case of a failure.
829
+ * @example
830
+ * const bacnet = require('bacstack');
831
+ * const client = new bacnet();
832
+ *
833
+ * client.reinitializeDevice('192.168.1.43', bacnet.enum.ReinitializedState.COLDSTART, (err) => {
834
+ * console.log('error: ', err);
835
+ * });
836
+ */
837
+ reinitializeDevice(address, state, options, next) {
838
+ next = next || options;
839
+ const settings = {
840
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
841
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
842
+ invokeId: options.invokeId || this._getInvokeId(),
843
+ password: options.password
844
+ };
845
+ const buffer = this._getBuffer();
846
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
847
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.REINITIALIZE_DEVICE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
848
+ baServices.reinitializeDevice.encode(buffer, state, settings.password);
849
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
850
+ this.sendBvlc(address, buffer);
851
+ this._addCallback(settings.invokeId, (err) => next(err));
852
+ }
853
+ /**
854
+ * The writeFile command writes a file buffer to a specific position of a file object.
855
+ * @function bacstack.writeFile
856
+ * @param {string} address - IP address of the target device.
857
+ * @param {object} objectId - The BACNET object ID representing the file object.
858
+ * @param {number} objectId.type - The BACNET object type representing the file object.
859
+ * @param {number} objectId.instance - The BACNET object instance representing the file object.
860
+ * @param {number} position - The position in the file to write at.
861
+ * @param {Array.<number[]>} fileBuffer - The content to be written to the file.
862
+ * @param {object=} options
863
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
864
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
865
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
866
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
867
+ * @example
868
+ * const bacnet = require('bacstack');
869
+ * const client = new bacnet();
870
+ *
871
+ * client.writeFile('192.168.1.43', {type: 8, instance: 44301}, 0, [[5, 6, 7, 8], [5, 6, 7, 8]], (err, value) => {
872
+ * console.log('value: ', value);
873
+ * });
874
+ */
875
+ writeFile(address, objectId, position, fileBuffer, options, next) {
876
+ next = next || options;
877
+ const settings = {
878
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
879
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
880
+ invokeId: options.invokeId || this._getInvokeId()
881
+ };
882
+ const buffer = this._getBuffer();
883
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
884
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ATOMIC_WRITE_FILE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
885
+ baServices.atomicWriteFile.encode(buffer, false, objectId, position, fileBuffer);
886
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
887
+ this.sendBvlc(address, buffer);
888
+ this._addCallback(settings.invokeId, (err, data) => {
889
+ if (err)
890
+ return next(err);
891
+ const result = baServices.atomicWriteFile.decodeAcknowledge(data.buffer, data.offset);
892
+ if (!result)
893
+ return next(new Error('INVALID_DECODING'));
894
+ next(null, result);
895
+ });
896
+ }
897
+ /**
898
+ * The readFile command reads a number of bytes at a specific position of a file object.
899
+ * @function bacstack.readFile
900
+ * @param {string} address - IP address of the target device.
901
+ * @param {object} objectId - The BACNET object ID representing the file object.
902
+ * @param {number} objectId.type - The BACNET object type representing the file object.
903
+ * @param {number} objectId.instance - The BACNET object instance representing the file object.
904
+ * @param {number} position - The position in the file to read at.
905
+ * @param {number} count - The number of octets to read.
906
+ * @param {object=} options
907
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
908
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
909
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
910
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
911
+ * @example
912
+ * const bacnet = require('bacstack');
913
+ * const client = new bacnet();
914
+ *
915
+ * client.readFile('192.168.1.43', {type: 8, instance: 44301}, 0, 100, (err, value) => {
916
+ * console.log('value: ', value);
917
+ * });
918
+ */
919
+ readFile(address, objectId, position, count, options, next) {
920
+ next = next || options;
921
+ const settings = {
922
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
923
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
924
+ invokeId: options.invokeId || this._getInvokeId()
925
+ };
926
+ const buffer = this._getBuffer();
927
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
928
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ATOMIC_READ_FILE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
929
+ baServices.atomicReadFile.encode(buffer, true, objectId, position, count);
930
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
931
+ this.sendBvlc(address, buffer);
932
+ this._addCallback(settings.invokeId, (err, data) => {
933
+ if (err)
934
+ return next(err);
935
+ const result = baServices.atomicReadFile.decodeAcknowledge(data.buffer, data.offset);
936
+ if (!result)
937
+ return next(new Error('INVALID_DECODING'));
938
+ next(null, result);
939
+ });
940
+ }
941
+ /**
942
+ * The readRange command reads a number if list items of an array or list object.
943
+ * @function bacstack.readRange
944
+ * @param {string} address - IP address of the target device.
945
+ * @param {object} objectId - The BACNET object ID to read.
946
+ * @param {number} objectId.type - The BACNET object type to read.
947
+ * @param {number} objectId.instance - The BACNET object instance to read.
948
+ * @param {number} idxBegin - The index of the first/last item to read.
949
+ * @param {number} quantity - The number of records to read.
950
+ * @param {object=} options
951
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
952
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
953
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
954
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
955
+ * @example
956
+ * const bacnet = require('bacstack');
957
+ * const client = new bacnet();
958
+ *
959
+ * client.readRange('192.168.1.43', {type: 8, instance: 44301}, 0, 200, (err, value) => {
960
+ * console.log('value: ', value);
961
+ * });
962
+ */
963
+ readRange(address, objectId, idxBegin, quantity, options, next) {
964
+ next = next || options;
965
+ const settings = {
966
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
967
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
968
+ invokeId: options.invokeId || this._getInvokeId()
969
+ };
970
+ const buffer = this._getBuffer();
971
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
972
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.READ_RANGE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
973
+ baServices.readRange.encode(buffer, objectId, baEnum.PropertyIdentifier.LOG_BUFFER, baEnum.ASN1_ARRAY_ALL, baEnum.ReadRangeType.BY_POSITION, idxBegin, new Date(), quantity);
974
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
975
+ this.sendBvlc(address, buffer);
976
+ this._addCallback(settings.invokeId, (err, data) => {
977
+ if (err)
978
+ return next(err);
979
+ const result = baServices.readRange.decodeAcknowledge(data.buffer, data.offset, data.length);
980
+ if (!result)
981
+ return next(new Error('INVALID_DECODING'));
982
+ next(null, result);
983
+ });
984
+ }
985
+ /**
986
+ * The subscribeCOV command subscribes to an object for "Change of Value" notifications.
987
+ * @function bacstack.subscribeCOV
988
+ * @param {string} address - IP address of the target device.
989
+ * @param {object} objectId - The BACNET object ID to subscribe for.
990
+ * @param {number} objectId.type - The BACNET object type to subscribe for.
991
+ * @param {number} objectId.instance - The BACNET object instance to subscribe for.
992
+ * @param {number} subscribeId - A unique identifier to map the subscription.
993
+ * @param {boolean} cancel - Cancel an existing subscription instead of creating a new one.
994
+ * @param {boolean} issueConfirmedNotifications - Identifies if unconfirmed/confirmed notifications shall be returned.
995
+ * @param {number} lifetime - Number of seconds for the subscription to stay active, 0 for infinite.
996
+ * @param {object=} options
997
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
998
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
999
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
1000
+ * @param {function} next - The callback containing an error, in case of a failure.
1001
+ * @example
1002
+ * const bacnet = require('bacstack');
1003
+ * const client = new bacnet();
1004
+ *
1005
+ * client.subscribeCOV('192.168.1.43', {type: 8, instance: 44301}, 7, false, false, 0, (err) => {
1006
+ * console.log('error: ', err);
1007
+ * });
1008
+ */
1009
+ subscribeCOV(address, objectId, subscribeId, cancel, issueConfirmedNotifications, lifetime, options, next) {
1010
+ next = next || options;
1011
+ const settings = {
1012
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1013
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1014
+ invokeId: options.invokeId || this._getInvokeId()
1015
+ };
1016
+ const buffer = this._getBuffer();
1017
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1018
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.SUBSCRIBE_COV, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1019
+ baServices.subscribeCov.encode(buffer, subscribeId, objectId, cancel, issueConfirmedNotifications, lifetime);
1020
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1021
+ this.sendBvlc(address, buffer);
1022
+ this._addCallback(settings.invokeId, (err) => next(err));
1023
+ }
1024
+ /**
1025
+ * The subscribeProperty command subscribes to a specific property of an object for "Change of Value" notifications.
1026
+ * @function bacstack.subscribeProperty
1027
+ * @param {string} address - IP address of the target device.
1028
+ * @param {object} objectId - The BACNET object ID to subscribe for.
1029
+ * @param {number} objectId.type - The BACNET object type to subscribe for.
1030
+ * @param {number} objectId.instance - The BACNET object instance to subscribe for.
1031
+ * @param {object} monitoredProperty
1032
+ * @param {object} monitoredProperty.id - The property ID to subscribe for.
1033
+ * @param {object} monitoredProperty.index - The property index to subscribe for.
1034
+ * @param {number} subscribeId - A unique identifier to map the subscription.
1035
+ * @param {boolean} cancel - Cancel an existing subscription instead of creating a new one.
1036
+ * @param {boolean} issueConfirmedNotifications - Identifies if unconfirmed/confirmed notifications shall be returned.
1037
+ * @param {object=} options
1038
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
1039
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
1040
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
1041
+ * @param {function} next - The callback containing an error, in case of a failure.
1042
+ * @example
1043
+ * const bacnet = require('bacstack');
1044
+ * const client = new bacnet();
1045
+ *
1046
+ * client.subscribeProperty('192.168.1.43', {type: 8, instance: 44301}, {id: 80, index: 0}, 8, false, false, (err) => {
1047
+ * console.log('error: ', err);
1048
+ * });
1049
+ */
1050
+ subscribeProperty(address, objectId, monitoredProperty, subscribeId, cancel, issueConfirmedNotifications, options, next) {
1051
+ next = next || options;
1052
+ const settings = {
1053
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1054
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1055
+ invokeId: options.invokeId || this._getInvokeId()
1056
+ };
1057
+ const buffer = this._getBuffer();
1058
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1059
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.SUBSCRIBE_COV_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1060
+ baServices.subscribeProperty.encode(buffer, subscribeId, objectId, cancel, issueConfirmedNotifications, 0, monitoredProperty, false, 0x0f);
1061
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1062
+ this.sendBvlc(address, buffer);
1063
+ this._addCallback(settings.invokeId, (err) => next(err));
1064
+ }
1065
+ createObject(address, objectId, values, options, next) {
1066
+ next = next || options;
1067
+ const settings = {
1068
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1069
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1070
+ invokeId: options.invokeId || this._getInvokeId()
1071
+ };
1072
+ const buffer = this._getBuffer();
1073
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1074
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.CREATE_OBJECT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1075
+ baServices.createObject.encode(buffer, objectId, values);
1076
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1077
+ this.sendBvlc(address, buffer);
1078
+ this._addCallback(settings.invokeId, (err) => next(err));
1079
+ }
1080
+ /**
1081
+ * The deleteObject command removes an object instance from a target device.
1082
+ * @function bacstack.deleteObject
1083
+ * @param {string} address - IP address of the target device.
1084
+ * @param {object} objectId - The BACNET object ID to delete.
1085
+ * @param {number} objectId.type - The BACNET object type to delete.
1086
+ * @param {number} objectId.instance - The BACNET object instance to delete.
1087
+ * @param {object=} options
1088
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
1089
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
1090
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
1091
+ * @param {function} next - The callback containing an error, in case of a failure.
1092
+ * @example
1093
+ * const bacnet = require('bacstack');
1094
+ * const client = new bacnet();
1095
+ *
1096
+ * client.deleteObject('192.168.1.43', {type: 8, instance: 44301}, (err) => {
1097
+ * console.log('error: ', err);
1098
+ * });
1099
+ */
1100
+ deleteObject(address, objectId, options, next) {
1101
+ next = next || options;
1102
+ const settings = {
1103
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1104
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1105
+ invokeId: options.invokeId || this._getInvokeId()
1106
+ };
1107
+ const buffer = this._getBuffer();
1108
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1109
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.DELETE_OBJECT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1110
+ baServices.deleteObject.encode(buffer, objectId);
1111
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1112
+ this.sendBvlc(address, buffer);
1113
+ this._addCallback(settings.invokeId, (err) => next(err));
1114
+ }
1115
+ removeListElement(address, objectId, reference, values, options, next) {
1116
+ next = next || options;
1117
+ const settings = {
1118
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1119
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1120
+ invokeId: options.invokeId || this._getInvokeId()
1121
+ };
1122
+ const buffer = this._getBuffer();
1123
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1124
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.REMOVE_LIST_ELEMENT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1125
+ baServices.addListElement.encode(buffer, objectId, reference.id, reference.index, values);
1126
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1127
+ this.sendBvlc(address, buffer);
1128
+ this._addCallback(settings.invokeId, (err) => next(err));
1129
+ }
1130
+ addListElement(address, objectId, reference, values, options, next) {
1131
+ next = next || options;
1132
+ const settings = {
1133
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1134
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1135
+ invokeId: options.invokeId || this._getInvokeId()
1136
+ };
1137
+ const buffer = this._getBuffer();
1138
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1139
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ADD_LIST_ELEMENT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1140
+ baServices.addListElement.encode(buffer, objectId, reference.id, reference.index, values);
1141
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1142
+ this.sendBvlc(address, buffer);
1143
+ this._addCallback(settings.invokeId, (err) => next(err));
1144
+ }
1145
+ /**
1146
+ * DEPRECATED The getAlarmSummary command returns a list of all active alarms on the target device.
1147
+ * @function bacstack.getAlarmSummary
1148
+ * @param {string} address - IP address of the target device.
1149
+ * @param {object=} options
1150
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
1151
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
1152
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
1153
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
1154
+ * @example
1155
+ * const bacnet = require('bacstack');
1156
+ * const client = new bacnet();
1157
+ *
1158
+ * client.getAlarmSummary('192.168.1.43', (err, value) => {
1159
+ * console.log('value: ', value);
1160
+ * });
1161
+ */
1162
+ getAlarmSummary(address, options, next) {
1163
+ next = next || options;
1164
+ const settings = {
1165
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1166
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1167
+ invokeId: options.invokeId || this._getInvokeId()
1168
+ };
1169
+ const buffer = this._getBuffer();
1170
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1171
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.GET_ALARM_SUMMARY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1172
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1173
+ this.sendBvlc(address, buffer);
1174
+ this._addCallback(settings.invokeId, (err, data) => {
1175
+ if (err)
1176
+ return next(err);
1177
+ const result = baServices.alarmSummary.decode(data.buffer, data.offset, data.length);
1178
+ if (!result)
1179
+ return next(new Error('INVALID_DECODING'));
1180
+ next(null, result);
1181
+ });
1182
+ }
1183
+ /**
1184
+ * The getEventInformation command returns a list of all active event states on the target device.
1185
+ * @function bacstack.getEventInformation
1186
+ * @param {string} address - IP address of the target device.
1187
+ * @param {object=} objectId - The optional BACNET object ID to continue preceding calls.
1188
+ * @param {number=} objectId.type - The optional BACNET object type to continue preceding calls.
1189
+ * @param {number=} objectId.instance - The optional BACNET object instance to continue preceding calls.
1190
+ * @param {object=} options
1191
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
1192
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
1193
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
1194
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
1195
+ * @example
1196
+ * const bacnet = require('bacstack');
1197
+ * const client = new bacnet();
1198
+ *
1199
+ * client.getEventInformation('192.168.1.43', {}, (err, value) => {
1200
+ * console.log('value: ', value);
1201
+ * });
1202
+ */
1203
+ getEventInformation(address, objectId, options, next) {
1204
+ next = next || options;
1205
+ const settings = {
1206
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1207
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1208
+ invokeId: options.invokeId || this._getInvokeId()
1209
+ };
1210
+ const buffer = this._getBuffer();
1211
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1212
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.GET_EVENT_INFORMATION, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1213
+ baAsn1.encodeContextObjectId(buffer, 0, objectId.type, objectId.instance);
1214
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1215
+ this.sendBvlc(address, buffer);
1216
+ this._addCallback(settings.invokeId, (err, data) => {
1217
+ if (err)
1218
+ return next(err);
1219
+ const result = baServices.eventInformation.decode(data.buffer, data.offset, data.length);
1220
+ if (!result)
1221
+ return next(new Error('INVALID_DECODING'));
1222
+ next(null, result);
1223
+ });
1224
+ }
1225
+ acknowledgeAlarm(address, objectId, eventState, ackText, evTimeStamp, ackTimeStamp, options, next) {
1226
+ next = next || options;
1227
+ const settings = {
1228
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1229
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1230
+ invokeId: options.invokeId || this._getInvokeId()
1231
+ };
1232
+ const buffer = this._getBuffer();
1233
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1234
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ACKNOWLEDGE_ALARM, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1235
+ baServices.alarmAcknowledge.encode(buffer, 57, objectId, eventState, ackText, evTimeStamp, ackTimeStamp);
1236
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1237
+ this.sendBvlc(address, buffer);
1238
+ this._addCallback(settings.invokeId, (err) => next(err));
1239
+ }
1240
+ /**
1241
+ * The confirmedPrivateTransfer command invokes a confirmed proprietary/non-standard service.
1242
+ * @function bacstack.confirmedPrivateTransfer
1243
+ * @param {string} address - IP address of the target device.
1244
+ * @param {number} vendorId - The unique vendor identification code.
1245
+ * @param {number} serviceNumber - The unique service identifier.
1246
+ * @param {number[]} [data] - Optional additional payload data.
1247
+ * @param {object=} options
1248
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
1249
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
1250
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
1251
+ * @param {function} next - The callback containing an error, in case of a failure.
1252
+ * @example
1253
+ * const bacnet = require('bacstack');
1254
+ * const client = new bacnet();
1255
+ *
1256
+ * client.confirmedPrivateTransfer('192.168.1.43', 0, 7, [0x00, 0xaa, 0xfa, 0xb1, 0x00], (err) => {
1257
+ * console.log('error: ', err);
1258
+ * });
1259
+ */
1260
+ confirmedPrivateTransfer(address, vendorId, serviceNumber, data, options, next) {
1261
+ next = next || options;
1262
+ const settings = {
1263
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1264
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1265
+ invokeId: options.invokeId || this._getInvokeId()
1266
+ };
1267
+ const buffer = this._getBuffer();
1268
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1269
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.CONFIRMED_PRIVATE_TRANSFER, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1270
+ baServices.privateTransfer.encode(buffer, vendorId, serviceNumber, data);
1271
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1272
+ this.sendBvlc(address, buffer);
1273
+ this._addCallback(settings.invokeId, (err) => next(err));
1274
+ }
1275
+ /**
1276
+ * The unconfirmedPrivateTransfer command invokes an unconfirmed proprietary/non-standard service.
1277
+ * @function bacstack.unconfirmedPrivateTransfer
1278
+ * @param {string} address - IP address of the target device.
1279
+ * @param {number} vendorId - The unique vendor identification code.
1280
+ * @param {number} serviceNumber - The unique service identifier.
1281
+ * @param {number[]} [data] - Optional additional payload data.
1282
+ * @example
1283
+ * const bacnet = require('bacstack');
1284
+ * const client = new bacnet();
1285
+ *
1286
+ * client.unconfirmedPrivateTransfer('192.168.1.43', 0, 7, [0x00, 0xaa, 0xfa, 0xb1, 0x00]);
1287
+ */
1288
+ unconfirmedPrivateTransfer(address, vendorId, serviceNumber, data) {
1289
+ const buffer = this._getBuffer();
1290
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, address);
1291
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.UNCONFIRMED_PRIVATE_TRANSFER);
1292
+ baServices.privateTransfer.encode(buffer, vendorId, serviceNumber, data);
1293
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1294
+ this.sendBvlc(address, buffer);
1295
+ }
1296
+ /**
1297
+ * DEPRECATED The getEnrollmentSummary command returns a list of event-initiating objects on the target device.
1298
+ * @function bacstack.getEnrollmentSummary
1299
+ * @param {string} address - IP address of the target device.
1300
+ * @param {number} acknowledgmentFilter - Filter for ALL/ACKED/NOT-ACKED, 0/1/2.
1301
+ * @param {object=} options
1302
+ * @param {object=} options.enrollmentFilter - Filter for enrollment.
1303
+ * @param {EventState=} options.eventStateFilter - Filter for event state.
1304
+ * @param {EventType=} options.eventTypeFilter - Filter for event type.
1305
+ * @param {object=} options.priorityFilter
1306
+ * @param {number} options.priorityFilter.min - Filter for minimal priority
1307
+ * @param {number} options.priorityFilter.max - Filter for maximal priority
1308
+ * @param {number=} options.notificationClassFilter - Filter for notification class.
1309
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
1310
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
1311
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
1312
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
1313
+ * @example
1314
+ * const bacnet = require('bacstack');
1315
+ * const client = new bacnet();
1316
+ *
1317
+ * client.getEnrollmentSummary('192.168.1.43', 0, (err, value) => {
1318
+ * console.log('value: ', value);
1319
+ * });
1320
+ */
1321
+ getEnrollmentSummary(address, acknowledgmentFilter, options, next) {
1322
+ next = next || options;
1323
+ const settings = {
1324
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1325
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1326
+ invokeId: options.invokeId || this._getInvokeId()
1327
+ };
1328
+ const buffer = this._getBuffer();
1329
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1330
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.GET_ENROLLMENT_SUMMARY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1331
+ baServices.getEnrollmentSummary.encode(buffer, acknowledgmentFilter, options.enrollmentFilter, options.eventStateFilter, options.eventTypeFilter, options.priorityFilter, options.notificationClassFilter);
1332
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1333
+ this.sendBvlc(address, buffer);
1334
+ this._addCallback(settings.invokeId, (err, data) => {
1335
+ if (err)
1336
+ return next(err);
1337
+ const result = baServices.getEnrollmentSummary.decodeAcknowledge(data.buffer, data.offset, data.length);
1338
+ if (!result)
1339
+ return next(new Error('INVALID_DECODING'));
1340
+ next(null, result);
1341
+ });
1342
+ }
1343
+ unconfirmedEventNotification(address, eventNotification) {
1344
+ const buffer = this._getBuffer();
1345
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, address);
1346
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.UNCONFIRMED_EVENT_NOTIFICATION);
1347
+ baServices.eventNotifyData.encode(buffer, eventNotification);
1348
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1349
+ this.sendBvlc(address, buffer);
1350
+ }
1351
+ confirmedEventNotification(address, eventNotification, options, next) {
1352
+ next = next || options;
1353
+ const settings = {
1354
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1355
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1356
+ invokeId: options.invokeId || this._getInvokeId()
1357
+ };
1358
+ const buffer = this._getBuffer();
1359
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address);
1360
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.CONFIRMED_EVENT_NOTIFICATION, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1361
+ baServices.eventNotifyData.encode(buffer, eventNotification);
1362
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1363
+ this.sendBvlc(address, buffer);
1364
+ this._addCallback(settings.invokeId, (err) => next(err));
1365
+ }
1366
+ // Public Device Functions
1367
+ readPropertyResponse(receiver, invokeId, objectId, property, value) {
1368
+ const buffer = this._getBuffer();
1369
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1370
+ baApdu.encodeComplexAck(buffer, baEnum.PduTypes.COMPLEX_ACK, baEnum.ConfirmedServiceChoice.READ_PROPERTY, invokeId);
1371
+ baServices.readProperty.encodeAcknowledge(buffer, objectId, property.id, property.index, value);
1372
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1373
+ this.sendBvlc(receiver, buffer);
1374
+ }
1375
+ readPropertyMultipleResponse(receiver, invokeId, values) {
1376
+ const buffer = this._getBuffer();
1377
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1378
+ baApdu.encodeComplexAck(buffer, baEnum.PduTypes.COMPLEX_ACK, baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE, invokeId);
1379
+ baServices.readPropertyMultiple.encodeAcknowledge(buffer, values);
1380
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1381
+ this.sendBvlc(receiver, buffer);
1382
+ }
1383
+ iAmResponse(deviceId, segmentation, vendorId) {
1384
+ const buffer = this._getBuffer();
1385
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, this._transport.getBroadcastAddress());
1386
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.I_AM);
1387
+ baServices.iAmBroadcast.encode(buffer, deviceId, this._transport.getMaxPayload(), segmentation, vendorId);
1388
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU, buffer.offset);
1389
+ this._transport.send(buffer.buffer, buffer.offset, this._transport.getBroadcastAddress());
1390
+ }
1391
+ iHaveResponse(deviceId, objectId, objectName) {
1392
+ const buffer = this._getBuffer();
1393
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, this._transport.getBroadcastAddress());
1394
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduTypes.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.I_HAVE);
1395
+ baServices.iHaveBroadcast.encode(buffer, deviceId, objectId, objectName);
1396
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU, buffer.offset);
1397
+ this._transport.send(buffer.buffer, buffer.offset, this._transport.getBroadcastAddress());
1398
+ }
1399
+ simpleAckResponse(receiver, service, invokeId) {
1400
+ const buffer = this._getBuffer();
1401
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1402
+ baApdu.encodeSimpleAck(buffer, baEnum.PduTypes.SIMPLE_ACK, service, invokeId);
1403
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1404
+ this.sendBvlc(receiver, buffer);
1405
+ }
1406
+ errorResponse(receiver, service, invokeId, errorClass, errorCode) {
1407
+ const buffer = this._getBuffer();
1408
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1409
+ baApdu.encodeError(buffer, baEnum.PduTypes.ERROR, service, invokeId);
1410
+ baServices.error.encode(buffer, errorClass, errorCode);
1411
+ //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1412
+ this.sendBvlc(receiver, buffer);
1413
+ }
1414
+ /**
1415
+ *
1416
+ * @param receiver
1417
+ * @param buffer
1418
+ */
1419
+ sendBvlc(receiver, buffer) {
1420
+ if (typeof receiver === 'string') {
1421
+ receiver = {
1422
+ address: receiver
1423
+ };
1424
+ }
1425
+ if (receiver && receiver.forwardedFrom) {
1426
+ // Remote node address given, forward to BBMD
1427
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.FORWARDED_NPDU, buffer.offset, receiver.forwardedFrom);
1428
+ } else if (receiver && receiver.address) {
1429
+ // Specific address, unicast
1430
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1431
+ } else {
1432
+ // No address, broadcast
1433
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU, buffer.offset);
1434
+ }
1435
+ this._transport.send(
1436
+ buffer.buffer,
1437
+ buffer.offset,
1438
+ (receiver && receiver.address) || null
1439
+ );
1440
+ }
1441
+ /**
1442
+ * Unloads the current BACstack instance and closes the underlying UDP socket.
1443
+ * @function bacstack.close
1444
+ * @example
1445
+ * const bacnet = require('bacstack');
1446
+ * const client = new bacnet();
1447
+ *
1448
+ * client.close();
1449
+ */
1450
+ close() {
1451
+ this._transport.close();
1452
+ }
1453
+ }
1454
+ exports.Client = Client;