@bitpoolos/edge-bacnet 1.0.6 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (181) hide show
  1. package/bacnet_client.js +650 -233
  2. package/bacnet_device.js +65 -16
  3. package/bacnet_gateway.html +242 -99
  4. package/bacnet_gateway.js +211 -27
  5. package/bacnet_object.js +1 -1
  6. package/bacnet_read.html +211 -133
  7. package/bacnet_read.js +24 -24
  8. package/bacnet_server.js +321 -0
  9. package/bacnet_write.html +24 -15
  10. package/bacnet_write.js +0 -2
  11. package/common.js +95 -9
  12. package/edge-bacnet-datastore.cfg +0 -0
  13. package/package.json +6 -4
  14. package/resources/confirmationservice.min.js +1 -0
  15. package/resources/confirmdialog.min.js +1 -0
  16. package/resources/fonts/primeicons.woff2 +0 -0
  17. package/resources/node-bacnet/CHANGELOG.md +481 -0
  18. package/resources/{bacstack → node-bacnet}/LICENSE.md +3 -1
  19. package/resources/node-bacnet/README.md +91 -0
  20. package/resources/node-bacnet/docs/Client.html +4422 -0
  21. package/resources/node-bacnet/docs/bacnet-icon-quad.png +0 -0
  22. package/resources/node-bacnet/docs/bacnet-icon-quad128.png +0 -0
  23. package/resources/node-bacnet/docs/bacnet-icon-quad64.png +0 -0
  24. package/resources/node-bacnet/docs/bacnet-icon-small.xcf +0 -0
  25. package/resources/node-bacnet/docs/bacnet-icon.xcf +0 -0
  26. package/resources/node-bacnet/docs/bacnet.html +7032 -0
  27. package/resources/node-bacnet/docs/client.js.html +1759 -0
  28. package/resources/node-bacnet/docs/enum.js.html +2530 -0
  29. package/resources/node-bacnet/docs/global.html +2068 -0
  30. package/resources/node-bacnet/docs/images/mocha-logo.svg +65 -0
  31. package/resources/node-bacnet/docs/index.html +283 -0
  32. package/resources/node-bacnet/docs/scripts/collapse.js +11 -0
  33. package/resources/node-bacnet/docs/scripts/jquery-3.1.1.min.js +4 -0
  34. package/resources/node-bacnet/docs/scripts/linenumber.js +26 -0
  35. package/resources/node-bacnet/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  36. package/resources/node-bacnet/docs/scripts/prettify/lang-css.js +2 -0
  37. package/resources/node-bacnet/docs/scripts/prettify/prettify.js +28 -0
  38. package/resources/node-bacnet/docs/scripts/search.js +47 -0
  39. package/resources/node-bacnet/docs/services_i-am.js.html +157 -0
  40. package/resources/node-bacnet/docs/services_time-sync.js.html +118 -0
  41. package/resources/node-bacnet/docs/services_who-is.js.html +138 -0
  42. package/resources/node-bacnet/docs/styles/jsdoc.css +683 -0
  43. package/resources/node-bacnet/docs/styles/prettify.css +82 -0
  44. package/resources/node-bacnet/examples/discover-devices.js +66 -0
  45. package/resources/node-bacnet/examples/read-device.js +510 -0
  46. package/resources/node-bacnet/examples/subscribe-cov.js +75 -0
  47. package/resources/{bacstack → node-bacnet}/index.js +3 -0
  48. package/resources/{bacstack → node-bacnet}/lib/apdu.js +56 -39
  49. package/resources/{bacstack → node-bacnet}/lib/asn1.js +550 -532
  50. package/resources/node-bacnet/lib/bvlc.js +90 -0
  51. package/resources/node-bacnet/lib/client.js +1695 -0
  52. package/resources/node-bacnet/lib/enum.js +2463 -0
  53. package/resources/node-bacnet/lib/npdu.js +123 -0
  54. package/resources/{bacstack → node-bacnet}/lib/services/add-list-element.js +12 -6
  55. package/resources/{bacstack → node-bacnet}/lib/services/alarm-acknowledge.js +3 -3
  56. package/resources/{bacstack → node-bacnet}/lib/services/alarm-summary.js +5 -4
  57. package/resources/{bacstack → node-bacnet}/lib/services/atomic-read-file.js +49 -26
  58. package/resources/{bacstack → node-bacnet}/lib/services/atomic-write-file.js +40 -23
  59. package/resources/{bacstack → node-bacnet}/lib/services/cov-notify.js +33 -17
  60. package/resources/{bacstack → node-bacnet}/lib/services/create-object.js +23 -13
  61. package/resources/{bacstack → node-bacnet}/lib/services/delete-object.js +7 -2
  62. package/resources/{bacstack → node-bacnet}/lib/services/device-communication-control.js +8 -3
  63. package/resources/{bacstack → node-bacnet}/lib/services/error.js +7 -0
  64. package/resources/{bacstack → node-bacnet}/lib/services/event-information.js +10 -9
  65. package/resources/{bacstack → node-bacnet}/lib/services/event-notify-data.js +38 -16
  66. package/resources/{bacstack → node-bacnet}/lib/services/get-enrollment-summary.js +24 -11
  67. package/resources/{bacstack → node-bacnet}/lib/services/get-event-information.js +28 -13
  68. package/resources/node-bacnet/lib/services/i-am.js +90 -0
  69. package/resources/{bacstack/lib/services/i-have-broadcast.js → node-bacnet/lib/services/i-have.js} +3 -2
  70. package/resources/{bacstack → node-bacnet}/lib/services/index.js +7 -4
  71. package/resources/{bacstack → node-bacnet}/lib/services/life-safety-operation.js +3 -2
  72. package/resources/{bacstack → node-bacnet}/lib/services/private-transfer.js +3 -2
  73. package/resources/{bacstack → node-bacnet}/lib/services/read-property-multiple.js +11 -6
  74. package/resources/{bacstack → node-bacnet}/lib/services/read-property.js +42 -24
  75. package/resources/{bacstack → node-bacnet}/lib/services/read-range.js +37 -27
  76. package/resources/node-bacnet/lib/services/register-foreign-device.js +18 -0
  77. package/resources/{bacstack → node-bacnet}/lib/services/reinitialize-device.js +9 -4
  78. package/resources/{bacstack → node-bacnet}/lib/services/subscribe-cov.js +9 -4
  79. package/resources/{bacstack → node-bacnet}/lib/services/subscribe-property.js +18 -8
  80. package/resources/{bacstack → node-bacnet}/lib/services/time-sync.js +28 -5
  81. package/resources/{bacstack → node-bacnet}/lib/services/who-has.js +3 -3
  82. package/resources/{bacstack → node-bacnet}/lib/services/who-is.js +42 -9
  83. package/resources/{bacstack → node-bacnet}/lib/services/write-property-multiple.js +33 -16
  84. package/resources/{bacstack → node-bacnet}/lib/services/write-property.js +23 -13
  85. package/resources/node-bacnet/lib/transport.js +82 -0
  86. package/resources/node-bacnet/package.json +92 -0
  87. package/resources/primeicons.css +90 -2
  88. package/resources/bacstack/.codeclimate.yml +0 -15
  89. package/resources/bacstack/.dockerignore +0 -5
  90. package/resources/bacstack/.editorconfig +0 -13
  91. package/resources/bacstack/.eslintrc.yml +0 -13
  92. package/resources/bacstack/.github/ISSUE_TEMPLATE.md +0 -26
  93. package/resources/bacstack/.github/PULL_REQUEST_TEMPLATE.md +0 -14
  94. package/resources/bacstack/.github/workflows/ci.yml +0 -39
  95. package/resources/bacstack/.jscsrc +0 -8
  96. package/resources/bacstack/.jshintrc +0 -50
  97. package/resources/bacstack/.travis.yml +0 -27
  98. package/resources/bacstack/CHANGELOG.md +0 -232
  99. package/resources/bacstack/CODE_OF_CONDUCT.md +0 -74
  100. package/resources/bacstack/CONTRIBUTING.md +0 -77
  101. package/resources/bacstack/Dockerfile +0 -15
  102. package/resources/bacstack/FAQ.md +0 -64
  103. package/resources/bacstack/README.md +0 -157
  104. package/resources/bacstack/docker-compose.yml +0 -9
  105. package/resources/bacstack/lib/adpu.js +0 -190
  106. package/resources/bacstack/lib/bvlc.js +0 -43
  107. package/resources/bacstack/lib/client.js +0 -1028
  108. package/resources/bacstack/lib/enum.js +0 -1314
  109. package/resources/bacstack/lib/npdu.js +0 -119
  110. package/resources/bacstack/lib/services/i-am-broadcast.js +0 -51
  111. package/resources/bacstack/lib/services.js +0 -1963
  112. package/resources/bacstack/lib/transport.js +0 -52
  113. package/resources/bacstack/package-lock.json +0 -7974
  114. package/resources/bacstack/package.json +0 -84
  115. package/resources/bacstack/test/compliance/who-is.spec.js +0 -37
  116. package/resources/bacstack/test/integration/acknowledge-alarm.spec.js +0 -14
  117. package/resources/bacstack/test/integration/add-list-element.spec.js +0 -16
  118. package/resources/bacstack/test/integration/confirmed-event-notification.spec.js +0 -30
  119. package/resources/bacstack/test/integration/confirmed-private-transfer.spec.js +0 -15
  120. package/resources/bacstack/test/integration/create-object.spec.js +0 -16
  121. package/resources/bacstack/test/integration/delete-object.spec.js +0 -14
  122. package/resources/bacstack/test/integration/device-communication-control.spec.js +0 -14
  123. package/resources/bacstack/test/integration/get-alarm-summary.spec.js +0 -14
  124. package/resources/bacstack/test/integration/get-enrollment-summary.spec.js +0 -15
  125. package/resources/bacstack/test/integration/get-event-information.spec.js +0 -14
  126. package/resources/bacstack/test/integration/read-file.spec.js +0 -14
  127. package/resources/bacstack/test/integration/read-property-multiple.spec.js +0 -110
  128. package/resources/bacstack/test/integration/read-property.spec.js +0 -14
  129. package/resources/bacstack/test/integration/read-range.spec.js +0 -14
  130. package/resources/bacstack/test/integration/reinitialize-sevice.spec.js +0 -14
  131. package/resources/bacstack/test/integration/remove-list-element.spec.js +0 -16
  132. package/resources/bacstack/test/integration/subscribe-cov.spec.js +0 -14
  133. package/resources/bacstack/test/integration/subscribe-property.spec.js +0 -14
  134. package/resources/bacstack/test/integration/time-sync-utc.spec.js +0 -10
  135. package/resources/bacstack/test/integration/time-sync.spec.js +0 -10
  136. package/resources/bacstack/test/integration/unconfirmed-event-notification.spec.js +0 -28
  137. package/resources/bacstack/test/integration/unconfirmed-private-transfer.spec.js +0 -11
  138. package/resources/bacstack/test/integration/utils.js +0 -30
  139. package/resources/bacstack/test/integration/who-is.spec.js +0 -17
  140. package/resources/bacstack/test/integration/write-file.spec.js +0 -14
  141. package/resources/bacstack/test/integration/write-property-multiple.spec.js +0 -19
  142. package/resources/bacstack/test/integration/write-property.spec.js +0 -14
  143. package/resources/bacstack/test/unit/apdu.spec.js +0 -162
  144. package/resources/bacstack/test/unit/asn1.spec.js +0 -39
  145. package/resources/bacstack/test/unit/bacnet-apdu.spec.js +0 -161
  146. package/resources/bacstack/test/unit/bacnet-asn1.spec.js +0 -32
  147. package/resources/bacstack/test/unit/bacnet-bvlc.spec.js +0 -57
  148. package/resources/bacstack/test/unit/bacnet-npdu.spec.js +0 -118
  149. package/resources/bacstack/test/unit/bacnet-services.spec.js +0 -2052
  150. package/resources/bacstack/test/unit/bvlc.spec.js +0 -58
  151. package/resources/bacstack/test/unit/npdu.spec.js +0 -119
  152. package/resources/bacstack/test/unit/service-add-list-element.spec.js +0 -24
  153. package/resources/bacstack/test/unit/service-alarm-acknowledge.spec.js +0 -71
  154. package/resources/bacstack/test/unit/service-alarm-summary.spec.js +0 -22
  155. package/resources/bacstack/test/unit/service-atomic-read-file.spec.js +0 -54
  156. package/resources/bacstack/test/unit/service-atomic-write-file.spec.js +0 -56
  157. package/resources/bacstack/test/unit/service-cov-notify.spec.js +0 -98
  158. package/resources/bacstack/test/unit/service-create-object.spec.js +0 -90
  159. package/resources/bacstack/test/unit/service-delete-object.spec.js +0 -17
  160. package/resources/bacstack/test/unit/service-device-communication-control.spec.js +0 -29
  161. package/resources/bacstack/test/unit/service-error.spec.js +0 -17
  162. package/resources/bacstack/test/unit/service-event-information.spec.js +0 -48
  163. package/resources/bacstack/test/unit/service-event-notify-data.spec.js +0 -310
  164. package/resources/bacstack/test/unit/service-get-enrollment-summary.spec.js +0 -45
  165. package/resources/bacstack/test/unit/service-get-event-information.spec.js +0 -62
  166. package/resources/bacstack/test/unit/service-i-am.spec.js +0 -19
  167. package/resources/bacstack/test/unit/service-i-have-broadcast.spec.js +0 -18
  168. package/resources/bacstack/test/unit/service-life-safety-operation.spec.js +0 -19
  169. package/resources/bacstack/test/unit/service-private-transfer.spec.js +0 -18
  170. package/resources/bacstack/test/unit/service-read-property-multiple.spec.js +0 -131
  171. package/resources/bacstack/test/unit/service-read-property.spec.js +0 -541
  172. package/resources/bacstack/test/unit/service-read-range.spec.js +0 -97
  173. package/resources/bacstack/test/unit/service-reinitialize-device.spec.js +0 -27
  174. package/resources/bacstack/test/unit/service-subscribe-cov.spec.js +0 -32
  175. package/resources/bacstack/test/unit/service-subscribe-property.spec.js +0 -50
  176. package/resources/bacstack/test/unit/service-time-sync.spec.js +0 -18
  177. package/resources/bacstack/test/unit/service-who-has.spec.js +0 -33
  178. package/resources/bacstack/test/unit/service-who-is.spec.js +0 -17
  179. package/resources/bacstack/test/unit/service-write-property-multiple.spec.js +0 -143
  180. package/resources/bacstack/test/unit/service-write-property.spec.js +0 -198
  181. package/resources/bacstack/test/unit/utils.js +0 -6
