node-red-contrib-knx-ultimate 4.0.6 → 4.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 4.0.7** - September 2025<br/>
10
+ - Fixed an issue where some secure fields were missing when creating a new config-node.<br/>
11
+ - HUE Light: enhanced the Homeassistant export yaml.<br/>
12
+
9
13
  **Version 4.0.6** - September 2025<br/>
10
14
  - Fixed regression in automatic datapoint selection, based on group address DPT.<br/>
11
15
 
@@ -214,7 +214,8 @@
214
214
  $("#rowTunnelIASelection").hide();
215
215
  $("#divTunnelIA").hide();
216
216
  }
217
- const showManualTunnelFields = isSecure && !isMulticast && manualMode;
217
+ // Allow manual/combined credentials to surface even before the user selects a unicast IP.
218
+ const showManualTunnelFields = isSecure && manualMode;
218
219
  $("#rowTunnelInterfaceIndividualAddress").toggle(showManualTunnelFields);
219
220
  $("#rowTunnelUserPassword").toggle(showManualTunnelFields);
220
221
  $("#rowTunnelUserId").toggle(showManualTunnelFields);
@@ -758,31 +759,77 @@
758
759
  border-bottom: 1px solid#377e00;
759
760
  outline: none;
760
761
  }
762
+
763
+ #knxUltimate-config-template .form-row {
764
+ display: flex;
765
+ align-items: center;
766
+ gap: 10px;
767
+ margin-bottom: 6px;
768
+ }
769
+
770
+ #knxUltimate-config-template .form-row > label {
771
+ flex: 0 0 230px;
772
+ display: flex;
773
+ align-items: center;
774
+ gap: 6px;
775
+ margin: 0;
776
+ }
777
+
778
+ #knxUltimate-config-template .form-row > label + input,
779
+ #knxUltimate-config-template .form-row > label + select,
780
+ #knxUltimate-config-template .form-row > label + textarea {
781
+ flex: 1 1 auto;
782
+ }
783
+
784
+ #knxUltimate-config-template .form-row.form-row-offset {
785
+ display: block;
786
+ margin-left: 230px;
787
+ }
788
+
789
+ #knxUltimate-config-template .form-row.form-row-checkbox {
790
+ align-items: flex-start;
791
+ }
792
+
793
+ #knxUltimate-config-template .form-row.form-row-checkbox input[type="checkbox"] {
794
+ margin-top: 4px;
795
+ }
796
+
797
+ #knxUltimate-config-template .form-row.form-row-checkbox label {
798
+ flex: 1 1 auto;
799
+ }
800
+
801
+ #knxUltimate-config-template #hintSecureMulticast,
802
+ #knxUltimate-config-template .form-row .form-tips {
803
+ margin-left: 230px;
804
+ }
805
+
806
+ #knxUltimate-config-template .form-section-heading {
807
+ margin-bottom: 12px;
808
+ }
761
809
  </style>
762
810
 
763
811
 
764
812
  <script type="text/html" data-template-name="knxUltimate-config">
765
- <div class="form-row">
766
- <b><span data-i18n="knxUltimate-config.properties.title"></span></b>
767
- <br/><br/>
768
- </div>
813
+ <div id="knxUltimate-config-template">
814
+ <div class="form-section-heading">
815
+ <b><span data-i18n="knxUltimate-config.properties.title"></span></b>
816
+ </div>
769
817
 
770
818
  <div class="form-row">
771
- <label for="node-config-input-name" style="width: 200px" >
819
+ <label for="node-config-input-name">
772
820
  <i class="fa fa-tag"></i> <span data-i18n="knxUltimate-config.properties.node-config-input-name"></span></label>
773
821
  <input type="text" id="node-config-input-name" style="width: 200px">
774
822
  </div>
775
823
  <div class="form-row">
776
- <label for="node-config-input-host" style="width: 200px"><i class="fa fa-server"></i> <span data-i18n="knxUltimate-config.properties.host"></span></label>
777
- <input type="text" id="node-config-input-host" style="width: 200px">
778
- <i id="refresh-interfaces" class="fa fa-refresh" style="cursor:pointer; color:#377e00; margin-left:6px;" data-i18n="[title]knxUltimate-config.properties.refresh_interfaces"></i>
824
+ <label for="node-config-input-host"><i class="fa fa-server"></i> <span data-i18n="knxUltimate-config.properties.host"></span></label>
825
+ <input type="text" id="node-config-input-host" style="width: 200px">
826
+ <i id="refresh-interfaces" class="fa fa-refresh" style="cursor:pointer; color:#377e00; margin-left:6px;" data-i18n="[title]knxUltimate-config.properties.refresh_interfaces"></i>
779
827
  </div>
