@bitpoolos/edge-bacnet 1.2.5 → 1.2.7

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/common.js CHANGED
@@ -2,86 +2,97 @@
2
2
  MIT License Copyright 2021, 2022 - Bitpool Pty Ltd
3
3
  */
4
4
 
5
- const { createLogger, format, transports } = require('winston');
6
- const { randomUUID } = require('crypto');
7
- const os = require('os');
5
+ const { createLogger, format, transports } = require("winston");
6
+ const { randomUUID } = require("crypto");
7
+ const os = require("os");
8
8
  const { exec } = require("child_process");
9
- const baEnum = require('./resources/node-bacstack-ts/dist/index.js').enum;
10
- const fs = require('fs');
9
+ const baEnum = require("./resources/node-bacstack-ts/dist/index.js").enum;
10
+ const fs = require("fs");
11
11
 
12
12
  const logger = createLogger({
13
- format: format.combine(
14
- format.timestamp({
15
- format: 'YYYY-MM-DD HH:mm:ss'
16
- }),
17
- format.json()
18
- ),
19
- transports: [new transports.Console()],
13
+ format: format.combine(
14
+ format.timestamp({
15
+ format: "YYYY-MM-DD HH:mm:ss",
16
+ }),
17
+ format.json()
18
+ ),
19
+ transports: [new transports.Console()],
20
20
  });
21
21
 
22
22
  class DeviceObjectId {
23
- constructor(type, instance) {
24
- this.type = type;
25
- this.instance = instance;
26
- }
23
+ constructor(type, instance) {
24
+ this.type = type;
25
+ this.instance = instance;
26
+ }
27
27
  }
28
28
 
29
29
  class DeviceObject {
30
- constructor(objectId, name, description, type, units, presentValue) {
31
- this.objectId = objectId;
32
- this.name = name;
33
- this.description = description;
34
- this.type = type;
35
- this.units = units;
36
- this.presentValue = presentValue;
37
- }
30
+ constructor(objectId, name, description, type, units, presentValue) {
31
+ this.objectId = objectId;
32
+ this.name = name;
33
+ this.description = description;
34
+ this.type = type;
35
+ this.units = units;
36
+ this.presentValue = presentValue;
37
+ }
38
38
  }
39
39
 
40
40
  class BacnetConfig {
41
- constructor(device, objects, bacnet_polling_schedule, apduTimeout, localIpAdrress, roundDecimal, local_device_port, apduSize, maxSegments, broadCastAddr) {
42
- this.device = {
43
- "deviceId": device.deviceId,
44
- "address": device.address
45
- };
46
- this.polling = {
47
- "schedule": bacnet_polling_schedule
48
- };
49
- this.objects = [{
50
- "objectId": {
51
- "type": objects.object_type,
52
- "instance": objects.instance,
53
- "properties": objects.object_props
54
- }
55
- }];
56
- this.apduTimeout = apduTimeout;
57
- this.localIpAdrress = localIpAdrress;
58
- this.roundDecimal = roundDecimal;
59
- this.port = local_device_port;
60
- this.apduSize = apduSize;
61
- this.maxSegments = maxSegments;
62
- this.broadCastAddr = broadCastAddr;
41
+ constructor(
42
+ device,
43
+ objects,
44
+ bacnet_polling_schedule,
45
+ apduTimeout,
46
+ localIpAdrress,
47
+ roundDecimal,
48
+ local_device_port,
49
+ apduSize,
50
+ maxSegments,
51
+ broadCastAddr
52
+ ) {
53
+ this.device = {
54
+ deviceId: device.deviceId,
55
+ address: device.address,
56
+ };
57
+ this.polling = {
58
+ schedule: bacnet_polling_schedule,
59
+ };
60
+ this.objects = [
61
+ {
62
+ objectId: {
63
+ type: objects.object_type,
64
+ instance: objects.instance,
65
+ properties: objects.object_props,
66
+ },
67
+ },
68
+ ];
69
+ this.apduTimeout = apduTimeout;
70
+ this.localIpAdrress = localIpAdrress;
71
+ this.roundDecimal = roundDecimal;
72
+ this.port = local_device_port;
73
+ this.apduSize = apduSize;
74
+ this.maxSegments = maxSegments;
75
+ this.broadCastAddr = broadCastAddr;
63
76
  }
64
- };
77
+ }
65
78
 
