@bitpoolos/edge-bacnet 1.4.2 → 1.4.3
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 +22 -0
- package/bacnet_gateway.js +134 -227
- package/bacnet_read.html +27 -2
- package/bacnet_read.js +10 -2
- package/bacnet_server.js +77 -106
- package/bitpool_inject.html +23 -0
- package/bitpool_inject.js +5 -0
- package/package.json +1 -1
- package/resources/style.css +12 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.3] - 01-08-2024
|
|
4
|
+
### Summary
|
|
5
|
+
|
|
6
|
+
Minor updates.
|
|
7
|
+
|
|
8
|
+
Added refresh button to readList tab on read node, to handle scenarios where read node jsons may be programatically created.
|
|
9
|
+
|
|
10
|
+
Added "Use device name in topic" topic property in inject and read nodes. This option toggles whether or not the device name is included in the msg.topic.
|
|
11
|
+
|
|
12
|
+
Merge github PR 19. Added ability to configure the creation of a BacnetServer object:
|
|
13
|
+
```javascript
|
|
14
|
+
payload = {
|
|
15
|
+
value: 12,
|
|
16
|
+
resolution: 0,
|
|
17
|
+
priorityArray: 0,
|
|
18
|
+
units: 0,
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Inject nodes may need to be deleted and replaced. Try deploying node-red 2 times to instantiate the new deviceName property.
|
|
23
|
+
|
|
24
|
+
|
|
3
25
|
## [1.4.2] - 23-07-2024
|
|
4
26
|
### Summary
|
|
5
27
|
|
package/bacnet_gateway.js
CHANGED
|
@@ -107,41 +107,42 @@ module.exports = function (RED) {
|
|
|
107
107
|
node.status({});
|
|
108
108
|
}, 3000);
|
|
109
109
|
}
|
|
110
|
+
let useDeviceName = outputType.useDeviceName;
|
|
110
111
|
if (outputType.json && !outputType.mqtt && !outputType.pointJson) {
|
|
111
112
|
//json
|
|
112
113
|
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
113
114
|
//simpleWithStatus
|
|
114
|
-
sendSimpleWithStatus(values, readNodeName, true);
|
|
115
|
+
sendSimpleWithStatus(values, readNodeName, true, useDeviceName);
|
|
115
116
|
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
116
117
|
//fullObject
|
|
117
|
-
sendJsonAsMqtt(values, readNodeName);
|
|
118
|
+
sendJsonAsMqtt(values, readNodeName, useDeviceName);
|
|
118
119
|
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
119
120
|
//simplePayload
|
|
120
|
-
sendSimpleJson(values, readNodeName);
|
|
121
|
+
sendSimpleJson(values, readNodeName, useDeviceName);
|
|
121
122
|
}
|
|
122
123
|
} else if (outputType.mqtt && !outputType.json && !outputType.pointJson) {
|
|
123
124
|
//mqtt
|
|
124
125
|
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
125
126
|
//simpleWithStatus
|
|
126
|
-
sendSimpleWithStatus(values, readNodeName, false);
|
|
127
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
127
128
|
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
128
129
|
//fullObject
|
|
129
|
-
sendAsMqtt(values, readNodeName);
|
|
130
|
+
sendAsMqtt(values, readNodeName, useDeviceName);
|
|
130
131
|
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
131
132
|
//simplePayload
|
|
132
|
-
sendSimpleMqtt(values, readNodeName);
|
|
133
|
+
sendSimpleMqtt(values, readNodeName, useDeviceName);
|
|
133
134
|
}
|
|
134
135
|
} else if (outputType.pointJson && !outputType.json && !outputType.mqtt) {
|
|
135
136
|
//pointJson
|
|
136
137
|
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
137
138
|
//simpleWithStatus
|
|
138
|
-
sendSimpleWithStatus(values, readNodeName, false);
|
|
139
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
139
140
|
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
140
141
|
//fullObject
|
|
141
|
-
sendIndividualMsgJson(values, readNodeName);
|
|
142
|
+
sendIndividualMsgJson(values, readNodeName, useDeviceName);
|
|
142
143
|
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
143
144
|
//simplePayload
|
|
144
|
-
sendSimpleJsonPerPoint(values, readNodeName);
|
|
145
|
+
sendSimpleJsonPerPoint(values, readNodeName, useDeviceName);
|
|
145
146
|
}
|
|
146
147
|
}
|
|
147
148
|
}
|
|
@@ -456,41 +457,42 @@ module.exports = function (RED) {
|
|
|
456
457
|
node.status({});
|
|
457
458
|
}, 3000);
|
|
458
459
|
}
|
|
460
|
+
let useDeviceName = outputType.useDeviceName;
|
|
459
461
|
if (outputType.json && !outputType.mqtt && !outputType.pointJson) {
|
|
460
462
|
//json
|
|
461
463
|
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
462
464
|
//simpleWithStatus
|
|
463
|
-
sendSimpleWithStatus(values, readNodeName, true);
|
|
465
|
+
sendSimpleWithStatus(values, readNodeName, true, useDeviceName);
|
|
464
466
|
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
465
467
|
//fullObject
|
|
466
|
-
sendJsonAsMqtt(values, readNodeName);
|
|
468
|
+
sendJsonAsMqtt(values, readNodeName, useDeviceName);
|
|
467
469
|
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
468
470
|
//simplePayload
|
|
469
|
-
sendSimpleJson(values, readNodeName);
|
|
471
|
+
sendSimpleJson(values, readNodeName, useDeviceName);
|
|
470
472
|
}
|
|
471
473
|
} else if (outputType.mqtt && !outputType.json && !outputType.pointJson) {
|
|
472
474
|
//mqtt
|
|
473
475
|
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
474
476
|
//simpleWithStatus
|
|
475
|
-
sendSimpleWithStatus(values, readNodeName, false);
|
|
477
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
476
478
|
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
477
479
|
//fullObject
|
|
478
|
-
sendAsMqtt(values, readNodeName);
|
|
480
|
+
sendAsMqtt(values, readNodeName, useDeviceName);
|
|
479
481
|
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
480
482
|
//simplePayload
|
|
481
|
-
sendSimpleMqtt(values, readNodeName);
|
|
483
|
+
sendSimpleMqtt(values, readNodeName, useDeviceName);
|
|
482
484
|
}
|
|
483
485
|
} else if (outputType.pointJson && !outputType.json && !outputType.mqtt) {
|
|
484
486
|
//pointJson
|
|
485
487
|
if (objectPropertyType.simpleWithStatus && !objectPropertyType.fullObject && !objectPropertyType.simplePayload) {
|
|
486
488
|
//simpleWithStatus
|
|
487
|
-
sendSimpleWithStatus(values, readNodeName, false);
|
|
489
|
+
sendSimpleWithStatus(values, readNodeName, false, useDeviceName);
|
|
488
490
|
} else if (objectPropertyType.fullObject && !objectPropertyType.simplePayload && !objectPropertyType.simpleWithStatus) {
|
|
489
491
|
//fullObject
|
|
490
|
-
sendIndividualMsgJson(values, readNodeName);
|
|
492
|
+
sendIndividualMsgJson(values, readNodeName, useDeviceName);
|
|
491
493
|
} else if (objectPropertyType.simplePayload && !objectPropertyType.fullObject && !objectPropertyType.simpleWithStatus) {
|
|
492
494
|
//simplePayload
|
|
493
|
-
sendSimpleJsonPerPoint(values, readNodeName);
|
|
495
|
+
sendSimpleJsonPerPoint(values, readNodeName, useDeviceName);
|
|
494
496
|
}
|
|
495
497
|
}
|
|
496
498
|
}
|
|
@@ -514,7 +516,94 @@ module.exports = function (RED) {
|
|
|
514
516
|
}
|
|
515
517
|
}
|
|
516
518
|
|
|
517
|
-
|
|
519
|
+
function getTopicString(type, useDeviceName, readNodeName, device, pointName, prop) {
|
|
520
|
+
let topic = "";
|
|
521
|
+
if (
|
|
522
|
+
node.nodeName !== "gateway" &&
|
|
523
|
+
node.nodeName !== "" &&
|
|
524
|
+
node.nodeName !== "null" &&
|
|
525
|
+
node.nodeName !== "undefined" &&
|
|
526
|
+
typeof node.nodeName == "string"
|
|
527
|
+
) {
|
|
528
|
+
if (readNodeName !== '' &&
|
|
529
|
+
readNodeName !== null &&
|
|
530
|
+
readNodeName !== undefined
|
|
531
|
+
) {
|
|
532
|
+
if (useDeviceName) {
|
|
533
|
+
topic = `${node.nodeName}/${readNodeName}/${device}`;
|
|
534
|
+
} else {
|
|
535
|
+
topic = `${node.nodeName}/${readNodeName}`;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
} else {
|
|
539
|
+
if (useDeviceName) {
|
|
540
|
+
topic = `${node.nodeName}/${device}`;
|
|
541
|
+
} else {
|
|
542
|
+
topic = `${node.nodeName}`;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
} else {
|
|
546
|
+
if (readNodeName !== '' &&
|
|
547
|
+
readNodeName !== null &&
|
|
548
|
+
readNodeName !== undefined
|
|
549
|
+
) {
|
|
550
|
+
if (useDeviceName) {
|
|
551
|
+
topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}`;
|
|
552
|
+
} else {
|
|
553
|
+
topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}`;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
} else {
|
|
557
|
+
if (useDeviceName) {
|
|
558
|
+
topic = `BITPOOL_BACNET_GATEWAY/${device}`;
|
|
559
|
+
} else {
|
|
560
|
+
topic = `BITPOOL_BACNET_GATEWAY`;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
switch (type) {
|
|
566
|
+
case "sendSimpleWithStatus":
|
|
567
|
+
topic += `/${pointName}`;
|
|
568
|
+
break;
|
|
569
|
+
|
|
570
|
+
case "sendSimpleWithStatusJson":
|
|
571
|
+
//do nothing
|
|
572
|
+
break;
|
|
573
|
+
|
|
574
|
+
case "sendSimpleMqtt":
|
|
575
|
+
topic += `/${pointName}`;
|
|
576
|
+
break;
|
|
577
|
+
|
|
578
|
+
case "sendAsMqtt":
|
|
579
|
+
topic += `/${pointName}/${prop}`;
|
|
580
|
+
break;
|
|
581
|
+
|
|
582
|
+
case "sendSimpleJson":
|
|
583
|
+
//do nothing
|
|
584
|
+
break;
|
|
585
|
+
|
|
586
|
+
case "sendJsonAsMqtt":
|
|
587
|
+
//do nothing
|
|
588
|
+
break;
|
|
589
|
+
|
|
590
|
+
case "sendIndividualMsgJson":
|
|
591
|
+
topic += `/${pointName}`;
|
|
592
|
+
break;
|
|
593
|
+
|
|
594
|
+
case "sendSimpleJsonPerPoint":
|
|
595
|
+
topic += `/${pointName}`;
|
|
596
|
+
break;
|
|
597
|
+
|
|
598
|
+
default:
|
|
599
|
+
break;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
return topic;
|
|
603
|
+
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
sendSimpleWithStatus = function (values, readNodeName, isJson, useDeviceName) {
|
|
518
607
|
let devices = Object.keys(values);
|
|
519
608
|
devices.forEach(function (device) {
|
|
520
609
|
if (device !== "_msgid") {
|
|
@@ -524,31 +613,9 @@ module.exports = function (RED) {
|
|
|
524
613
|
for (let point in points) {
|
|
525
614
|
if (points[point] && "presentValue" in points[point]) {
|
|
526
615
|
let pointName = getPointName(points[point], point);
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
node.nodeName !== "null" &&
|
|
531
|
-
node.nodeName !== "undefined" &&
|
|
532
|
-
typeof node.nodeName == "string"
|
|
533
|
-
) {
|
|
534
|
-
if (readNodeName !== '' &&
|
|
535
|
-
readNodeName !== null &&
|
|
536
|
-
readNodeName !== undefined
|
|
537
|
-
) {
|
|
538
|
-
msgg.topic = `${node.nodeName}/${readNodeName}/${device}/${pointName}`;
|
|
539
|
-
} else {
|
|
540
|
-
msgg.topic = `${node.nodeName}/${device}/${pointName}`;
|
|
541
|
-
}
|
|
542
|
-
} else {
|
|
543
|
-
if (readNodeName !== '' &&
|
|
544
|
-
readNodeName !== null &&
|
|
545
|
-
readNodeName !== undefined
|
|
546
|
-
) {
|
|
547
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}/${pointName}`;
|
|
548
|
-
} else {
|
|
549
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${device}/${pointName}`;
|
|
550
|
-
}
|
|
551
|
-
}
|
|
616
|
+
let topic = getTopicString("sendSimpleWithStatus", useDeviceName, readNodeName, device, pointName);
|
|
617
|
+
|
|
618
|
+
msgg.topic = topic;
|
|
552
619
|
let payload = {
|
|
553
620
|
presentValue: points[point]["presentValue"],
|
|
554
621
|
timestamp: points[point]["timestamp"],
|
|
@@ -569,32 +636,7 @@ module.exports = function (RED) {
|
|
|
569
636
|
|
|
570
637
|
if (isJson) {
|
|
571
638
|
//json payload
|
|
572
|
-
let topic = "";
|
|
573
|
-
if (
|
|
574
|
-
node.nodeName !== "gateway" &&
|
|
575
|
-
node.nodeName !== "" &&
|
|
576
|
-
node.nodeName !== "null" &&
|
|
577
|
-
node.nodeName !== "undefined" &&
|
|
578
|
-
typeof node.nodeName == "string"
|
|
579
|
-
) {
|
|
580
|
-
if (readNodeName !== '' &&
|
|
581
|
-
readNodeName !== null &&
|
|
582
|
-
readNodeName !== undefined
|
|
583
|
-
) {
|
|
584
|
-
topic = `${node.nodeName}/${readNodeName}/${device}`;
|
|
585
|
-
} else {
|
|
586
|
-
topic = `${node.nodeName}/${device}`;
|
|
587
|
-
}
|
|
588
|
-
} else {
|
|
589
|
-
if (readNodeName !== '' &&
|
|
590
|
-
readNodeName !== null &&
|
|
591
|
-
readNodeName !== undefined
|
|
592
|
-
) {
|
|
593
|
-
topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}`;
|
|
594
|
-
} else {
|
|
595
|
-
topic = `BITPOOL_BACNET_GATEWAY/${device}`;
|
|
596
|
-
}
|
|
597
|
-
}
|
|
639
|
+
let topic = getTopicString("sendSimpleWithStatusJson", useDeviceName, readNodeName, device);
|
|
598
640
|
|
|
599
641
|
msgg.topic = topic;
|
|
600
642
|
msgg.payload = structuredObject;
|
|
@@ -605,7 +647,7 @@ module.exports = function (RED) {
|
|
|
605
647
|
});
|
|
606
648
|
}
|
|
607
649
|
|
|
608
|
-
sendSimpleMqtt = function (values, readNodeName) {
|
|
650
|
+
sendSimpleMqtt = function (values, readNodeName, useDeviceName) {
|
|
609
651
|
let devices = Object.keys(values);
|
|
610
652
|
devices.forEach(function (device) {
|
|
611
653
|
if (device !== "_msgid") {
|
|
@@ -617,31 +659,9 @@ module.exports = function (RED) {
|
|
|
617
659
|
pointProps.forEach(function (prop) {
|
|
618
660
|
let msg = {};
|
|
619
661
|
if (prop == "presentValue") {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
node.nodeName !== "null" &&
|
|
624
|
-
node.nodeName !== "undefined" &&
|
|
625
|
-
typeof node.nodeName == "string"
|
|
626
|
-
) {
|
|
627
|
-
if (readNodeName !== '' &&
|
|
628
|
-
readNodeName !== null &&
|
|
629
|
-
readNodeName !== undefined
|
|
630
|
-
) {
|
|
631
|
-
msg.topic = `${node.nodeName}/${readNodeName}/${device}/${pointName}`;
|
|
632
|
-
} else {
|
|
633
|
-
msg.topic = `${node.nodeName}/${device}/${pointName}`;
|
|
634
|
-
}
|
|
635
|
-
} else {
|
|
636
|
-
if (readNodeName !== '' &&
|
|
637
|
-
readNodeName !== null &&
|
|
638
|
-
readNodeName !== undefined
|
|
639
|
-
) {
|
|
640
|
-
msg.topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}/${pointName}`;
|
|
641
|
-
} else {
|
|
642
|
-
msg.topic = `BITPOOL_BACNET_GATEWAY/${device}/${pointName}`;
|
|
643
|
-
}
|
|
644
|
-
}
|
|
662
|
+
let topic = getTopicString("sendSimpleMqtt", useDeviceName, readNodeName, device, pointName);
|
|
663
|
+
|
|
664
|
+
msg.topic = topic;
|
|
645
665
|
msg.payload = points[point][prop];
|
|
646
666
|
node.send(msg);
|
|
647
667
|
}
|
|
@@ -653,7 +673,7 @@ module.exports = function (RED) {
|
|
|
653
673
|
};
|
|
654
674
|
|
|
655
675
|
// Breaks down response JSON object into mqtt topic / payload
|
|
656
|
-
sendAsMqtt = function (values, readNodeName) {
|
|
676
|
+
sendAsMqtt = function (values, readNodeName, useDeviceName) {
|
|
657
677
|
let devices = Object.keys(values);
|
|
658
678
|
devices.forEach(function (device) {
|
|
659
679
|
if (device !== "_msgid") {
|
|
@@ -665,31 +685,8 @@ module.exports = function (RED) {
|
|
|
665
685
|
pointProps.forEach(function (prop) {
|
|
666
686
|
let msg = {};
|
|
667
687
|
if (prop !== "objectName") {
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
node.nodeName !== "" &&
|
|
671
|
-
node.nodeName !== "null" &&
|
|
672
|
-
node.nodeName !== "undefined" &&
|
|
673
|
-
typeof node.nodeName == "string"
|
|
674
|
-
) {
|
|
675
|
-
if (readNodeName !== '' &&
|
|
676
|
-
readNodeName !== null &&
|
|
677
|
-
readNodeName !== undefined
|
|
678
|
-
) {
|
|
679
|
-
msg.topic = `${node.nodeName}/${readNodeName}/${device}/${pointName}/${prop}`;
|
|
680
|
-
} else {
|
|
681
|
-
msg.topic = `${node.nodeName}/${device}/${pointName}/${prop}`;
|
|
682
|
-
}
|
|
683
|
-
} else {
|
|
684
|
-
if (readNodeName !== '' &&
|
|
685
|
-
readNodeName !== null &&
|
|
686
|
-
readNodeName !== undefined
|
|
687
|
-
) {
|
|
688
|
-
msg.topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}/${pointName}/${prop}`;
|
|
689
|
-
} else {
|
|
690
|
-
msg.topic = `BITPOOL_BACNET_GATEWAY/${device}/${pointName}/${prop}`;
|
|
691
|
-
}
|
|
692
|
-
}
|
|
688
|
+
let topic = getTopicString("sendAsMqtt", useDeviceName, readNodeName, device, pointName, prop);
|
|
689
|
+
msg.topic = topic;
|
|
693
690
|
msg.payload = points[point][prop];
|
|
694
691
|
node.send(msg);
|
|
695
692
|
}
|
|
@@ -700,7 +697,7 @@ module.exports = function (RED) {
|
|
|
700
697
|
});
|
|
701
698
|
};
|
|
702
699
|
|
|
703
|
-
sendSimpleJson = function (values, readNodeName) {
|
|
700
|
+
sendSimpleJson = function (values, readNodeName, useDeviceName) {
|
|
704
701
|
let devices = Object.keys(values);
|
|
705
702
|
devices.forEach(function (device) {
|
|
706
703
|
let msgg = {};
|
|
@@ -722,81 +719,36 @@ module.exports = function (RED) {
|
|
|
722
719
|
});
|
|
723
720
|
}
|
|
724
721
|
}
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
node.nodeName !== "" &&
|
|
728
|
-
node.nodeName !== "null" &&
|
|
729
|
-
node.nodeName !== "undefined" &&
|
|
730
|
-
typeof node.nodeName == "string"
|
|
731
|
-
) {
|
|
732
|
-
if (readNodeName !== '' &&
|
|
733
|
-
readNodeName !== null &&
|
|
734
|
-
readNodeName !== undefined
|
|
735
|
-
) {
|
|
736
|
-
msgg.topic = `${node.nodeName}/${readNodeName}/${device}`;
|
|
737
|
-
} else {
|
|
738
|
-
msgg.topic = `${node.nodeName}/${device}`;
|
|
739
|
-
}
|
|
740
|
-
} else {
|
|
741
|
-
if (readNodeName !== '' &&
|
|
742
|
-
readNodeName !== null &&
|
|
743
|
-
readNodeName !== undefined
|
|
744
|
-
) {
|
|
745
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}`;
|
|
746
|
-
} else {
|
|
747
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${device}`;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
722
|
+
let topic = getTopicString("sendSimpleJson", useDeviceName, readNodeName, device);
|
|
723
|
+
msgg.topic = topic;
|
|
750
724
|
msgg.payload = value[device];
|
|
751
725
|
node.send(msgg);
|
|
752
726
|
}
|
|
753
727
|
});
|
|
754
728
|
};
|
|
755
729
|
|
|
756
|
-
sendJsonAsMqtt = function (values, readNodeName) {
|
|
730
|
+
sendJsonAsMqtt = function (values, readNodeName, useDeviceName) {
|
|
757
731
|
if (typeof values == "object") {
|
|
758
732
|
let keys = Object.keys(values);
|
|
759
733
|
keys.forEach(function (key) {
|
|
760
734
|
let points = values[key];
|
|
761
735
|
let msgg = {};
|
|
762
736
|
let structuredObject = {};
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
node.nodeName !== "undefined" &&
|
|
768
|
-
typeof node.nodeName == "string"
|
|
769
|
-
) {
|
|
770
|
-
if (readNodeName !== '' &&
|
|
771
|
-
readNodeName !== null &&
|
|
772
|
-
readNodeName !== undefined
|
|
773
|
-
) {
|
|
774
|
-
msgg.topic = `${node.nodeName}/${readNodeName}/${key}`;
|
|
775
|
-
} else {
|
|
776
|
-
msgg.topic = `${node.nodeName}/${key}`;
|
|
777
|
-
}
|
|
778
|
-
} else {
|
|
779
|
-
if (readNodeName !== '' &&
|
|
780
|
-
readNodeName !== null &&
|
|
781
|
-
readNodeName !== undefined
|
|
782
|
-
) {
|
|
783
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${key}`;
|
|
784
|
-
} else {
|
|
785
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${key}`;
|
|
786
|
-
}
|
|
787
|
-
}
|
|
737
|
+
|
|
738
|
+
let topic = getTopicString("sendJsonAsMqtt", useDeviceName, readNodeName, key);
|
|
739
|
+
msgg.topic = topic;
|
|
740
|
+
|
|
788
741
|
for (let point in points) {
|
|
789
742
|
let pointName = getPointName(points[point], point);
|
|
790
743
|
structuredObject[pointName] = points[point];
|
|
791
744
|
}
|
|
792
|
-
|
|
793
745
|
msgg.payload = structuredObject;
|
|
794
746
|
node.send(msgg);
|
|
795
747
|
});
|
|
796
748
|
}
|
|
797
749
|
};
|
|
798
750
|
|
|
799
|
-
sendIndividualMsgJson = function (values, readNodeName) {
|
|
751
|
+
sendIndividualMsgJson = function (values, readNodeName, useDeviceName) {
|
|
800
752
|
if (typeof values == "object") {
|
|
801
753
|
let keys = Object.keys(values);
|
|
802
754
|
keys.forEach(function (key) {
|
|
@@ -804,31 +756,8 @@ module.exports = function (RED) {
|
|
|
804
756
|
let msgg = {};
|
|
805
757
|
for (let point in points) {
|
|
806
758
|
let pointName = getPointName(points[point], point);
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
node.nodeName !== "" &&
|
|
810
|
-
node.nodeName !== "null" &&
|
|
811
|
-
node.nodeName !== "undefined" &&
|
|
812
|
-
typeof node.nodeName == "string"
|
|
813
|
-
) {
|
|
814
|
-
if (readNodeName !== '' &&
|
|
815
|
-
readNodeName !== null &&
|
|
816
|
-
readNodeName !== undefined
|
|
817
|
-
) {
|
|
818
|
-
msgg.topic = `${node.nodeName}/${readNodeName}/${key}/${pointName}`;
|
|
819
|
-
} else {
|
|
820
|
-
msgg.topic = `${node.nodeName}/${key}/${pointName}`;
|
|
821
|
-
}
|
|
822
|
-
} else {
|
|
823
|
-
if (readNodeName !== '' &&
|
|
824
|
-
readNodeName !== null &&
|
|
825
|
-
readNodeName !== undefined
|
|
826
|
-
) {
|
|
827
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${key}/${pointName}`;
|
|
828
|
-
} else {
|
|
829
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${key}/${pointName}`;
|
|
830
|
-
}
|
|
831
|
-
}
|
|
759
|
+
let topic = getTopicString("sendIndividualMsgJson", useDeviceName, readNodeName, key, pointName);
|
|
760
|
+
msgg.topic = topic;
|
|
832
761
|
|
|
833
762
|
msgg.payload = points[point];
|
|
834
763
|
node.send(msgg);
|
|
@@ -838,7 +767,7 @@ module.exports = function (RED) {
|
|
|
838
767
|
}
|
|
839
768
|
}
|
|
840
769
|
|
|
841
|
-
sendSimpleJsonPerPoint = function (values, readNodeName) {
|
|
770
|
+
sendSimpleJsonPerPoint = function (values, readNodeName, useDeviceName) {
|
|
842
771
|
let devices = Object.keys(values);
|
|
843
772
|
devices.forEach(function (device) {
|
|
844
773
|
if (device !== "_msgid") {
|
|
@@ -847,31 +776,9 @@ module.exports = function (RED) {
|
|
|
847
776
|
for (let point in points) {
|
|
848
777
|
if (points[point] && "presentValue" in points[point]) {
|
|
849
778
|
let pointName = getPointName(points[point], point);
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
node.nodeName !== "null" &&
|
|
854
|
-
node.nodeName !== "undefined" &&
|
|
855
|
-
typeof node.nodeName == "string"
|
|
856
|
-
) {
|
|
857
|
-
if (readNodeName !== '' &&
|
|
858
|
-
readNodeName !== null &&
|
|
859
|
-
readNodeName !== undefined
|
|
860
|
-
) {
|
|
861
|
-
msgg.topic = `${node.nodeName}/${readNodeName}/${device}/${pointName}`;
|
|
862
|
-
} else {
|
|
863
|
-
msgg.topic = `${node.nodeName}/${device}/${pointName}`;
|
|
864
|
-
}
|
|
865
|
-
} else {
|
|
866
|
-
if (readNodeName !== '' &&
|
|
867
|
-
readNodeName !== null &&
|
|
868
|
-
readNodeName !== undefined
|
|
869
|
-
) {
|
|
870
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${readNodeName}/${device}/${pointName}`;
|
|
871
|
-
} else {
|
|
872
|
-
msgg.topic = `BITPOOL_BACNET_GATEWAY/${device}/${pointName}`;
|
|
873
|
-
}
|
|
874
|
-
}
|
|
779
|
+
let topic = getTopicString("sendSimpleJsonPerPoint", useDeviceName, readNodeName, device, pointName);
|
|
780
|
+
|
|
781
|
+
msgg.topic = topic;
|
|
875
782
|
let payload = {
|
|
876
783
|
presentValue: points[point]["presentValue"]
|
|
877
784
|
};
|
package/bacnet_read.html
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
object_property_simplePayload: { value: false },
|
|
23
23
|
object_property_simpleWithStatus: { value: false },
|
|
24
24
|
object_property_fullObject: { value: true },
|
|
25
|
+
useDeviceName: { value: true },
|
|
25
26
|
},
|
|
26
27
|
inputs: 1,
|
|
27
28
|
outputs: 1,
|
|
@@ -838,6 +839,9 @@
|
|
|
838
839
|
|
|
839
840
|
app.$forceUpdate();
|
|
840
841
|
},
|
|
842
|
+
refreshReadListTree() {
|
|
843
|
+
this.addToReadDevices(this.pointsToRead);
|
|
844
|
+
},
|
|
841
845
|
calculateMstpCount(slotProps) {
|
|
842
846
|
let count = 0;
|
|
843
847
|
slotProps.node.children.forEach(function (child) {
|
|
@@ -894,6 +898,8 @@
|
|
|
894
898
|
document.getElementById("node-input-pointJson").checked = node.pointJson;
|
|
895
899
|
document.getElementById("node-input-pointJson").onclick = handleMsgTypeClick;
|
|
896
900
|
|
|
901
|
+
document.getElementById("node-input-useDeviceName").checked = node.useDeviceName;
|
|
902
|
+
|
|
897
903
|
var menu = document.querySelector(".context-menu");
|
|
898
904
|
window.addEventListener("click", (event) => {
|
|
899
905
|
menu.style.display = "none";
|
|
@@ -1218,8 +1224,11 @@
|
|
|
1218
1224
|
<input type="file" id="readlist-file-upload" accept="application/JSON" class="inputStyle" style="display: none;" />
|
|
1219
1225
|
|
|
1220
1226
|
<button @click="removeAllDevices()" class="removeAllDevicesButton" title="Remove all devices">
|
|
1221
|
-
<
|
|
1222
|
-
|
|
1227
|
+
<a style="color: #ff0000;">Remove All Devices</a>
|
|
1228
|
+
</button>
|
|
1229
|
+
|
|
1230
|
+
<button @click="refreshReadListTree()" class="refreshReadListButton" title="Refresh tree">
|
|
1231
|
+
<i class="pi pi-refresh" style="color: #00AEEF;"> </i>
|
|
1223
1232
|
</button>
|
|
1224
1233
|
</div>
|
|
1225
1234
|
|
|
@@ -1349,6 +1358,22 @@
|
|
|
1349
1358
|
</div>
|
|
1350
1359
|
</div>
|
|
1351
1360
|
|
|
1361
|
+
<hr />
|
|
1362
|
+
|
|
1363
|
+
<div class="objectPropertiesLabel" style="margin-top: 20px; margin-bottom: 20px;">
|
|
1364
|
+
<label
|
|
1365
|
+
for="node-input-useDeviceName"
|
|
1366
|
+
style="width: auto; align-items: start;"
|
|
1367
|
+
class="objectPropertiesLabel">
|
|
1368
|
+
<i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.useDeviceName"></span>
|
|
1369
|
+
<input
|
|
1370
|
+
class=" objectProp"
|
|
1371
|
+
type="checkbox"
|
|
1372
|
+
id="node-input-useDeviceName" />
|
|
1373
|
+
<a style="white-space: nowrap; padding-left: 20px;">Use device name in topic</a>
|
|
1374
|
+
</label>
|
|
1375
|
+
</div>
|
|
1376
|
+
|
|
1352
1377
|
<div class="form-row">
|
|
1353
1378
|
<label for="node-input-roundDecimal"> Decimal place precision </label>
|
|
1354
1379
|
<input type="number" id="node-input-roundDecimal" placeholder="None" />
|
package/bacnet_read.js
CHANGED
|
@@ -26,7 +26,7 @@ module.exports = function (RED) {
|
|
|
26
26
|
this.object_property_simpleWithStatus = config.object_property_simpleWithStatus;
|
|
27
27
|
this.object_property_fullObject = config.object_property_fullObject;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
this.useDeviceName = config.useDeviceName;
|
|
30
30
|
|
|
31
31
|
this.object_props = getObjectProps(this);
|
|
32
32
|
|
|
@@ -63,6 +63,7 @@ module.exports = function (RED) {
|
|
|
63
63
|
let jsonType = false;
|
|
64
64
|
let mqttType = false;
|
|
65
65
|
let pointJsonType = false;
|
|
66
|
+
let useDeviceName = false;
|
|
66
67
|
|
|
67
68
|
if (msg.simplePayload) {
|
|
68
69
|
object_property_simplePayload = msg.simplePayload;
|
|
@@ -88,6 +89,12 @@ module.exports = function (RED) {
|
|
|
88
89
|
pointJsonType = node.pointJson
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
if (msg.useDeviceName) {
|
|
93
|
+
useDeviceName = msg.useDeviceName;
|
|
94
|
+
} else {
|
|
95
|
+
useDeviceName = node.useDeviceName;
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
let readConfig = new ReadCommandConfig(node.pointsToRead, node.object_props, node.roundDecimal);
|
|
92
99
|
|
|
93
100
|
let output = {
|
|
@@ -103,7 +110,8 @@ module.exports = function (RED) {
|
|
|
103
110
|
outputType: {
|
|
104
111
|
json: jsonType,
|
|
105
112
|
mqtt: mqttType,
|
|
106
|
-
pointJson: pointJsonType
|
|
113
|
+
pointJson: pointJsonType,
|
|
114
|
+
useDeviceName: useDeviceName
|
|
107
115
|
}
|
|
108
116
|
};
|
|
109
117
|
|
package/bacnet_server.js
CHANGED
|
@@ -6,12 +6,12 @@ const { EventEmitter } = require("events");
|
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Class representing a BACnet Server.
|
|
9
|
-
*
|
|
9
|
+
*
|
|
10
10
|
* This class initializes a BACnet server with specified client, device ID, and Node-Red version.
|
|
11
11
|
* It provides methods to set device name, add objects, retrieve objects, clear server points, clear server point, and get server points.
|
|
12
|
-
*
|
|
12
|
+
*
|
|
13
13
|
* Simulates a BACnet IP device on a regular IP network
|
|
14
|
-
*
|
|
14
|
+
*
|
|
15
15
|
* @constructor
|
|
16
16
|
* @param {Object} client - The BACnet client object.
|
|
17
17
|
* @param {number} deviceId - The ID of the device.
|
|
@@ -248,7 +248,7 @@ class BacnetServer extends EventEmitter {
|
|
|
248
248
|
|
|
249
249
|
/**
|
|
250
250
|
* Set the name of the device.
|
|
251
|
-
*
|
|
251
|
+
*
|
|
252
252
|
* @param {string} nodeName - The new name for the device.
|
|
253
253
|
*/
|
|
254
254
|
setDeviceName(nodeName) {
|
|
@@ -259,116 +259,85 @@ class BacnetServer extends EventEmitter {
|
|
|
259
259
|
}
|
|
260
260
|
|
|
261
261
|
/**
|
|
262
|
-
* Adds a new object to the BacnetServer's object store based on the provided name and
|
|
263
|
-
*
|
|
262
|
+
* Adds a new object to the BacnetServer's object store based on the provided name and payload.
|
|
263
|
+
*
|
|
264
264
|
* @param {string} name - The name of the object to be added.
|
|
265
|
-
* @param {number|boolean|string}
|
|
265
|
+
* @param {number|boolean|string|object} payload - The payload of the object to be added.
|
|
266
266
|
* @returns {void}
|
|
267
267
|
*/
|
|
268
|
-
addObject(name,
|
|
268
|
+
addObject(name, payload) {
|
|
269
269
|
let that = this;
|
|
270
|
-
let objectType = that.getBacnetObjectType(value);
|
|
270
|
+
let objectType = that.getBacnetObjectType(payload.value ?? payload);
|
|
271
271
|
if (name && objectType) {
|
|
272
272
|
let instanceNumber;
|
|
273
273
|
if (name.includes('|')) {
|
|
274
274
|
// split name, assign last part to instanceNumber and the rest to name
|
|
275
275
|
let nameParts = name.split('|');
|
|
276
|
-
instanceNumber = nameParts
|
|
277
|
-
nameParts.pop();
|
|
276
|
+
instanceNumber = nameParts.pop();
|
|
278
277
|
name = nameParts.join('|');
|
|
279
278
|
}
|
|
280
|
-
let formattedName = name.replaceAll('.', '_');
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
[baEnum.PropertyIdentifier.STATUS_FLAGS]: [{ value: 0, type: 8 }],
|
|
293
|
-
[baEnum.PropertyIdentifier.EVENT_STATE]: [{ value: 0, type: 9 }],
|
|
294
|
-
[baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{ value: 0, type: 9 }],
|
|
295
|
-
[baEnum.PropertyIdentifier.UNITS]: [{ value: 95, type: 9 }],
|
|
296
|
-
[baEnum.PropertyIdentifier.PRIORITY_ARRAY]: [{ value: 0, type: 9 }],
|
|
297
|
-
[baEnum.PropertyIdentifier.MAX_PRES_VALUE]: [{ value: value, type: 4 }],
|
|
298
|
-
[baEnum.PropertyIdentifier.MIN_PRES_VALUE]: [{ value: value, type: 4 }],
|
|
299
|
-
[baEnum.PropertyIdentifier.RESOLUTION]: [{ value: 0, type: 4 }],
|
|
300
|
-
[baEnum.PropertyIdentifier.PROPERTY_LIST]:
|
|
301
|
-
[
|
|
302
|
-
{ value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
|
|
303
|
-
{ value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
|
|
304
|
-
{ value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
|
|
305
|
-
{ value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
|
|
306
|
-
{ value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 },
|
|
307
|
-
{ value: baEnum.PropertyIdentifier.STATUS_FLAGS, type: 9 },
|
|
308
|
-
{ value: baEnum.PropertyIdentifier.EVENT_STATE, type: 9 },
|
|
309
|
-
{ value: baEnum.PropertyIdentifier.OUT_OF_SERVICE, type: 9 },
|
|
310
|
-
{ value: baEnum.PropertyIdentifier.UNITS, type: 9 },
|
|
311
|
-
{ value: baEnum.PropertyIdentifier.PRIORITY_ARRAY, type: 9 },
|
|
312
|
-
{ value: baEnum.PropertyIdentifier.MAX_PRES_VALUE, type: 9 },
|
|
313
|
-
{ value: baEnum.PropertyIdentifier.MIN_PRES_VALUE, type: 9 },
|
|
314
|
-
{ value: baEnum.PropertyIdentifier.RESOLUTION, type: 9 },
|
|
315
|
-
],
|
|
316
|
-
});
|
|
317
|
-
|
|
318
|
-
that.objectList.push({ value: { type: baEnum.ObjectType.ANALOG_VALUE, instance: objectId }, type: 12 })
|
|
319
|
-
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
320
|
-
} else if (foundIndex !== -1) {
|
|
321
|
-
let foundObject = that.objectStore[baEnum.ObjectType.ANALOG_VALUE][foundIndex];
|
|
322
|
-
foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
|
|
323
|
-
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
324
|
-
}
|
|
325
|
-
} else if (objectType == "boolean") {
|
|
326
|
-
let foundIndex = that.objectStore[baEnum.ObjectType.BINARY_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
|
|
327
|
-
if (foundIndex == -1) {
|
|
328
|
-
let objectId = that.getObjectIdentifier(baEnum.ObjectType.BINARY_VALUE);
|
|
329
|
-
that.objectStore[baEnum.ObjectType.BINARY_VALUE].push({
|
|
330
|
-
[baEnum.PropertyIdentifier.OBJECT_NAME]: [{ value: formattedName, type: 7 }],
|
|
331
|
-
[baEnum.PropertyIdentifier.OBJECT_TYPE]: [{ value: baEnum.ObjectType.BINARY_VALUE, type: 9 }],
|
|
332
|
-
[baEnum.PropertyIdentifier.DESCRIPTION]: [{ value: '', type: 7 }],
|
|
333
|
-
[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{ value: { type: baEnum.ObjectType.BINARY_VALUE, instance: objectId }, type: 12 }],
|
|
334
|
-
[baEnum.PropertyIdentifier.PRESENT_VALUE]: [{ value: value, type: 1 }],
|
|
335
|
-
[baEnum.PropertyIdentifier.STATUS_FLAGS]: [{ value: 0, type: 8 }],
|
|
336
|
-
[baEnum.PropertyIdentifier.EVENT_STATE]: [{ value: 0, type: 9 }],
|
|
337
|
-
[baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{ value: 0, type: 9 }],
|
|
338
|
-
[baEnum.PropertyIdentifier.ACTIVE_TEXT]: [{ value: 'ACTIVE', type: 7 }],
|
|
339
|
-
[baEnum.PropertyIdentifier.INACTIVE_TEXT]: [{ value: 'INACTIVE', type: 7 }],
|
|
340
|
-
});
|
|
279
|
+
let formattedName = name.replaceAll('.', '_').replaceAll('/', '_');
|
|
280
|
+
|
|
281
|
+
const getCommonProperties = (type, valueType) => ({
|
|
282
|
+
[baEnum.PropertyIdentifier.OBJECT_NAME]: [{ value: formattedName, type: 7 }],
|
|
283
|
+
[baEnum.PropertyIdentifier.OBJECT_TYPE]: [{ value: type, type: 9 }],
|
|
284
|
+
[baEnum.PropertyIdentifier.DESCRIPTION]: [{ value: payload.description ?? '', type: 7 }],
|
|
285
|
+
[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER]: [{ value: { type: type, instance: that.getObjectIdentifier(type, instanceNumber) }, type: 12 }],
|
|
286
|
+
[baEnum.PropertyIdentifier.PRESENT_VALUE]: [{ value: payload.value ?? payload, type: valueType }],
|
|
287
|
+
[baEnum.PropertyIdentifier.STATUS_FLAGS]: [{ value: payload.statusFlags ?? 0, type: 8 }],
|
|
288
|
+
[baEnum.PropertyIdentifier.EVENT_STATE]: [{ value: payload.eventState ?? 0, type: 9 }],
|
|
289
|
+
[baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{ value: payload.outOfService ?? 0, type: 9 }],
|
|
290
|
+
});
|
|
341
291
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
} else if (foundIndex !== -1) {
|
|
345
|
-
let foundObject = that.objectStore[baEnum.ObjectType.BINARY_VALUE][foundIndex];
|
|
346
|
-
foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
|
|
347
|
-
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
348
|
-
}
|
|
349
|
-
} else if (objectType == "string") {
|
|
350
|
-
let foundIndex = that.objectStore[baEnum.ObjectType.CHARACTERSTRING_VALUE].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
|
|
292
|
+
const addObjectToStore = (type, valueType, extraProperties = {}) => {
|
|
293
|
+
let foundIndex = that.objectStore[type].findIndex(ele => ele[baEnum.PropertyIdentifier.OBJECT_NAME][0].value == formattedName);
|
|
351
294
|
if (foundIndex == -1) {
|
|
352
|
-
let
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
[baEnum.PropertyIdentifier.PRESENT_VALUE]: [{ value: value, type: 7 }],
|
|
359
|
-
[baEnum.PropertyIdentifier.STATUS_FLAGS]: [{ value: 0, type: 8 }],
|
|
360
|
-
[baEnum.PropertyIdentifier.EVENT_STATE]: [{ value: 0, type: 9 }],
|
|
361
|
-
[baEnum.PropertyIdentifier.OUT_OF_SERVICE]: [{ value: 0, type: 9 }],
|
|
362
|
-
[baEnum.PropertyIdentifier.UNITS]: [{ value: 95, type: 9 }]
|
|
363
|
-
});
|
|
364
|
-
|
|
365
|
-
that.objectList.push({ value: { type: baEnum.ObjectType.CHARACTERSTRING_VALUE, instance: objectId }, type: 12 })
|
|
295
|
+
let newObject = {
|
|
296
|
+
...getCommonProperties(type, valueType),
|
|
297
|
+
...extraProperties
|
|
298
|
+
};
|
|
299
|
+
that.objectStore[type].push(newObject);
|
|
300
|
+
that.objectList.push({ value: { type: type, instance: newObject[baEnum.PropertyIdentifier.OBJECT_IDENTIFIER][0].value.instance }, type: 12 });
|
|
366
301
|
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
367
|
-
} else
|
|
368
|
-
let foundObject = that.objectStore[
|
|
369
|
-
foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = value;
|
|
302
|
+
} else {
|
|
303
|
+
let foundObject = that.objectStore[type][foundIndex];
|
|
304
|
+
foundObject[baEnum.PropertyIdentifier.PRESENT_VALUE][0].value = payload.value ?? payload;
|
|
370
305
|
that.objectStore[baEnum.ObjectType.DEVICE][baEnum.PropertyIdentifier.OBJECT_LIST] = that.objectList;
|
|
371
306
|
}
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
if (objectType === "number") {
|
|
310
|
+
addObjectToStore(baEnum.ObjectType.ANALOG_VALUE, 4, {
|
|
311
|
+
[baEnum.PropertyIdentifier.UNITS]: [{ value: payload.units ?? 95, type: 9 }],
|
|
312
|
+
[baEnum.PropertyIdentifier.MAX_PRES_VALUE]: [{ value: payload.value ?? payload, type: 4 }],
|
|
313
|
+
[baEnum.PropertyIdentifier.MIN_PRES_VALUE]: [{ value: payload.value ?? payload, type: 4 }],
|
|
314
|
+
[baEnum.PropertyIdentifier.RESOLUTION]: [{ value: payload.resolution ?? 0, type: 4 }],
|
|
315
|
+
[baEnum.PropertyIdentifier.PRIORITY_ARRAY]: [{ value: payload.priorityArray ?? 0, type: 9 }],
|
|
316
|
+
[baEnum.PropertyIdentifier.PROPERTY_LIST]: [
|
|
317
|
+
{ value: baEnum.PropertyIdentifier.OBJECT_NAME, type: 9 },
|
|
318
|
+
{ value: baEnum.PropertyIdentifier.OBJECT_TYPE, type: 9 },
|
|
319
|
+
{ value: baEnum.PropertyIdentifier.DESCRIPTION, type: 9 },
|
|
320
|
+
{ value: baEnum.PropertyIdentifier.OBJECT_IDENTIFIER, type: 9 },
|
|
321
|
+
{ value: baEnum.PropertyIdentifier.PRESENT_VALUE, type: 9 },
|
|
322
|
+
{ value: baEnum.PropertyIdentifier.STATUS_FLAGS, type: 9 },
|
|
323
|
+
{ value: baEnum.PropertyIdentifier.EVENT_STATE, type: 9 },
|
|
324
|
+
{ value: baEnum.PropertyIdentifier.OUT_OF_SERVICE, type: 9 },
|
|
325
|
+
{ value: baEnum.PropertyIdentifier.UNITS, type: 9 },
|
|
326
|
+
{ value: baEnum.PropertyIdentifier.PRIORITY_ARRAY, type: 9 },
|
|
327
|
+
{ value: baEnum.PropertyIdentifier.MAX_PRES_VALUE, type: 9 },
|
|
328
|
+
{ value: baEnum.PropertyIdentifier.MIN_PRES_VALUE, type: 9 },
|
|
329
|
+
{ value: baEnum.PropertyIdentifier.RESOLUTION, type: 9 },
|
|
330
|
+
]
|
|
331
|
+
});
|
|
332
|
+
} else if (objectType === "boolean") {
|
|
333
|
+
addObjectToStore(baEnum.ObjectType.BINARY_VALUE, 1, {
|
|
334
|
+
[baEnum.PropertyIdentifier.ACTIVE_TEXT]: [{ value: 'ACTIVE', type: 7 }],
|
|
335
|
+
[baEnum.PropertyIdentifier.INACTIVE_TEXT]: [{ value: 'INACTIVE', type: 7 }]
|
|
336
|
+
});
|
|
337
|
+
} else if (objectType === "string") {
|
|
338
|
+
addObjectToStore(baEnum.ObjectType.CHARACTERSTRING_VALUE, 7, {
|
|
339
|
+
[baEnum.PropertyIdentifier.UNITS]: [{ value: payload.units ?? 95, type: 9 }]
|
|
340
|
+
});
|
|
372
341
|
}
|
|
373
342
|
}
|
|
374
343
|
Store_Config_Server(JSON.stringify({ objectList: that.objectList, objectStore: that.objectStore }));
|
|
@@ -376,7 +345,7 @@ class BacnetServer extends EventEmitter {
|
|
|
376
345
|
|
|
377
346
|
/**
|
|
378
347
|
* Retrieves a specific property of an object based on the object ID, property ID, and instance number.
|
|
379
|
-
*
|
|
348
|
+
*
|
|
380
349
|
* @param {number} objectId - The ID of the object type.
|
|
381
350
|
* @param {number} propId - The ID of the property to retrieve.
|
|
382
351
|
* @param {number} instance - The instance number of the object.
|
|
@@ -405,7 +374,7 @@ class BacnetServer extends EventEmitter {
|
|
|
405
374
|
|
|
406
375
|
/**
|
|
407
376
|
* Retrieves a specific property of an object based on the object ID, property ID, and instance number and modify his value.
|
|
408
|
-
*
|
|
377
|
+
*
|
|
409
378
|
* @param {number} objectId - The ID of the object type.
|
|
410
379
|
* @param {number} propId - The ID of the property to retrieve.
|
|
411
380
|
* @param {number} instance - The instance number of the object.
|
|
@@ -436,7 +405,7 @@ class BacnetServer extends EventEmitter {
|
|
|
436
405
|
|
|
437
406
|
/**
|
|
438
407
|
* Retrieves the properties of a specific object instance from the objectStore based on the provided parameters.
|
|
439
|
-
*
|
|
408
|
+
*
|
|
440
409
|
* @param {number} objectId - The type of the object to retrieve.
|
|
441
410
|
* @param {number} propId - The property identifier to retrieve.
|
|
442
411
|
* @param {number} instance - The instance number of the object to retrieve.
|
|
@@ -534,7 +503,7 @@ class BacnetServer extends EventEmitter {
|
|
|
534
503
|
|
|
535
504
|
/**
|
|
536
505
|
* Removes a server point from the objectStore and objectList based on the provided JSON data.
|
|
537
|
-
*
|
|
506
|
+
*
|
|
538
507
|
* @param {Object} json - The JSON data containing information about the server point to be removed.
|
|
539
508
|
* @param {string} json.body.type - The type of the server point ('SV' for CharacterString, 'BV' for BinaryValue, default is AnalogValue).
|
|
540
509
|
* @param {number} json.body.instance - The instance number of the server point to be removed.
|
|
@@ -597,7 +566,7 @@ class BacnetServer extends EventEmitter {
|
|
|
597
566
|
* - name: The name of the object.
|
|
598
567
|
* - type: The type of the object (AV for Analog Value, SV for Character String Value, BV for Binary Value).
|
|
599
568
|
* - instance: The instance number of the object.
|
|
600
|
-
*
|
|
569
|
+
*
|
|
601
570
|
* @returns {Promise<Array>} A promise that resolves with an array of points sorted by instance number.
|
|
602
571
|
* @throws {Error} If an error occurs during the retrieval process.
|
|
603
572
|
*/
|
|
@@ -688,7 +657,7 @@ class BacnetServer extends EventEmitter {
|
|
|
688
657
|
|
|
689
658
|
/**
|
|
690
659
|
* Determines the BACnet object type based on the provided value.
|
|
691
|
-
*
|
|
660
|
+
*
|
|
692
661
|
* @param {any} value - The value to determine the BACnet object type for.
|
|
693
662
|
* @returns {string|null} The BACnet object type as a string ('string', 'number', 'boolean') or null if the type is not recognized.
|
|
694
663
|
*/
|
|
@@ -702,6 +671,8 @@ class BacnetServer extends EventEmitter {
|
|
|
702
671
|
return "number"
|
|
703
672
|
case "boolean":
|
|
704
673
|
return "boolean"
|
|
674
|
+
case "object":
|
|
675
|
+
return "object"
|
|
705
676
|
default:
|
|
706
677
|
return null
|
|
707
678
|
}
|
|
@@ -709,7 +680,7 @@ class BacnetServer extends EventEmitter {
|
|
|
709
680
|
|
|
710
681
|
/**
|
|
711
682
|
* Returns the object identifier for the given type and instance number.
|
|
712
|
-
*
|
|
683
|
+
*
|
|
713
684
|
* @param {string} type - The type of the object.
|
|
714
685
|
* @param {number} instanceNumber - The instance number of the object.
|
|
715
686
|
* @returns {number} The object identifier.
|
|
@@ -728,4 +699,4 @@ class BacnetServer extends EventEmitter {
|
|
|
728
699
|
}
|
|
729
700
|
}
|
|
730
701
|
|
|
731
|
-
module.exports = { BacnetServer };
|
|
702
|
+
module.exports = { BacnetServer };
|
package/bitpool_inject.html
CHANGED
|
@@ -142,6 +142,26 @@
|
|
|
142
142
|
</div>
|
|
143
143
|
</div>
|
|
144
144
|
|
|
145
|
+
|
|
146
|
+
<div class="injectHeading" style="margin-top: 20px;">
|
|
147
|
+
<a>Topic Properties</a>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<div class="objectPropertiesLabel" style="margin-top: 20px;">
|
|
151
|
+
<label
|
|
152
|
+
for="node-input-useDeviceName"
|
|
153
|
+
style="padding-left: 4px; width: auto; align-items: start;"
|
|
154
|
+
class="objectPropertiesLabel">
|
|
155
|
+
<i class="icon-tag"></i> <span data-i18n="bitpool-bacnet.label.useDeviceName"></span>
|
|
156
|
+
<input
|
|
157
|
+
style="margin-left: 5px;"
|
|
158
|
+
class=" objectProp"
|
|
159
|
+
type="checkbox"
|
|
160
|
+
id="node-input-useDeviceName" />
|
|
161
|
+
<a style="white-space: nowrap; padding-left: 20px;">Use device name in topic</a>
|
|
162
|
+
</label>
|
|
163
|
+
</div>
|
|
164
|
+
|
|
145
165
|
<div class="injectHeading" style="margin-top: 20px;">
|
|
146
166
|
<a>Msg Properties</a>
|
|
147
167
|
</div>
|
|
@@ -476,6 +496,7 @@
|
|
|
476
496
|
object_property_simplePayload: { value: false },
|
|
477
497
|
object_property_simpleWithStatus: { value: false },
|
|
478
498
|
object_property_fullObject: { value: true },
|
|
499
|
+
useDeviceName: { value: true },
|
|
479
500
|
},
|
|
480
501
|
icon: "bitpool.svg",
|
|
481
502
|
inputs: 0,
|
|
@@ -779,6 +800,8 @@
|
|
|
779
800
|
document.getElementById("node-input-object_property_fullObject").checked = node.object_property_fullObject;
|
|
780
801
|
document.getElementById("node-input-object_property_fullObject").onclick = handlePayloadCheckboxClick;
|
|
781
802
|
|
|
803
|
+
document.getElementById("node-input-useDeviceName").checked = node.useDeviceName;
|
|
804
|
+
|
|
782
805
|
|
|
783
806
|
document.getElementById("node-input-doDiscover").onclick = handleCheckboxClick;
|
|
784
807
|
document.getElementById("node-input-doPoll").onclick = handleCheckboxClick;
|
package/bitpool_inject.js
CHANGED
|
@@ -60,6 +60,9 @@ module.exports = function (RED) {
|
|
|
60
60
|
this.object_property_simplePayload = n.object_property_simplePayload;
|
|
61
61
|
this.object_property_simpleWithStatus = n.object_property_simpleWithStatus;
|
|
62
62
|
this.object_property_fullObject = n.object_property_fullObject;
|
|
63
|
+
|
|
64
|
+
this.useDeviceName = n.useDeviceName;
|
|
65
|
+
|
|
63
66
|
this.json = n.json;
|
|
64
67
|
this.mqtt = n.mqtt;
|
|
65
68
|
this.pointJson = n.pointJson;
|
|
@@ -121,6 +124,8 @@ module.exports = function (RED) {
|
|
|
121
124
|
msg.mqtt = node.mqtt;
|
|
122
125
|
msg.pointJson = node.pointJson;
|
|
123
126
|
|
|
127
|
+
msg.useDeviceName = node.useDeviceName;
|
|
128
|
+
|
|
124
129
|
|
|
125
130
|
var errors = [];
|
|
126
131
|
var props = this.props;
|
package/package.json
CHANGED
package/resources/style.css
CHANGED
|
@@ -15,6 +15,16 @@
|
|
|
15
15
|
|
|
16
16
|
/* Read node styles */
|
|
17
17
|
|
|
18
|
+
.refreshReadListButton {
|
|
19
|
+
border: none;
|
|
20
|
+
border-radius: 40px;
|
|
21
|
+
height: 35px;
|
|
22
|
+
width: 35px;
|
|
23
|
+
& i {
|
|
24
|
+
color: #6c757d !important;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
.p-treenode-label {
|
|
19
29
|
color: black;
|
|
20
30
|
width: 100%;
|
|
@@ -150,6 +160,8 @@
|
|
|
150
160
|
float: right;
|
|
151
161
|
display: flex;
|
|
152
162
|
align-items: center;
|
|
163
|
+
padding: 5px;
|
|
164
|
+
font-weight: bold;
|
|
153
165
|
}
|
|
154
166
|
.removeAllDevicesButton:hover {
|
|
155
167
|
background-color: #d5d5d5;
|
|
@@ -247,7 +259,6 @@
|
|
|
247
259
|
z-index: 10;
|
|
248
260
|
}
|
|
249
261
|
|
|
250
|
-
|
|
251
262
|
.context-menu {
|
|
252
263
|
--mouse-x: 0;
|
|
253
264
|
--mouse-y: 0;
|