780
- <div class="form-row">
781
- <label style="width: 200px"></label>
828
+ <div class="form-row form-row-offset">
782
829
  <span id="interfaces-count" style="font-size: 12px; color:#377e00; margin-top: 2px;"></span>
783
830
  </div>
784
831
  <div class="form-row" id="rowPhysAddr">
785
- <label for="node-config-input-physAddr" style="width: 200px">
832
+ <label for="node-config-input-physAddr">
786
833
  <i class="fa fa-microchip"></i>
787
834
  <span data-i18n="knxUltimate-config.advanced.knx_phy_addr"></span>
788
835
  </label>
@@ -873,13 +920,13 @@
873
920
  <p>
874
921
 
875
922
  <div class="form-row">
876
- <label for="node-config-input-port" style="width: 200px">
923
+ <label for="node-config-input-port">
877
924
  <span data-i18n="knxUltimate-config.properties.ip_port"></span>
878
925
  </label>
879
926
  <input type="text" id="node-config-input-port" style="width: 100px">
880
927
  </div>
881
928
  <div class="form-row">
882
- <label for="node-config-input-hostProtocol" style="width: 200px">
929
+ <label for="node-config-input-hostProtocol">
883
930
  <span data-i18n="knxUltimate-config.properties.ip_protocol"></span>
884
931
  </label>
885
932
  <select id="node-config-input-hostProtocol" >
@@ -892,7 +939,7 @@
892
939
 
893
940
 
894
941
  <div class="form-row">
895
- <label for="node-config-input-KNXEthInterface" style="width: 200px">
942
+ <label for="node-config-input-KNXEthInterface">
896
943
  <i class="fa fa-wifi"></i>
897
944
  <span data-i18n="knxUltimate-config.properties.bind_local_int"></span>
898
945
  </label>
@@ -904,7 +951,7 @@
904
951
  data-i18n="[placeholder]knxUltimate-config.properties.iface_name_placeholder">
905
952
  </div>
906
953
  <div class="form-row">
907
- <label for="node-config-input-autoReconnect" style="width: 200px">
954
+ <label for="node-config-input-autoReconnect">
908
955
  <i class="fa fa-plug"></i>
909
956
  <span data-i18n="knxUltimate-config.properties.autoReconnect"></span>
910
957
  </label>
@@ -918,26 +965,26 @@
918
965
  <div id="tabs-2">
919
966
  <p>
920
967
 
921
- <div class="form-row">
968
+ <div class="form-row form-row-checkbox">
922
969
  <input type="checkbox" id="node-config-input-ignoreTelegramsWithRepeatedFlag"
923
970
  style="display:inline-block; width:auto; vertical-align:top;">
924
- <label style="width:85%" for="node-config-input-ignoreTelegramsWithRepeatedFlag">
971
+ <label for="node-config-input-ignoreTelegramsWithRepeatedFlag">
925
972
  <i class="fa fa-ban"></i>
926
973
  <span data-i18n="knxUltimate-config.advanced.ignoreTelegramsWithRepeatedFlag"></span>
927
974
  </label>
928
975
  </div>
929
976
 
930
- <div class="form-row">
977
+ <div class="form-row form-row-checkbox">
931
978
  <input type="checkbox" id="node-config-input-suppressACKRequest"
932
979
  style="display:inline-block; width:auto; vertical-align:top;">
933
- <label style="width:85%" for="node-config-input-suppressACKRequest">
980
+ <label for="node-config-input-suppressACKRequest">
934
981
  <i class="fa fa-ban"></i>
935
982
  <span data-i18n="knxUltimate-config.advanced.suppress_ack"></span>
936
983
  </label>
937
984
  </div>
938
985
 
939
986
  <div class="form-row">
940
- <label for="node-config-input-delaybetweentelegrams" style="width:auto">
987
+ <label for="node-config-input-delaybetweentelegrams">
941
988
  <i class="fa fa-hourglass-start"></i>
942
989
  <span data-i18n="knxUltimate-config.advanced.delaybetweentelegrams"></span>
943
990
  </label>
@@ -976,7 +1023,7 @@
976
1023
  <span style="color:red" data-i18n="[html]knxUltimate-config.ets.youtube"></span>
977
1024
  </div>
978
1025
  <div class="form-row">
979
- <label for="node-config-input-stopETSImportIfNoDatapoint" style="width:250px">
1026
+ <label for="node-config-input-stopETSImportIfNoDatapoint">
980
1027
  <i class="fa fa-question-circle"></i>
981
1028
  <span data-i18n="knxUltimate-config.ets.help_ga"></span>
982
1029
  </label>
@@ -987,7 +1034,7 @@
987
1034
  </select>
988
1035
  </div>
989
1036
  <div class="form-row">
990
- <label style="width:auto" for="node-config-input-csv">
1037
+ <label for="node-config-input-csv">
991
1038
  <i class="fa fa-th-list"></i> <span data-i18n="knxUltimate-config.ets.ga_list_label"></span>
