@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.
- package/README.md +2 -2
- package/bacnet_client.js +331 -168
- package/bacnet_device.js +50 -16
- package/bacnet_gateway.html +119 -15
- package/bacnet_gateway.js +388 -395
- package/bacnet_read.html +32 -11
- package/bacnet_read.js +1 -1
- package/bacnet_server.js +86 -24
- package/common.js +26 -19
- package/examples/1-Discover-Read.json +1 -1
- package/examples/2-Discover-Write.json +1 -1
- package/examples/3-Discover-Read-Write.json +1 -1
- package/package.json +3 -3
- package/resources/{node-bacnet/LICENSE.md → node-bacstack-ts/LICENSE} +3 -4
- package/resources/node-bacstack-ts/README.md +75 -0
- package/resources/{node-bacnet → node-bacstack-ts/dist}/index.js +0 -2
- package/resources/node-bacstack-ts/dist/lib/apdu.js +193 -0
- package/resources/node-bacstack-ts/dist/lib/asn1.js +1660 -0
- package/resources/node-bacstack-ts/dist/lib/bvlc.js +47 -0
- package/resources/node-bacstack-ts/dist/lib/client.js +1454 -0
- package/resources/node-bacstack-ts/dist/lib/enum.js +2114 -0
- package/resources/node-bacstack-ts/dist/lib/npdu.js +112 -0
- package/resources/node-bacstack-ts/dist/lib/services/add-list-element.js +58 -0
- package/resources/node-bacstack-ts/dist/lib/services/alarm-acknowledge.js +93 -0
- package/resources/node-bacstack-ts/dist/lib/services/alarm-summary.js +42 -0
- package/resources/node-bacstack-ts/dist/lib/services/atomic-read-file.js +157 -0
- package/resources/node-bacstack-ts/dist/lib/services/atomic-write-file.js +136 -0
- package/resources/node-bacstack-ts/dist/lib/services/cov-notify.js +119 -0
- package/resources/node-bacstack-ts/dist/lib/services/create-object.js +104 -0
- package/resources/node-bacstack-ts/dist/lib/services/delete-object.js +21 -0
- package/resources/node-bacstack-ts/dist/lib/services/device-communication-control.js +46 -0
- package/resources/node-bacstack-ts/dist/lib/services/error.js +27 -0
- package/resources/node-bacstack-ts/dist/lib/services/event-information.js +100 -0
- package/resources/node-bacstack-ts/dist/lib/services/event-notify-data.js +219 -0
- package/resources/node-bacstack-ts/dist/lib/services/get-enrollment-summary.js +172 -0
- package/resources/node-bacstack-ts/dist/lib/services/get-event-information.js +135 -0
- package/resources/node-bacstack-ts/dist/lib/services/i-am-broadcast.js +59 -0
- package/resources/node-bacstack-ts/dist/lib/services/i-have-broadcast.js +34 -0
- package/resources/node-bacstack-ts/dist/lib/services/index.js +32 -0
- package/resources/node-bacstack-ts/dist/lib/services/life-safety-operation.js +40 -0
- package/resources/node-bacstack-ts/dist/lib/services/private-transfer.js +43 -0
- package/resources/node-bacstack-ts/dist/lib/services/read-property-multiple.js +44 -0
- package/resources/node-bacstack-ts/dist/lib/services/read-property.js +122 -0
- package/resources/node-bacstack-ts/dist/lib/services/read-range.js +201 -0
- package/resources/node-bacstack-ts/dist/lib/services/reinitialize-device.js +35 -0
- package/resources/node-bacstack-ts/dist/lib/services/subscribe-cov.js +55 -0
- package/resources/node-bacstack-ts/dist/lib/services/subscribe-property.js +93 -0
- package/resources/node-bacstack-ts/dist/lib/services/time-sync.js +31 -0
- package/resources/node-bacstack-ts/dist/lib/services/who-has.js +56 -0
- package/resources/node-bacstack-ts/dist/lib/services/who-is.js +45 -0
- package/resources/node-bacstack-ts/dist/lib/services/write-property-multiple.js +105 -0
- package/resources/node-bacstack-ts/dist/lib/services/write-property.js +90 -0
- package/resources/node-bacstack-ts/dist/lib/transport.js +49 -0
- package/resources/node-bacstack-ts/dist/lib/types.js +2 -0
- package/resources/node-bacstack-ts/package.json +94 -0
- package/resources/node-bacnet/CHANGELOG.md +0 -481
- package/resources/node-bacnet/README.md +0 -91
- package/resources/node-bacnet/docs/Client.html +0 -4422
- package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
- package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
- package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
- package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
- package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
- package/resources/node-bacnet/docs/bacnet.html +0 -7032
- package/resources/node-bacnet/docs/client.js.html +0 -1759
- package/resources/node-bacnet/docs/enum.js.html +0 -2530
- package/resources/node-bacnet/docs/global.html +0 -2068
- package/resources/node-bacnet/docs/images/mocha-logo.svg +0 -65
- package/resources/node-bacnet/docs/index.html +0 -283
- package/resources/node-bacnet/docs/scripts/collapse.js +0 -11
- package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +0 -4
- package/resources/node-bacnet/docs/scripts/linenumber.js +0 -26
- package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +0 -202
- package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +0 -2
- package/resources/node-bacnet/docs/scripts/prettify/prettify.js +0 -28
- package/resources/node-bacnet/docs/scripts/search.js +0 -47
- package/resources/node-bacnet/docs/services_i-am.js.html +0 -157
- package/resources/node-bacnet/docs/services_time-sync.js.html +0 -118
- package/resources/node-bacnet/docs/services_who-is.js.html +0 -138
- package/resources/node-bacnet/docs/styles/jsdoc.css +0 -683
- package/resources/node-bacnet/docs/styles/prettify.css +0 -82
- package/resources/node-bacnet/examples/discover-devices.js +0 -66
- package/resources/node-bacnet/examples/read-device.js +0 -510
- package/resources/node-bacnet/examples/subscribe-cov.js +0 -75
- package/resources/node-bacnet/lib/apdu.js +0 -209
- package/resources/node-bacnet/lib/asn1.js +0 -1733
- package/resources/node-bacnet/lib/bvlc.js +0 -90
- package/resources/node-bacnet/lib/client.js +0 -1695
- package/resources/node-bacnet/lib/enum.js +0 -2463
- package/resources/node-bacnet/lib/npdu.js +0 -123
- package/resources/node-bacnet/lib/services/add-list-element.js +0 -64
- package/resources/node-bacnet/lib/services/alarm-acknowledge.js +0 -90
- package/resources/node-bacnet/lib/services/alarm-summary.js +0 -42
- package/resources/node-bacnet/lib/services/atomic-read-file.js +0 -162
- package/resources/node-bacnet/lib/services/atomic-write-file.js +0 -138
- package/resources/node-bacnet/lib/services/cov-notify.js +0 -126
- package/resources/node-bacnet/lib/services/create-object.js +0 -106
- package/resources/node-bacnet/lib/services/delete-object.js +0 -23
- package/resources/node-bacnet/lib/services/device-communication-control.js +0 -48
- package/resources/node-bacnet/lib/services/error.js +0 -33
- package/resources/node-bacnet/lib/services/event-information.js +0 -99
- package/resources/node-bacnet/lib/services/event-notify-data.js +0 -229
- package/resources/node-bacnet/lib/services/get-enrollment-summary.js +0 -178
- package/resources/node-bacnet/lib/services/get-event-information.js +0 -144
- package/resources/node-bacnet/lib/services/i-am.js +0 -90
- package/resources/node-bacnet/lib/services/i-have.js +0 -34
- package/resources/node-bacnet/lib/services/index.js +0 -34
- package/resources/node-bacnet/lib/services/life-safety-operation.js +0 -40
- package/resources/node-bacnet/lib/services/private-transfer.js +0 -43
- package/resources/node-bacnet/lib/services/read-property-multiple.js +0 -50
- package/resources/node-bacnet/lib/services/read-property.js +0 -130
- package/resources/node-bacnet/lib/services/read-range.js +0 -201
- package/resources/node-bacnet/lib/services/register-foreign-device.js +0 -18
- package/resources/node-bacnet/lib/services/reinitialize-device.js +0 -37
- package/resources/node-bacnet/lib/services/subscribe-cov.js +0 -57
- package/resources/node-bacnet/lib/services/subscribe-property.js +0 -97
- package/resources/node-bacnet/lib/services/time-sync.js +0 -51
- package/resources/node-bacnet/lib/services/who-has.js +0 -54
- package/resources/node-bacnet/lib/services/who-is.js +0 -71
- package/resources/node-bacnet/lib/services/write-property-multiple.js +0 -117
- package/resources/node-bacnet/lib/services/write-property.js +0 -94
- package/resources/node-bacnet/lib/transport.js +0 -82
- 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;
|