@halsystems/red-bacnet 2.0.3 → 2.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.1.0-alpha.0]
4
+ ### Added
5
+ - BACnet client now listening to both `interface` and `broadcastAddress`
6
+
7
+ ### Changed
8
+ - `discover_devices` to drop devices that are not within the low and high limit
9
+
10
+ ### Fixed
11
+ - Fixed unable to discover devices from broadcast when `interface` is not set to `0.0.0.0`
12
+
13
+
3
14
  ## [2.0.3]
4
15
  ### Fixed
5
16
  - Added unique job id to same node type to avoid same time triggered nodes job being coalesced
@@ -165,7 +165,12 @@ module.exports = {
165
165
  const adr = device.adr
166
166
  const net = device.net
167
167
 
168
+ // Check for duplicate
168
169
  if (this.knownDevices.has(deviceId)) return;
170
+
171
+ // Drop device if deviceId is not within the low and high limit
172
+ if (deviceId < this.lowLimit || deviceId > this.highLimit) return;
173
+
169
174
  this.discoverList.push({
170
175
  deviceId: deviceId,
171
176
  address: address,
@@ -59,6 +59,13 @@ class Client extends events_1.EventEmitter {
59
59
  // Setup code
60
60
  this._transport.on('message', this._receiveData.bind(this));
61
61
  this._transport.on('error', this._receiveError.bind(this));
62
+
63
+ // Add a default error handler to prevent unhandled error events
64
+ // This will be overridden if the user adds their own error listener
65
+ this.on('error', (err) => {
66
+ debug('Unhandled error event:', err);
67
+ });
68
+
62
69
  this._transport.open();
63
70
  }
64
71
  // Helper utils
@@ -1,62 +1,114 @@
1
- 'use strict';
1
+ "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Transport = void 0;
4
4
  const dgram_1 = require("dgram");
5
5
  const events_1 = require("events");
6
6
  const DEFAULT_BACNET_PORT = 47808;
7
+ const GLOBAL_BROADCAST_ADDRESS = "255.255.255.255";
8
+ const UDP_TYPE = "udp4";
9
+
7
10
  class Transport extends events_1.EventEmitter {
8
11
  constructor(settings) {
9
12
  super();
10
- try {
11
- this._lastSendMessages = {};
12
- this._settings = settings;
13
- this._server = (0, dgram_1.createSocket)({ type: 'udp4', reuseAddr: true });
14
- this._server.on('message', (msg, rinfo) => {
15
- // NOTE HAL modified
16
- const port = rinfo.port || DEFAULT_BACNET_PORT;
17
- // this.emit('message', msg, `${rinfo.address}:${port}`);
18
- if (port === DEFAULT_BACNET_PORT)
19
- this.emit('message', msg, rinfo.address);
20
- else
21
- this.emit('message', msg, `${rinfo.address}:${rinfo.port || DEFAULT_BACNET_PORT}`);
22
- });
23
- this._server.on('error', (err) => this.emit('message', err));
13
+ this._settings = settings;
14
+ this._server = null;
15
+ this._broadcastServer = null;
24
16
 
25
- } catch (e) {
26
- //console.log("Transport constructor error: ", e);
17
+ this._server = (0, dgram_1.createSocket)({
18
+ type: UDP_TYPE,
19
+ reuseAddr: true,
20
+ });
21
+ this._setupSocket(this._server);
22
+
23
+ if (
24
+ this._settings.broadcastAddress &&
25
+ this._settings.broadcastAddress !== GLOBAL_BROADCAST_ADDRESS &&
26
+ this._settings.broadcastAddress !== this._settings.interface
27
+ ) {
28
+ this._broadcastServer = (0, dgram_1.createSocket)({
29
+ type: UDP_TYPE,
30
+ reuseAddr: true,
31
+ });
32
+ this._setupSocket(this._broadcastServer);
27
33
  }
28
34
  }
35
+
36
+ _setupSocket(socket) {
37
+ socket.on("message", (msg, rinfo) => {
38
+ const port = rinfo.port || DEFAULT_BACNET_PORT;
39
+ if (port === DEFAULT_BACNET_PORT) {
40
+ this.emit("message", msg, rinfo.address);
41
+ } else {
42
+ this.emit("message", msg, `${rinfo.address}:${port}`);
43
+ }
44
+ });
45
+ socket.on("error", (err) => this.emit("error", err));
46
+ }
47
+
29
48
  getBroadcastAddress() {
30
49
  return this._settings.broadcastAddress;
31
50
  }
51
+
32
52
  getMaxPayload() {
33
53
  return 1482;
34
54
  }
55
+
35
56
  send(buffer, offset, receiver) {
36
- if (!receiver) {
37
- receiver = this.getBroadcastAddress();
38
- const dataToSend = Buffer.alloc(offset);
39
- // Sort out broadcasted messages that we also receive
40
- // TODO Find a better way?
41
- const hrTime = process.hrtime();
42
- const messageKey = hrTime[0] * 1000000000 + hrTime[1];
43
- buffer.copy(dataToSend, 0, 0, offset);
44
- this._lastSendMessages[messageKey] = dataToSend;
45
- setTimeout(() => {
46
- delete this._lastSendMessages[messageKey];
47
- }, 10000); // delete after 10s, hopefully all cases are handled by that
57
+ const target = receiver || this.getBroadcastAddress();
58
+ if (!target) {
59
+ this.emit(
60
+ "error",
61
+ new Error("No receiver specified and no broadcast address configured"),
62
+ );
63
+ return;
48
64
  }
49
65
 
50
- const [address, port] = receiver.split(':');
51
- this._server.send(buffer, 0, offset, port || this._settings.port || DEFAULT_BACNET_PORT, address);
66
+ const [address, port] = target.split(":");
67
+ this._server.send(
68
+ buffer,
69
+ 0,
70
+ offset,
71
+ port || this._settings.port || DEFAULT_BACNET_PORT,
72
+ address,
73
+ (err) => {
74
+ if (err) {
75
+ this.emit("error", err);
76
+ }
77
+ },
78
+ );
52
79
  }
80
+
53
81
  open() {
82
+ this._server.on("error", (err) => this.emit("error", err));
54
83
  this._server.bind(this._settings.port, this._settings.interface, () => {
55
84
  this._server.setBroadcast(true);
56
85
  });
86
+
87
+ if (this._broadcastServer) {
88
+ this._broadcastServer.on("error", (err) => {
89
+ this.emit("error", err);
90
+ this._broadcastServer.close();
91
+ this._broadcastServer = null;
92
+ });
93
+ this._broadcastServer.bind(
94
+ this._settings.port,
95
+ this._settings.broadcastAddress,
96
+ () => {
97
+ this._broadcastServer.setBroadcast(true);
98
+ }
99
+ );
100
+ }
57
101
  }
102
+
58
103
  close() {
59
- this._server.close();
104
+ if (this._server) {
105
+ this._server.removeAllListeners();
106
+ this._server.close();
107
+ }
108
+ if (this._broadcastServer) {
109
+ this._broadcastServer.removeAllListeners();
110
+ this._broadcastServer.close();
111
+ }
60
112
  }
61
113
  }
62
114
  exports.Transport = Transport;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@halsystems/red-bacnet",
3
- "version": "2.0.3",
3
+ "version": "2.1.0-alpha.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"