node-red-contrib-knx-ultimate 1.3.38 → 1.3.41
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 -1
- package/KNXEngine/KNXClient.js +66 -24
- package/KNXEngine/util/ipAddressHelper.js +9 -4
- package/img/wiki/etslogo.png +0 -0
- package/nodes/knxUltimate-config.html +7 -12
- package/nodes/knxUltimate-config.js +45 -45
- package/nodes/knxUltimate.js +1 -1
- package/nodes/knxUltimateAlerter.html +3 -2
- package/nodes/knxUltimateGlobalContext.js +1 -1
- package/nodes/knxUltimateSceneController.js +1 -1
- package/nodes/knxUltimateWatchDog.js +2 -2
- package/nodes/locales/de/knxUltimate-config.json +2 -2
- package/nodes/locales/de/knxUltimateAlerter.json +2 -1
- package/nodes/locales/en-US/knxUltimate-config.json +2 -2
- package/nodes/locales/en-US/knxUltimateAlerter.json +2 -1
- package/nodes/locales/it/knxUltimate-config.json +2 -2
- package/nodes/locales/it/knxUltimateAlerter.json +2 -1
- package/nodes/locales/zh-CN/knxUltimate-config.json +2 -2
- package/nodes/locales/zh-CN/knxUltimateAlerter.json +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,27 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
<p>
|
|
10
|
+
<b>Version 1.3.41</b> - Mai 2022<br/>
|
|
11
|
+
- Fixed an issue in the gateway config node UI, where you manually set the IP interface name.<br />
|
|
12
|
+
- Fixed an issue introduced by a breaking change in Node 18.<br />
|
|
13
|
+
- Added more "trace" log in the ipAddressHelper function, to better track the ethernet interface details.<br />
|
|
14
|
+
</p>
|
|
15
|
+
<p>
|
|
16
|
+
<b>Version 1.3.40</b> - Mai 2022<br/>
|
|
17
|
+
- Fixed an issue in the GlobalContext node, preventing the node from searching for the DPT, if the CSV ETS file has been imported and you don't specify the DPT in the msg input. Thanks to @Sebastien-Posca for pointing me out that.<br />
|
|
18
|
+
</p>
|
|
19
|
+
<p>
|
|
20
|
+
<b>Version 1.3.39</b> - April 2022<br/>
|
|
21
|
+
- Fixed an empty text in the KNX Alerter config node, about the Read States at start.<br/>
|
|
22
|
+
- Fixed an improperly cleaned queue in the config node close function.<br/>
|
|
23
|
+
- Fixed a possible issue in case of multiple disconnection from the KNX Bus in a short timeframe.<br/>
|
|
24
|
+
- Fixed sending disconnection_request with a null connection_ID, in the KNX Engine.<br/>
|
|
25
|
+
- Fixed re-sending per KNX Standards, of not ACKnowledged telegrams, not always working in some circumstances.<br/>
|
|
26
|
+
- Protected some function with a try-catch.<br/>
|
|
27
|
+
- Now the telegram handler function stops whenever the connection is lost and restart from fresh on connection.<br />
|
|
28
|
+
- Optimized the retain mechanism of the queue handling, in case of shorttimed disconnections.<br />
|
|
29
|
+
</p>
|
|
9
30
|
<p>
|
|
10
31
|
<b>Version 1.3.38</b> - April 2022<br/>
|
|
11
32
|
- Memory footprint decreased.<br/>
|
|
@@ -13,7 +34,7 @@
|
|
|
13
34
|
</p>
|
|
14
35
|
<p>
|
|
15
36
|
<b>Version 1.3.37</b> - April 2022<br/>
|
|
16
|
-
- Changed: the KNX Gateway don't care anymore for ROUTING_LOST_MESSAGE and ROUTING_BUSY. Previously, it was disconnecting. Now it only advises in LOG.<br/>
|
|
37
|
+
- Changed: the KNX Gateway Node don't care anymore for ROUTING_LOST_MESSAGE and ROUTING_BUSY. Previously, it was disconnecting. Now it only advises in LOG.<br/>
|
|
17
38
|
- Updated and beautifullyfied the WIKI.<br/>
|
|
18
39
|
- Totally rewrote the CIRCULAR REFERENCE PROTECTION and FLOOD PROTECTION wiki page, in all languages.<br/>
|
|
19
40
|
</p>
|
package/KNXEngine/KNXClient.js
CHANGED
|
@@ -51,6 +51,7 @@ var KNXClientEvents;
|
|
|
51
51
|
KNXClientEvents["ready"] = "ready";
|
|
52
52
|
KNXClientEvents["response"] = "response";
|
|
53
53
|
KNXClientEvents["connecting"] = "connecting";
|
|
54
|
+
KNXClientEvents["ackReceived"] = "ackReceived";
|
|
54
55
|
})(KNXClientEvents || (KNXClientEvents = {}));
|
|
55
56
|
|
|
56
57
|
// const KNXClientEvents = {
|
|
@@ -349,7 +350,8 @@ class KNXClient extends EventEmitter {
|
|
|
349
350
|
} else {
|
|
350
351
|
// Tunneling
|
|
351
352
|
const cEMIMessage = CEMIFactory.CEMIFactory.newLDataRequestMessage("write", srcAddress, dstAddress, data);
|
|
352
|
-
cEMIMessage.control.ack = this._options.suppress_ack_ldatareq ? 0 : 1;
|
|
353
|
+
//cEMIMessage.control.ack = this._options.suppress_ack_ldatareq ? 0 : 1; // No ack like telegram sent from ETS (0 means don't care)
|
|
354
|
+
cEMIMessage.control.ack = 0;// No ack like telegram sent from ETS (0 means don't care)
|
|
353
355
|
cEMIMessage.control.broadcast = 1;
|
|
354
356
|
cEMIMessage.control.priority = 3;
|
|
355
357
|
cEMIMessage.control.addressType = 1;
|
|
@@ -382,7 +384,7 @@ class KNXClient extends EventEmitter {
|
|
|
382
384
|
if (this._options.hostProtocol === "Multicast") {
|
|
383
385
|
// Multicast
|
|
384
386
|
const cEMIMessage = CEMIFactory.CEMIFactory.newLDataIndicationMessage("response", srcAddress, dstAddress, data);
|
|
385
|
-
cEMIMessage.control.ack = 0;
|
|
387
|
+
cEMIMessage.control.ack = 0; // No ack like telegram sent from ETS (0 means don't care)
|
|
386
388
|
cEMIMessage.control.broadcast = 1;
|
|
387
389
|
cEMIMessage.control.priority = 3;
|
|
388
390
|
cEMIMessage.control.addressType = 1;
|
|
@@ -394,7 +396,8 @@ class KNXClient extends EventEmitter {
|
|
|
394
396
|
} else {
|
|
395
397
|
// Tunneling
|
|
396
398
|
const cEMIMessage = CEMIFactory.CEMIFactory.newLDataRequestMessage("response", srcAddress, dstAddress, data);
|
|
397
|
-
cEMIMessage.control.ack = this._options.suppress_ack_ldatareq ? 0 : 1;
|
|
399
|
+
//cEMIMessage.control.ack = this._options.suppress_ack_ldatareq ? 0 : 1;
|
|
400
|
+
cEMIMessage.control.ack = 0;// No ack like telegram sent from ETS (0 means don't care)
|
|
398
401
|
cEMIMessage.control.broadcast = 1;
|
|
399
402
|
cEMIMessage.control.priority = 3;
|
|
400
403
|
cEMIMessage.control.addressType = 1;
|
|
@@ -435,7 +438,8 @@ class KNXClient extends EventEmitter {
|
|
|
435
438
|
} else {
|
|
436
439
|
// Tunneling
|
|
437
440
|
const cEMIMessage = CEMIFactory.CEMIFactory.newLDataRequestMessage("read", srcAddress, dstAddress, null);
|
|
438
|
-
|
|
441
|
+
//cEMIMessage.control.ack = this._options.suppress_ack_ldatareq ? 0 : 1;
|
|
442
|
+
cEMIMessage.control.ack = 0;// No ack like telegram sent from ETS (0 means don't care)
|
|
439
443
|
cEMIMessage.control.broadcast = 1;
|
|
440
444
|
cEMIMessage.control.priority = 3;
|
|
441
445
|
cEMIMessage.control.addressType = 1;
|
|
@@ -594,7 +598,10 @@ class KNXClient extends EventEmitter {
|
|
|
594
598
|
}, 1000 * KNXConstants.KNX_CONSTANTS.CONNECT_REQUEST_TIMEOUT);
|
|
595
599
|
this._awaitingResponseType = KNXConstants.KNX_CONSTANTS.CONNECT_RESPONSE;
|
|
596
600
|
this._clientTunnelSeqNumber = -1;
|
|
597
|
-
|
|
601
|
+
try {
|
|
602
|
+
this._sendConnectRequestMessage(new TunnelCRI.TunnelCRI(knxLayer));
|
|
603
|
+
} catch (error) { }
|
|
604
|
+
|
|
598
605
|
|
|
599
606
|
} else if (this._options.hostProtocol === "TunnelTCP") {
|
|
600
607
|
|
|
@@ -655,16 +662,26 @@ class KNXClient extends EventEmitter {
|
|
|
655
662
|
}
|
|
656
663
|
}, 1000 * KNXConstants.KNX_CONSTANTS.CONNECTIONSTATE_REQUEST_TIMEOUT);
|
|
657
664
|
this._awaitingResponseType = KNXConstants.KNX_CONSTANTS.CONNECTIONSTATE_RESPONSE;
|
|
658
|
-
|
|
665
|
+
try {
|
|
666
|
+
this._sendConnectionStateRequestMessage(this._channelID);
|
|
667
|
+
} catch (error) { }
|
|
659
668
|
}
|
|
660
669
|
Disconnect() {
|
|
661
|
-
if (this._clientSocket
|
|
670
|
+
if (this._clientSocket === null) {
|
|
662
671
|
throw new Error('No client socket defined');
|
|
663
672
|
}
|
|
673
|
+
// 20/04/2022 this._channelID === null can happen when the KNX Gateway is already disconnected
|
|
674
|
+
if (this._channelID === null) {
|
|
675
|
+
throw new Error('KNX Socket is already disconnected');
|
|
676
|
+
}
|
|
664
677
|
this.stopHeartBeat();
|
|
665
678
|
this._connectionState = STATE.DISCONNECTING;
|
|
666
679
|
this._awaitingResponseType = KNXConstants.KNX_CONSTANTS.DISCONNECT_RESPONSE;
|
|
667
|
-
|
|
680
|
+
try {
|
|
681
|
+
this._sendDisconnectRequestMessage(this._channelID);
|
|
682
|
+
} catch (error) {
|
|
683
|
+
}
|
|
684
|
+
|
|
668
685
|
// 12/03/2021 Set disconnected if not already set by DISCONNECT_RESPONSE sent from the IP Interface
|
|
669
686
|
let t = setTimeout(() => { // 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
|
|
670
687
|
if (this._connectionState !== STATE.DISCONNECTED) this._setDisconnected("Forced call from KNXClient Disconnect() function, because the KNX Interface hasn't sent the DISCONNECT_RESPONSE in time.");
|
|
@@ -732,20 +749,27 @@ class KNXClient extends EventEmitter {
|
|
|
732
749
|
this._numFailedTelegramACK += 1;
|
|
733
750
|
if (this._numFailedTelegramACK > 2) {
|
|
734
751
|
this._numFailedTelegramACK = 0;
|
|
752
|
+
// 08/04/2022 Emits the event informing that the last ACK has not been acknowledge.
|
|
753
|
+
try {
|
|
754
|
+
this.emit(KNXClientEvents.ackReceived, knxTunnelingRequest, false);
|
|
755
|
+
} catch (error) {
|
|
756
|
+
}
|
|
735
757
|
this._clearToSend = true;
|
|
736
758
|
this.emit(KNXClientEvents.error, timeoutErr);
|
|
759
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.error("KNXClient: _setTimerWaitingForACK: " + (timeoutErr.message || "Undef error") + " no ACK received. ABORT sending datagram with seqNumber " + this._getSeqNumber() + " from " + knxTunnelingRequest.cEMIMessage.srcAddress.toString() + " to " + knxTunnelingRequest.cEMIMessage.dstAddress.toString());
|
|
737
760
|
} else {
|
|
738
761
|
// 26/12/2021 // If no ACK received, resend the datagram once with the same sequence number
|
|
739
762
|
this._setTimerWaitingForACK(knxTunnelingRequest);
|
|
740
763
|
this.send(knxTunnelingRequest);
|
|
741
|
-
if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.error("KNXClient: _setTimerWaitingForACK: " + (timeoutErr.message || "Undef error") + " no ACK received. Retransmit datagram with seqNumber " + this._getSeqNumber());
|
|
764
|
+
if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.error("KNXClient: _setTimerWaitingForACK: " + (timeoutErr.message || "Undef error") + " no ACK received. Retransmit datagram with seqNumber " + this._getSeqNumber() + " from " + knxTunnelingRequest.cEMIMessage.srcAddress.toString() + " to " + knxTunnelingRequest.cEMIMessage.dstAddress.toString());
|
|
742
765
|
}
|
|
743
766
|
} catch (error) { }
|
|
744
767
|
}, KNXConstants.KNX_CONSTANTS.TUNNELING_REQUEST_TIMEOUT * 1000);
|
|
745
768
|
|
|
746
769
|
}
|
|
770
|
+
|
|
747
771
|
_processInboundMessage(msg, rinfo) {
|
|
748
|
-
|
|
772
|
+
|
|
749
773
|
try {
|
|
750
774
|
// Composing debug string
|
|
751
775
|
try {
|
|
@@ -769,14 +793,14 @@ class KNXClient extends EventEmitter {
|
|
|
769
793
|
try {
|
|
770
794
|
this.emit(KNXClientEvents.error, new Error('ROUTING_LOST_MESSAGE'));
|
|
771
795
|
//this._setDisconnected("Routing Lost Message"); // 31/03/2022 Commented, because it doesn't matter. Non need to disconnect.
|
|
772
|
-
return;
|
|
773
796
|
} catch (error) { }
|
|
797
|
+
return;
|
|
774
798
|
} else if (knxHeader.service_type === KNXConstants.KNX_CONSTANTS.ROUTING_BUSY) {
|
|
775
799
|
try {
|
|
776
800
|
this.emit(KNXClientEvents.error, new Error('ROUTING_BUSY'));
|
|
777
801
|
//this._setDisconnected("Routing Busy"); // 31/03/2022 Commented, because it doesn't matter. Non need to disconnect.
|
|
778
|
-
return;
|
|
779
802
|
} catch (error) { }
|
|
803
|
+
return;
|
|
780
804
|
}
|
|
781
805
|
|
|
782
806
|
if (knxHeader.service_type === KNXConstants.KNX_CONSTANTS.SEARCH_RESPONSE) {
|
|
@@ -846,7 +870,10 @@ class KNXClient extends EventEmitter {
|
|
|
846
870
|
} catch (error) { }
|
|
847
871
|
|
|
848
872
|
this._connectionState = STATE.DISCONNECTING;
|
|
849
|
-
|
|
873
|
+
try {
|
|
874
|
+
this._sendDisconnectResponseMessage(knxDisconnectRequest.channelID);
|
|
875
|
+
} catch (error) { }
|
|
876
|
+
|
|
850
877
|
// 12/03/2021 Added 1 sec delay.
|
|
851
878
|
let t = setTimeout(() => { // 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
|
|
852
879
|
this._setDisconnected("Received KNX packet: DISCONNECT_REQUEST, ChannelID:" + this._channelID + " Host:" + this._options.ipAddr + ":" + this._options.ipPort);
|
|
@@ -856,8 +883,25 @@ class KNXClient extends EventEmitter {
|
|
|
856
883
|
|
|
857
884
|
const knxTunnelingRequest = knxMessage;
|
|
858
885
|
if (knxTunnelingRequest.channelID !== this._channelID) {
|
|
886
|
+
try {
|
|
887
|
+
this.sysLogger.debug("Received KNX packet: TUNNELING: L_DATA_IND, NOT FOR ME: MyChannelID:" + this._channelID + " ReceivedPacketChannelID: " + knxTunnelingRequest.channelID + " ReceivedPacketseqCounter:" + knxTunnelingRequest.seqCounter + " Host:" + this._options.ipAddr + ":" + this._options.ipPort);
|
|
888
|
+
} catch (error) { }
|
|
859
889
|
return;
|
|
860
890
|
}
|
|
891
|
+
// 26/12/2021 send the ACK if the server requestet that
|
|
892
|
+
// Then REMOVED, because some interfaces sets the "ack request" always to 0 even if it needs ack.
|
|
893
|
+
//if (knxMessage.cEMIMessage.control.ack){
|
|
894
|
+
//setTimeout(() => {
|
|
895
|
+
try {
|
|
896
|
+
let knxTunnelAck = KNXProtocol.KNXProtocol.newKNXTunnelingACK(knxTunnelingRequest.channelID, knxTunnelingRequest.seqCounter, KNXConstants.KNX_CONSTANTS.E_NO_ERROR);
|
|
897
|
+
this.send(knxTunnelAck);
|
|
898
|
+
} catch (error) {
|
|
899
|
+
this.sysLogger.error("Received KNX packet: TUNNELING: L_DATA_IND, ERROR BUOLDING THE TUNNELINK ACK: " + error.message + " MyChannelID:" + this._channelID + " ReceivedPacketChannelID: " + knxTunnelingRequest.channelID + " ReceivedPacketseqCounter:" + knxTunnelingRequest.seqCounter + " Host:" + this._options.ipAddr + ":" + this._options.ipPort);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
//}, 20);
|
|
903
|
+
|
|
904
|
+
//}
|
|
861
905
|
|
|
862
906
|
if (knxTunnelingRequest.cEMIMessage.msgCode === CEMIConstants.CEMIConstants.L_DATA_IND) {
|
|
863
907
|
|
|
@@ -886,15 +930,8 @@ class KNXClient extends EventEmitter {
|
|
|
886
930
|
|
|
887
931
|
}
|
|
888
932
|
|
|
889
|
-
// 26/12/2021 send the ACK if the server requestet that
|
|
890
|
-
// Then REMOVED, because some interfaces sets the "ack request" always to 0 even if it needs ack.
|
|
891
|
-
//if (knxMessage.cEMIMessage.control.ack){
|
|
892
|
-
const knxTunnelAck = KNXProtocol.KNXProtocol.newKNXTunnelingACK(knxTunnelingRequest.channelID, knxTunnelingRequest.seqCounter, KNXConstants.KNX_CONSTANTS.E_NO_ERROR);
|
|
893
|
-
this.send(knxTunnelAck);
|
|
894
|
-
//}
|
|
895
|
-
|
|
896
933
|
} else if (knxHeader.service_type === KNXConstants.KNX_CONSTANTS.TUNNELING_ACK) {
|
|
897
|
-
|
|
934
|
+
|
|
898
935
|
const knxTunnelingAck = knxMessage;
|
|
899
936
|
if (knxTunnelingAck.channelID !== this._channelID) {
|
|
900
937
|
return;
|
|
@@ -906,10 +943,16 @@ class KNXClient extends EventEmitter {
|
|
|
906
943
|
|
|
907
944
|
// Check the received ACK sequence number
|
|
908
945
|
if (!this._options.suppress_ack_ldatareq) {
|
|
946
|
+
|
|
909
947
|
if (knxTunnelingAck.seqCounter === this._getSeqNumber()) {
|
|
910
948
|
if (this._timerWaitingForACK !== null) clearTimeout(this._timerWaitingForACK);
|
|
911
949
|
this._numFailedTelegramACK = 0; // 25/12/2021 clear the current ACK failed telegram number
|
|
912
950
|
this._clearToSend = true; // I'm ready to send a new datagram now
|
|
951
|
+
// 08/04/2022 Emits the event informing that the last ACK has been acknowledge.
|
|
952
|
+
try {
|
|
953
|
+
this.emit(KNXClientEvents.ackReceived, knxMessage, true);
|
|
954
|
+
} catch (error) {
|
|
955
|
+
}
|
|
913
956
|
try {
|
|
914
957
|
if (this.sysLogger !== undefined && this.sysLogger !== null) this.sysLogger.debug("Received KNX packet: TUNNELING: DELETED_TUNNELING_ACK FROM PENDING ACK's, ChannelID:" + this._channelID + " seqCounter:" + knxTunnelingAck.seqCounter + " Host:" + this._options.ipAddr + ":" + this._options.ipPort);
|
|
915
958
|
} catch (error) { }
|
|
@@ -945,6 +988,8 @@ class KNXClient extends EventEmitter {
|
|
|
945
988
|
this.emit(KNXClientEvents.indication, knxRoutingInd, false);
|
|
946
989
|
} catch (error) {
|
|
947
990
|
}
|
|
991
|
+
|
|
992
|
+
|
|
948
993
|
}
|
|
949
994
|
else if (knxRoutingInd.cEMIMessage.msgCode === CEMIConstants.CEMIConstants.L_DATA_CON) {
|
|
950
995
|
|
|
@@ -954,9 +999,6 @@ class KNXClient extends EventEmitter {
|
|
|
954
999
|
|
|
955
1000
|
}
|
|
956
1001
|
|
|
957
|
-
} else if (knxHeader.service_type === KNXConstants.KNX_CONSTANTS.ROUTING_LOST_MESSAGE) {
|
|
958
|
-
// Multicast, ho perso il mondo dei messaggi
|
|
959
|
-
|
|
960
1002
|
} else {
|
|
961
1003
|
if (knxHeader.service_type === this._awaitingResponseType) {
|
|
962
1004
|
if (this._awaitingResponseType === KNXConstants.KNX_CONSTANTS.CONNECTIONSTATE_RESPONSE) {
|
|
@@ -3,16 +3,20 @@ const knxLog = require('../KnxLog');
|
|
|
3
3
|
const os = require('os');
|
|
4
4
|
|
|
5
5
|
//#region "GET LOCAL INTERFACE PROPERTIES"
|
|
6
|
-
|
|
6
|
+
function getIPv4Interfaces () {
|
|
7
7
|
// get the local address of the IPv4 interface we're going to use
|
|
8
8
|
let candidateInterfaces = {}
|
|
9
9
|
let interfaces = os.networkInterfaces()
|
|
10
10
|
for (let iface in interfaces) {
|
|
11
11
|
for (let key in interfaces[iface]) {
|
|
12
12
|
let intf = interfaces[iface][key]
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
// 11/05/2022 Fixed a breaking change introduced by node 18 (https://nodejs.org/api/os.html#osnetworkinterfaces)
|
|
14
|
+
// In Node < 18, intf.family is a string "IPv4" or "IPv6", from node 18, is an integer, for example 4.
|
|
15
|
+
if (intf.family.toString().includes("4") && !intf.internal) {
|
|
16
|
+
knxLog.get().trace('ipAddressHelper.js: Found suitable interface: %s (%j)', iface, intf);
|
|
15
17
|
candidateInterfaces[iface] = intf
|
|
18
|
+
} else {
|
|
19
|
+
knxLog.get().trace('ipAddressHelper.js: Found NOT suitable interface: %s (%j)', iface, intf);
|
|
16
20
|
}
|
|
17
21
|
}
|
|
18
22
|
}
|
|
@@ -21,7 +25,8 @@ const getIPv4Interfaces = function () {
|
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
exports.getLocalAddress = function (_interface = "") {
|
|
24
|
-
|
|
28
|
+
knxLog.get().trace("ipAddressHelper.js: getLocalAddress: getting interfaces");
|
|
29
|
+
let candidateInterfaces = getIPv4Interfaces();
|
|
25
30
|
// if user has declared a desired interface then use it
|
|
26
31
|
if (_interface !== "") {
|
|
27
32
|
if (!candidateInterfaces.hasOwnProperty(_interface)) {
|
|
Binary file
|
|
@@ -278,6 +278,10 @@
|
|
|
278
278
|
</label>
|
|
279
279
|
<select id="node-config-input-KNXEthInterface"></select>
|
|
280
280
|
</div>
|
|
281
|
+
<div class="form-row" id="divKNXEthInterfaceManuallyInput" style="display: none;">
|
|
282
|
+
<label for="node-config-input-KNXEthInterfaceManuallyInput">Interface name:</label>
|
|
283
|
+
<input type="text" id="node-config-input-KNXEthInterfaceManuallyInput" placeholder="Interface name, ex: eth0 or ens1 or Ethernet 1 and so on..."></input>
|
|
284
|
+
</div>
|
|
281
285
|
<div class="form-row">
|
|
282
286
|
<label for="node-config-input-autoReconnect" style="width: 200px">
|
|
283
287
|
<i class="fa fa-plug"></i>
|
|
@@ -288,10 +292,7 @@
|
|
|
288
292
|
<option value="no" data-i18n="knxUltimate-config.properties.autoReconnect_no"></option>
|
|
289
293
|
</select>
|
|
290
294
|
</div>
|
|
291
|
-
|
|
292
|
-
<label for="node-config-input-KNXEthInterfaceManuallyInput"></label>
|
|
293
|
-
<input type="text" id="node-config-input-KNXEthInterfaceManuallyInput" placeholder="Interface name, ex: eth0 or ens1 or Ethernet 1 and so on..."></input>
|
|
294
|
-
</div>
|
|
295
|
+
|
|
295
296
|
<div id="advancedOptionsAccordion">
|
|
296
297
|
<h3><span data-i18n="knxUltimate-config.properties.adv_options"></span></h3>
|
|
297
298
|
<div>
|
|
@@ -392,16 +393,10 @@
|
|
|
392
393
|
<span data-i18n="knxUltimate-config.ets.description"></span>
|
|
393
394
|
</div>
|
|
394
395
|
<div class="form-row">
|
|
395
|
-
<
|
|
396
|
-
<a href="https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/1.-Gateway-configuration" target="_blank">
|
|
397
|
-
<span data-i18n="knxUltimate-config.ets.instruction"></span>
|
|
398
|
-
</a>
|
|
396
|
+
<span style="color:red" data-i18n="[html]knxUltimate-config.ets.instruction"></span>
|
|
399
397
|
</div>
|
|
400
398
|
<div class="form-row">
|
|
401
|
-
<
|
|
402
|
-
<a href="https://youtu.be/egRbR_KwP9I" target="_blank">
|
|
403
|
-
<span data-i18n="knxUltimate-config.ets.youtube"></span>
|
|
404
|
-
</a>
|
|
399
|
+
<span style="color:red" data-i18n="[html]knxUltimate-config.ets.youtube"></span>
|
|
405
400
|
</div>
|
|
406
401
|
<div class="form-row">
|
|
407
402
|
<label style="width:auto" for="node-config-input-stopETSImportIfNoDatapoint">
|
|
@@ -130,8 +130,8 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
130
130
|
node.statusDisplayDeviceNameWhenALL = typeof config.statusDisplayDeviceNameWhenALL === "undefined" ? false : config.statusDisplayDeviceNameWhenALL;
|
|
131
131
|
node.statusDisplayDataPoint = typeof config.statusDisplayDataPoint === "undefined" ? false : config.statusDisplayDataPoint;
|
|
132
132
|
node.telegramsQueue = []; // 02/01/2020 Queue containing telegrams
|
|
133
|
-
node.timerSendTelegramFromQueue;
|
|
134
|
-
node.delaybetweentelegramsfurtherdelayREAD = (typeof config.delaybetweentelegramsfurtherdelayREAD === "undefined" || config.delaybetweentelegramsfurtherdelayREAD < 1) ? 1 : config.delaybetweentelegramsfurtherdelayREAD; // 18/05/2020 delay multiplicator only for "read" telegrams.
|
|
133
|
+
node.timerSendTelegramFromQueue = null;
|
|
134
|
+
node.delaybetweentelegramsfurtherdelayREAD = (typeof config.delaybetweentelegramsfurtherdelayREAD === "undefined" || Number(config.delaybetweentelegramsfurtherdelayREAD < 1)) ? 1 : Number(config.delaybetweentelegramsfurtherdelayREAD); // 18/05/2020 delay multiplicator only for "read" telegrams.
|
|
135
135
|
node.delaybetweentelegramsREADCount = 0;// 18/05/2020 delay multiplicator only for "read" telegrams.
|
|
136
136
|
node.timerDoInitialRead = null; // 17/02/2020 Timer (timeout) to do initial read of all nodes requesting initial read, after all nodes have been registered to the sercer
|
|
137
137
|
node.stopETSImportIfNoDatapoint = typeof config.stopETSImportIfNoDatapoint === "undefined" ? "stop" : config.stopETSImportIfNoDatapoint; // 09/01/2020 Stop, Import Fake or Skip the import if a group address has unset datapoint
|
|
@@ -431,6 +431,7 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
431
431
|
|
|
432
432
|
// 16/02/2020 KNX-Ultimate nodes calls this function, then this funcion calls the same function on the Watchdog
|
|
433
433
|
node.reportToWatchdogCalledByKNXUltimateNode = (_oError) => {
|
|
434
|
+
// _oError is = { nodeid: node.id, topic: node.outputtopic, devicename: devicename, GA: GA, text: text };
|
|
434
435
|
var readHistory = [];
|
|
435
436
|
let delay = 0;
|
|
436
437
|
node.nodeClients
|
|
@@ -441,18 +442,6 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
441
442
|
})
|
|
442
443
|
}
|
|
443
444
|
|
|
444
|
-
node.Disconnect = () => {
|
|
445
|
-
if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead); // 17/02/2020 Stop the initial read timer
|
|
446
|
-
try {
|
|
447
|
-
if (node.knxConnection !== null) node.knxConnection.Disconnect();
|
|
448
|
-
} catch (error) { }
|
|
449
|
-
|
|
450
|
-
node.startTimerClearTelegramQueue(); // 21/01/2022 Clear the telegram queue after a while
|
|
451
|
-
node.setAllClientsStatus("Disconnected", "grey", "")
|
|
452
|
-
node.linkStatus = "disconnected"; // 29/08/2019 signal disconnection
|
|
453
|
-
|
|
454
|
-
saveExposedGAs(); // 04/04/2021 save the current values of GA payload
|
|
455
|
-
}
|
|
456
445
|
|
|
457
446
|
// node.addClient = (_Node) => {
|
|
458
447
|
// // Check if node already exists
|
|
@@ -790,14 +779,11 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
790
779
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("knxUltimate-config: received KNXClientEvents.error: " + (err.message === undefined ? err : err.message));
|
|
791
780
|
} catch (error) { }
|
|
792
781
|
// 31/03/2022 Don't care about some errors
|
|
793
|
-
if (err.message !== undefined && err.message === "ROUTING_LOST_MESSAGE") {
|
|
794
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.
|
|
782
|
+
if (err.message !== undefined && (err.message === "ROUTING_LOST_MESSAGE" || err.message === "ROUTING_BUSY")) {
|
|
783
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("knxUltimate-config: KNXClientEvents.error: " + (err.message === undefined ? err : err.message) + " consider DECREASING the transmission speed, by increasing the telegram's DELAY in the gateway configuration node!");
|
|
795
784
|
return;
|
|
796
785
|
}
|
|
797
|
-
|
|
798
|
-
node.startTimerClearTelegramQueue(); // 21/01/2022 Clear the telegram queue after a while
|
|
799
|
-
node.linkStatus = "disconnected";
|
|
800
|
-
node.setAllClientsStatus("Disconnected by error " + (err.message === undefined ? err : err.message), "red", "");
|
|
786
|
+
node.Disconnect("Disconnected by error " + (err.message === undefined ? err : err.message), "red");
|
|
801
787
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("knxUltimate-config: Disconnected by: " + (err.message === undefined ? err : err.message));
|
|
802
788
|
});
|
|
803
789
|
// Call discoverCB when a knx gateway has been discovered.
|
|
@@ -806,13 +792,11 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
806
792
|
// discoverCB(ip, port);
|
|
807
793
|
// });
|
|
808
794
|
node.knxConnection.on(knx.KNXClient.KNXClientEvents.disconnected, info => {
|
|
809
|
-
saveExposedGAs(); // 13/12/2021 save the current values of GA payload
|
|
810
795
|
node.startTimerClearTelegramQueue(); // 21/01/2022 Clear the telegram queue after a while
|
|
811
796
|
if (node.linkStatus !== "disconnected") {
|
|
812
797
|
node.linkStatus = "disconnected";
|
|
813
|
-
node.setAllClientsStatus("Disconnected by event: " + info || "", "red", "");
|
|
814
798
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.warn("knxUltimate-config: Disconnected event %s", info);
|
|
815
|
-
node.Disconnect(); // 11/03/2022
|
|
799
|
+
node.Disconnect("Disconnected by event: " + info || "", "red"); // 11/03/2022
|
|
816
800
|
}
|
|
817
801
|
});
|
|
818
802
|
node.knxConnection.on(knx.KNXClient.KNXClientEvents.close, info => {
|
|
@@ -823,7 +807,11 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
823
807
|
clearTimeout(node.timerClearTelegramQueue); // Connected. Stop the timer that clears the telegrams queue.
|
|
824
808
|
node.timerClearTelegramQueue = null;
|
|
825
809
|
}
|
|
810
|
+
// 12/11/2021 Starts the telegram out queue handler
|
|
811
|
+
if (node.timerSendTelegramFromQueue !== null) clearInterval(node.timerSendTelegramFromQueue);
|
|
812
|
+
node.timerSendTelegramFromQueue = setInterval(handleTelegramQueue, (config.delaybetweentelegrams === undefined || Number(config.delaybetweentelegrams) < 20) ? 20 : Number(config.delaybetweentelegrams)); // 02/01/2020 Start the timer that handles the queue of telegrams
|
|
826
813
|
node.linkStatus = "connected";
|
|
814
|
+
|
|
827
815
|
// Start the timer to do initial read.
|
|
828
816
|
if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead);
|
|
829
817
|
node.timerDoInitialRead = setTimeout(DoInitialReadFromKNXBusOrFile, 6000); // 17/02/2020 Do initial read of all nodes requesting initial read
|
|
@@ -834,8 +822,6 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
834
822
|
});
|
|
835
823
|
node.knxConnection.on(knx.KNXClient.KNXClientEvents.connecting, info => {
|
|
836
824
|
node.linkStatus = "connecting";
|
|
837
|
-
// Start the timer to do initial read.
|
|
838
|
-
if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead);
|
|
839
825
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Connecting to" + info.ipAddr || "");
|
|
840
826
|
node.setAllClientsStatus(info.ipAddr || "", "grey", "Connecting...")
|
|
841
827
|
});
|
|
@@ -1489,21 +1475,6 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
1489
1475
|
};
|
|
1490
1476
|
|
|
1491
1477
|
|
|
1492
|
-
node.on("close", function (done) {
|
|
1493
|
-
if (node.timerSendTelegramFromQueue !== undefined) clearInterval(node.timerSendTelegramFromQueue); // 02/01/2020 Stop queue timer
|
|
1494
|
-
node.lockHandleTelegramQueue = false; // Unlock the telegram handling function
|
|
1495
|
-
|
|
1496
|
-
saveExposedGAs(); // 04/04/2021 save the current values of GA payload
|
|
1497
|
-
node.nodeClients = []; // 05/04/2023 Nullify
|
|
1498
|
-
try {
|
|
1499
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.destroy();
|
|
1500
|
-
} catch (error) { }
|
|
1501
|
-
try {
|
|
1502
|
-
node.Disconnect();
|
|
1503
|
-
} catch (error) { }
|
|
1504
|
-
done();
|
|
1505
|
-
})
|
|
1506
|
-
|
|
1507
1478
|
function readCSV(_csvText) {
|
|
1508
1479
|
// 24/02/2020, in the middle of Coronavirus emergency in Italy. Check if it a CSV ETS Export of group addresses, or if it's an EFS
|
|
1509
1480
|
if (_csvText.split("\n")[0].toUpperCase().indexOf("\"") == -1) return readESF(_csvText);
|
|
@@ -1821,9 +1792,6 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
1821
1792
|
} catch (error) { }
|
|
1822
1793
|
}
|
|
1823
1794
|
|
|
1824
|
-
// 12/11/2021 Starts the telegram out queue handler
|
|
1825
|
-
if (node.timerSendTelegramFromQueue !== null) clearInterval(node.timerSendTelegramFromQueue);
|
|
1826
|
-
node.timerSendTelegramFromQueue = setInterval(handleTelegramQueue, (config.delaybetweentelegrams === undefined || config.delaybetweentelegrams < 30) ? 30 : config.delaybetweentelegrams); // 02/01/2020 Start the timer that handles the queue of telegrams
|
|
1827
1795
|
|
|
1828
1796
|
// 08/10/2021 Every xx seconds, i check if the connection is up and running
|
|
1829
1797
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.info("KNXUltimate-config: Autoconnection: " + (node.autoReconnect === false ? "no." : "yes") + " Node " + node.name);
|
|
@@ -1835,7 +1803,7 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
1835
1803
|
let t = setTimeout(() => { // 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
|
|
1836
1804
|
node.setAllClientsStatus("Auto reconnect in progress...", "grey", "");
|
|
1837
1805
|
}, 100);
|
|
1838
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Auto Reconect by timerKNXUltimateCheckState in progress. node.LinkStatus:" + node.linkStatus + ", node.autoReconnect:" + node.autoReconnect);
|
|
1806
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Auto Reconect by timerKNXUltimateCheckState in progress. node.LinkStatus: " + node.linkStatus + ", node.autoReconnect:" + node.autoReconnect);
|
|
1839
1807
|
node.initKNXConnection();
|
|
1840
1808
|
return;
|
|
1841
1809
|
}
|
|
@@ -1844,12 +1812,44 @@ return msg;`, "helplink": "https://github.com/Supergiovane/node-red-contrib-knx-
|
|
|
1844
1812
|
let t = setTimeout(() => { // 21/03/2022 fixed possible memory leak. Previously was setTimeout without "let t = ".
|
|
1845
1813
|
node.setAllClientsStatus("Next cycle will reconnect...", "grey", "");
|
|
1846
1814
|
}, 1000);
|
|
1847
|
-
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Waiting next cycle to reconect. node.LinkStatus:" + node.linkStatus + ", node.autoReconnect:" + node.autoReconnect);
|
|
1815
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Waiting next cycle to reconect. node.LinkStatus: " + node.linkStatus + ", node.autoReconnect:" + node.autoReconnect);
|
|
1848
1816
|
//node.initKNXConnection();
|
|
1849
1817
|
}
|
|
1850
1818
|
}, 10000);
|
|
1851
1819
|
|
|
1820
|
+
node.Disconnect = (_sNodeStatus = "", _sColor = "grey") => {
|
|
1821
|
+
if (node.linkStatus === "disconnected") {
|
|
1822
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Disconnect: already not connected:" + node.linkStatus + ", node.autoReconnect:" + node.autoReconnect);
|
|
1823
|
+
return;
|
|
1824
|
+
}
|
|
1825
|
+
if (node.timerSendTelegramFromQueue !== null) clearInterval(node.timerSendTelegramFromQueue); // 02/01/2020 Stop queue timer
|
|
1826
|
+
node.linkStatus = "disconnected"; // 29/08/2019 signal disconnection
|
|
1827
|
+
node.lockHandleTelegramQueue = false; // Unlock the telegram handling function
|
|
1828
|
+
if (node.timerDoInitialRead !== null) clearTimeout(node.timerDoInitialRead); // 17/02/2020 Stop the initial read timer
|
|
1829
|
+
try {
|
|
1830
|
+
if (node.knxConnection !== null) node.knxConnection.Disconnect();
|
|
1831
|
+
} catch (error) {
|
|
1832
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Disconnected: node.knxConnection.Disconnect() " + (error.message || "") + " , node.autoReconnect:" + node.autoReconnect);
|
|
1833
|
+
}
|
|
1834
|
+
node.startTimerClearTelegramQueue(); // 21/01/2022 Clear the telegram queue after a while
|
|
1835
|
+
node.setAllClientsStatus("Disconnected", _sColor, _sNodeStatus);
|
|
1836
|
+
saveExposedGAs(); // 04/04/2021 save the current values of GA payload
|
|
1837
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.debug("knxUltimate-config: Disconnected, node.autoReconnect:" + node.autoReconnect);
|
|
1838
|
+
|
|
1839
|
+
}
|
|
1852
1840
|
|
|
1841
|
+
node.on("close", function (done) {
|
|
1842
|
+
try {
|
|
1843
|
+
node.Disconnect();
|
|
1844
|
+
} catch (error) { }
|
|
1845
|
+
if (node.timerClearTelegramQueue !== null) clearTimeout(node.timerClearTelegramQueue);
|
|
1846
|
+
node.telegramsQueue = [];
|
|
1847
|
+
node.nodeClients = []; // 05/04/2023 Nullify
|
|
1848
|
+
try {
|
|
1849
|
+
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.destroy();
|
|
1850
|
+
} catch (error) { }
|
|
1851
|
+
done();
|
|
1852
|
+
})
|
|
1853
1853
|
|
|
1854
1854
|
}
|
|
1855
1855
|
|
package/nodes/knxUltimate.js
CHANGED
|
@@ -51,7 +51,7 @@ module.exports = function (RED) {
|
|
|
51
51
|
// 16/02/2020 signal errors to the server
|
|
52
52
|
if (fill.toUpperCase() === "RED") {
|
|
53
53
|
if (node.server) {
|
|
54
|
-
|
|
54
|
+
let oError = { nodeid: node.id, topic: node.outputtopic, devicename: devicename, GA: GA, text: text };
|
|
55
55
|
node.server.reportToWatchdogCalledByKNXUltimateNode(oError);
|
|
56
56
|
};
|
|
57
57
|
};
|
|
@@ -210,12 +210,13 @@
|
|
|
210
210
|
<br/>
|
|
211
211
|
<br/>
|
|
212
212
|
<dt><i class="fa fa-code-fork"></i> <span data-i18n="knxUltimateAlerter.other.sceneConfig"></dt>
|
|
213
|
+
<br/>
|
|
213
214
|
<div class="form-row" id="divNode-input-initialreadGAInRules">
|
|
214
|
-
<label style="width:
|
|
215
|
+
<label style="width:60%" for="node-input-initialreadGAInRules">
|
|
215
216
|
<i class="fa fa-question-circle-o"></i>
|
|
216
217
|
<span data-i18n="knxUltimateAlerter.properties.node-input-initialreadGAInRules"></span>
|
|
217
218
|
</label>
|
|
218
|
-
<select style="width:
|
|
219
|
+
<select style="width:30%" id="node-input-initialreadGAInRules">
|
|
219
220
|
<option value="0" data-i18n="knxUltimateAlerter.properties.node-input-initialread0"></option>
|
|
220
221
|
<option value="1" data-i18n="knxUltimateAlerter.properties.node-input-initialread1"></option>
|
|
221
222
|
</select>
|
|
@@ -92,7 +92,7 @@ module.exports = function (RED) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// 13/09/2021 retrieve the datapoint if not specified
|
|
95
|
-
if (!element.hasOwnProperty("dpt") || element.dpt
|
|
95
|
+
if (!element.hasOwnProperty("dpt") || element.dpt === undefined || element.dpt === "") {
|
|
96
96
|
try {
|
|
97
97
|
let sDPT = node.server.csv.find(item => item.ga === element.address).dpt;
|
|
98
98
|
element.dpt = sDPT;
|
|
@@ -106,7 +106,7 @@ module.exports = function (RED) {
|
|
|
106
106
|
// 16/02/2020 signal errors to the server
|
|
107
107
|
if (fill.toUpperCase() == "RED") {
|
|
108
108
|
if (node.server) {
|
|
109
|
-
|
|
109
|
+
let oError = { nodeid: node.id, topic: node.outputtopic, devicename: devicename, GA: GA, text: text };
|
|
110
110
|
node.server.reportToWatchdogCalledByKNXUltimateNode(oError);
|
|
111
111
|
};
|
|
112
112
|
};
|
|
@@ -48,7 +48,7 @@ module.exports = function (RED) {
|
|
|
48
48
|
if (node.beatNumber > node.maxRetry) {
|
|
49
49
|
// Confirmed connection error
|
|
50
50
|
node.beatNumber = 0; // Reset Counter
|
|
51
|
-
|
|
51
|
+
let msg = {
|
|
52
52
|
type: "BUSError",
|
|
53
53
|
checkPerformed: node.checkLevel,
|
|
54
54
|
nodeid: node.id,
|
|
@@ -102,7 +102,7 @@ module.exports = function (RED) {
|
|
|
102
102
|
// 16/02/2020 This function is called by the knx-ultimate config node.
|
|
103
103
|
node.signalNodeErrorCalledByConfigNode = _oError => {
|
|
104
104
|
// Report an error from knx-ultimate node.
|
|
105
|
-
//
|
|
105
|
+
// let oError = {nodeid:node.id,topic:node.outputtopic,devicename:devicename,GA:GA,text:text};
|
|
106
106
|
let msg = {
|
|
107
107
|
type: "NodeError",
|
|
108
108
|
checkPerformed: "Self KNX-Ultimate node reporting a red color status",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
"ets": {
|
|
48
48
|
"description": "Sie können entweder eine ETS CSV-Gruppenadressliste oder eine ESF-Gruppenadressliste importieren. Bitte bevorzugen Sie die Adressliste der ETS CSV-Gruppe, da die Datenpunkte vollständiger sind.",
|
|
49
|
-
"instruction": "
|
|
50
|
-
"youtube": "Anleitung des ETS CSV Exports auf Youtube",
|
|
49
|
+
"instruction" : " <i class=\"fa fa-question-circle\"></i> <a target=\"_blank\" href=\"https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/de-1.-Gateway-configuration\"><u>Erlauterung ETS import.</u></a>",
|
|
50
|
+
"youtube" : " <i class=\"fa fa-youtube-play\"></i> <a target=\"_blank\" href=\"https://youtu.be/egRbR_KwP9I\"><u>Anleitung des ETS CSV Exports auf Youtube.</u></a>",
|
|
51
51
|
"help_ga": "Wenn die Gruppenadresse keinen Datenpunkt hat...",
|
|
52
52
|
"import_select_stop": "Beenden und abbruch des Imports",
|
|
53
53
|
"import_select_fake": "Import mit einem gefälschten 1.001-Datenpunkt (nicht empfohlen)",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"node-input-whentostart": "Starttyp des Alarmierungszyklus",
|
|
11
11
|
"node-input-initialread": "Bei Verbindung/Wiederverbindung je Gerat-Wert lesen",
|
|
12
12
|
"node-input-initialread0": "Nein",
|
|
13
|
-
"node-input-initialread1": "Lesen vom KNX-BUS"
|
|
13
|
+
"node-input-initialread1": "Lesen vom KNX-BUS",
|
|
14
|
+
"node-input-initialreadGAInRules": "Bei Verbindung/Wiederverbindung je Gerat-Wert lesen"
|
|
14
15
|
},
|
|
15
16
|
"selectlists": {
|
|
16
17
|
"manualstart": "Starten den Alarmzyklus manuell über eine eingehende MSG",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
},
|
|
44
44
|
"ets": {
|
|
45
45
|
"description": "You can import either an ETS CSV group address list, or an ESF group address list. Please prefer the ETS CSV group address list, as the datapoints are more complete.",
|
|
46
|
-
"instruction": "Click for instruction on how to export ETS CSV group address list
|
|
47
|
-
"youtube": "See how to export the CSV on Youtube",
|
|
46
|
+
"instruction" : " <i class=\"fa fa-question-circle\"></i> <a target=\"_blank\" href=\"https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/1.-Gateway-configuration\"><u>Click for instruction on how to export ETS CSV group address list.</u></a>",
|
|
47
|
+
"youtube" : " <i class=\"fa fa-youtube-play\"></i> <a target=\"_blank\" href=\"https://youtu.be/egRbR_KwP9I\"><u>See how to export the CSV on Youtube.</u></a>",
|
|
48
48
|
"help_ga": "If Group Address has no Datapoint",
|
|
49
49
|
"import_select_stop": "Stop and abort import",
|
|
50
50
|
"import_select_skip": "Skip the affected group address",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"node-input-whentostart": "Alerting cycle start type",
|
|
11
11
|
"node-input-initialread": "Read value of each device on connection/reconnect",
|
|
12
12
|
"node-input-initialread0": "No",
|
|
13
|
-
"node-input-initialread1": "Read from KNX BUS"
|
|
13
|
+
"node-input-initialread1": "Read from KNX BUS",
|
|
14
|
+
"node-input-initialreadGAInRules": "Read states at start/reconnection"
|
|
14
15
|
},
|
|
15
16
|
"selectlists": {
|
|
16
17
|
"manualstart": "Start alert cycle manually via incoming message",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
},
|
|
47
47
|
"ets": {
|
|
48
48
|
"description": "Puoi importare sia il file ETS in CSV, che ESF. Usa il CSV se possibile, perchè i datapoints sono più precisi.",
|
|
49
|
-
"instruction": "Clicca per vedere come si importa un file ETS CSV
|
|
50
|
-
"youtube": "Guarda come si esporta un file CSV su YouTube",
|
|
49
|
+
"instruction" : " <i class=\"fa fa-question-circle\"></i> <a target=\"_blank\" href=\"https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/it-1.-Gateway-configuration\"><u>Clicca per vedere come si importa un file ETS CSV.</u></a>",
|
|
50
|
+
"youtube" : " <i class=\"fa fa-youtube-play\"></i> <a target=\"_blank\" href=\"https://youtu.be/egRbR_KwP9I\"><u>Guarda come si esporta un file CSV su YouTube.</u></a>",
|
|
51
51
|
"help_ga": "Se l'indirizzo di gruppo non ha datapoint",
|
|
52
52
|
"import_select_stop": "Blocca ed annulla l'importazione",
|
|
53
53
|
"import_select_skip": "Salta l'importazione dell'indirizzo di gruppo",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"node-input-whentostart": "Modalità avvio allerta",
|
|
11
11
|
"node-input-initialread": "Leggi il valore di ogni device alla connessione/riconnessione",
|
|
12
12
|
"node-input-initialread0": "No",
|
|
13
|
-
"node-input-initialread1": "Leggi dal BUS KNX"
|
|
13
|
+
"node-input-initialread1": "Leggi dal BUS KNX",
|
|
14
|
+
"node-input-initialreadGAInRules": "Leggi stati alla connessione/riconnessione"
|
|
14
15
|
},
|
|
15
16
|
"selectlists": {
|
|
16
17
|
"manualstart": "Avvia ciclo allerta manualmente tramite messaggio in ingresso",
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
},
|
|
43
43
|
"ets": {
|
|
44
44
|
"description": "您可以导入 ETS CSV 组地址列表或 ESF 组地址列表。 请优先选择 ETS CSV 组地址列表,因为数据类型更完整.",
|
|
45
|
-
"instruction": "
|
|
46
|
-
"youtube": "
|
|
45
|
+
"instruction" : " <i class=\"fa fa-question-circle\"></i> <a target=\"_blank\" href=\"https://github.com/Supergiovane/node-red-contrib-knx-ultimate/wiki/cn-1.-Gateway-configuration\"><u>单击以获取有关如何导出 ETS CSV 组地址列表的说明.</u></a>",
|
|
46
|
+
"youtube" : " <i class=\"fa fa-youtube-play\"></i> <a target=\"_blank\" href=\"https://youtu.be/egRbR_KwP9I\"><u>在Youtube上看怎么导入CSV文件.</u></a>",
|
|
47
47
|
"help_ga": "如果组地址没有数据类型",
|
|
48
48
|
"import_select_stop": "停止并且中断导入",
|
|
49
49
|
"import_select_skip": "跳过受影响的组地址",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"node-input-whentostart": "警报周期启动类型",
|
|
11
11
|
"node-input-initialread": "在连接/重新连接时读取每个设备的值",
|
|
12
12
|
"node-input-initialread0": "不使用",
|
|
13
|
-
"node-input-initialread1": "从KNX总线读取"
|
|
13
|
+
"node-input-initialread1": "从KNX总线读取",
|
|
14
|
+
"node-input-initialreadGAInRules": "Read states at start/reconnection"
|
|
14
15
|
},
|
|
15
16
|
"selectlists": {
|
|
16
17
|
"manualstart": "通过传入消息手动启动警报周期",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-knx-ultimate",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.41",
|
|
4
4
|
"description": "Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable.",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"mkdirp": "1.0.4",
|