992
1039
  </label>
993
1040
  </div>
@@ -1003,12 +1050,12 @@
1003
1050
  <div id="tabs-4">
1004
1051
  <p>
1005
1052
  <div class="form-row">
1006
- <label style="width:300px"><i class="fa fa-sign-in"></i> <span data-i18n="knxUltimate-config.utility.gather_debug"></span></label>
1053
+ <label><i class="fa fa-sign-in"></i> <span data-i18n="knxUltimate-config.utility.gather_debug"></span></label>
1007
1054
  <input type="button" id="getinfocam" class="ui-button ui-corner-all ui-widget"
1008
1055
  style="background-color:#AEE1FF;width:150px" data-i18n="[value]knxUltimate-config.utility.read_button">
1009
1056
  </div>
1010
1057
  <div class="form-row">
1011
- <label style="width:300px"><i class="fa fa-sign-in"></i> <span data-i18n="knxUltimate-config.utility.get_all_used_ga"></span></label>
1058
+ <label><i class="fa fa-sign-in"></i> <span data-i18n="knxUltimate-config.utility.get_all_used_ga"></span></label>
1012
1059
  <input type="button" id="getallgaused" class="ui-button ui-corner-all ui-widget"
1013
1060
  style="background-color:#AEE1FF;width:150px" data-i18n="[value]knxUltimate-config.utility.read_button">
1014
1061
  </div>
@@ -1018,6 +1065,8 @@
1018
1065
  </div>
1019
1066
  </p>
1020
1067
  </div>
1021
- </div>
1068
+ </div>
1069
+
1070
+ </div>
1022
1071
 
1023
1072
  </script>
@@ -897,56 +897,69 @@
897
897
  }
