@bitpoolos/edge-bacnet 1.2.6 → 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/bacnet_write.html CHANGED
@@ -162,11 +162,27 @@
162
162
  //update UI
163
163
  let parentDeviceName = slotProps.node.parentDevice;
164
164
  let foundDeviceIndex = this.writeDevices ? this.writeDevices.findIndex(ele => ele.label == parentDeviceName) : -1;
165
- let parentDevice = this.devices.find(ele => ele.label == parentDeviceName);
165
+ let device = this.deviceList.find(ele => ele.deviceName == parentDeviceName);
166
+ let deviceAddress = app.getDeviceAddress(device.address);
167
+ let key = `${deviceAddress}-${device.deviceId}`;
168
+ let parentDevice = this.devices.find(ele => ele.ipAddr == deviceAddress);
169
+ let childDevice;
170
+ if(device.isMstp) {
171
+ let foundChildIndex = parentDevice.children[1].children.findIndex(ele => ele.label == parentDeviceName);
172
+ if(foundChildIndex !== -1) {
173
+ childDevice = parentDevice.children[1].children[foundChildIndex];
174
+ }
175
+ }
166
176
 
167
177
  if (foundDeviceIndex == -1) {
168
178
  //no read devices present, add new
169
- let newReadParent = {...parentDevice};
179
+ let newReadParent;
180
+ if(childDevice) {
181
+ newReadParent = {...childDevice};
182
+ } else {
183
+ newReadParent = {...parentDevice};
184
+ }
185
+
170
186
  newReadParent.children = [];
171
187
  newReadParent.children.push(slotProps.node);
172
188
 
@@ -183,18 +199,12 @@
183
199
 
184
200
  slotProps.node.showAdded = true;
185
201
 
202
+ console.log("write point added, slotProps.node: ", slotProps.node);
203
+
186
204
  this.$forceUpdate();
187
205
 
188
206
  //update node-red data structure
189
- let device = this.deviceList.find(ele => {
190
- if(ele.address.address) {
191
- return ele.address.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
192
- } else {
193
- return ele.address == parentDevice.ipAddr && ele.deviceId == parentDevice.deviceId;
194
- }
195
- });
196
- let deviceAddress = app.getDeviceAddress(device.address);
197
- let key = `${deviceAddress}-${device.deviceId}`;
207
+
198
208
  let point = this.pointList[key][slotProps.node.pointName];
199
209
  point.deviceId = device.deviceId;
200
210
  point.deviceAddress = device.address;
@@ -212,6 +222,8 @@
212
222
 
213
223
  if (!found) this.pointsToWrite.push(point);
214
224
 
225
+ console.log("this.pointsToWrite: ", this.pointsToWrite);
226
+
215
227
  //force a deploy state
216
228
  node.hiddenDeployToggle = !node.prevHiddenToggleState;
217
229
  },
@@ -365,13 +377,13 @@
365
377
  <script type="text/html" data-template-name="Bacnet-Write">
366
378
  <style>
367
379
  .p-treenode-label {
368
- /* color: white; */
369
380
  color: black;
370
381
  width: 100%;
371
382
  }
372
383
  .p-tree {
373
384
  background: inherit !important;
374
385
  border: inherit !important;
386
+ padding-right: 0px !important;
375
387
  }
376
388
  .p-button {
377
389
  margin-right: .5rem;
@@ -383,15 +395,11 @@
383
395
  float: right;
384
396
  }
385
397
  .addPointButton:hover, .minusPointButton:hover {
386
- /* background: #282A36 !important; */
387
398
  background: #d5d5d5 !important;
388
399
  }
389
400
  .pointLabel {
390
401
  font-weight: 400;
391
402
  }
392
- /* .p-treenode-children {
393
- background-color: #f0f0f0;
394
- } */
395
403
  .deviceLabel {
396
404
  font-weight: 100;
397
405
  }
@@ -404,12 +412,10 @@
404
412
  .bacnetbutton {
405
413
  background: none;
406
414
  border: none;
407
- /* color: white; */
408
415
  color: black;
409
416
  font-weight: 400;
410
417
  }
411
418
  .bacnetbutton:hover {
412
- /* background: #21232e; */
413
419
  background: #f0f0f0;
414
420
  border-radius: 10px;
415
421
  }
@@ -419,17 +425,13 @@
419
425
  }
