@bitpoolos/edge-bacnet 1.0.9 → 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.
package/bacnet_read.html CHANGED
@@ -118,9 +118,17 @@
118
118
  });
119
119
 
120
120
 
121
+ },
122
+ addAllDevices() {
123
+ let app = this;
124
+ app.devices.forEach(function (device) {
125
+ app.addAllClicked({"node": device});
126
+ });
127
+
121
128
  },
122
129
  addAllClicked(slotProps) {
123
130
  //update UI
131
+ let app = this;
124
132
 
125
133
  let clone = JSON.parse(JSON.stringify(slotProps.node));
126
134
 
@@ -144,48 +152,71 @@
144
152
 
145
153
  //update node-red data structure to forward to gateway
146
154
  let device = this.deviceList.find(ele => ele.deviceName == slotProps.node.label);
147
- let points = this.pointList[slotProps.node.deviceId];
155
+ let deviceAddress = app.getDeviceAddress(device.address);
156
+ let key = `${deviceAddress}-${device.deviceId}`;
157
+ let points = this.pointList[key];
148
158
 
149
- if (!this.pointsToRead[device.deviceId]) {
150
- this.pointsToRead[device.deviceId] = {};
159
+ if (!this.pointsToRead[key]) {
160
+ this.pointsToRead[key] = {};
151
161
  }
152
162
 
153
163
  for (let pointName in points) {
154
- let point = this.pointList[device.deviceId][pointName];
155
- this.pointsToRead[device.deviceId][point.objectName] = point;
164
+ let point = this.pointList[key][pointName];
165
+ this.pointsToRead[key][point.objectName] = point;
156
166
  }
157
167
 
158
168
  //force a deploy state
159
169
  node.hiddenDeployToggle = !node.prevHiddenToggleState;
160
170
  },
171
+ removeAllDevices() {
172
+ let app = this;
173
+
174
+ let clone = JSON.parse(JSON.stringify(app.readDevices));
175
+
176
+ clone.forEach(function (device) {
177
+ app.removeAllClicked({"node": device});
178
+ });
179
+
180
+ app.$forceUpdate();
181
+
182
+ },
161
183
  removeAllClicked(slotProps) {
162
- //update UI
163
- if (this.readDevices.length > 0) {
164
- let foundIndex = this.readDevices.findIndex(ele => ele.key == slotProps.node.key && ele.label == slotProps.node.label);
165
- if (foundIndex !== -1) this.readDevices.splice(foundIndex, 1);
166
- }
184
+ let app = this;
185
+ try {
186
+ //update UI
187
+ if (this.readDevices.length > 0) {
188
+ let foundIndex = this.readDevices.findIndex(ele => ele.key == slotProps.node.key && ele.label == slotProps.node.label);
189
+ if (foundIndex !== -1) this.readDevices.splice(foundIndex, 1);
190
+ }
167
191
 
168
- let deviceSlot = this.devices.find(ele => ele.label == slotProps.node.label);
169
- if(deviceSlot) {
170
- deviceSlot.showAdded = false;
171
- deviceSlot.children.forEach(function(child) {
172
- child.showAdded = false;
173
- });
174
- }
175
- slotProps.node.showAdded = false;
176
- this.$forceUpdate();
192
+ let deviceSlot = this.devices.find(ele => ele.label == slotProps.node.label);
193
+ if(deviceSlot) {
194
+ deviceSlot.showAdded = false;
195
+ deviceSlot.children.forEach(function(child) {
196
+ child.showAdded = false;
197
+ });
198
+ }
199
+ slotProps.node.showAdded = false;
200
+ this.$forceUpdate();
201
+
202
+ //update node-red data structure
203
+ let device = this.deviceList.find(ele => ele.deviceName == slotProps.node.label);
204
+ let deviceAddress = app.getDeviceAddress(device.address);
205
+ let key = `${deviceAddress}-${device.deviceId}`;
206
+ if (this.pointsToRead[key]) {
207
+ delete this.pointsToRead[key];
208
+ }
177
209
 
178
- //update node-red data structure
179
- let device = this.deviceList.find(ele => ele.deviceName == slotProps.node.label);
180
- if (this.pointsToRead[device.deviceId]) {
181
- delete this.pointsToRead[device.deviceId];
210
+ //force a deploy state
211
+ node.hiddenDeployToggle = !node.prevHiddenToggleState;
212
+
213
+ } catch(e){
214
+ console.log("removeAllClicked error: ", e);
182
215
  }
183
216
 
184
- //force a deploy state
185
- node.hiddenDeployToggle = !node.prevHiddenToggleState;
186
217
  },
187
218
  addPointClicked(slotProps) {
188
-
219
+ let app = this;
189
220
  //update UI
190
221
  let parentDeviceName = slotProps.node.parentDevice;
191
222
  let foundDeviceIndex = this.readDevices ? this.readDevices.findIndex(ele => ele.label == parentDeviceName) : -1;
@@ -215,17 +246,21 @@
215
246
 
216
247
  //update node-red data structure
217
248
  let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
218
- if (!this.pointsToRead[device.deviceId]) {
219
- this.pointsToRead[device.deviceId] = {};
249
+ let deviceAddress = app.getDeviceAddress(device.address);
250
+ let key = `${deviceAddress}-${device.deviceId}`;
251
+
252
+ if (!this.pointsToRead[key]) {
253
+ this.pointsToRead[key] = {};
220
254
  }
221
255
 
222
- let point = this.pointList[parentDevice.deviceId][slotProps.node.pointName];
223
- this.pointsToRead[device.deviceId][point.objectName] = point;
256
+ let point = this.pointList[key][slotProps.node.pointName];
257
+ this.pointsToRead[key][point.objectName] = point;
224
258
 
225
259
  //force a deploy state
226
260
  node.hiddenDeployToggle = !node.prevHiddenToggleState;
227
261
  },
228
262
  removePointClicked(slotProps) {
263
+ let app = this;
229
264
  //update UI
230
265
  let parentDeviceName = slotProps.node.parentDevice;
231
266
  let foundDeviceIndex = this.readDevices ? this.readDevices.findIndex(ele => ele.label == parentDeviceName) : -1;
@@ -247,12 +282,26 @@
247
282
 
248
283
  //update node-red data stucture
249
284
  let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
250
- let point = this.pointList[parentDevice.deviceId][slotProps.node.pointName];
251
- if (this.pointsToRead[device.deviceId][point.objectName]) delete this.pointsToRead[device.deviceId][point.objectName];
285
+ let deviceAddress = app.getDeviceAddress(device.address);
286
+ let key = `${deviceAddress}-${device.deviceId}`;
287
+ let point = this.pointList[key][slotProps.node.pointName];
288
+ if (this.pointsToRead[key][point.objectName]) delete this.pointsToRead[key][point.objectName];
289
+ //if last point is removed, deleted whole entry
290
+ if(Object.keys(this.pointsToRead[key]).length == 0) delete this.pointsToRead[key];
252
291
 
253
292
  //force a deploy state
254
293
  node.hiddenDeployToggle = !node.prevHiddenToggleState;
255
294
  },
295
+ getDeviceAddress(addr) {
296
+ switch(typeof addr) {
297
+ case "object":
298
+ return addr.address;
299
+ case "string":
300
+ return addr;
301
+ default:
302
+ return addr;
303
+ }
304
+ },
256
305
  isDeviceActive(slotProps) {
257
306
  let app = this;
258
307
  if (((Date.now() - slotProps.node.lastSeen) / 1000) < (app.pollFrequency + 5)) {
@@ -498,7 +547,7 @@
498
547
  outline: none !important;
499
548
  }
500
549
  .p-tree-filter:focus, .p-tree-filter:focus-visible, .p-inputtext:enabled:hover {
501
- box-shadow: inset 0 0 0 0.15rem #44475a !important;
550
+ box-shadow: inset 0 0 0 0.15rem #dfdcdc !important;
502
551
  border-color: transparent !important;
503
552
  }
504
553
  .bacnetbutton > .pi {
@@ -510,6 +559,18 @@
510
559
  .reloadButtonIcon {
511
560
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
512
561
  }
562
+ .removeAllDevicesButton {
563
+ border: none;
564
+ background: none;
565
+ font-size: 14px !important;
566
+ float: right;
567
+ display: flex;
568
+ align-items: center;
569
+ }
570
+ .removeAllDevicesButton:hover {
571
+ background-color: #d5d5d5;
572
+ border-radius: 10px;
573
+ }
513
574
  .reloadButton {
514
575
  border: none;
515
576
  background: none;
@@ -553,6 +614,14 @@
553
614
  .buttonGroup {
554
615
  padding-left: 7px;
555
616
  }
617
+ #read-readList-tab {
618
+ display: flex;
619
+ flex-direction: column;
620
+ }
621
+ .removeAllDevicesDiv {
622
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
623
+ padding-right: 20px;
624
+ }
556
625
 
557
626
  </style>
558
627
 
@@ -588,6 +657,9 @@
588
657
  <button @click="getData()" class="reloadButton" title="Reload Data">
589
658
  <i class="pi pi-refresh" style="color: #00AEEF;"></i>
590
659
  </button>
660
+ <button @click="addAllDevices()" class="reloadButton" title="Add all devices">
661
+ <i class="pi pi-plus" style="color: #00AEEF;"></i>
662
+ </button>
591
663
  </div>
592
664
  </div>
593
665
 
@@ -655,7 +727,11 @@
655
727
  *
656
728
  -->
657
729
  <div id='read-readList-tab' style='display:none'>
658
-
730
+ <div class="removeAllDevicesDiv" >
731
+ <button @click="removeAllDevices()" class="removeAllDevicesButton" title="Remove all devices">
732
+ <i class="pi pi-minus-circle" style="color: #ff0000; padding-right: 5px;"> </i><a style="color: #ff0000;">Remove All Devices</a>
733
+ </button>
734
+ </div>
659
735
 
660
736
  <p-tree :value="readDevices">
661
737
  <template #device="slotProps">
@@ -0,0 +1,321 @@
1
+ const bacnet = require('./resources/node-bacnet/index.js');
2
+ const baEnum = bacnet.enum;
3
+ const { ToadScheduler, SimpleIntervalJob, Task } = require('toad-scheduler')
4
+
5
+ class BacnetServer {
6
+
7
+ constructor(client, deviceId, rebuildSchedule, nodeRedVersion){
8
+ let that = this;
9
+ that.bacnetClient = client;
10
+ that.rebuildScheduleSeconds = rebuildSchedule;
11
+ that.scheduler = new ToadScheduler();
12
+ that.objectIdNumber = 1;
13
+ that.nodeRedVersion = nodeRedVersion;
14
+ that.deviceId = deviceId;
15
+ that.objectList = [
16
+ {value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}
17
+ ];
18
+ that.objectStore = {
19
+ [baEnum.ObjectType.DEVICE]: {
20
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}], // OBJECT_IDENTIFIER
21
+ [baEnum.PropertyIdentifier.OBJECT_LIST]: that.objectList, // OBJECT_IDENTIFIER
22
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: 'Bitpool Edge BACnet Gateway', type: 7}], // OBJECT_NAME
23
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: 8, type: 9}], // OBJECT_TYPE
24
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: 'Bitpool Edge BACnet gateway', type: 7}], // DESCRIPTION
25
+ [baEnum.PropertyIdentifier.SYSTEM_STATUS]: [{value: 0, type: 9}], // SYSTEM_STATUS
26
+ [baEnum.PropertyIdentifier.VENDOR_NAME]: [{value: "Bitpool", type: 7}], //VENDOR_NAME
27
+ [baEnum.PropertyIdentifier.VENDOR_IDENTIFIER]: [{value: 1401, type: 7}], //VENDOR_IDENTIFIER
28
+ [baEnum.PropertyIdentifier.MODEL_NAME]: [{value: "bitpool-edge", type: 7}], //MODEL_NAME
29
+ [baEnum.PropertyIdentifier.FIRMWARE_REVISION]: [{value: "Node-Red " + that.nodeRedVersion, type: 7}], //FIRMWARE_REVISION
30
+ },
31
+ [baEnum.ObjectType.ANALOG_VALUE]: [],
32
+ [baEnum.ObjectType.CHARACTERSTRING_VALUE]: []
33
+ };
34
+
35
+ that.bacnetClient.client.on('whoIs', (device) => {
36
+ that.bacnetClient.client.iAmResponse(that.bacnetClient.broadCastAddr, that.deviceId, baEnum.Segmentation.SEGMENTED_BOTH, 27823);
37
+ });
38
+
39
+ that.bacnetClient.client.on('readPropertyMultiple', (data) => {
40
+
41
+ let senderAddress = data.header.sender.address;
42
+ let requestProps = data.payload.properties;
43
+ let responseObject = [];
44
+
45
+ try {
46
+ if(requestProps) {
47
+
48
+ for(let i = 0; i < requestProps.length; i++) {
49
+
50
+ let prop = requestProps[i].properties[0].id;
51
+ let type = requestProps[i].objectId.type;
52
+ let instance = requestProps[i].objectId.instance;
53
+ let foundObject = that.getObjectMultiple(type, prop, instance, requestProps[i].properties);
54
+
55
+ if(foundObject !== null && foundObject !== undefined && foundObject !== "undefined") {
56
+ responseObject.push({objectId: {type: type, instance: instance}, values: foundObject});
57
+ }
58
+
59
+ if(i == requestProps.length - 1) {
60
+ if(responseObject.length > 0) {
61
+ that.bacnetClient.client.readPropertyMultipleResponse(senderAddress, data.invokeId, responseObject);
62
+ } else {
63
+ that.bacnetClient.client.errorResponse(
64
+ data.address,
65
+ baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE,
66
+ data.invokeId,
67
+ baEnum.ErrorClass.PROPERTY,
68
+ baEnum.ErrorCode.UNKNOWN_PROPERTY
69
+ );
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ } catch(e) {
76
+ console.log("Bacnet server readPropertyMultiple error: ", e);
77
+
78
+ that.bacnetClient.client.errorResponse(
79
+ data.address,
80
+ baEnum.ConfirmedServiceChoice.READ_PROPERTY_MULTIPLE,
81
+ data.invokeId,
82
+ baEnum.ErrorClass.PROPERTY,
83
+ baEnum.ErrorCode.UNKNOWN_PROPERTY
84
+ );
85
+ }
86
+ });
87
+
88
+ that.bacnetClient.client.on('readProperty', (data) => {
89
+ try {
90
+ let objectId = data.payload.objectId.type;
91
+ let objectInstance = data.payload.objectId.instance;
92
+ let propId = data.payload.property.id.toString();
93
+ let responseObj = that.getObject(objectId, propId, objectInstance);
94
+
95
+ if(responseObj !== null && responseObj !== undefined && typeof responseObj !== "undefined") {
96
+ that.bacnetClient.client.readPropertyResponse(data.header.sender.address, data.invokeId, objectId, data.payload.property, responseObj);
97
+ } else {
98
+ that.bacnetClient.client.errorResponse(
99
+ data.address,
100
+ baEnum.ConfirmedServiceChoice.READ_PROPERTY,
101
+ data.invokeId,
102
+ baEnum.ErrorClass.PROPERTY,
103
+ baEnum.ErrorCode.UNKNOWN_PROPERTY
104
+ );
105
+ }
106
+ } catch(e) {
107
+ console.log("Local BACnet device readProperty error: ", e);
108
+ }
109
+
110
+ });
111
+
112
+ //do initial iAm broadcast when BACnet server starts
113
+ that.bacnetClient.client.iAmResponse(that.bacnetClient.broadCastAddr, that.deviceId, baEnum.Segmentation.SEGMENTED_BOTH, 27823);
114
+
115
+ try {
116
+ //add clear server job to schedule
117
+ const task = new Task('simple task', () => {
118
+ that.clearServerPoints();
119
+ });
120
+
121
+ const job = new SimpleIntervalJob({ seconds: parseInt(that.rebuildScheduleSeconds), }, task)
122
+
123
+ that.scheduler.addSimpleIntervalJob(job)
124
+
125
+ } catch (error) {
126
+
127
+ }
128
+ }
129
+
130
+ addObject(name, value) {
131
+ let that = this;
132
+ if(name && value) {
133
+ let formattedName = name.replaceAll('.', '');
134
+ let objectType = that.getBacnetObjectType(value);
135
+
136
+ if(objectType == "number") {
137
+ let foundIndex = that.objectStore[baEnum.ObjectType.ANALOG_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
138
+ if(foundIndex == -1) {
139
+ let objectId = that.getObjectIdentifier();
140
+ that.objectStore[baEnum.ObjectType.ANALOG_VALUE].push({
141
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
142
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.ANALOG_VALUE, type: 9}],
143
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: '', type: 7}],
144
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId}, type: 12}],
145
+ [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type: 4}],
146
+ [baEnum.PropertyIdentifier.PROPERTY_LIST]:
147
+ [
148
+ {value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
149
+ {value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
150
+ {value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
151
+ {value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
152
+ {value: baEnum.PropertyIdentifier.PROPERTY_LIST, type: 9 },
153
+ {value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 }
154
+ ],
155
+ });
156
+
157
+ that.objectList.push({value: {type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId}, type: 12})
158
+ } else if(foundIndex !== -1) {
159
+
160
+ let foundObject = that.objectStore[baEnum.ObjectType.ANALOG_VALUE][foundIndex];
161
+ foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
162
+ }
163
+ } else if(objectType == "string") {
164
+ let foundIndex = that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
165
+ if(foundIndex == -1) {
166
+ let objectId = that.getObjectIdentifier();
167
+ that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].push({
168
+ [baEnum.PropertyIdentifier.OBJECT_NAME]: [{value: formattedName, type: 7}],
169
+ [baEnum.PropertyIdentifier.OBJECT_TYPE]: [{value: baEnum.ObjectType.CHARACTERSTRING_VALUE, type: 9}],
170
+ [baEnum.PropertyIdentifier.DESCRIPTION]: [{value: '', type: 7}],
171
+ [baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{value: {type: baEnum.ObjectType.CHARACTERSTRING_VALUE, instance: objectId}, type: 12}],
172
+ [baEnum.PropertyIdentifier.PRESENT_VALUE]: [{value: value, type: 7}],
173
+ [baEnum.PropertyIdentifier.PROPERTY_LIST]:
174
+ [
175
+ {value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
176
+ {value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
177
+ {value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
178
+ {value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
179
+ {value: baEnum.PropertyIdentifier.PROPERTY_LIST, type: 9 },
180
+ {value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 }
181
+ ],
182
+ });
183
+
184
+ that.objectList.push({value: {type: baEnum.ObjectType.CHARACTERSTRING_VALUE, instance: objectId}, type: 12})
185
+ } else if(foundIndex !== -1) {
186
+ let foundObject = that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE][foundIndex];
187
+ foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ getObject(objectId, propId, instance) {
194
+ let that = this;
195
+ let objectGroup = that.objectStore[objectId];
196
+
197
+ if(Array.isArray(objectGroup)) {
198
+ for(let i = 0; i < objectGroup.length; i++) {
199
+ let object = objectGroup[i];
200
+ if(object[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance == instance) {
201
+ let requestedProperty = object[propId];
202
+ if(requestedProperty !== null && requestedProperty !== undefined && typeof requestedProperty !== "undefined") {
203
+ return requestedProperty;
204
+ }
205
+ }
206
+ }
207
+ } else {
208
+ return objectGroup[propId];
209
+ }
210
+
211
+ return null;
212
+ }
213
+
214
+ getObjectMultiple(objectId, propId, instance, properties) {
215
+ let that = this;
216
+ let objectGroup = that.objectStore[objectId];
217
+
218
+ try {
219
+
220
+ if(Array.isArray(objectGroup)) {
221
+ for(let i = 0; i < objectGroup.length; i++) {
222
+ let object = objectGroup[i];
223
+ if(object[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance == instance) {
224
+ if(propId == baEnum.PropertyIdentifier.ALL) {
225
+ let propList = [];
226
+ let keys = Object.keys(object);
227
+ keys.forEach(function(key) {
228
+ propList.push({property: {id: key, index: 0xFFFFFFFF}, value: object[key]});
229
+ });
230
+
231
+ return propList;
232
+
233
+ } else if(properties && properties.length > 1) {
234
+ let propList = [];
235
+ properties.forEach(function(p) {
236
+ if(object[p.id]){
237
+ propList.push({property: {id: p.id, index: 0xFFFFFFFF}, value: object[p.id]});
238
+ }
239
+ });
240
+
241
+ return propList;
242
+
243
+ } else {
244
+ return [{property: {id: propId, index: 0xFFFFFFFF}, value: object[propId]}];
245
+ }
246
+ }
247
+ }
248
+ } else {
249
+ if(propId == baEnum.PropertyIdentifier.ALL) {
250
+ let propList = [];
251
+ let keys = Object.keys(objectGroup);
252
+ keys.forEach(function(key) {
253
+ propList.push({property: {id: key, index: 0xFFFFFFFF}, value: objectGroup[key]});
254
+ });
255
+
256
+ return propList;
257
+
258
+ } else if(properties && properties.length > 1) {
259
+ let propList = [];
260
+ properties.forEach(function(p) {
261
+ if(objectGroup[p.id]){
262
+ propList.push({property: {id: p.id, index: 0xFFFFFFFF}, value: objectGroup[p.id]});
263
+ }
264
+ });
265
+
266
+ return propList;
267
+
268
+ } else {
269
+ return [{property: {id: propId, index: 0xFFFFFFFF}, value: objectGroup[propId]}];
270
+ }
271
+ }
272
+
273
+ } catch(e){
274
+ //console.log("properties error: ", e);
275
+ }
276
+
277
+ return null;
278
+ }
279
+
280
+ clearServerPoints() {
281
+ let that = this;
282
+
283
+ that.objectStore[baEnum.ObjectType.ANALOG_VALUE] = [];
284
+ that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE] = [];
285
+
286
+ that.objectList = [
287
+ {value: {type: baEnum.ObjectType.DEVICE, instance: that.deviceId}, type: 12}
288
+ ];
289
+
290
+ that.objectIdNumber = 1;
291
+ }
292
+
293
+ getRandomArbitrary(min, max) {
294
+ return Math.random() * (max - min) + min;
295
+ }
296
+
297
+ getBacnetObjectType(value) {
298
+ let type = typeof value;
299
+
300
+ switch (type) {
301
+ case "string":
302
+ return "string"
303
+ case "number":
304
+ return "number"
305
+ default:
306
+ return null
307
+ }
308
+ }
309
+
310
+ getObjectIdentifier() {
311
+ let that = this;
312
+ let objectId = that.objectIdNumber;
313
+ that.objectIdNumber++;
314
+
315
+ return objectId;
316
+ }
317
+
318
+
319
+ }
320
+
321
+ module.exports = { BacnetServer };
package/bacnet_write.html CHANGED
@@ -109,15 +109,16 @@
109
109
 
110
110
  //update node-red data structure to forward to gateway
111
111
  let device = this.deviceList.find(ele => ele.deviceName == slotProps.node.label);
112
- let points = this.pointList[slotProps.node.deviceId];
112
+ let key = `${device.address}-${device.deviceId}`;
113
+ let points = this.pointList[key];
113
114
 
114
- if (!this.pointsToWrite[device.deviceId] || typeof this.pointsToWrite[device.deviceId] == 'undefined') {
115
- this.pointsToWrite[device.deviceId] = {};
115
+ if (!this.pointsToWrite[key] || typeof this.pointsToWrite[key] == 'undefined') {
116
+ this.pointsToWrite[key] = {};
116
117
  }
117
118
 
118
119
  for (let pointName in points) {
119
- let point = this.pointList[device.deviceId][pointName];
120
- this.pointsToWrite[device.deviceId][point.objectName] = point;
120
+ let point = this.pointList[key][pointName];
121
+ this.pointsToWrite[key][point.objectName] = point;
121
122
  }
122
123
 
123
124
  //force a deploy state
@@ -133,8 +134,9 @@
133
134
 
134
135
  //update node-red data structure
135
136
  let device = this.deviceList.find(ele => ele.deviceName == slotProps.node.label);
136
- if (this.pointsToWrite[device.deviceId]) {
137
- delete this.pointsToWrite[device.deviceId];
137
+ let key = `${device.address}-${device.deviceId}`;
138
+ if (this.pointsToWrite[key]) {
139
+ delete this.pointsToWrite[key];
138
140
  }
139
141
 
140
142
  //force a deploy state
@@ -170,8 +172,10 @@
170
172
 
171
173
  //update node-red data structure
172
174
  let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
173
- let point = this.pointList[device.deviceId][slotProps.node.pointName];
175
+ let key = `${device.address}-${device.deviceId}`;
176
+ let point = this.pointList[key][slotProps.node.pointName];
174
177
  point.deviceId = device.deviceId;
178
+ point.deviceAddress = device.address;
175
179
 
176
180
  if (!this.pointsToWrite || this.pointsToWrite.length == 'undefined') {
177
181
  this.pointsToWrite = [];
@@ -208,7 +212,8 @@
208
212
 
209
213
  //update node-red data stucture
210
214
  let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
211
- let point = this.pointList[parentDeviceName][slotProps.node.label];
215
+ let key = `${device.address}-${device.deviceId}`;
216
+ let point = this.pointList[key][slotProps.node.pointName];
212
217
  point.deviceId = device.deviceId;
213
218
 
214
219
  let foundIndex = this.pointsToWrite.findIndex(ele =>