898
898
  function yamelize() {
899
899
  try {
900
- // Get the HUE Node properties and transform it into yaml
901
- let sYaml = '- name: "' + $("#node-input-name").val() + '"' + "\n";
902
- sYaml += $("#node-input-GALightSwitch").val() != '' ? ' address: "' + $("#node-input-GALightSwitch").val() + '"' + "\n" : '';
903
- sYaml += $("#node-input-GALightState").val() != '' ? ' state_address: "' + $("#node-input-GALightState").val() + '"' + "\n" : '';
904
- sYaml += $("#node-input-GALightBrightness").val() != '' ? ' brightness_address: "' + $("#node-input-GALightBrightness").val() + '"' + "\n" : '';
905
- sYaml += $("#node-input-GALightBrightnessState").val() != '' ? ' brightness_state_address: "' + $("#node-input-GALightBrightnessState").val() + '"' + "\n" : '';
906
-
907
- //#region color_temperature_mode
908
- // ----------------------------
909
- if ($("#node-input-GALightKelvinPercentage").val !== '') {
910
-
911
- // color_temperature_mode: relative
912
- sYaml += ' color_temperature_mode: relative' + '\n';
913
- sYaml += ' color_temperature_address: "' + $("#node-input-GALightKelvinPercentage").val() + '"\n';
914
- sYaml += $("#node-input-GALightKelvinPercentageState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightKelvinPercentageState").val() + '"' + "\n" : '';
915
- sYaml += ' min_kelvin: 2200' + '\n';
916
- sYaml += ' max_kelvin: 6500' + '\n';
917
-
918
- } else if ($("#node-input-GALightKelvin").val() !== '') {
919
-
920
- if ($("#node-input-dptLightKelvin").val() === '7.600') {
921
- sYaml += ' color_temperature_mode: absolute' + '\n';
922
- sYaml += ' color_temperature_address: "' + $("#node-input-GALightKelvin").val() + '"\n';
923
- if ($("#node-input-dptLightKelvinState").val() === '7.600') {
924
- // Add the status only if also 7.600
925
- sYaml += $("#node-input-GALightKelvinState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightKelvinState").val() + '"' + "\n" : '';
926
- }
927
- sYaml += ' min_kelvin: 2200' + '\n';
928
- sYaml += ' max_kelvin: 6500' + '\n';
929
-
930
- } else if ($("#node-input-dptLightKelvin").val() === '9.002') {
900
+ const getVal = (selector) => {
901
+ const $el = $(selector);
902
+ if (!$el || !$el.length) return '';
903
+ const raw = $el.val();
904
+ if (raw === undefined || raw === null) return '';
905
+ return typeof raw === 'string' ? raw.trim() : String(raw);
906
+ };
907
+ const appendLine = (label, value) => {
908
+ if (value) {
909
+ sYaml += ` ${label}: "${value}"\n`;
910
+ }
911
+ };
931
912
 
932
- sYaml += ' color_temperature_mode: absolute_float' + '\n';
933
- sYaml += ' color_temperature_address: "' + $("#node-input-GALightKelvin").val() + '"\n';
934
- if ($("#node-input-dptLightKelvinState").val() === '9.002') {
935
- // Add the status only if also 7.600
936
- sYaml += $("#node-input-GALightKelvinState").val() != '' ? ' color_temperature_state_address: "' + $("#node-input-GALightKelvinState").val() + '"' + "\n" : '';
913
+ const name = getVal('#node-input-name').replace(/"/g, '\\"');
914
+ let sYaml = `- name: "${name}"\n`;
915
+
916
+ appendLine('address', getVal('#node-input-GALightSwitch'));
917
+ appendLine('state_address', getVal('#node-input-GALightState'));
918
+ appendLine('brightness_address', getVal('#node-input-GALightBrightness'));
919
+ appendLine('brightness_state_address', getVal('#node-input-GALightBrightnessState'));
920
+
921
+ // Color temperature handling -----------------------------------
922
+ let colorTemperatureConfigured = false;
923
+ const kelvinPercent = getVal('#node-input-GALightKelvinPercentage');
924
+ if (kelvinPercent) {
925
+ sYaml += ' color_temperature_mode: relative\n';
926
+ appendLine('color_temperature_address', kelvinPercent);
927
+ appendLine('color_temperature_state_address', getVal('#node-input-GALightKelvinPercentageState'));
928
+ colorTemperatureConfigured = true;
929
+ } else {
930
+ const kelvinAddress = getVal('#node-input-GALightKelvin');
931
+ if (kelvinAddress) {
932
+ const kelvinDpt = getVal('#node-input-dptLightKelvin');
933
+ if (kelvinDpt === '7.600') {
934
+ sYaml += ' color_temperature_mode: absolute\n';
935
+ appendLine('color_temperature_address', kelvinAddress);
936
+ if (getVal('#node-input-dptLightKelvinState') === '7.600') {
937
+ appendLine('color_temperature_state_address', getVal('#node-input-GALightKelvinState'));
938
+ }
939
+ colorTemperatureConfigured = true;
940
+ } else if (kelvinDpt === '9.002') {
941
+ sYaml += ' color_temperature_mode: absolute_float\n';
942
+ appendLine('color_temperature_address', kelvinAddress);
943
+ if (getVal('#node-input-dptLightKelvinState') === '9.002') {
944
+ appendLine('color_temperature_state_address', getVal('#node-input-GALightKelvinState'));
945
+ }
946
+ colorTemperatureConfigured = true;
937
947
  }
938
- sYaml += ' min_kelvin: 2200' + '\n';
939
- sYaml += ' max_kelvin: 6500' + '\n';
940
-
941
948
  }
942
949
  }
943
- // ----------------------------
944
- //#endregion
950
+ if (colorTemperatureConfigured) {
951
+ sYaml += ' min_kelvin: 2200\n';
952
+ sYaml += ' max_kelvin: 6500\n';
953
+ }
945
954
 
946
- sYaml += $("#node-input-GALightColor").val() != '' ? ' color_address: "' + $("#node-input-GALightColor").val() + '"' + "\n" : '';
947
- sYaml += $("#node-input-GALightColorState").val() != '' ? ' color_state_address: "' + $("#node-input-GALightColorState").val() + '"' + "\n" : '';
955
+ appendLine('color_address', getVal('#node-input-GALightColor'));
956
+ appendLine('color_state_address', getVal('#node-input-GALightColorState'));
957
+ appendLine('hue_address', getVal('#node-input-GALightHSV_H_DIM'));
958
+ appendLine('hue_state_address', getVal('#node-input-GALightHSV_H_State'));
959
+ appendLine('saturation_address', getVal('#node-input-GALightHSV_S_DIM'));
960
+ appendLine('saturation_state_address', getVal('#node-input-GALightHSV_S_State'));
948
961
 
949
- return (sYaml);
962
+ return sYaml;
950
963
  } catch (error) { }
951
964
  }
952
965
 
@@ -1489,4 +1502,3 @@
1489
1502
  <br />
1490
1503
  </script>
1491
1504
 
1492
-
package/package.json CHANGED
@@ -3,14 +3,14 @@
3
3
  "engines": {
4
4
  "node": ">=20.18.1"
5
5
  },
6
- "version": "4.0.6",
6
+ "version": "4.0.7",
7
7
  "description": "Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control and ETS group address importer. Easy to use and highly configurable.",
8
8
  "dependencies": {
9
9
  "binary-parser": "2.2.1",
10
10
  "crypto-js": "4.2.0",
11
11
  "dns-sync": "0.2.1",
12
12
  "js-yaml": "4.1.0",
13
- "knxultimate": "5.1.1",
13
+ "knxultimate": "5.1.2",
14
14
  "lodash": "4.17.21",
15
15
  "mkdirp": "3.0.1",
16
16
  "node-color-log": "12.0.1",