420
426
  .p-treenode-children > li > .p-treenode-children > li {
421
427
  font-size: 14px;
422
- height: 25px;
428
+ /* height: 35px; */
423
429
  color: #b5b5b5 !important;
424
430
  }
425
431
  .p-treenode-children > li > .p-treenode-children > .p-treenode-label {
426
432
  color: #b5b5b5 !important;
427
433
  }
428
- .p-treenode-children > li > .p-treenode-children > li:last-child {
429
- padding-bottom: 30px;
430
- }
431
434
  .p-tree-toggler:enabled:hover {
432
- /* background: #21232e !important; */
433
435
  background: #d5d5d5 !important;
434
436
  }
435
437
  .p-tree-toggler:focus {
@@ -441,14 +443,15 @@
441
443
  }
442
444
  .statusOnline {
443
445
  color: #11c511;
444
-
445
446
  }
446
447
  .statusOffline {
447
448
  color: red;
448
449
  }
450
+ /*
449
451
  .deviceLabel {
450
- position: relative;
452
+ position: absolute;
451
453
  }
454
+ */
452
455
  .objectPropertiesLabel {
453
456
  display: flex !important;
454
457
  flex-direction: row;
@@ -457,23 +460,60 @@
457
460
  .p-tree .p-tree-container .p-treenode .p-treenode-content:focus {
458
461
  outline: 0 none !important;
459
462
  outline-offset: 0 !important;
460
- box-shadow: inset 0 0 0 0.15rem #44475a !important;
463
+ box-shadow: inset 0 0 0 1px #bdbdbd !important;
464
+ }
465
+ .checkbox-round {
466
+ width: 13px !important;
467
+ height: 13px !important;
468
+ background-color: white;
469
+ border-radius: 50%;
470
+ vertical-align: middle;
471
+ border: 1px solid #ddd;
472
+ appearance: none;
473
+ -webkit-appearance: none;
474
+ outline: none;
475
+ cursor: pointer;
476
+ }
477
+ .checkbox-round:checked {
478
+ background-color: #00AEEF;
479
+ }
480
+ .checkbox-round:focus {
481
+ outline: none !important;
461
482
  }
462
483
  .p-tree-filter:focus, .p-tree-filter:focus-visible, .p-inputtext:enabled:hover {
463
- box-shadow: inset 0 0 0 0.15rem #44475a !important;
484
+ box-shadow: inset 0 0 0 0.15rem #dfdcdc !important;
464
485
  border-color: transparent !important;
465
486
  }
466
487
  .bacnetbutton > .pi {
467
488
  display: flex;
468
489
  }
490
+ .p-tree-container {
491
+ margin: 0 !important;
492
+ }
469
493
  .reloadButtonIcon {
470
494
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol" !important;
471
495
  }
496
+ .removeAllDevicesButton {
497
+ border: none;
498
+ background: none;
499
+ font-size: 14px !important;
500
+ float: right;
501
+ display: flex;
502
+ align-items: center;
503
+ }
504
+ .removeAllDevicesButton:hover {
505
+ background-color: #d5d5d5;
506
+ border-radius: 10px;
507
+ }
472
508
  .reloadButton {
473
509
  border: none;
474
510
  background: none;
475
- margin-right: 20px !important;
476
- margin-bottom: 10px !important;
511
+ font-size: 14px !important;
512
+ float: right;
513
+ }
514
+ .rebuildDataButton {
515
+ border: none;
516
+ background: none;
477
517
  font-size: 14px !important;
478
518
  float: right;
479
519
  }
@@ -481,11 +521,47 @@
481
521
  background-color: #d5d5d5;
482
522
  border-radius: 10px;
483
523
  }
524
+ .rebuildDataButton:hover {
525
+ background-color: #d5d5d5;
526
+ border-radius: 10px;
527
+ }
528
+ .headerDiv {
529
+ display: flex;
530
+ flex-direction: row;
531
+ flex-wrap: nowrap;
532
+ justify-content: space-around;
533
+ height: 20px;
534
+ }
535
+ .msgTypeDiv {
536
+ display: flex;
537
+ align-items: flex-start;
538
+ flex-direction: column;
539
+ }
540
+ .p-progressbar .p-progressbar-value {
541
+ background: #00AEEF !important;
542
+ }
484
543
  .p-treenode-label {
485
544
  overflow: hidden;
486
545
  white-space: nowrap;
487
546
  text-overflow: ellipsis;
488
547
  }
