@bitpoolos/edge-bacnet 1.6.6 → 1.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.6.7] - 15-01-2026
4
+
5
+ Bug fix:
6
+
7
+ - Fix UI tree rendering issue with MSTP folders
8
+
9
+ Minor update:
10
+
11
+ - Styling
12
+ - Added properties to device points and minor change to device point polling
13
+
3
14
  ## [1.6.6] - 20-11-2025
4
15
 
5
16
  Minor update:
package/bacnet_client.js CHANGED
@@ -362,7 +362,7 @@ class BacnetClient extends EventEmitter {
362
362
  let that = this;
363
363
  let address = device.getAddress().address;
364
364
  let deviceId = device.getDeviceId();
365
- let foundParentIndex = that.deviceList.findIndex((ele) => that.getDeviceAddress(ele) == address);
365
+ let foundParentIndex = that.deviceList.findIndex((ele) => that.getDeviceAddress(ele) == address && !ele.getIsMstpDevice());
366
366
  if (foundParentIndex !== -1) {
367
367
  that.deviceList[foundParentIndex].addChildDevice(deviceId);
368
368
  device.setParentDeviceId(that.deviceList[foundParentIndex].getDeviceId());
@@ -1368,8 +1368,8 @@ class BacnetClient extends EventEmitter {
1368
1368
  port: device.getPort(),
1369
1369
  };
1370
1370
 
1371
- // Define all properties to be read
1372
- const allProperties = [
1371
+ // Define default properties for non-device objects
1372
+ const defaultProperties = [
1373
1373
  { id: baEnum.PropertyIdentifier.PRESENT_VALUE },
1374
1374
  { id: baEnum.PropertyIdentifier.DESCRIPTION },
1375
1375
  { id: baEnum.PropertyIdentifier.UNITS },
@@ -1384,8 +1384,66 @@ class BacnetClient extends EventEmitter {
1384
1384
  { id: baEnum.PropertyIdentifier.VENDOR_NAME },
1385
1385
  ];
1386
1386
 
1387
+ // Use device-specific properties for type 8, otherwise use default
1388
+ const propertiesToRead = type === 8 ? BacnetDevice.getDeviceObjectProperties() : defaultProperties;
1389
+
1390
+ // Function to read properties individually
1391
+ const readPropertiesIndividually = (resolve, reject) => {
1392
+ const promises = propertiesToRead.map(
1393
+ (property) =>
1394
+ new Promise((propertyResolve) => {
1395
+ that.client.readProperty(
1396
+ addressObject,
1397
+ { type: type, instance: instance },
1398
+ property.id,
1399
+ readIndividualPropsOptions,
1400
+ (err, value) => {
1401
+ if (err) {
1402
+ propertyResolve(null);
1403
+ } else {
1404
+ propertyResolve({
1405
+ id: property.id,
1406
+ index: value.property.index,
1407
+ value: value.values,
1408
+ });
1409
+ }
1410
+ }
1411
+ );
1412
+ })
1413
+ );
1414
+
1415
+ Promise.all(promises)
1416
+ .then((resultArray) => {
1417
+ // Filter out null results
1418
+ const validResults = resultArray.filter((result) => result !== null);
1419
+
1420
+ resolve({
1421
+ error: null,
1422
+ value: {
1423
+ values: [
1424
+ {
1425
+ objectId: {
1426
+ type: type,
1427
+ instance: instance,
1428
+ },
1429
+ values: validResults,
1430
+ },
1431
+ ],
1432
+ },
1433
+ });
1434
+ })
1435
+ .catch(reject);
1436
+ };
1437
+
1387
1438
  return new Promise((resolve, reject) => {
1388
- // Try to read all properties at once
1439
+ // For Device objects (type 8), skip ALL attempt - many MSTP devices don't support it
1440
+ // Go straight to reading individual properties for better reliability
1441
+ if (type === 8) {
1442
+ readPropertiesIndividually(resolve, reject);
1443
+ return;
1444
+ }
1445
+
1446
+ // For other object types, try to read all properties at once first
1389
1447
  that
1390
1448
  ._readObject(addressObject, type, instance, [{ id: baEnum.PropertyIdentifier.ALL }], readOptions)
1391
1449
  .then((result) => {
@@ -1394,61 +1452,13 @@ class BacnetClient extends EventEmitter {
1394
1452
  resolve(result);
1395
1453
  } else {
1396
1454
  // If not, proceed to read individual properties
1397
- readPropertiesIndividually();
1455
+ readPropertiesIndividually(resolve, reject);
1398
1456
  }
1399
1457
  })
1400
1458
  .catch(() => {
1401
1459
  // On error, proceed to read individual properties
1402
- readPropertiesIndividually();
1460
+ readPropertiesIndividually(resolve, reject);
1403
1461
  });
1404
-
1405
- // Function to read properties individually
1406
- const readPropertiesIndividually = () => {
1407
- const promises = allProperties.map(
1408
- (property, index) =>
1409
- new Promise((propertyResolve) => {
1410
- that.client.readProperty(
1411
- addressObject,
1412
- { type: type, instance: instance },
1413
- property.id,
1414
- readIndividualPropsOptions,
1415
- (err, value) => {
1416
- if (err) {
1417
- propertyResolve(null);
1418
- } else {
1419
- propertyResolve({
1420
- id: property.id,
1421
- index: value.property.index,
1422
- value: value.values,
1423
- });
1424
- }
1425
- }
1426
- );
1427
- })
1428
- );
1429
-
1430
- Promise.all(promises)
1431
- .then((resultArray) => {
1432
- // Filter out null results
1433
- const validResults = resultArray.filter((result) => result !== null);
1434
-
1435
- resolve({
1436
- error: null,
1437
- value: {
1438
- values: [
1439
- {
1440
- objectId: {
1441
- type: type,
1442
- instance: instance,
1443
- },
1444
- values: validResults,
1445
- },
1446
- ],
1447
- },
1448
- });
1449
- })
1450
- .catch(reject);
1451
- };
1452
1462
  });
1453
1463
  }
1454
1464
 
@@ -2102,10 +2112,23 @@ class BacnetClient extends EventEmitter {
2102
2112
  }
2103
2113
  break;
2104
2114
  case baEnum.PropertyIdentifier.VENDOR_NAME:
2105
- if (object.value) {
2106
- if (object.value[0].value && typeof object.value[0].value == "string") {
2107
- values[objectId].vendorName = object.value[0].value;
2108
- }
2115
+ if (object.value && object.value[0] && object.value[0].value && typeof object.value[0].value == "string") {
2116
+ values[objectId].vendorName = object.value[0].value;
2117
+ }
2118
+ break;
2119
+ case baEnum.PropertyIdentifier.MODEL_NAME:
2120
+ if (object.value && object.value[0] && object.value[0].value && typeof object.value[0].value == "string") {
2121
+ values[objectId].modelName = object.value[0].value;
2122
+ }
2123
+ break;
2124
+ case baEnum.PropertyIdentifier.FIRMWARE_REVISION:
2125
+ if (object.value && object.value[0] && object.value[0].value && typeof object.value[0].value == "string") {
2126
+ values[objectId].firmwareRevision = object.value[0].value;
2127
+ }
2128
+ break;
2129
+ case baEnum.PropertyIdentifier.APPLICATION_SOFTWARE_VERSION:
2130
+ if (object.value && object.value[0] && object.value[0].value && typeof object.value[0].value == "string") {
2131
+ values[objectId].applicationSoftwareVersion = object.value[0].value;
2109
2132
  }
2110
2133
  break;
2111
2134
  }
package/bacnet_device.js CHANGED
@@ -1,4 +1,31 @@
1
+ const bacnet = require("./resources/node-bacstack-ts/dist/index.js");
2
+ const baEnum = bacnet.enum;
3
+
4
+ // Device Object (type 8) properties - critical properties guaranteed per ASHRAE 135
5
+ // These are the minimum required properties that all BACnet devices must support
6
+ const DEVICE_OBJECT_PROPERTIES = [
7
+ { id: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER },
8
+ { id: baEnum.PropertyIdentifier.OBJECT_NAME },
9
+ { id: baEnum.PropertyIdentifier.OBJECT_TYPE },
10
+ { id: baEnum.PropertyIdentifier.SYSTEM_STATUS },
11
+ { id: baEnum.PropertyIdentifier.VENDOR_NAME },
12
+ { id: baEnum.PropertyIdentifier.VENDOR_IDENTIFIER },
13
+ { id: baEnum.PropertyIdentifier.MODEL_NAME },
14
+ { id: baEnum.PropertyIdentifier.FIRMWARE_REVISION },
15
+ { id: baEnum.PropertyIdentifier.APPLICATION_SOFTWARE_VERSION },
16
+ { id: baEnum.PropertyIdentifier.DESCRIPTION },
17
+ ];
18
+
1
19
  class BacnetDevice {
20
+ /**
21
+ * Returns the standardized list of properties to read for Device objects (type 8).
22
+ * These are critical properties guaranteed to exist on all BACnet devices per ASHRAE 135.
23
+ * @returns {Array} Array of property identifier objects
24
+ */
25
+ static getDeviceObjectProperties() {
26
+ return DEVICE_OBJECT_PROPERTIES;
27
+ }
28
+
2
29
  constructor(fromImport, config) {
3
30
  let that = this;
4
31
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitpoolos/edge-bacnet",
3
- "version": "1.6.6",
3
+ "version": "1.6.7",
4
4
  "description": "A bacnet gateway for node-red",
5
5
  "dependencies": {
6
6
  "@plus4nodered/ts-node-bacnet": "^1.0.0-beta.2",
@@ -26,13 +26,15 @@
26
26
  }
27
27
  },
28
28
  "keywords": [
29
+ "BACnet",
29
30
  "node-red",
30
31
  "bitpool",
31
32
  "bitpoolos",
32
33
  "edge",
33
34
  "big data",
34
35
  "iot",
35
- "BACnet"
36
+ "building automation",
37
+ "bms"
36
38
  ],
37
39
  "engines": {
38
40
  "node": ">=12.0.0"
@@ -319,8 +319,13 @@
319
319
  margin-left: 10px;
320
320
  background-color: #00aeef;
321
321
  color: #ffffff;
322
- border-radius: 45%;
323
- font-size: 12px;
322
+ border-radius: 4px;
323
+ font-size: 11px;
324
+ font-weight: 500;
325
+ padding: 2px 6px;
326
+ display: inline-block;
327
+ vertical-align: middle;
328
+ line-height: 1.2;
324
329
  }
325
330
 
326
331
  .pointAddedToRead {
package/treeBuilder.js CHANGED
@@ -355,6 +355,12 @@ class treeBuilder {
355
355
  this.addPointProperty(pointProperties, "Modification Date", point.modificationDate);
356
356
  this.addPointProperty(pointProperties, "Program State", point.programState);
357
357
  this.addPointProperty(pointProperties, "Record Count", point.recordCount);
358
+
359
+ // Add device-specific properties (type 8)
360
+ this.addPointProperty(pointProperties, "Vendor Name", point.vendorName);
361
+ this.addPointProperty(pointProperties, "Model Name", point.modelName);
362
+ this.addPointProperty(pointProperties, "Firmware Revision", point.firmwareRevision);
363
+ this.addPointProperty(pointProperties, "Application Software Version", point.applicationSoftwareVersion);
358
364
 
359
365
  // Return the array of point properties
360
366
  return pointProperties;