66
79
  class BacnetClientConfig {
67
80
  constructor(
68
- apduTimeout,
69
- localIpAdrress,
70
- local_device_port,
71
- apduSize,
72
- maxSegments,
73
- broadCastAddr,
81
+ apduTimeout,
82
+ localIpAdrress,
83
+ local_device_port,
84
+ apduSize,
85
+ maxSegments,
86
+ broadCastAddr,
74
87
  discover_polling_schedule,
75
- device_id_range_enabled,
76
- device_id_range_start,
77
- device_id_range_end,
78
- toRestartNodeRed,
88
+ toRestartNodeRed,
79
89
  deviceId,
80
90
  manual_instance_range_enabled,
81
91
  manual_instance_range_start,
82
92
  manual_instance_range_end,
83
93
  device_read_schedule,
84
- retries
94
+ retries,
95
+ cacheFileEnabled
85
96
  ) {
86
97
  this.apduTimeout = apduTimeout;
87
98
  this.localIpAdrress = localIpAdrress;
@@ -90,9 +101,6 @@ class BacnetClientConfig {
90
101
  this.maxSegments = maxSegments;
91
102
  this.broadCastAddr = broadCastAddr;
92
103
  this.discover_polling_schedule = discover_polling_schedule;
93
- this.device_id_range_enabled = device_id_range_enabled;
94
- this.device_id_range_start = device_id_range_start;
95
- this.device_id_range_end = device_id_range_end;
96
104
  this.toRestartNodeRed = toRestartNodeRed;
97
105
  this.deviceId = deviceId;
98
106
  this.manual_instance_range_enabled = manual_instance_range_enabled;
@@ -100,8 +108,9 @@ class BacnetClientConfig {
100
108
  this.manual_instance_range_end = manual_instance_range_end;
101
109
  this.device_read_schedule = device_read_schedule;
102
110
  this.retries = retries;
111
+ this.cacheFileEnabled = cacheFileEnabled;
103
112
  }
104
- };
113
+ }
105
114
 
106
115
  class ReadCommandConfig {
107
116
  constructor(pointsToRead, objectProperties, decimalPrecision) {
@@ -109,33 +118,35 @@ class ReadCommandConfig {
109
118
  this.objectProperties = objectProperties;
110
119
  this.precision = decimalPrecision;
111
120
  }
112
- };
121
+ }
113
122
 
114
123
  class WriteCommandConfig {
115
124
  constructor(device, objects) {
116
125
  this.device = {
117
- "deviceId": device.deviceId,
118
- "address": device.address
126
+ deviceId: device.deviceId,
127
+ address: device.address,
119
128
  };
120
- this.objects = [{
121
- "objectId": {
122
- "type": objects.object_type,
123
- "instance": objects.instance,
124
- "properties": objects.object_props
125
- }
126
- }];
129
+ this.objects = [
130
+ {
131
+ objectId: {
132
+ type: objects.object_type,
133
+ instance: objects.instance,
134
+ properties: objects.object_props,
135
+ },
136
+ },
137
+ ];
127
138
  }
128
- };
139
+ }
129
140
 