548
+ .buttonGroup {
549
+ padding-left: 7px;
550
+ }
551
+ #read-readList-tab {
552
+ display: flex;
553
+ flex-direction: column;
554
+ }
555
+ .removeAllDevicesDiv {
556
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
557
+ padding-right: 20px;
558
+ }
559
+ .p-tree .p-treenode-children {
560
+ padding: 0 !important;
561
+ }
562
+ .p-tree-toggler .p-link {
563
+ width: 25px !important;
564
+ }
489
565
 
490
566
  </style>
491
567
 
package/bacnet_write.js CHANGED
@@ -15,7 +15,7 @@ module.exports = function (RED) {
15
15
 
16
16
  node.on('input', function(msg) {
17
17
 
18
- let value = msg.payload == "null" ? null : parseInt(msg.payload);
18
+ let value = msg.payload == "null" ? null : msg.payload;
19
19
  let priority = node.priority == "null" ? null : parseInt(node.priority);
20
20
 
21
21
  let output = {
package/common.js CHANGED
@@ -91,7 +91,8 @@ class BacnetClientConfig {
91
91
  manual_instance_range_start,
92
92
  manual_instance_range_end,
93
93
  device_read_schedule,
94
- retries
94
+ retries,
95
+ cacheFileEnabled
95
96
  ) {
96
97
  this.apduTimeout = apduTimeout;
97
98
  this.localIpAdrress = localIpAdrress;
@@ -107,6 +108,7 @@ class BacnetClientConfig {
107
108
  this.manual_instance_range_end = manual_instance_range_end;
108
109
  this.device_read_schedule = device_read_schedule;
109
110
  this.retries = retries;
111
+ this.cacheFileEnabled = cacheFileEnabled;
110
112
  }
111
113
  }
112
114
 
@@ -220,17 +222,25 @@ const doNodeRedRestart = function () {
220
222
  // STORE CONFIG FUNCTION ==========================================================
221
223
  //
222
224
  // ================================================================================
223
- async function Store_Config(data) {
225
+ function Store_Config(data) {
224
226
  try {
225
- await fs.writeFile("edge-bacnet-datastore.cfg", data, (err) => {
226
- if (err) {
227
- 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
+ });
228
236
  }
229
237
  });
230
- } catch (e) {
238
+ } catch(e){
231
239
  //do nothing
232
240
  }
233
- }
241
+ };
242
+
243
+
234
244
 
235
245
  // READ CONFIG SYNC FUNCTION ======================================================
236
246
  //
@@ -238,14 +248,15 @@ async function Store_Config(data) {
238
248
  function Read_Config_Sync() {
239
249
  var data = "{}";
240
250
  try {
241
- data = fs.readFileSync("edge-bacnet-datastore.cfg", { encoding: "utf8", flag: "r" });
242
- } catch (err) {
243
- //console.log("Read_Config_Sync error:", err);
244
- data = "{}";
251
+ data = fs.readFileSync("edge-bacnet-datastore.cfg", { encoding: 'utf8', flag: 'r' });
252
+ }
253
+ catch (err) {
254
+ console.log("Read_Config_Sync error:", err);
255
+ data = '{}';
245
256
  Store_Config(data);
246
257
  }
247
258
  return data;
248
- }
259
+ };
249
260
 
250
261
  // STORE CONFIG FUNCTION - BACNET SERVER ==========================================
251
262
  //
@@ -276,6 +287,10 @@ function Read_Config_Sync_Server() {
276
287
  return data;
277
288
  }
278
289
 
290
+ function isNumber(value) {
291
+ return value != null && typeof value === 'number' && !isNaN(value);
292
+ }
293
+
279
294
  module.exports = {
280
295
  BacnetConfig,
281
296
  BacnetClientConfig,
@@ -290,4 +305,5 @@ module.exports = {
290
305
  Read_Config_Sync,
291
306
  Store_Config_Server,
292
307
  Read_Config_Sync_Server,
308
+ isNumber,
293
309
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitpoolos/edge-bacnet",
3
- "version": "1.2.6",
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",
@@ -50,4 +50,4 @@
50
50
  "type": "github",
51
51
  "url": "git+https://github.com/bitpool/edge-bacnet.git"
52
52
  }
53
- }
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
+ }