@@ -0,0 +1,1759 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>client.js - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+
12
+ <link type="text/css" rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:400,700">
13
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
14
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
15
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
16
+ </head>
17
+ <body>
18
+
19
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
20
+ <label for="nav-trigger" class="navicon-button x">
21
+ <div class="navicon"></div>
22
+ </label>
23
+
24
+ <label for="nav-trigger" class="overlay"></label>
25
+
26
+ <nav >
27
+
28
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="bacnet.html">bacnet</a><ul class='methods'><li data-type='method'><a href="bacnet.html#.close">close</a></li><li data-type='method'><a href="bacnet.html#.confirmedCOVNotification">confirmedCOVNotification</a></li><li data-type='method'><a href="bacnet.html#.deviceCommunicationControl">deviceCommunicationControl</a></li><li data-type='method'><a href="bacnet.html#.iAmResponse">iAmResponse</a></li><li data-type='method'><a href="bacnet.html#.readProperty">readProperty</a></li><li data-type='method'><a href="bacnet.html#.readPropertyMultiple">readPropertyMultiple</a></li><li data-type='method'><a href="bacnet.html#.readPropertyResponse">readPropertyResponse</a></li><li data-type='method'><a href="bacnet.html#.reinitializeDevice">reinitializeDevice</a></li><li data-type='method'><a href="bacnet.html#.resultResponse">resultResponse</a></li><li data-type='method'><a href="bacnet.html#.timeSync">timeSync</a></li><li data-type='method'><a href="bacnet.html#.timeSyncUTC">timeSyncUTC</a></li><li data-type='method'><a href="bacnet.html#.unconfirmedCOVNotification">unconfirmedCOVNotification</a></li><li data-type='method'><a href="bacnet.html#.whoIs">whoIs</a></li><li data-type='method'><a href="bacnet.html#.writeProperty">writeProperty</a></li><li data-type='method'><a href="bacnet.html#.writePropertyMultiple">writePropertyMultiple</a></li></ul></li><li><a href="Client.html">Client</a><ul class='methods'><li data-type='method'><a href="Client.html#.createBitstring">createBitstring</a></li><li data-type='method'><a href="Client.html#acknowledgeAlarm">acknowledgeAlarm</a></li><li data-type='method'><a href="Client.html#addListElement">addListElement</a></li><li data-type='method'><a href="Client.html#confirmedEventNotification">confirmedEventNotification</a></li><li data-type='method'><a href="Client.html#confirmedPrivateTransfer">confirmedPrivateTransfer</a></li><li data-type='method'><a href="Client.html#createObject">createObject</a></li><li data-type='method'><a href="Client.html#deleteObject">deleteObject</a></li><li data-type='method'><a href="Client.html#errorResponse">errorResponse</a></li><li data-type='method'><a href="Client.html#getAlarmSummary">getAlarmSummary</a></li><li data-type='method'><a href="Client.html#getEnrollmentSummary">getEnrollmentSummary</a></li><li data-type='method'><a href="Client.html#getEventInformation">getEventInformation</a></li><li data-type='method'><a href="Client.html#iHaveResponse">iHaveResponse</a></li><li data-type='method'><a href="Client.html#readFile">readFile</a></li><li data-type='method'><a href="Client.html#readRange">readRange</a></li><li data-type='method'><a href="Client.html#removeListElement">removeListElement</a></li><li data-type='method'><a href="Client.html#sendBvlc">sendBvlc</a></li><li data-type='method'><a href="Client.html#simpleAckResponse">simpleAckResponse</a></li><li data-type='method'><a href="Client.html#subscribeCov">subscribeCov</a></li><li data-type='method'><a href="Client.html#subscribeProperty">subscribeProperty</a></li><li data-type='method'><a href="Client.html#unconfirmedEventNotification">unconfirmedEventNotification</a></li><li data-type='method'><a href="Client.html#unconfirmedPrivateTransfer">unconfirmedPrivateTransfer</a></li><li data-type='method'><a href="Client.html#writeFile">writeFile</a></li></ul></li></ul><h3>Events</h3><ul><li><a href="bacnet.html#.event:error">error</a></li><li><a href="bacnet.html#.event:iAm">iAm</a></li><li><a href="bacnet.html#.event:timeSync">timeSync</a></li><li><a href="bacnet.html#.event:whoIs">whoIs</a></li></ul><h3>Global</h3><ul><li><a href="global.html#ApplicationTag">ApplicationTag</a></li><li><a href="global.html#EnableDisable">EnableDisable</a></li><li><a href="global.html#MaxApduLengthAccepted">MaxApduLengthAccepted</a></li><li><a href="global.html#MaxSegmentsAccepted">MaxSegmentsAccepted</a></li><li><a href="global.html#ReinitializedState">ReinitializedState</a></li><li><a href="global.html#usc">usc</a></li></ul>
29
+ </nav>
30
+
31
+ <div id="main">
32
+
33
+ <h1 class="page-title">client.js</h1>
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+ <section>
42
+ <article>
43
+ <pre class="prettyprint source linenums"><code>'use strict';
44
+
45
+ // Util Modules
46
+ const EventEmitter = require('events').EventEmitter;
47
+ const debug = require('debug')('bacnet:client:debug');
48
+ const trace = require('debug')('bacnet:client:trace');
49
+ const usc = require('underscore');
50
+
51
+ // Local Modules
52
+ const baTransport = require('./transport');
53
+ const baServices = require('./services');
54
+ const baAsn1 = require('./asn1');
55
+ const baApdu = require('./apdu');
56
+ const baNpdu = require('./npdu');
57
+ const baBvlc = require('./bvlc');
58
+ const baEnum = require('./enum');
59
+
60
+ const ALL_INTERFACES = '0.0.0.0';
61
+ const LOCALHOST_INTERFACES_IPV4 = '127.0.0.1';
62
+ const BROADCAST_ADDRESS = '255.255.255.255';
63
+ const DEFAULT_HOP_COUNT = 0xFF;
64
+ const BVLC_HEADER_LENGTH = 4;
65
+ const BVLC_FWD_HEADER_LENGTH = 10; // FORWARDED_NPDU
66
+
67
+ const beU = baEnum.UnconfirmedServiceChoice;
68
+ const unconfirmedServiceMap = {
69
+ [beU.I_AM]: 'iAm',
70
+ [beU.WHO_IS]: 'whoIs',
71
+ [beU.WHO_HAS]: 'whoHas',
72
+ [beU.UNCONFIRMED_COV_NOTIFICATION]: 'covNotifyUnconfirmed',
73
+ [beU.TIME_SYNCHRONIZATION]: 'timeSync',
74
+ [beU.UTC_TIME_SYNCHRONIZATION]: 'timeSyncUTC',
75
+ [beU.UNCONFIRMED_EVENT_NOTIFICATION]: 'eventNotify',
76
+ [beU.I_HAVE]: 'iHave',
77
+ [beU.UNCONFIRMED_PRIVATE_TRANSFER]: 'privateTransfer',
78
+ };
79
+ const beC = baEnum.ConfirmedServiceChoice;
80
+ const confirmedServiceMap = {
81
+ [beC.READ_PROPERTY]: 'readProperty',
82
+ [beC.WRITE_PROPERTY]: 'writeProperty',
83
+ [beC.READ_PROPERTY_MULTIPLE]: 'readPropertyMultiple',
84
+ [beC.WRITE_PROPERTY_MULTIPLE]: 'writePropertyMultiple',
85
+ [beC.CONFIRMED_COV_NOTIFICATION]: 'covNotify',
86
+ [beC.ATOMIC_WRITE_FILE]: 'atomicWriteFile',
87
+ [beC.ATOMIC_READ_FILE]: 'atomicReadFile',
88
+ [beC.SUBSCRIBE_COV]: 'subscribeCov',
89
+ [beC.SUBSCRIBE_COV_PROPERTY]: 'subscribeProperty',
90
+ [beC.DEVICE_COMMUNICATION_CONTROL]: 'deviceCommunicationControl',
91
+ [beC.REINITIALIZE_DEVICE]: 'reinitializeDevice',
92
+ [beC.CONFIRMED_EVENT_NOTIFICATION]: 'eventNotify',
93
+ [beC.READ_RANGE]: 'readRange',
94
+ [beC.CREATE_OBJECT]: 'createObject',
95
+ [beC.DELETE_OBJECT]: 'deleteObject',
96
+ [beC.ACKNOWLEDGE_ALARM]: 'alarmAcknowledge',
97
+ [beC.GET_ALARM_SUMMARY]: 'getAlarmSummary',
98
+ [beC.GET_ENROLLMENT_SUMMARY]: 'getEnrollmentSummary',
99
+ [beC.GET_EVENT_INFORMATION]: 'getEventInformation',
100
+ [beC.LIFE_SAFETY_OPERATION]: 'lifeSafetyOperation',
101
+ [beC.ADD_LIST_ELEMENT]: 'addListElement',
102
+ [beC.REMOVE_LIST_ELEMENT]: 'removeListElement',
103
+ [beC.CONFIRMED_PRIVATE_TRANSFER]: 'privateTransfer',
104
+ };
105
+
106
+ /**
107
+ * To be able to communicate to BACNET devices, you have to initialize a new bacnet instance.
108
+ * @class bacnet
109
+ * @param {object=} this._settings - The options object used for parameterizing the bacnet.
110
+ * @param {number=} [options.port=47808] - BACNET communication port for listening and sending.
111
+ * @param {string=} options.interface - Specific BACNET communication interface if different from primary one.
112
+ * @param {string=} [options.broadcastAddress=255.255.255.255] - The address used for broadcast messages.
113
+ * @param {number=} [options.apduTimeout=3000] - The timeout in milliseconds until a transaction should be interpreted as error.
114
+ * @example
115
+ * const bacnet = require('node-bacnet');
116
+ *
117
+ * const client = new bacnet({
118
+ * port: 47809, // Use BAC1 as communication port
119
+ * interface: '192.168.251.10', // Listen on a specific interface
120
+ * broadcastAddress: '192.168.251.255', // Use the subnet broadcast address
121
+ * apduTimeout: 6000 // Wait twice as long for response
122
+ * });
123
+ */
124
+ class Client extends EventEmitter {
125
+ /**
126
+ *
127
+ * @param options
128
+ */
129
+ constructor(options) {
130
+ super();
131
+
132
+ options = options || {};
133
+
134
+ this._invokeCounter = 1;
135
+ this._invokeStore = {};
136
+
137
+ this._lastSequenceNumber = 0;
138
+ this._segmentStore = [];
139
+
140
+ this._settings = {
141
+ port: options.port || 47808,
142
+ interface: options.interface || ALL_INTERFACES,
143
+ transport: options.transport,
144
+ broadcastAddress: options.broadcastAddress || BROADCAST_ADDRESS,
145
+ apduTimeout: options.apduTimeout || 3000
146
+ };
147
+
148
+ options.reuseAddr = options.reuseAddr === undefined ? true : !!options.reuseAddr;
149
+
150
+ this._transport = this._settings.transport || new baTransport({
151
+ port: this._settings.port,
152
+ interface: this._settings.interface,
153
+ broadcastAddress: this._settings.broadcastAddress,
154
+ reuseAddr: options.reuseAddr
155
+ });
156
+
157
+ // Setup code
158
+ this._transport.on('message', this._receiveData.bind(this));
159
+ this._transport.on('error', this._receiveError.bind(this));
160
+ this._transport.on('listening', () => this.emit('listening'));
161
+ this._transport.open();
162
+ }
163
+
164
+ /**
165
+ *
166
+ * @returns {number}
167
+ * @private
168
+ */
169
+ _getInvokeId() {
170
+ const id = this._invokeCounter++;
171
+ if (id >= 256) this._invokeCounter = 1;
172
+ return id - 1;
173
+ }
174
+
175
+ /**
176
+ *
177
+ * @param id
178
+ * @param err
179
+ * @param result
180
+ * @returns {*}
181
+ * @private
182
+ */
183
+ _invokeCallback(id, err, result) {
184
+ const callback = this._invokeStore[id];
185
+ if (callback) {
186
+ return void callback(err, result);
187
+ }
188
+ debug('InvokeId', id, 'not found -> drop package');
189
+ }
190
+
191
+ /**
192
+ *
193
+ * @param id
194
+ * @param callback
195
+ * @private
196
+ */
197
+ _addCallback(id, callback) {
198
+ const timeout = setTimeout(() => {
199
+ delete this._invokeStore[id];
200
+ callback(new Error('ERR_TIMEOUT'));
201
+ }, this._settings.apduTimeout);
202
+ this._invokeStore[id] = (err, data) => {
203
+ clearTimeout(timeout);
204
+ delete this._invokeStore[id];
205
+ callback(err, data);
206
+ };
207
+ }
208
+
209
+ /**
210
+ *
211
+ * @param isForwarded
212
+ * @returns {{offset: (number), buffer: *}}
213
+ * @private
214
+ */
215
+ _getBuffer(isForwarded) {
216
+ return Object.assign({}, {
217
+ buffer: Buffer.alloc(this._transport.getMaxPayload()),
218
+ offset: isForwarded ? BVLC_FWD_HEADER_LENGTH : BVLC_HEADER_LENGTH
219
+ });
220
+ }
221
+
222
+ /**
223
+ *
224
+ * @param invokeId
225
+ * @param buffer
226
+ * @param offset
227
+ * @param length
228
+ * @returns {*}
229
+ * @private
230
+ */
231
+ _processError(invokeId, buffer, offset, length) {
232
+ const result = baServices.error.decode(buffer, offset, length);
233
+ trace('Received error:', result);
234
+ if (!result) {
235
+ return debug('Couldn`t decode Error');
236
+ }
237
+ const err = new Error(baServices.error.buildMessage(result));
238
+ err.bacnetErrorClass = result.class;
239
+ err.bacnetErrorCode = result.code;
240
+ this._invokeCallback(invokeId, err);
241
+ }
242
+
243
+ /**
244
+ *
245
+ * @param invokeId
246
+ * @param reason
247
+ * @private
248
+ */
249
+ _processAbort(invokeId, reason) {
250
+ const err = new Error('BacnetAbort - Reason:' + reason);
251
+ err.bacnetAbortReason = reason;
252
+ this._invokeCallback(invokeId, err);
253
+ }
254
+
255
+ /**
256
+ *
257
+ * @param receiver
258
+ * @param negative
259
+ * @param server
260
+ * @param originalInvokeId
261
+ * @param sequencenumber
262
+ * @param actualWindowSize
263
+ * @private
264
+ */
265
+ _segmentAckResponse(receiver, negative, server, originalInvokeId, sequencenumber, actualWindowSize) {
266
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
267
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
268
+ baApdu.encodeSegmentAck(buffer, baEnum.PduType.SEGMENT_ACK | (negative ? baEnum.PduSegAckBit.NEGATIVE_ACK : 0) | (server ? baEnum.PduSegAckBit.SERVER : 0), originalInvokeId, sequencenumber, actualWindowSize);
269
+ this.sendBvlc(receiver, buffer);
270
+ }
271
+
272
+ /**
273
+ *
274
+ * @param msg
275
+ * @param first
276
+ * @param moreFollows
277
+ * @param buffer
278
+ * @param offset
279
+ * @param length
280
+ * @private
281
+ */
282
+ _performDefaultSegmentHandling(msg, first, moreFollows, buffer, offset, length) {
283
+ if (first) {
284
+ this._segmentStore = [];
285
+ msg.type &amp;= ~baEnum.PduConReqBit.SEGMENTED_MESSAGE;
286
+ let apduHeaderLen = 3;
287
+ if ((msg.type &amp; baEnum.PDU_TYPE_MASK) === baEnum.PduType.CONFIRMED_REQUEST) {
288
+ apduHeaderLen = 4;
289
+ }
290
+ const apdubuffer = this._getBuffer();
291
+ apdubuffer.offset = 0;
292
+ buffer.copy(apdubuffer.buffer, apduHeaderLen, offset, offset + length);
293
+ if ((msg.type &amp; baEnum.PDU_TYPE_MASK) === baEnum.PduType.CONFIRMED_REQUEST) {
294
+ baApdu.encodeConfirmedServiceRequest(
295
+ apdubuffer,
296
+ msg.type,
297
+ msg.service,
298
+ msg.maxSegments,
299
+ msg.maxApdu,
300
+ msg.invokeId,
301
+ 0,
302
+ 0
303
+ );
304
+ } else {
305
+ baApdu.encodeComplexAck(apdubuffer, msg.type, msg.service, msg.invokeId, 0, 0);
306
+ }
307
+ this._segmentStore.push(apdubuffer.buffer.slice(0, length + apduHeaderLen));
308
+ } else {
309
+ this._segmentStore.push(buffer.slice(offset, offset + length));
310
+ }
311
+ if (!moreFollows) {
312
+ const apduBuffer = Buffer.concat(this._segmentStore);
313
+ this._segmentStore = [];
314
+ msg.type &amp;= ~baEnum.PduConReqBit.SEGMENTED_MESSAGE;
315
+ this._handlePdu(apduBuffer, 0, apduBuffer.length, msg.header);
316
+ }
317
+ }
318
+
319
+ /**
320
+ *
321
+ * @param msg
322
+ * @param server
323
+ * @param buffer
324
+ * @param offset
325
+ * @param length
326
+ * @private
327
+ */
328
+ _processSegment(msg, server, buffer, offset, length) {
329
+ let first = false;
330
+ if (msg.sequencenumber === 0 &amp;&amp; this._lastSequenceNumber === 0) {
331
+ first = true;
332
+ } else {
333
+ if (msg.sequencenumber !== this._lastSequenceNumber + 1) {
334
+ return this._segmentAckResponse(msg.header.address, true, server, msg.invokeId, this._lastSequenceNumber, msg.proposedWindowNumber);
335
+ }
336
+ }
337
+ this._lastSequenceNumber = msg.sequencenumber;
338
+ const moreFollows = msg.type &amp; baEnum.PduConReqBit.MORE_FOLLOWS;
339
+ if (!moreFollows) {
340
+ this._lastSequenceNumber = 0;
341
+ }
342
+ if ((msg.sequencenumber % msg.proposedWindowNumber) === 0 || !moreFollows) {
343
+ this._segmentAckResponse(msg.header.address, false, server, msg.invokeId, msg.sequencenumber, msg.proposedWindowNumber);
344
+ }
345
+ this._performDefaultSegmentHandling(msg, first, moreFollows, buffer, offset, length);
346
+ }
347
+
348
+ /**
349
+ *
350
+ * @param serviceMap
351
+ * @param content
352
+ * @param buffer
353
+ * @param offset
354
+ * @param length
355
+ * @returns {*}
356
+ * @private
357
+ */
358
+ _processServiceRequest(serviceMap, content, buffer, offset, length) {
359
+ let result;
360
+
361
+ const sender = content.header.sender;
362
+ if (sender.address === LOCALHOST_INTERFACES_IPV4) {
363
+ debug('Received and skipped localhost service request:', content.service);
364
+ return;
365
+ }
366
+
367
+ const name = serviceMap[content.service];
368
+ if (!name) {
369
+ debug('Received unsupported service request:', content.service);
370
+ return;
371
+ }
372
+
373
+ const id = content.invokeId ? '@' + content.invokeId : '';
374
+ trace(`Received service request${id}:`, name);
375
+
376
+ // Find a function to decode the packet.
377
+ const serviceHandler = baServices[name];
378
+ if (serviceHandler) {
379
+ try {
380
+ content.payload = serviceHandler.decode(buffer, offset, length);
381
+ trace(`Handled service request${id}:`, name, JSON.stringify(content));
382
+ } catch (e) {
383
+ // Sometimes incomplete or corrupted messages will cause exceptions
384
+ // during decoding, but we don't want these to terminate the program, so
385
+ // we'll just log them and ignore them.
386
+ debug('Exception thrown when processing message:', e);
387
+ debug('Original message was', name + ':', content);
388
+ return;
389
+ }
390
+ if (!content.payload) {
391
+ return debug('Received invalid', name, 'message');
392
+ }
393
+ } else {
394
+ debug('No serviceHandler defined for:', name);
395
+ // Call the callback anyway, just with no payload.
396
+ }
397
+ //trace('Passing payload over to callback:', content);
398
+
399
+ // Call the user code, if they've defined a callback.
400
+ if (this.listenerCount(name)) {
401
+ trace('listener count by name emits ' + name + ' with content');
402
+ this.emit(name, content);
403
+ } else {
404
+ if (this.listenerCount('unhandledEvent')) {
405
+ trace('unhandled event emiting with content');
406
+ this.emit('unhandledEvent', content);
407
+ } else {
408
+ // No 'unhandled event' handler, so respond with an error ourselves.
409
+ // This is better than doing nothing, which can often make the other
410
+ // device think we have gone offline.
411
+ trace('no unhandled event handler with header: ' + JSON.stringify(content.header));
412
+ if (content.header.expectingReply) {
413
+ debug('Replying with error for unhandled service:', name);
414
+ // Make sure we don't reply pretending to be the caller, if we got a
415
+ // forwarded message! Really this should be overridden to be your
416
+ // own IP, but only if it's not null/undefined to begin with.
417
+ content.header.sender.forwardedFrom = null;
418
+ this.errorResponse(
419
+ content.header.sender,
420
+ content.service,
421
+ content.invokeId,
422
+ baEnum.ErrorClass.SERVICES,
423
+ baEnum.ErrorCode.REJECT_UNRECOGNIZED_SERVICE
424
+ );
425
+ }
426
+ }
427
+ }
428
+ }
429
+
430
+ /**
431
+ *
432
+ * @param buffer
433
+ * @param offset
434
+ * @param length
435
+ * @param header
436
+ * @private
437
+ */
438
+ _handlePdu(buffer, offset, length, header) {
439
+ let msg;
440
+ trace('handlePdu Header: ', header);
441
+ // Handle different PDU types
442
+ switch (header.apduType &amp; baEnum.PDU_TYPE_MASK) {
443
+ case baEnum.PduType.UNCONFIRMED_REQUEST:
444
+ msg = baApdu.decodeUnconfirmedServiceRequest(buffer, offset);
445
+ msg.header = header;
446
+ msg.header.confirmedService = false;
447
+ this._processServiceRequest(unconfirmedServiceMap, msg, buffer, offset + msg.len, length - msg.len);
448
+ break;
449
+ case baEnum.PduType.SIMPLE_ACK:
450
+ msg = baApdu.decodeSimpleAck(buffer, offset);
451
+ offset += msg.len;
452
+ length -= msg.len;
453
+ this._invokeCallback(msg.invokeId, null, {msg: msg, buffer: buffer, offset: offset + msg.len, length: length - msg.len});
454
+ break;
455
+ case baEnum.PduType.COMPLEX_ACK:
456
+ msg = baApdu.decodeComplexAck(buffer, offset);
457
+ msg.header = header;
458
+ if ((header.apduType &amp; baEnum.PduConReqBit.SEGMENTED_MESSAGE) === 0) {
459
+ this._invokeCallback(msg.invokeId, null, {msg: msg, buffer: buffer, offset: offset + msg.len, length: length - msg.len});
460
+ } else {
461
+ this._processSegment(msg, true, buffer, offset + msg.len, length - msg.len);
462
+ }
463
+ break;
464
+ case baEnum.PduType.SEGMENT_ACK:
465
+ msg = baApdu.decodeSegmentAck(buffer, offset);
466
+ msg.header = header;
467
+ this._processSegment(msg, true, buffer, offset + msg.len, length - msg.len);
468
+ break;
469
+ case baEnum.PduType.ERROR:
470
+ msg = baApdu.decodeError(buffer, offset);
471
+ this._processError(msg.invokeId, buffer, offset + msg.len, length - msg.len);
472
+ break;
473
+ case baEnum.PduType.REJECT:
474
+ case baEnum.PduType.ABORT:
475
+ msg = baApdu.decodeAbort(buffer, offset);
476
+ this._processAbort(msg.invokeId, msg.reason);
477
+ break;
478
+ case baEnum.PduType.CONFIRMED_REQUEST:
479
+ msg = baApdu.decodeConfirmedServiceRequest(buffer, offset);
480
+ msg.header = header;
481
+ msg.header.confirmedService = true;
482
+ if ((header.apduType &amp; baEnum.PduConReqBit.SEGMENTED_MESSAGE) === 0) {
483
+ this._processServiceRequest(confirmedServiceMap, msg, buffer, offset + msg.len, length - msg.len);
484
+ } else {
485
+ this._processSegment(msg, true, buffer, offset + msg.len, length - msg.len);
486
+ }
487
+ break;
488
+ default:
489
+ debug(`Received unknown PDU type ${header.apduType} -> Drop packet`);
490
+ break;
491
+ }
492
+ }
493
+
494
+ /**
495
+ *
496
+ * @param buffer
497
+ * @param offset
498
+ * @param msgLength
499
+ * @param header
500
+ * @returns {*}
501
+ * @private
502
+ */
503
+ _handleNpdu(buffer, offset, msgLength, header) {
504
+ // Check data length
505
+ if (msgLength &lt;= 0) {
506
+ return trace('No NPDU data -> Drop package');
507
+ }
508
+ // Parse baNpdu header
509
+ const result = baNpdu.decode(buffer, offset);
510
+ if (!result) {
511
+ return trace('Received invalid NPDU header -> Drop package');
512
+ }
513
+ if (result.funct &amp; baEnum.NpduControlBit.NETWORK_LAYER_MESSAGE) {
514
+ return trace('Received network layer message -> Drop package');
515
+ }
516
+ offset += result.len;
517
+ msgLength -= result.len;
518
+ if (msgLength &lt;= 0) {
519
+ return trace('No APDU data -> Drop package');
520
+ }
521
+ header.apduType = baApdu.getDecodedType(buffer, offset);
522
+ header.expectingReply = !!(result.funct &amp; baEnum.NpduControlBit.EXPECTING_REPLY);
523
+ this._handlePdu(buffer, offset, msgLength, header);
524
+ }
525
+
526
+ /**
527
+ *
528
+ * @param buffer
529
+ * @param remoteAddress
530
+ * @returns {*}
531
+ * @private
532
+ */
533
+ _receiveData(buffer, remoteAddress) {
534
+ // Check data length
535
+ if (buffer.length &lt; baEnum.BVLC_HEADER_LENGTH) {
536
+ return trace('Received invalid data -> Drop package');
537
+ }
538
+ // Parse BVLC header
539
+ const result = baBvlc.decode(buffer, 0);
540
+ if (!result) {
541
+ return trace('Received invalid BVLC header -> Drop package');
542
+ }
543
+ let header = {
544
+ // Which function the packet came in on, so later code can distinguish
545
+ // between ORIGINAL_BROADCAST_NPDU and DISTRIBUTE_BROADCAST_TO_NETWORK.
546
+ func: result.func,
547
+ sender: {
548
+ // Address of the host we are directly connected to. String, IP:port.
549
+ address: remoteAddress,
550
+ // If the host is a BBMD passing messages along to another node, this
551
+ // is the address of the distant BACnet node. String, IP:port.
552
+ // Typically we won't have network connectivity to this address, but
553
+ // we have to include it in replies so the host we are connect to knows
554
+ // where to forward the messages.
555
+ forwardedFrom: null,
556
+ },
557
+ };
558
+ // Check BVLC function
559
+ switch (result.func) {
560
+ case baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU:
561
+ case baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU:
562
+ this._handleNpdu(buffer, result.len, buffer.length - result.len, header);
563
+ break;
564
+ case baEnum.BvlcResultPurpose.FORWARDED_NPDU:
565
+ // Preserve the IP of the node behind the BBMD so we know where to send
566
+ // replies back to.
567
+ header.sender.forwardedFrom = result.originatingIP;
568
+ this._handleNpdu(buffer, result.len, buffer.length - result.len, header);
569
+ break;
570
+ case baEnum.BvlcResultPurpose.REGISTER_FOREIGN_DEVICE:
571
+ let decodeResult = baServices.registerForeignDevice.decode(buffer, result.len, buffer.length - result.len);
572
+ if (!decodeResult) {
573
+ return trace('Received invalid registerForeignDevice message');
574
+ }
575
+ this.emit('registerForeignDevice', {
576
+ header: header,
577
+ payload: decodeResult,
578
+ });
579
+ break;
580
+ case baEnum.BvlcResultPurpose.DISTRIBUTE_BROADCAST_TO_NETWORK:
581
+ this._handleNpdu(buffer, result.len, buffer.length - result.len, header);
582
+ break;
583
+ default:
584
+ debug('Received unknown BVLC function ' + result.func + ' -> Drop package');
585
+ break;
586
+ }
587
+ }
588
+
589
+ /**
590
+ * @event bacnet.error
591
+ * @param {error} err - The error object thrown by the underlying transport layer.
592
+ * @example
593
+ * const bacnet = require('node-bacnet');
594
+ * const client = new bacnet();
595
+ *
596
+ * client.on('error', (err) => {
597
+ * console.log('Error occurred: ', err);
598
+ * client.close();
599
+ * });
600
+ */
601
+ _receiveError(err) {
602
+ this.emit('error', err);
603
+ }
604
+
605
+ /**
606
+ * The whoIs command discovers all BACNET devices in a network.
607
+ * @function bacnet.whoIs
608
+ * @param {string} receiver - IP address of the target device.
609
+ * @param {object=} options
610
+ * @param {number=} options.lowLimit - Minimal device instance number to search for.
611
+ * @param {number=} options.highLimit - Maximal device instance number to search for.
612
+ * @fires bacnet.iAm
613
+ * @example
614
+ * const bacnet = require('node-bacnet');
615
+ * const client = new bacnet();
616
+ *
617
+ * client.whoIs();
618
+ */
619
+ whoIs(receiver, options) {
620
+ if (!options) {
621
+ if (
622
+ receiver &amp;&amp;
623
+ typeof receiver === 'object' &amp;&amp;
624
+ receiver.address === undefined &amp;&amp;
625
+ receiver.forwardedFrom === undefined &amp;&amp;
626
+ (receiver.lowLimit !== undefined || receiver.highLimit !== undefined)
627
+ ) {
628
+ // receiver seems to be an options object
629
+ options = receiver;
630
+ receiver = undefined;
631
+ }
632
+ }
633
+ options = options || {};
634
+
635
+ const settings = {
636
+ lowLimit: options.lowLimit,
637
+ highLimit: options.highLimit,
638
+ };
639
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
640
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
641
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.WHO_IS);
642
+ baServices.whoIs.encode(buffer, settings.lowLimit, settings.highLimit);
643
+ this.sendBvlc(receiver, buffer);
644
+ }
645
+
646
+ /**
647
+ * The timeSync command sets the time of a target device.
648
+ * @function bacnet.timeSync
649
+ * @param {string} receiver - IP address of the target device.
650
+ * @param {date} dateTime - The date and time to set on the target device.
651
+ * @example
652
+ * const bacnet = require('node-bacnet');
653
+ * const client = new bacnet();
654
+ *
655
+ * client.timeSync('192.168.1.43', new Date());
656
+ */
657
+ timeSync(receiver, dateTime) {
658
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
659
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
660
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.TIME_SYNCHRONIZATION);
661
+ baServices.timeSync.encode(buffer, dateTime);
662
+ this.sendBvlc(receiver, buffer);
663
+ }
664
+
665
+ /**
666
+ * The timeSyncUTC command sets the UTC time of a target device.
667
+ * @function bacnet.timeSyncUTC
668
+ * @param {string} receiver - IP address of the target device.
669
+ * @param {date} dateTime - The date and time to set on the target device.
670
+ * @example
671
+ * const bacnet = require('node-bacnet');
672
+ * const client = new bacnet();
673
+ *
674
+ * client.timeSyncUTC('192.168.1.43', new Date());
675
+ */
676
+ timeSyncUTC(receiver, dateTime) {
677
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
678
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
679
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.UTC_TIME_SYNCHRONIZATION);
680
+ baServices.timeSync.encode(buffer, dateTime);
681
+ this.sendBvlc(receiver, buffer);
682
+ }
683
+
684
+ /**
685
+ * The readProperty command reads a single property of an object from a device.
686
+ * @function bacnet.readProperty
687
+ * @param {string} receiver - IP address of the target device.
688
+ * @param {object} objectId - The BACNET object ID to read.
689
+ * @param {number} objectId.type - The BACNET object type to read.
690
+ * @param {number} objectId.instance - The BACNET object instance to read.
691
+ * @param {number} propertyId - The BACNET property id in the specified object to read.
692
+ * @param {object=} options
693
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
694
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
695
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
696
+ * @param {number=} options.arrayIndex - The array index of the property to be read.
697
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
698
+ * @example
699
+ * const bacnet = require('node-bacnet');
700
+ * const client = new bacnet();
701
+ *
702
+ * client.readProperty('192.168.1.43', {type: 8, instance: 44301}, 28, (err, value) => {
703
+ * console.log('value: ', value);
704
+ * });
705
+ */
706
+ readProperty(receiver, objectId, propertyId, options, next) {
707
+ next = next || options;
708
+ const settings = {
709
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
710
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
711
+ invokeId: options.invokeId || this._getInvokeId(),
712
+ arrayIndex: (options.arrayIndex || options.arrayIndex === 0) ? options.arrayIndex : baEnum.ASN1_ARRAY_ALL
713
+ };
714
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
715
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
716
+ const type = baEnum.PduType.CONFIRMED_REQUEST | (settings.maxSegments !== baEnum.MaxSegmentsAccepted.SEGMENTS_0 ? baEnum.PduConReqBit.SEGMENTED_RESPONSE_ACCEPTED : 0);
717
+ baApdu.encodeConfirmedServiceRequest(buffer, type, baEnum.ConfirmedServiceChoice.READ_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
718
+ baServices.readProperty.encode(buffer, objectId.type, objectId.instance, propertyId, settings.arrayIndex);
719
+ this.sendBvlc(receiver, buffer);
720
+ this._addCallback(settings.invokeId, (err, data) => {
721
+ if (err) {
722
+ return void next(err);
723
+ }
724
+ const result = baServices.readProperty.decodeAcknowledge(data.buffer, data.offset, data.length);
725
+ if (!result) {
726
+ return void next(new Error('INVALID_DECODING'));
727
+ }
728
+ next(null, result);
729
+ });
730
+ }
731
+
732
+ /**
733
+ * The writeProperty command writes a single property of an object to a device.
734
+ * @function bacnet.writeProperty
735
+ * @param {string} receiver - IP address of the target device.
736
+ * @param {object} objectId - The BACNET object ID to write.
737
+ * @param {number} objectId.type - The BACNET object type to write.
738
+ * @param {number} objectId.instance - The BACNET object instance to write.
739
+ * @param {number} propertyId - The BACNET property id in the specified object to write.
740
+ * @param {object[]} values - A list of values to be written to the specified property.
741
+ * @param {ApplicationTag} values.type - The data-type of the value to be written.
742
+ * @param {number} values.value - The actual value to be written.
743
+ * @param {object=} options
744
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
745
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
746
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
747
+ * @param {number=} options.arrayIndex - The array index of the property to be read.
748
+ * @param {number=} options.priority - The priority of the value to be written.
749
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
750
+ * @example
751
+ * const bacnet = require('node-bacnet');
752
+ * const client = new bacnet();
753
+ *
754
+ * client.writeProperty('192.168.1.43', {type: 8, instance: 44301}, 28, [
755
+ * {type: bacnet.enum.ApplicationTag.REAL, value: 100}
756
+ * ], (err, value) => {
757
+ * console.log('value: ', value);
758
+ * });
759
+ */
760
+ writeProperty(receiver, objectId, propertyId, values, options, next) {
761
+ next = next || options;
762
+ const settings = {
763
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
764
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
765
+ invokeId: options.invokeId || this._getInvokeId(),
766
+ arrayIndex: options.arrayIndex || baEnum.ASN1_ARRAY_ALL,
767
+ priority: options.priority || baEnum.ASN1_NO_PRIORITY
768
+ };
769
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
770
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
771
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.WRITE_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
772
+ baServices.writeProperty.encode(buffer, objectId.type, objectId.instance, propertyId, settings.arrayIndex, settings.priority, values);
773
+ this.sendBvlc(receiver, buffer);
774
+ this._addCallback(settings.invokeId, (err, data) => {
775
+ next(err);
776
+ });
777
+ }
778
+
779
+ /**
780
+ * The readPropertyMultiple command reads multiple properties in multiple objects from a device.
781
+ * @function bacnet.readPropertyMultiple
782
+ * @param {string} receiver - IP address of the target device.
783
+ * @param {object[]} propertiesArray - List of object and property specifications to be read.
784
+ * @param {object} propertiesArray.objectId - Specifies which object to read.
785
+ * @param {number} propertiesArray.objectId.type - The BACNET object type to read.
786
+ * @param {number} propertiesArray.objectId.instance - The BACNET object instance to read.
787
+ * @param {object[]} propertiesArray.properties - List of properties to be read.
788
+ * @param {number} propertiesArray.properties.id - The BACNET property id in the specified object to read. Also supports 8 for all properties.
789
+ * @param {object=} options
790
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
791
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
792
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
793
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
794
+ * @example
795
+ * const bacnet = require('node-bacnet');
796
+ * const client = new bacnet();
797
+ *
798
+ * const requestArray = [
799
+ * {objectId: {type: 8, instance: 4194303}, properties: [{id: 8}]}
800
+ * ];
801
+ * client.readPropertyMultiple('192.168.1.43', requestArray, (err, value) => {
802
+ * console.log('value: ', value);
803
+ * });
804
+ */
805
+ readPropertyMultiple(receiver, propertiesArray, options, next) {
806
+ next = next || options;
807
+ const settings = {
808
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
809
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
810
+ invokeId: options.invokeId || this._getInvokeId()
811
+ };
812
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
813
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
814
+ const type = baEnum.PduType.CONFIRMED_REQUEST | (settings.maxSegments !== baEnum.MaxSegmentsAccepted.SEGMENTS_0 ? baEnum.PduConReqBit.SEGMENTED_RESPONSE_ACCEPTED : 0);
815
+ baApdu.encodeConfirmedServiceRequest(buffer, type, baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
816
+ baServices.readPropertyMultiple.encode(buffer, propertiesArray);
817
+ this.sendBvlc(receiver, buffer);
818
+ this._addCallback(settings.invokeId, (err, data) => {
819
+ if (err) {
820
+ return void next(err);
821
+ }
822
+ const result = baServices.readPropertyMultiple.decodeAcknowledge(data.buffer, data.offset, data.length);
823
+ if (!result) {
824
+ return void next(new Error('INVALID_DECODING'));
825
+ }
826
+ next(null, result);
827
+ });
828
+ }
829
+
830
+ /**
831
+ * The writePropertyMultiple command writes multiple properties in multiple objects to a device.
832
+ * @function bacnet.writePropertyMultiple
833
+ * @param {string} receiver - IP address of the target device.
834
+ * @param {object[]} values - List of object and property specifications to be written.
835
+ * @param {object} values.objectId - Specifies which object to read.
836
+ * @param {number} values.objectId.type - The BACNET object type to read.
837
+ * @param {number} values.objectId.instance - The BACNET object instance to read.
838
+ * @param {object[]} values.values - List of properties to be written.
839
+ * @param {object} values.values.property - Property specifications to be written.
840
+ * @param {number} values.values.property.id - The BACNET property id in the specified object to write.
841
+ * @param {number} values.values.property.index - The array index of the property to be written.
842
+ * @param {object[]} values.values.value - A list of values to be written to the specified property.
843
+ * @param {ApplicationTag} values.values.value.type - The data-type of the value to be written.
844
+ * @param {object} values.values.value.value - The actual value to be written.
845
+ * @param {number} values.values.priority - The priority to be used for writing to the property.
846
+ * @param {object=} options
847
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
848
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
849
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
850
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
851
+ * @example
852
+ * const bacnet = require('node-bacnet');
853
+ * const client = new bacnet();
854
+ *
855
+ * const values = [
856
+ * {objectId: {type: 8, instance: 44301}, values: [
857
+ * {property: {id: 28, index: 12}, value: [{type: bacnet.enum.ApplicationTag.BOOLEAN, value: true}], priority: 8}
858
+ * ]}
859
+ * ];
860
+ * client.writePropertyMultiple('192.168.1.43', values, (err, value) => {
861
+ * console.log('value: ', value);
862
+ * });
863
+ */
864
+ writePropertyMultiple(receiver, values, options, next) {
865
+ next = next || options;
866
+ const settings = {
867
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
868
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
869
+ invokeId: options.invokeId || this._getInvokeId()
870
+ };
871
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
872
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
873
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.WRITE_PROPERTY_MULTIPLE, settings.maxSegments, settings.maxApdu, settings.invokeId);
874
+ baServices.writePropertyMultiple.encodeObject(buffer, values);
875
+ this.sendBvlc(receiver, buffer);
876
+ this._addCallback(settings.invokeId, (err, data) => {
877
+ next(err);
878
+ });
879
+ }
880
+
881
+ /**
882
+ * The confirmedCOVNotification command is used to push notifications to other
883
+ * systems that have registered with us via a subscribeCOV message.
884
+ * @function bacnet.confirmedCOVNotification
885
+ * @param {string} receiver - IP address of the target device.
886
+ * @param {object} monitoredObject - The object being monitored, from subscribeCOV.
887
+ * @param {number} monitoredObject.type - Object type.
888
+ * @param {number} monitoredObject.instance - Object instance.
889
+ * @param {number} subscribeId - Subscriber ID from subscribeCOV,
890
+ * @param {number} initiatingDeviceId - Our BACnet device ID.
891
+ * @param {number} lifetime - Number of seconds left until the subscription expires.
892
+ * @param {array} values - values for the monitored object. See example.
893
+ * @param {object=} options
894
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
895
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
896
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
897
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
898
+ * @example
899
+ * const bacnet = require('node-bacnet');
900
+ * const client = new bacnet();
901
+ *
902
+ * const settings = {deviceId: 123}; // our BACnet device
903
+ *
904
+ * // Items saved from subscribeCOV message
905
+ * const monitoredObject = {type: 1, instance: 1};
906
+ * const subscriberProcessId = 123;
907
+ *
908
+ * client.confirmedCOVNotification(
909
+ * '192.168.1.43',
910
+ * monitoredObject,
911
+ * subscriberProcessId,
912
+ * settings.deviceId,
913
+ * 30, // should be lifetime of subscription really
914
+ * [
915
+ * {
916
+ * property: { id: bacnet.enum.PropertyIdentifier.PRESENT_VALUE },
917
+ * value: [
918
+ * {value: 123, type: bacnet.enum.ApplicationTag.REAL},
919
+ * ],
920
+ * },
921
+ * ],
922
+ * (err) => {
923
+ * console.log('error: ', err);
924
+ * }
925
+ * );
926
+ */
927
+ confirmedCOVNotification(receiver, monitoredObject, subscribeId, initiatingDeviceId, lifetime, values, options, next) {
928
+ next = next || options;
929
+ const settings = {
930
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
931
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
932
+ invokeId: options.invokeId || this._getInvokeId()
933
+ };
934
+ const buffer = this._getBuffer();
935
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
936
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.CONFIRMED_COV_NOTIFICATION, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
937
+ baServices.covNotify.encode(buffer, subscribeId, initiatingDeviceId, monitoredObject, lifetime, values);
938
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
939
+ this.sendBvlc(receiver, buffer);
940
+ this._addCallback(settings.invokeId, (err, data) => {
941
+ if (err) {
942
+ return void next(err);
943
+ }
944
+ next();
945
+ });
946
+ }
947
+
948
+ /**
949
+ * The deviceCommunicationControl command enables or disables network communication of the target device.
950
+ * @function bacnet.deviceCommunicationControl
951
+ * @param {string} receiver - IP address of the target device.
952
+ * @param {number} timeDuration - The time to hold the network communication state in seconds. 0 for infinite.
953
+ * @param {EnableDisable} enableDisable - The network communication state to set.
954
+ * @param {object=} options
955
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
956
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
957
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
958
+ * @param {string=} options.password - The optional password used to set the network communication state.
959
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
960
+ * @example
961
+ * const bacnet = require('node-bacnet');
962
+ * const client = new bacnet();
963
+ *
964
+ * client.deviceCommunicationControl('192.168.1.43', 0, bacnet.enum.EnableDisable.DISABLE, (err) => {
965
+ * console.log('error: ', err);
966
+ * });
967
+ */
968
+ deviceCommunicationControl(receiver, timeDuration, enableDisable, options, next) {
969
+ next = next || options;
970
+ const settings = {
971
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
972
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
973
+ invokeId: options.invokeId || this._getInvokeId(),
974
+ password: options.password
975
+ };
976
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
977
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
978
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.DEVICE_COMMUNICATION_CONTROL, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
979
+ baServices.deviceCommunicationControl.encode(buffer, timeDuration, enableDisable, settings.password);
980
+ this.sendBvlc(receiver, buffer);
981
+ this._addCallback(settings.invokeId, (err, data) => {
982
+ next(err);
983
+ });
984
+ }
985
+
986
+ /**
987
+ * The reinitializeDevice command initiates a restart of the target device.
988
+ * @function bacnet.reinitializeDevice
989
+ * @param {string} receiver - IP address of the target device.
990
+ * @param {ReinitializedState} state - The type of restart to be initiated.
991
+ * @param {object=} options
992
+ * @param {MaxSegmentsAccepted=} options.maxSegments - The maximimal allowed number of segments.
993
+ * @param {MaxApduLengthAccepted=} options.maxApdu - The maximal allowed APDU size.
994
+ * @param {number=} options.invokeId - The invoke ID of the confirmed service telegram.
995
+ * @param {string=} options.password - The optional password used to restart the device.
996
+ * @param {function} next - The callback containing an error, in case of a failure and value object in case of success.
997
+ * @example
998
+ * const bacnet = require('node-bacnet');
999
+ * const client = new bacnet();
1000
+ *
1001
+ * client.reinitializeDevice('192.168.1.43', bacnet.enum.ReinitializedState.COLDSTART, (err, value) => {
1002
+ * console.log('value: ', value);
1003
+ * });
1004
+ */
1005
+ reinitializeDevice(receiver, state, options, next) {
1006
+ next = next || options;
1007
+ const settings = {
1008
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1009
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1010
+ invokeId: options.invokeId || this._getInvokeId(),
1011
+ password: options.password
1012
+ };
1013
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1014
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1015
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.REINITIALIZE_DEVICE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1016
+ baServices.reinitializeDevice.encode(buffer, state, settings.password);
1017
+ this.sendBvlc(receiver, buffer);
1018
+ this._addCallback(settings.invokeId, (err, data) => {
1019
+ next(err);
1020
+ });
1021
+ }
1022
+
1023
+ /**
1024
+ *
1025
+ * @param receiver
1026
+ * @param objectId
1027
+ * @param position
1028
+ * @param fileBuffer
1029
+ * @param options
1030
+ * @param next
1031
+ */
1032
+ writeFile(receiver, objectId, position, fileBuffer, options, next) {
1033
+ next = next || options;
1034
+ const settings = {
1035
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1036
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1037
+ invokeId: options.invokeId || this._getInvokeId()
1038
+ };
1039
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1040
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1041
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ATOMIC_WRITE_FILE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1042
+ baServices.atomicWriteFile.encode(buffer, false, objectId, position, fileBuffer);
1043
+ this.sendBvlc(receiver, buffer);
1044
+ this._addCallback(settings.invokeId, (err, data) => {
1045
+ if (err) {
1046
+ return void next(err);
1047
+ }
1048
+ const result = baServices.atomicWriteFile.decodeAcknowledge(data.buffer, data.offset, data.length);
1049
+ if (!result) {
1050
+ return void next(new Error('INVALID_DECODING'));
1051
+ }
1052
+ next(null, result);
1053
+ });
1054
+ }
1055
+
1056
+ /**
1057
+ *
1058
+ * @param receiver
1059
+ * @param objectId
1060
+ * @param position
1061
+ * @param count
1062
+ * @param options
1063
+ * @param next
1064
+ */
1065
+ readFile(receiver, objectId, position, count, 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(receiver &amp;&amp; receiver.forwardedFrom);
1073
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1074
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ATOMIC_READ_FILE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1075
+ baServices.atomicReadFile.encode(buffer, true, objectId, position, count);
1076
+ this.sendBvlc(receiver, buffer);
1077
+ this._addCallback(settings.invokeId, (err, data) => {
1078
+ if (err) {
1079
+ return void next(err);
1080
+ }
1081
+ const result = baServices.atomicReadFile.decodeAcknowledge(data.buffer, data.offset, data.length);
1082
+ if (!result) {
1083
+ return void next(new Error('INVALID_DECODING'));
1084
+ }
1085
+ next(null, result);
1086
+ });
1087
+ }
1088
+
1089
+ /**
1090
+ *
1091
+ * @param receiver
1092
+ * @param objectId
1093
+ * @param idxBegin
1094
+ * @param quantity
1095
+ * @param options
1096
+ * @param next
1097
+ */
1098
+ readRange(receiver, objectId, idxBegin, quantity, options, next) {
1099
+ next = next || options;
1100
+ const settings = {
1101
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1102
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1103
+ invokeId: options.invokeId || this._getInvokeId()
1104
+ };
1105
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1106
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1107
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.READ_RANGE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1108
+ baServices.readRange.encode(buffer, objectId, baEnum.PropertyIdentifier.LOG_BUFFER, baEnum.ASN1_ARRAY_ALL, baEnum.ReadRangeType.BY_POSITION, idxBegin, new Date(), quantity);
1109
+ this.sendBvlc(receiver, buffer);
1110
+ this._addCallback(settings.invokeId, (err, data) => {
1111
+ if (err) {
1112
+ return void next(err);
1113
+ }
1114
+ const result = baServices.readRange.decodeAcknowledge(data.buffer, data.offset, data.length);
1115
+ if (!result) {
1116
+ return void next(new Error('INVALID_DECODING'));
1117
+ }
1118
+ next(null, result);
1119
+ });
1120
+ }
1121
+
1122
+ /**
1123
+ *
1124
+ * @param receiver
1125
+ * @param objectId
1126
+ * @param subscribeId
1127
+ * @param cancel
1128
+ * @param issueConfirmedNotifications
1129
+ * @param lifetime
1130
+ * @param options
1131
+ * @param next
1132
+ */
1133
+ subscribeCov(receiver, objectId, subscribeId, cancel, issueConfirmedNotifications, lifetime, options, next) {
1134
+ next = next || options;
1135
+ const settings = {
1136
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1137
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1138
+ invokeId: options.invokeId || this._getInvokeId()
1139
+ };
1140
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1141
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1142
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.SUBSCRIBE_COV, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1143
+ baServices.subscribeCov.encode(buffer, subscribeId, objectId, cancel, issueConfirmedNotifications, lifetime);
1144
+ this.sendBvlc(receiver, buffer);
1145
+ this._addCallback(settings.invokeId, (err, data) => {
1146
+ if (err) {
1147
+ return void next(err);
1148
+ }
1149
+ next();
1150
+ });
1151
+ }
1152
+
1153
+ /**
1154
+ *
1155
+ * @param receiver
1156
+ * @param objectId
1157
+ * @param monitoredProperty
1158
+ * @param subscribeId
1159
+ * @param cancel
1160
+ * @param issueConfirmedNotifications
1161
+ * @param options
1162
+ * @param next
1163
+ */
1164
+ subscribeProperty(receiver, objectId, monitoredProperty, subscribeId, cancel, issueConfirmedNotifications, options, next) {
1165
+ next = next || options;
1166
+ const settings = {
1167
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1168
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1169
+ invokeId: options.invokeId || this._getInvokeId()
1170
+ };
1171
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1172
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1173
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.SUBSCRIBE_COV_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1174
+ baServices.subscribeProperty.encode(buffer, subscribeId, objectId, cancel, issueConfirmedNotifications, 0, monitoredProperty, false, 0x0f);
1175
+ this.sendBvlc(receiver, buffer);
1176
+ this._addCallback(settings.invokeId, (err, data) => {
1177
+ if (err) {
1178
+ return void next(err);
1179
+ }
1180
+ next();
1181
+ });
1182
+ }
1183
+
1184
+ /**
1185
+ * The unconfirmedCOVNotification command sends an unconfirmed COV notification to a device
1186
+ * @function bacnet.unconfirmedCOVNotification
1187
+ * @param {string} receiver - IP address of the target device.
1188
+ * @param {number} subscriberProcessId - The process id which was used by a target device in the subscription.
1189
+ * @param {number} initiatingDeviceId - The id of this device.
1190
+ * @param {object} monitoredObjectId - Specifies about which object the notification is.
1191
+ * @param {number} monitoredObjectId.type - The BACNET object type of the notification.
1192
+ * @param {number} monitoredObjectId.instance - The BACNET object instance of the notification.
1193
+ * @param {number} timeRemaining - How long the subscription is still active in seconds.
1194
+ * @param {object[]} values - List of properties with updated values.
1195
+ * @param {object} values.property - Property specifications.
1196
+ * @param {number} values.property.id - The updated BACNET property id.
1197
+ * @param {number} values.property.index - The array index of the updated property.
1198
+ * @param {object[]} values.value - A list of updated values.
1199
+ * @param {ApplicationTag} values.value.type - The data-type of the updated value.
1200
+ * @param {object} values.value.value - The actual updated value.
1201
+ * @param {number} values.priority - The priority of the updated property.
1202
+ * @example
1203
+ * const bacnet = require('node-bacnet');
1204
+ * const client = new bacnet();
1205
+ *
1206
+ * client.unconfirmedCOVNotification(
1207
+ * '127.0.0.1',
1208
+ * 3,
1209
+ * 433,
1210
+ * {type: 2, instance: 122},
1211
+ * 120,
1212
+ * [
1213
+ * {
1214
+ * property: {id: 85},
1215
+ * value: [{type: baEnum.ApplicationTag.REAL, value: 12.3}]
1216
+ * },
1217
+ * {
1218
+ * property: {id: 111},
1219
+ * value: [{type: baEnum.ApplicationTag.BIT_STRING, value: 0xFFFF}]
1220
+ * }
1221
+ * ]);
1222
+ */
1223
+ unconfirmedCOVNotification(receiver, subscriberProcessId, initiatingDeviceId, monitoredObjectId, timeRemaining, values) {
1224
+ const buffer = this._getBuffer();
1225
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1226
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.UNCONFIRMED_COV_NOTIFICATION);
1227
+ baServices.covNotify.encode(buffer, subscriberProcessId, initiatingDeviceId, monitoredObjectId, timeRemaining, values);
1228
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1229
+ this._transport.send(buffer.buffer, buffer.offset, receiver);
1230
+ }
1231
+
1232
+ /**
1233
+ *
1234
+ * @param receiver
1235
+ * @param objectId
1236
+ * @param values
1237
+ * @param options
1238
+ * @param next
1239
+ */
1240
+ createObject(receiver, objectId, values, options, next) {
1241
+ next = next || options;
1242
+ const settings = {
1243
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1244
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1245
+ invokeId: options.invokeId || this._getInvokeId()
1246
+ };
1247
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1248
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1249
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.CREATE_OBJECT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1250
+ baServices.createObject.encode(buffer, objectId, values);
1251
+ this.sendBvlc(receiver, buffer);
1252
+ this._addCallback(settings.invokeId, (err, data) => {
1253
+ if (err) {
1254
+ return void next(err);
1255
+ }
1256
+ next();
1257
+ });
1258
+ }
1259
+
1260
+ /**
1261
+ *
1262
+ * @param receiver
1263
+ * @param objectId
1264
+ * @param options
1265
+ * @param next
1266
+ */
1267
+ deleteObject(receiver, objectId, options, next) {
1268
+ next = next || options;
1269
+ const settings = {
1270
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1271
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1272
+ invokeId: options.invokeId || this._getInvokeId()
1273
+ };
1274
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1275
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1276
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.DELETE_OBJECT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1277
+ baServices.deleteObject.encode(buffer, objectId);
1278
+ this.sendBvlc(receiver, buffer);
1279
+ this._addCallback(settings.invokeId, (err, data) => {
1280
+ if (err) {
1281
+ return void next(err);
1282
+ }
1283
+ next();
1284
+ });
1285
+ }
1286
+
1287
+ /**
1288
+ *
1289
+ * @param receiver
1290
+ * @param objectId
1291
+ * @param reference
1292
+ * @param values
1293
+ * @param options
1294
+ * @param next
1295
+ */
1296
+ removeListElement(receiver, objectId, reference, values, options, next) {
1297
+ next = next || options;
1298
+ const settings = {
1299
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1300
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1301
+ invokeId: options.invokeId || this._getInvokeId()
1302
+ };
1303
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1304
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1305
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.REMOVE_LIST_ELEMENT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1306
+ baServices.addListElement.encode(buffer, objectId, reference.id, reference.index, values);
1307
+ this.sendBvlc(receiver, buffer);
1308
+ this._addCallback(settings.invokeId, (err, data) => {
1309
+ if (err) {
1310
+ return void next(err);
1311
+ }
1312
+ next();
1313
+ });
1314
+ }
1315
+
1316
+ /**
1317
+ *
1318
+ * @param receiver
1319
+ * @param objectId
1320
+ * @param reference
1321
+ * @param values
1322
+ * @param options
1323
+ * @param next
1324
+ */
1325
+ addListElement(receiver, objectId, reference, values, options, next) {
1326
+ next = next || options;
1327
+ const settings = {
1328
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1329
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1330
+ invokeId: options.invokeId || this._getInvokeId()
1331
+ };
1332
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1333
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1334
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ADD_LIST_ELEMENT, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1335
+ baServices.addListElement.encode(buffer, objectId, reference.id, reference.index, values);
1336
+ this.sendBvlc(receiver, buffer);
1337
+ this._addCallback(settings.invokeId, (err, data) => {
1338
+ if (err) {
1339
+ return void next(err);
1340
+ }
1341
+ next();
1342
+ });
1343
+ }
1344
+
1345
+ /**
1346
+ *
1347
+ * @param receiver
1348
+ * @param options
1349
+ * @param next
1350
+ */
1351
+ getAlarmSummary(receiver, 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(receiver &amp;&amp; receiver.forwardedFrom);
1359
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1360
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.GET_ALARM_SUMMARY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1361
+ this.sendBvlc(receiver, buffer);
1362
+ this._addCallback(settings.invokeId, (err, data) => {
1363
+ if (err) {
1364
+ return void next(err);
1365
+ }
1366
+ const result = baServices.alarmSummary.decode(data.buffer, data.offset, data.length);
1367
+ if (!result) {
1368
+ return void next(new Error('INVALID_DECODING'));
1369
+ }
1370
+ next(null, result);
1371
+ });
1372
+ }
1373
+
1374
+ /**
1375
+ *
1376
+ * @param receiver
1377
+ * @param objectId
1378
+ * @param options
1379
+ * @param next
1380
+ */
1381
+ getEventInformation(receiver, objectId, options, next) {
1382
+ next = next || options;
1383
+ const settings = {
1384
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1385
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1386
+ invokeId: options.invokeId || this._getInvokeId()
1387
+ };
1388
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1389
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1390
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.GET_EVENT_INFORMATION, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1391
+ baAsn1.encodeContextObjectId(buffer, 0, objectId.type, objectId.instance);
1392
+ this.sendBvlc(receiver, buffer);
1393
+ this._addCallback(settings.invokeId, (err, data) => {
1394
+ if (err) {
1395
+ return void next(err);
1396
+ }
1397
+ const result = baServices.eventInformation.decode(data.buffer, data.offset, data.length);
1398
+ if (!result) {
1399
+ return void next(new Error('INVALID_DECODING'));
1400
+ }
1401
+ next(null, result);
1402
+ });
1403
+ }
1404
+
1405
+ /**
1406
+ *
1407
+ * @param receiver
1408
+ * @param objectId
1409
+ * @param eventState
1410
+ * @param ackText
1411
+ * @param evTimeStamp
1412
+ * @param ackTimeStamp
1413
+ * @param options
1414
+ * @param next
1415
+ */
1416
+ acknowledgeAlarm(receiver, objectId, eventState, ackText, evTimeStamp, ackTimeStamp, options, next) {
1417
+ next = next || options;
1418
+ const settings = {
1419
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1420
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1421
+ invokeId: options.invokeId || this._getInvokeId()
1422
+ };
1423
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1424
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1425
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.ACKNOWLEDGE_ALARM, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1426
+ baServices.alarmAcknowledge.encode(buffer, 57, objectId, eventState, ackText, evTimeStamp, ackTimeStamp);
1427
+ this.sendBvlc(receiver, buffer);
1428
+ this._addCallback(settings.invokeId, (err, data) => {
1429
+ if (err) {
1430
+ return void next(err);
1431
+ }
1432
+ next();
1433
+ });
1434
+ }
1435
+
1436
+ /**
1437
+ *
1438
+ * @param receiver
1439
+ * @param vendorId
1440
+ * @param serviceNumber
1441
+ * @param data
1442
+ * @param options
1443
+ * @param next
1444
+ */
1445
+ confirmedPrivateTransfer(receiver, vendorId, serviceNumber, data, options, next) {
1446
+ next = next || options;
1447
+ const settings = {
1448
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1449
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1450
+ invokeId: options.invokeId || this._getInvokeId()
1451
+ };
1452
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1453
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1454
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.CONFIRMED_PRIVATE_TRANSFER, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1455
+ baServices.privateTransfer.encode(buffer, vendorId, serviceNumber, data);
1456
+ this.sendBvlc(receiver, buffer);
1457
+ this._addCallback(settings.invokeId, (err, data) => {
1458
+ if (err) {
1459
+ return void next(err);
1460
+ }
1461
+ next();
1462
+ });
1463
+ }
1464
+
1465
+ /**
1466
+ *
1467
+ * @param receiver
1468
+ * @param vendorId
1469
+ * @param serviceNumber
1470
+ * @param data
1471
+ */
1472
+ unconfirmedPrivateTransfer(receiver, vendorId, serviceNumber, data) {
1473
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1474
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1475
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.UNCONFIRMED_PRIVATE_TRANSFER);
1476
+ baServices.privateTransfer.encode(buffer, vendorId, serviceNumber, data);
1477
+ this.sendBvlc(receiver, buffer);
1478
+ }
1479
+
1480
+ /**
1481
+ *
1482
+ * @param receiver
1483
+ * @param acknowledgmentFilter
1484
+ * @param options
1485
+ * @param next
1486
+ */
1487
+ getEnrollmentSummary(receiver, acknowledgmentFilter, options, next) {
1488
+ next = next || options;
1489
+ const settings = {
1490
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1491
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1492
+ invokeId: options.invokeId || this._getInvokeId()
1493
+ };
1494
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1495
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1496
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.GET_ENROLLMENT_SUMMARY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1497
+ baServices.getEnrollmentSummary.encode(buffer, acknowledgmentFilter, options.enrollmentFilter, options.eventStateFilter, options.eventTypeFilter, options.priorityFilter, options.notificationClassFilter);
1498
+ this.sendBvlc(receiver, buffer);
1499
+ this._addCallback(settings.invokeId, (err, data) => {
1500
+ if (err) {
1501
+ return void next(err);
1502
+ }
1503
+ const result = baServices.getEnrollmentSummary.decodeAcknowledge(data.buffer, data.offset, data.length);
1504
+ if (!result) {
1505
+ return void next(new Error('INVALID_DECODING'));
1506
+ }
1507
+ next(null, result);
1508
+ });
1509
+ }
1510
+
1511
+ /**
1512
+ *
1513
+ * @param receiver
1514
+ * @param eventNotification
1515
+ */
1516
+ unconfirmedEventNotification(receiver, eventNotification) {
1517
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1518
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1519
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.UNCONFIRMED_EVENT_NOTIFICATION);
1520
+ baServices.eventNotifyData.encode(buffer, eventNotification);
1521
+ this.sendBvlc(receiver, buffer);
1522
+ }
1523
+
1524
+ /**
1525
+ *
1526
+ * @param receiver
1527
+ * @param eventNotification
1528
+ * @param options
1529
+ * @param next
1530
+ */
1531
+ confirmedEventNotification(receiver, eventNotification, options, next) {
1532
+ next = next || options;
1533
+ const settings = {
1534
+ maxSegments: options.maxSegments || baEnum.MaxSegmentsAccepted.SEGMENTS_65,
1535
+ maxApdu: options.maxApdu || baEnum.MaxApduLengthAccepted.OCTETS_1476,
1536
+ invokeId: options.invokeId || this._getInvokeId()
1537
+ };
1538
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1539
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBit.EXPECTING_REPLY, receiver);
1540
+ baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduType.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.CONFIRMED_EVENT_NOTIFICATION, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
1541
+ baServices.eventNotifyData.encode(buffer, eventNotification);
1542
+ this.sendBvlc(receiver, buffer);
1543
+ this._addCallback(settings.invokeId, (err, data) => {
1544
+ if (err) {
1545
+ return void next(err);
1546
+ }
1547
+ next();
1548
+ });
1549
+ }
1550
+
1551
+ /**
1552
+ * The readPropertyResponse call sends a response with information about one of our properties.
1553
+ * @function bacnet.readPropertyResponse
1554
+ * @param {string} receiver - IP address of the target device.
1555
+ * @param {number} invokeId - ID of the original readProperty request.
1556
+ * @param {object} objectId - objectId from the original request,
1557
+ * @param {object} property - property being read, taken from the original request.
1558
+ * @param {object=} options varying behaviour for special circumstances
1559
+ * @param {string=} options.forwardedFrom - If functioning as a BBMD, the IP address this message originally came from.
1560
+ */
1561
+ readPropertyResponse(receiver, invokeId, objectId, property, value, options = {}) {
1562
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1563
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1564
+ baApdu.encodeComplexAck(buffer, baEnum.PduType.COMPLEX_ACK, baEnum.ConfirmedServiceChoice.READ_PROPERTY, invokeId);
1565
+ baServices.readProperty.encodeAcknowledge(buffer, objectId, property.id, property.index, value);
1566
+ this.sendBvlc(receiver, buffer);
1567
+ }
1568
+
1569
+ readPropertyMultipleResponse(receiver, invokeId, values) {
1570
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1571
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1572
+ baApdu.encodeComplexAck(buffer, baEnum.PduType.COMPLEX_ACK, baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE, invokeId);
1573
+ baServices.readPropertyMultiple.encodeAcknowledge(buffer, values);
1574
+ this.sendBvlc(receiver, buffer);
1575
+ }
1576
+
1577
+ /**
1578
+ * The iAmResponse command is sent as a reply to a whoIs request.
1579
+ * @function bacnet.iAmResponse
1580
+ * @param {object} receiver - address to send packet to, null for local broadcast.
1581
+ * @param {number} deviceId - Our device ID.
1582
+ * @param {number} segmentation - an enum.Segmentation value.
1583
+ * @param {number} vendorId - The numeric ID assigned to the organisation providing this application.
1584
+ */
1585
+ iAmResponse(receiver, deviceId, segmentation, vendorId) {
1586
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1587
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1588
+ baApdu.encodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.I_AM);
1589
+ baServices.iAm.encode(buffer, deviceId, this._transport.getMaxPayload(), segmentation, vendorId);
1590
+ this.sendBvlc(receiver, buffer);
1591
+ }
1592
+
1593
+ /**
1594
+ *
1595
+ * @param receiver
1596
+ * @param deviceId
1597
+ * @param objectId
1598
+ * @param objectName
1599
+ */
1600
+ iHaveResponse(receiver, deviceId, objectId, objectName) {
1601
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1602
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1603
+ baApdu.EecodeUnconfirmedServiceRequest(buffer, baEnum.PduType.UNCONFIRMED_REQUEST, baEnum.UnconfirmedServiceChoice.I_HAVE);
1604
+ baServices.iHave(buffer, deviceId, objectId, objectName);
1605
+ this.sendBvlc(receiver, buffer);
1606
+ }
1607
+
1608
+ /**
1609
+ *
1610
+ * @param receiver
1611
+ * @param service
1612
+ * @param invokeId
1613
+ */
1614
+ simpleAckResponse(receiver, service, invokeId) {
1615
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1616
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1617
+ baApdu.encodeSimpleAck(buffer, baEnum.PduType.SIMPLE_ACK, service, invokeId);
1618
+ this.sendBvlc(receiver, buffer);
1619
+ }
1620
+
1621
+ /**
1622
+ *
1623
+ * @param receiver
1624
+ * @param service
1625
+ * @param invokeId
1626
+ * @param errorClass
1627
+ * @param errorCode
1628
+ */
1629
+ errorResponse(receiver, service, invokeId, errorClass, errorCode) {
1630
+ trace(`error response on ${JSON.stringify(receiver)} service: ${JSON.stringify(service)} invokeId: ${invokeId} errorClass: ${errorClass} errorCode: ${errorCode}`);
1631
+ trace(`error message ${baServices.error.buildMessage({ 'class': errorClass, 'code': errorCode })}`);
1632
+ const buffer = this._getBuffer(receiver &amp;&amp; receiver.forwardedFrom);
1633
+ baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE, receiver);
1634
+ baApdu.encodeError(buffer, baEnum.PduType.ERROR, service, invokeId);
1635
+ baServices.error.encode(buffer, errorClass, errorCode);
1636
+ this.sendBvlc(receiver, buffer);
1637
+ }
1638
+
1639
+ /**
1640
+ *
1641
+ * @param receiver
1642
+ * @param buffer
1643
+ */
1644
+ sendBvlc(receiver, buffer) {
1645
+ if (typeof receiver === 'string') {
1646
+ receiver = {
1647
+ address: receiver
1648
+ };
1649
+ }
1650
+ if (receiver &amp;&amp; receiver.forwardedFrom) {
1651
+ // Remote node address given, forward to BBMD
1652
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.FORWARDED_NPDU, buffer.offset, receiver.forwardedFrom);
1653
+ } else if (receiver &amp;&amp; receiver.address) {
1654
+ // Specific address, unicast
1655
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
1656
+ } else {
1657
+ // No address, broadcast
1658
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_BROADCAST_NPDU, buffer.offset);
1659
+ }
1660
+ this._transport.send(
1661
+ buffer.buffer,
1662
+ buffer.offset,
1663
+ (receiver &amp;&amp; receiver.address) || null
1664
+ );
1665
+ }
1666
+
1667
+ /**
1668
+ * The resultResponse is a BVLC-Result message used to respond to certain events, such as BBMD registration.
1669
+ * This message cannot be wrapped for passing through a BBMD, as it is used as a BBMD control message.
1670
+ * @function bacnet.resultResponse
1671
+ * @param {string} receiver - IP address of the target device.
1672
+ * @param {number} resultCode - Single value from BvlcResultFormat enum.
1673
+ */
1674
+ resultResponse(receiver, resultCode) {
1675
+ const buffer = this._getBuffer();
1676
+ baApdu.encodeResult(buffer, resultCode);
1677
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.BVLC_RESULT, buffer.offset);
1678
+ this._transport.send(buffer.buffer, buffer.offset, receiver.address);
1679
+ }
1680
+
1681
+ /**
1682
+ * Unloads the current bacnet instance and closes the underlying UDP socket.
1683
+ * @function bacnet.close
1684
+ * @example
1685
+ * const bacnet = require('node-bacnet');
1686
+ * const client = new bacnet();
1687
+ *
1688
+ * client.close();
1689
+ */
1690
+ close() {
1691
+ this._transport.close();
1692
+ }
1693
+
1694
+ /**
1695
+ * Helper function to take an array of enums and produce a bitstring suitable
1696
+ * for inclusion as a property.
1697
+ *
1698
+ * @example
1699
+ * [bacnet.enum.PropertyIdentifier.PROTOCOL_OBJECT_TYPES_SUPPORTED]: [
1700
+ * {value: bacnet.createBitstring([
1701
+ * bacnet.enum.ObjectTypesSupported.ANALOG_INPUT,
1702
+ * bacnet.enum.ObjectTypesSupported.ANALOG_OUTPUT,
1703
+ * ]),
1704
+ * type: bacnet.enum.ApplicationTag.BIT_STRING},
1705
+ * ],
1706
+ */
1707
+ static createBitstring(items) {
1708
+ let offset = 0;
1709
+ let bytes = [];
1710
+ let bitsUsed = 0;
1711
+ while (items.length) {
1712
+ // Find any values between offset and offset+8, for the next byte
1713
+ let value = 0;
1714
+ items = items.filter(i => {
1715
+ if (i >= offset + 8) {
1716
+ return true;
1717
+ } // leave for future iteration
1718
+ value |= 1 &lt;&lt; (i - offset);
1719
+ bitsUsed = Math.max(bitsUsed, i);
1720
+ return false; // remove from list
1721
+ });
1722
+ bytes.push(value);
1723
+ offset += 8;
1724
+ }
1725
+ bitsUsed++;
1726
+
1727
+ return {
1728
+ value: bytes,
1729
+ bitsUsed,
1730
+ };
1731
+ }
1732
+
1733
+ }
1734
+ module.exports = Client;
1735
+ </code></pre>
1736
+ </article>
1737
+ </section>
1738
+
1739
+
1740
+
1741
+
1742
+
1743
+
1744
+ </div>
1745
+
1746
+ <br class="clear">
1747
+
1748
+ <footer>
1749
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.4</a> on Tue Jun 02 2020 20:24:55 GMT+0200 (Central European Summer Time) using the <a href="https://github.com/mochajs/mocha-docdash">@mocha/docdash</a> theme.
1750
+ </footer>
1751
+
1752
+ <script src="scripts/prettify/prettify.js"></script>
1753
+ <script src="scripts/prettify/lang-css.js"></script>
1754
+ <script>prettyPrint();</script>
1755
+ <script src="scripts/linenumber.js"></script>
1756
+
1757
+
1758
+ </body>
1759
+ </html>