130
- const getUnit = function(id) {
141
+ const getUnit = function (id) {
131
142
  for (var key in baEnum.EngineeringUnits) {
132
- if(baEnum.EngineeringUnits[key] == id) {
143
+ if (baEnum.EngineeringUnits[key] == id) {
133
144
  if (baEnum.EngineeringUnits.hasOwnProperty(key)) {
134
145
  let unitsArr = key.split("_");
135
146
  let unit;
136
- unitsArr.forEach((ele, index) =>{
137
- if(index == 0){
138
- unit = ele.toLowerCase();
147
+ unitsArr.forEach((ele, index) => {
148
+ if (index == 0) {
149
+ unit = ele.toLowerCase();
139
150
  } else {
140
151
  unit += "-" + ele.toLowerCase();
141
152
  }
@@ -147,61 +158,61 @@ const getUnit = function(id) {
147
158
  return "no-units";
148
159
  };
149
160
 
150
- const generateId = function() {
161
+ const generateId = function () {
151
162
  return randomUUID();
152
163
  };
153
164
 
154
- const getIpAddress = function() {
155
- return new Promise(function(resolve, reject) {
165
+ const getIpAddress = function () {
166
+ return new Promise(function (resolve, reject) {
156
167
  const nets = os.networkInterfaces();
157
168
  const results = Object.create(null); // Or just '{}', an empty object
158
169
  for (const name of Object.keys(nets)) {
159
- for (const net of nets[name]) {
160
- // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
161
- let family = parseInt(net.family.toString().match(/[0-9]/));
162
- if (family === 4 && !net.internal) {
163
- if (!results[name]) {
164
- results[name] = [];
165
- }
166
- results[name].push(net.address);
167
- }
170
+ for (const net of nets[name]) {
171
+ // Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
172
+ let family = parseInt(net.family.toString().match(/[0-9]/));
173
+ if (family === 4 && !net.internal) {
174
+ if (!results[name]) {
175
+ results[name] = [];
176
+ }
177
+ results[name].push(net.address);
168
178
  }
179
+ }
169
180
  }
170
181
 
171
- if(os.version().includes('Ubuntu')) {
172
- let allInterfaceName = 'All interfaces';
182
+ if (os.version().includes("Ubuntu")) {
183
+ let allInterfaceName = "All interfaces";
173
184
  if (!results[allInterfaceName]) {
174
185
  results[allInterfaceName] = [];
175
186
  }
176
- results[allInterfaceName].push('0.0.0.0');
177
- } else if(os.version().includes('Windows')) {
187
+ results[allInterfaceName].push("0.0.0.0");
188
+ } else if (os.version().includes("Windows")) {
178
189
  //do nothing
179
190
  }
180
-
191
+
181
192
  resolve(results);
182
193
  });
183
- }
194
+ };
184
195
 
185
- const roundDecimalPlaces = function(value, decimals) {
186
- if(decimals) return Number(Math.round(value+'e'+decimals)+'e-'+decimals);
196
+ const roundDecimalPlaces = function (value, decimals) {
197
+ if (decimals) return Number(Math.round(value + "e" + decimals) + "e-" + decimals);
187
198
  return value;
188
- }
199
+ };
189
200
 
190
- const doNodeRedRestart = function() {
191
- return new Promise(function(resolve, reject) {
201
+ const doNodeRedRestart = function () {
202
+ return new Promise(function (resolve, reject) {
192
203
  try {
193
204
  exec("restart", (error, stdout, stderr) => {
194
205
  if (error) {
195
- console.log(`Node-Red restart error: ${error.message}`);
196
- reject(error.message);
206
+ console.log(`Node-Red restart error: ${error.message}`);
207
+ reject(error.message);
197
208
  }
198
209
  if (stderr) {
199
- console.log(`Node-Red restart stderr: ${stderr}`);
200
- reject(stderr);
210
+ console.log(`Node-Red restart stderr: ${stderr}`);
211
+ reject(stderr);
201
212
  }
202
213
  resolve(stdout);
203
214
  });
204
- } catch(e){
215
+ } catch (e) {
205
216
  console.log(`Node-Red restart error: ${e}`);
206
217
  reject(e);
207
218
  }
@@ -211,11 +222,17 @@ const doNodeRedRestart = function() {
211
222
  // STORE CONFIG FUNCTION ==========================================================
212
223
  //
213
224
  // ================================================================================
214
- async function Store_Config(data) {
225
+ function Store_Config(data) {
215
226
  try {
216
- await fs.writeFile("edge-bacnet-datastore.cfg", data, (err) => {
217
- if (err) {
218
- console.log("Store_Config writeFile error: ", err);
227
+ fs.access("edge-bacnet-datastore.cfg", fs.constants.W_OK, async function(err) {
228
+ if(err){
229
+ console.log("Store_Config writeAccess error found: ", err);
230
+ } else {
231
+ await fs.writeFile("edge-bacnet-datastore.cfg", data, {encoding: "utf8", flag: "w"}, (err) => {
232
+ if (err) {
233
+ console.log("Store_Config writeFile error: ", err);
234
+ }
235
+ });
219
236
  }
220
237
  });
221
238
  } catch(e){
@@ -223,6 +240,8 @@ async function Store_Config(data) {
223
240
  }
224
241
  };
225
242
 
243
+
244
+
226
245
  // READ CONFIG SYNC FUNCTION ======================================================
227
246
  //
228
247
  // ================================================================================
@@ -246,13 +265,11 @@ async function Store_Config_Server(data) {
246
265
  try {
247
266
  await fs.writeFile("edge-bacnet-server-datastore.cfg", data, (err) => {
248
267
  if (err) {
249
- console.log("Store_Config_Server writeFile error: ", err);
268
+ //console.log("Store_Config_Server writeFile error: ", err);
250
269
  }
251
270
  });
252
- }
253
- catch (err) {
254
- }
255
- };
271
+ } catch (err) {}
272
+ }
256
273
 
257
274
  // READ CONFIG SYNC FUNCTION - BACNET SERVER ======================================
258
275
  //
@@ -260,29 +277,33 @@ async function Store_Config_Server(data) {
260
277
  function Read_Config_Sync_Server() {
261
278
  var data = "{}";
262
279
  try {
263
- data = fs.readFileSync("edge-bacnet-server-datastore.cfg", {encoding:'utf8', flag:'r'});
264
- }
265
- catch(err) {
266
- console.log("Read_Config_Sync_Server error:", err);
267
- if(err.errno == -4058) console.log("Edge-BACnet Server: No save file found, creating new file");
268
- data = '{}';
280
+ data = fs.readFileSync("edge-bacnet-server-datastore.cfg", { encoding: "utf8", flag: "r" });
281
+ } catch (err) {
282
+ //console.log("Read_Config_Sync_Server error:", err);
283
+ if (err.errno == -4058) console.log("Edge-BACnet Server: No save file found, creating new file");
284
+ data = "{}";
269
285
  Store_Config_Server(data);
270
286
  }
271
287
  return data;
272
- };
288
+ }
289
+
290
+ function isNumber(value) {
291
+ return value != null && typeof value === 'number' && !isNaN(value);
292
+ }
273
293
 
274
294
  module.exports = {
275
- BacnetConfig,
276
- BacnetClientConfig,
277
- ReadCommandConfig,
295
+ BacnetConfig,
296
+ BacnetClientConfig,
297
+ ReadCommandConfig,
278
298
  WriteCommandConfig,
279
- getUnit,
280
- generateId,
281
- getIpAddress,
282
- roundDecimalPlaces,
299
+ getUnit,
300
+ generateId,
301
+ getIpAddress,
302
+ roundDecimalPlaces,
283
303
  doNodeRedRestart,
284
304
  Store_Config,
285
305
  Read_Config_Sync,
286
306
  Store_Config_Server,
287
- Read_Config_Sync_Server
288
- };
307
+ Read_Config_Sync_Server,
308
+ isNumber,
309
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitpoolos/edge-bacnet",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "description": "A bacnet gateway for node-red",
5
5
  "dependencies": {
6
6
  "@plus4nodered/ts-node-bacnet": "^1.0.0-beta.2",
@@ -8,7 +8,6 @@
8
8
  "cronosjs": "^1.7.1",
9
9
  "debug": "^4.1.1",
10
10
  "iconv-lite": "^0.5.1",
11
- "node-fetch": "^2.6.1",
12
11
  "toad-scheduler": "^1.6.0",
13
12
  "underscore": "^1.10.2",
14
13
  "winston": "^3.2.1"
@@ -51,4 +50,4 @@
51
50
  "type": "github",
52
51
  "url": "git+https://github.com/bitpool/edge-bacnet.git"
53
52
  }
54
- }
53
+ }
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
3
+ <defs>
4
+ <style>
5
+ .cls-1 {
6
+ fill: none;
7
+ stroke: #6c757d;
8
+ stroke-linecap: round;
9
+ stroke-linejoin: round;
10
+ stroke-width: 2px;
11
+ }
12
+ </style>
13
+ </defs>
14
+ <circle class="cls-1" cx="15" cy="15" r="14"/>
15
+ <g>
16
+ <path class="cls-1" d="M11.21,22s0-14,0-14h5.13c1.91,0,3.46,1.55,3.46,3.46v.54c0,1.91-1.55,3.46-3.46,3.46h-5.13"/>
17
+ <line class="cls-1" x1="15.51" y1="15.45" x2="20.03" y2="21.94"/>
18
+ </g>
19
+ </svg>
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30">
3
+ <defs>
4
+ <style>
5
+ .cls-1 {
6
+ fill: none;
7
+ stroke: #6c757d;
8
+ stroke-linecap: round;
9
+ stroke-linejoin: round;
10
+ stroke-width: 2px;
11
+ }
12
+ </style>
13
+ </defs>
14
+ <circle class="cls-1" cx="15" cy="15" r="14"/>
15
+ <polyline class="cls-1" points="22.21 9.75 18.61 21.35 15 9.75 11.39 21.35 7.79 9.75"/>
16
+ </svg>
@@ -616,7 +616,7 @@ class Client extends events_1.EventEmitter {
616
616
  const type = baEnum.PduTypes.CONFIRMED_REQUEST | (settings.maxSegments !== baEnum.MaxSegmentsAccepted.SEGMENTS_0 ? baEnum.PduConReqBits.SEGMENTED_RESPONSE_ACCEPTED : 0);
617
617
  baApdu.encodeConfirmedServiceRequest(buffer, type, baEnum.ConfirmedServiceChoice.READ_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
618
618
  baServices.readProperty.encode(buffer, objectId.type, objectId.instance, propertyId, settings.arrayIndex);
619
- //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
619
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
620
620
  this.sendBvlc(address, buffer);
621
621
  this._addCallback(settings.invokeId, (err, data) => {
622
622
  try{
@@ -672,7 +672,7 @@ class Client extends events_1.EventEmitter {
672
672
  baNpdu.encode(buffer, baEnum.NpduControlPriority.NORMAL_MESSAGE | baEnum.NpduControlBits.EXPECTING_REPLY, address, null, DEFAULT_HOP_COUNT, baEnum.NetworkLayerMessageType.WHO_IS_ROUTER_TO_NETWORK, 0);
673
673
  baApdu.encodeConfirmedServiceRequest(buffer, baEnum.PduTypes.CONFIRMED_REQUEST, baEnum.ConfirmedServiceChoice.WRITE_PROPERTY, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
674
674
  baServices.writeProperty.encode(buffer, objectId.type, objectId.instance, propertyId, settings.arrayIndex, settings.priority, values);
675
- //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
675
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
676
676
  this.sendBvlc(address, buffer);
677
677
  this._addCallback(settings.invokeId, (err) => next(err));
678
678
  }
@@ -714,7 +714,7 @@ class Client extends events_1.EventEmitter {
714
714
  const type = baEnum.PduTypes.CONFIRMED_REQUEST | (settings.maxSegments !== baEnum.MaxSegmentsAccepted.SEGMENTS_0 ? baEnum.PduConReqBits.SEGMENTED_RESPONSE_ACCEPTED : 0);
715
715
  baApdu.encodeConfirmedServiceRequest(buffer, type, baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE, settings.maxSegments, settings.maxApdu, settings.invokeId, 0, 0);
716
716
  baServices.readPropertyMultiple.encode(buffer, propertiesArray);
717
- //baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
717
+ baBvlc.encode(buffer.buffer, baEnum.BvlcResultPurpose.ORIGINAL_UNICAST_NPDU, buffer.offset);
718
718
  this.sendBvlc(address, buffer);
719
719
  //this.sendBvlc(address, buffer);
720
720
  this._addCallback(settings.invokeId, (err, data) => {
@@ -0,0 +1,11 @@
1
+ .writePointIcon {
2
+ background: url("icons/icon-write.svg") no-repeat !important;
3
+ width: 20px;
4
+ height: 20px;
5
+ }
6
+
7
+ .readPointIcon {
8
+ background: url("icons/icon-read.svg") no-repeat !important;
9
+ width: 20px;
10
+ height: 20px;
11
+ }