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 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>
@@ -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
- cEMIMessage.control.ack = 0;// No ack like telegram sent from ETS
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
- this._sendConnectRequestMessage(new TunnelCRI.TunnelCRI(knxLayer));
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
- this._sendConnectionStateRequestMessage(this._channelID);
665
+ try {
666
+ this._sendConnectionStateRequestMessage(this._channelID);
667
+ } catch (error) { }
659
668
  }
660
669
  Disconnect() {
661
- if (this._clientSocket == null) {
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
- this._sendDisconnectRequestMessage(this._channelID);
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
- this._sendDisconnectResponseMessage(knxDisconnectRequest.channelID);
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
- //const knxTunnelingAck = lodash.cloneDeep(knxMessage);
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
- const getIPv4Interfaces = function () {
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
- if (intf.family === 'IPv4' && !intf.internal) {
14
- knxLog.get().trace('candidate interface: %s (%j)', iface, intf);
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
- let candidateInterfaces = getIPv4Interfaces()
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
- <div class="form-row" id="divKNXEthInterfaceManuallyInput" style="display: none;">
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
- <i class="fa fa-link"></i>
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
- <i class="fa fa-youtube"></i>
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.debug("knxUltimate-config: Don't care about KNXClientEvents.error: " + (err.message === undefined ? err : err.message));
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
- saveExposedGAs(); // 13/12/2021 save the current values of GA payload
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
 
@@ -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
- var oError = { nodeid: node.id, topic: node.outputtopic, devicename: devicename, GA: GA, text: text };
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>&nbsp; <span data-i18n="knxUltimateAlerter.other.sceneConfig"></dt>
213
+ <br/>
213
214
  <div class="form-row" id="divNode-input-initialreadGAInRules">
214
- &nbsp;&nbsp;<label style="width:70%" for="node-input-initialreadGAInRules">
215
+ &nbsp;&nbsp;<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:100px" id="node-input-initialreadGAInRules">
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 !== undefined) {
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
- var oError = { nodeid: node.id, topic: node.outputtopic, devicename: devicename, GA: GA, text: text };
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
- let msg = {
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
- // var oError = {nodeid:node.id,topic:node.outputtopic,devicename:devicename,GA:GA,text:text};
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": "Klicken Sie hier, um Anweisungen zum Exportieren der Adressliste der ETS Gruppenadressen als CSV zu erhalten.",
50
- "youtube": "Anleitung des ETS CSV Exports auf Youtube",
49
+ "instruction" : "&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<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" : "&nbsp<i class=\"fa fa-youtube-play\"></i>&nbsp<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" : "&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<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" : "&nbsp<i class=\"fa fa-youtube-play\"></i>&nbsp<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" : "&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<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" : "&nbsp<i class=\"fa fa-youtube-play\"></i>&nbsp<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": "单击以获取有关如何导出 ETS CSV 组地址列表的说明.",
46
- "youtube": "Youtube上看怎么导入CSV文件",
45
+ "instruction" : "&nbsp<i class=\"fa fa-question-circle\"></i>&nbsp<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" : "&nbsp<i class=\"fa fa-youtube-play\"></i>&nbsp<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.38",
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",