node-red-contrib-knx-ultimate 3.3.38 → 3.3.40
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 +7 -0
- package/img/wiki/MQQT-INFLUXDB.jpg +0 -0
- package/nodes/knxUltimate-config.js +92 -78
- package/nodes/knxUltimate.html +13 -1
- package/nodes/knxUltimate.js +1 -1
- package/nodes/knxUltimateAutoResponder.js +12 -3
- package/package.json +1 -1
- package/resources/KNXFunctionCodeSnippets.js +21 -0
- /package/{KNXUltimate.code-workspace → Node-Red-KNXUltimate.code-workspace} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 3.3.40** - August 2025<br/>
|
|
10
|
+
- KNX Peristent value files are now saved every 5 seconds, other than at the node disconnection.<br/>
|
|
11
|
+
- Fixed an issue preventing the AutoResponder node to start, if the imported ETS file contains malformed structure.<br/>
|
|
12
|
+
|
|
13
|
+
**Version 3.3.39** - July 2025<br/>
|
|
14
|
+
- Added other snippets to the KNX Device function tab.<br/>
|
|
15
|
+
|
|
9
16
|
**Version 3.3.38** - May 2025<br/>
|
|
10
17
|
- FIX: fixed possible issue having tabulator chars in the group address names.<br/>
|
|
11
18
|
- KNX Engine: better handling of disconnections telegrams.<br/>
|
|
Binary file
|
|
@@ -68,7 +68,6 @@ module.exports = (RED) => {
|
|
|
68
68
|
node.KNXEthInterfaceManuallyInput = typeof config.KNXEthInterfaceManuallyInput === "undefined" ? "" : config.KNXEthInterfaceManuallyInput; // If you manually set the interface name, it will be wrote here
|
|
69
69
|
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
|
|
70
70
|
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
|
|
71
|
-
node.csv = readCSV(config.csv); // Array from ETS CSV Group Addresses {ga:group address, dpt: datapoint, devicename: full device name with main and subgroups}
|
|
72
71
|
node.localEchoInTunneling = typeof config.localEchoInTunneling !== "undefined" ? config.localEchoInTunneling : true;
|
|
73
72
|
node.userDir = path.join(RED.settings.userDir, "knxultimatestorage"); // 04/04/2021 Supergiovane: Storage for service files
|
|
74
73
|
node.exposedGAs = [];
|
|
@@ -79,6 +78,8 @@ module.exports = (RED) => {
|
|
|
79
78
|
try {
|
|
80
79
|
node.sysLogger = new loggerClass({ loglevel: node.loglevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
|
|
81
80
|
} catch (error) { console.log(error.stack) }
|
|
81
|
+
node.csv = readCSV(config.csv); // Array from ETS CSV Group Addresses {ga:group address, dpt: datapoint, devicename: full device name with main and subgroups}
|
|
82
|
+
|
|
82
83
|
// 12/11/2021 Connect at start delay
|
|
83
84
|
node.autoReconnect = true; // 20/03/2022 Default
|
|
84
85
|
if (config.autoReconnect === "no" || config.autoReconnect === false) {
|
|
@@ -99,6 +100,7 @@ module.exports = (RED) => {
|
|
|
99
100
|
node.delaybetweentelegrams = (config.delaybetweentelegrams === undefined || config.delaybetweentelegrams === null || config.delaybetweentelegrams === '') ? 25 : Number(config.delaybetweentelegrams);
|
|
100
101
|
if (node.delaybetweentelegrams < 25) node.delaybetweentelegrams = 25; // Protection avoiding handleKNXQueue hangs
|
|
101
102
|
if (node.delaybetweentelegrams > 100) node.delaybetweentelegrams = 100; // Protection avoiding handleKNXQueue hangs
|
|
103
|
+
node.timerSaveExposedGAs = null; // Timer to save the exposed GA every once in a while
|
|
102
104
|
|
|
103
105
|
// 05/12/2021 Set the protocol (this is undefined if coming from ild versions
|
|
104
106
|
if (node.hostProtocol === "Auto") {
|
|
@@ -194,7 +196,7 @@ module.exports = (RED) => {
|
|
|
194
196
|
node.sysLogger?.info("payload cache set to " + path.join(node.userDir, "knxpersistvalues"));
|
|
195
197
|
}
|
|
196
198
|
|
|
197
|
-
function saveExposedGAs() {
|
|
199
|
+
async function saveExposedGAs() {
|
|
198
200
|
const sFile = path.join(node.userDir, "knxpersistvalues", "knxpersist" + node.id + ".json");
|
|
199
201
|
try {
|
|
200
202
|
if (node.exposedGAs.length > 0) {
|
|
@@ -277,10 +279,16 @@ module.exports = (RED) => {
|
|
|
277
279
|
// 17/02/2020 Do initial read (called by node.timerDoInitialRead timer)
|
|
278
280
|
function DoInitialReadFromKNXBusOrFile() {
|
|
279
281
|
if (node.linkStatus !== "connected") return; // 29/08/2019 If not connected, exit
|
|
282
|
+
node.sysLogger?.info("Do DoInitialReadFromKNXBusOrFile");
|
|
280
283
|
loadExposedGAs(); // 04/04/2021 load the current values of GA payload
|
|
284
|
+
node.sysLogger?.info("Loaded persist GA values", node.exposedGAs?.length);
|
|
285
|
+
|
|
286
|
+
if (node.timerSaveExposedGAs !== null) clearInterval(node.timerSaveExposedGAs);
|
|
287
|
+
node.timerSaveExposedGAs = setInterval(async () => {
|
|
288
|
+
await saveExposedGAs();
|
|
289
|
+
}, 5000);
|
|
290
|
+
node.sysLogger?.info("Started timerSaveExposedGAs with array lenght ", node.exposedGAs?.length);
|
|
281
291
|
|
|
282
|
-
node.sysLogger?.info("Loaded saved GA values", node.exposedGAs?.length);
|
|
283
|
-
node.sysLogger?.info("Do DoInitialReadFromKNXBusOrFile");
|
|
284
292
|
try {
|
|
285
293
|
const readHistory = [];
|
|
286
294
|
|
|
@@ -1592,87 +1600,92 @@ module.exports = (RED) => {
|
|
|
1592
1600
|
let sSecondGroupName = "";
|
|
1593
1601
|
let sFather = "";
|
|
1594
1602
|
for (let index = 0; index < fileGA.length; index++) {
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1603
|
+
try {
|
|
1604
|
+
let element = fileGA[index];
|
|
1605
|
+
element = element.replace(/\"/g, ""); // Rimuovo le virgolette
|
|
1606
|
+
element = element.replace(/\#/g, ""); // Rimuovo evetuali #
|
|
1607
|
+
|
|
1608
|
+
if (element !== "") {
|
|
1609
|
+
// Main and secondary group names
|
|
1610
|
+
if ((element.split("\t")[1].match(/-/g) || []).length == 2) {
|
|
1611
|
+
// Found main group family name (Example Light Actuators)
|
|
1612
|
+
sFirstGroupName = element.split("\t")[0] || "";
|
|
1613
|
+
sSecondGroupName = "";
|
|
1614
|
+
}
|
|
1615
|
+
if ((element.split("\t")[1].match(/-/g) || []).length == 1) {
|
|
1616
|
+
// Found second group family name (Example First Floor light)
|
|
1617
|
+
sSecondGroupName = element.split("\t")[0] || "";
|
|
1618
|
+
}
|
|
1619
|
+
if (sFirstGroupName !== "" && sSecondGroupName !== "") {
|
|
1620
|
+
sFather = "(" + sFirstGroupName + "->" + sSecondGroupName + ") ";
|
|
1621
|
+
}
|
|
1613
1622
|
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1623
|
+
if (element.split("\t")[1].search("-") == -1 && element.split("\t")[1].search("/") !== -1) {
|
|
1624
|
+
// Ho trovato una riga contenente un GA valido, cioè con 2 "/"
|
|
1625
|
+
if (element.split("\t")[5] == "") {
|
|
1626
|
+
if (node.stopETSImportIfNoDatapoint === "stop") {
|
|
1627
|
+
node.error(
|
|
1628
|
+
"KNXUltimate-config: ABORT IMPORT OF ETS CSV FILE. To skip the invalid datapoint and continue import, change the related setting, located in the config node in the ETS import section.",
|
|
1629
|
+
);
|
|
1630
|
+
return;
|
|
1631
|
+
}
|
|
1632
|
+
if (node.stopETSImportIfNoDatapoint === "fake") {
|
|
1633
|
+
// 02/03/2020 Whould you like to continue without datapoint? Good. Here a totally fake datapoint
|
|
1634
|
+
node.warn(
|
|
1635
|
+
"KNXUltimate-config: WARNING IMPORT OF ETS CSV FILE. Datapoint not set. You choosed to continue import with a fake datapoint 1.001. -> " +
|
|
1636
|
+
element.split("\t")[0] +
|
|
1637
|
+
" " +
|
|
1638
|
+
element.split("\t")[1],
|
|
1639
|
+
);
|
|
1640
|
+
ajsonOutput.push({
|
|
1641
|
+
ga: element.split("\t")[1],
|
|
1642
|
+
dpt: "1.001",
|
|
1643
|
+
devicename: sFather + element.split("\t")[0] + " (DPT NOT SET IN ETS - FAKE DPT USED)",
|
|
1644
|
+
});
|
|
1645
|
+
} else {
|
|
1646
|
+
// 31/03/2020 Skip import
|
|
1647
|
+
node.warn(
|
|
1648
|
+
"KNXUltimate-config: WARNING IMPORT OF ETS CSV FILE. Datapoint not set. You choosed to skip -> " +
|
|
1649
|
+
element.split("\t")[0] +
|
|
1650
|
+
" " +
|
|
1651
|
+
element.split("\t")[1],
|
|
1652
|
+
);
|
|
1653
|
+
}
|
|
1654
|
+
} else {
|
|
1655
|
+
const DPTa = element.split("\t")[5].split("-")[1];
|
|
1656
|
+
let DPTb = element.split("\t")[5].split("-")[2];
|
|
1657
|
+
if (typeof DPTb === "undefined") {
|
|
1658
|
+
node.warn(
|
|
1659
|
+
"KNXUltimate-config: WARNING: Datapoint not fully set (there is only the main type). I applied a default .001, but please check if i'ts ok ->" +
|
|
1660
|
+
element.split("\t")[0] +
|
|
1661
|
+
" " +
|
|
1662
|
+
element.split("\t")[1] +
|
|
1663
|
+
" Datapoint: " +
|
|
1664
|
+
element.split("\t")[5],
|
|
1665
|
+
);
|
|
1666
|
+
DPTb = "001"; // default
|
|
1667
|
+
}
|
|
1668
|
+
// Trailing zeroes
|
|
1669
|
+
if (DPTb.length == 1) {
|
|
1670
|
+
DPTb = "00" + DPTb;
|
|
1671
|
+
} else if (DPTb.length == 2) {
|
|
1672
|
+
DPTb = "0" + DPTb;
|
|
1673
|
+
}
|
|
1674
|
+
if (DPTb.length == 3) {
|
|
1675
|
+
DPTb = "" + DPTb; // stupid, but for readability
|
|
1676
|
+
}
|
|
1631
1677
|
ajsonOutput.push({
|
|
1632
1678
|
ga: element.split("\t")[1],
|
|
1633
|
-
dpt: "
|
|
1634
|
-
devicename: sFather + element.split("\t")[0]
|
|
1679
|
+
dpt: DPTa + "." + DPTb,
|
|
1680
|
+
devicename: sFather + element.split("\t")[0],
|
|
1635
1681
|
});
|
|
1636
|
-
} else {
|
|
1637
|
-
// 31/03/2020 Skip import
|
|
1638
|
-
node.warn(
|
|
1639
|
-
"KNXUltimate-config: WARNING IMPORT OF ETS CSV FILE. Datapoint not set. You choosed to skip -> " +
|
|
1640
|
-
element.split("\t")[0] +
|
|
1641
|
-
" " +
|
|
1642
|
-
element.split("\t")[1],
|
|
1643
|
-
);
|
|
1644
|
-
}
|
|
1645
|
-
} else {
|
|
1646
|
-
const DPTa = element.split("\t")[5].split("-")[1];
|
|
1647
|
-
let DPTb = element.split("\t")[5].split("-")[2];
|
|
1648
|
-
if (typeof DPTb === "undefined") {
|
|
1649
|
-
node.warn(
|
|
1650
|
-
"KNXUltimate-config: WARNING: Datapoint not fully set (there is only the main type). I applied a default .001, but please check if i'ts ok ->" +
|
|
1651
|
-
element.split("\t")[0] +
|
|
1652
|
-
" " +
|
|
1653
|
-
element.split("\t")[1] +
|
|
1654
|
-
" Datapoint: " +
|
|
1655
|
-
element.split("\t")[5],
|
|
1656
|
-
);
|
|
1657
|
-
DPTb = "001"; // default
|
|
1658
|
-
}
|
|
1659
|
-
// Trailing zeroes
|
|
1660
|
-
if (DPTb.length == 1) {
|
|
1661
|
-
DPTb = "00" + DPTb;
|
|
1662
|
-
} else if (DPTb.length == 2) {
|
|
1663
|
-
DPTb = "0" + DPTb;
|
|
1664
1682
|
}
|
|
1665
|
-
if (DPTb.length == 3) {
|
|
1666
|
-
DPTb = "" + DPTb; // stupid, but for readability
|
|
1667
|
-
}
|
|
1668
|
-
ajsonOutput.push({
|
|
1669
|
-
ga: element.split("\t")[1],
|
|
1670
|
-
dpt: DPTa + "." + DPTb,
|
|
1671
|
-
devicename: sFather + element.split("\t")[0],
|
|
1672
|
-
});
|
|
1673
1683
|
}
|
|
1674
1684
|
}
|
|
1685
|
+
} catch (error) {
|
|
1686
|
+
node.sysLogger?.error("readCSV " + " ROW:" + fileGA[index] + " Error:" + error.stack);
|
|
1675
1687
|
}
|
|
1688
|
+
|
|
1676
1689
|
}
|
|
1677
1690
|
|
|
1678
1691
|
return ajsonOutput;
|
|
@@ -1840,6 +1853,7 @@ module.exports = (RED) => {
|
|
|
1840
1853
|
}, 10000);
|
|
1841
1854
|
|
|
1842
1855
|
node.Disconnect = async (_sNodeStatus = "", _sColor = "grey") => {
|
|
1856
|
+
if (node.timerSaveExposedGAs !== null) clearInterval(node.timerSaveExposedGAs);
|
|
1843
1857
|
if (node.linkStatus === "disconnected") {
|
|
1844
1858
|
node.sysLogger?.debug("Disconnect: already not connected:" + node.linkStatus + ", node.autoReconnect:" + node.autoReconnect);
|
|
1845
1859
|
return;
|
|
@@ -1854,7 +1868,7 @@ module.exports = (RED) => {
|
|
|
1854
1868
|
);
|
|
1855
1869
|
}
|
|
1856
1870
|
node.setAllClientsStatus("Disconnected", _sColor, _sNodeStatus);
|
|
1857
|
-
saveExposedGAs(); // 04/04/2021 save the current values of GA payload
|
|
1871
|
+
await saveExposedGAs(); // 04/04/2021 save the current values of GA payload
|
|
1858
1872
|
node.sysLogger?.debug("Disconnected, node.autoReconnect:" + node.autoReconnect);
|
|
1859
1873
|
};
|
|
1860
1874
|
|
package/nodes/knxUltimate.html
CHANGED
|
@@ -128,6 +128,15 @@
|
|
|
128
128
|
$("#snippetThree").on("click", function (event) {
|
|
129
129
|
node.receiveMsgFromKNXCodeEditor.session.setValue(KNXFunctionSnippetThree);
|
|
130
130
|
});
|
|
131
|
+
$("#snippetFour").on("click", function (event) {
|
|
132
|
+
node.sendMsgToKNXCodeEditor.session.setValue(KNXFunctionSnippetFour);
|
|
133
|
+
});
|
|
134
|
+
$("#snippetFive").on("click", function (event) {
|
|
135
|
+
node.sendMsgToKNXCodeEditor.session.setValue(KNXFunctionSnippetFive);
|
|
136
|
+
});
|
|
137
|
+
$("#snippetSix").on("click", function (event) {
|
|
138
|
+
node.sendMsgToKNXCodeEditor.session.setValue(KNXFunctionSnippetSix);
|
|
139
|
+
});
|
|
131
140
|
|
|
132
141
|
function checkUI() {
|
|
133
142
|
|
|
@@ -746,6 +755,9 @@
|
|
|
746
755
|
</div>
|
|
747
756
|
<i class="fa fa-code"></i> Select a snippet to be inserted<br />
|
|
748
757
|
<button type="button" id="snippetOne" class="red-ui-button">Status GA check</button>
|
|
758
|
+
<button type="button" id="snippetFour" class="red-ui-button">Toggle value</button>
|
|
759
|
+
<button type="button" id="snippetFive" class="red-ui-button">Send false after 5 secs</button>
|
|
760
|
+
<button type="button" id="snippetSix" class="red-ui-button">Send 20% to another GA</button>
|
|
749
761
|
<hr>
|
|
750
762
|
<div class="form-row">
|
|
751
763
|
<dt>
|
|
@@ -839,7 +851,7 @@ If enabled, "f(x)" indication will be added to node's name.
|
|
|
839
851
|
| getGAValue (string GA, optional string DPT) | Get the specified GA's value, for example **'1/0/1'**, or also **'1/0/1 Bed table light'** (All text after a blank space will be ignored by the function. This is useful if you want to add the GA name as a reminder. With the ETS file imported, you can also copy and paste the GA and GA Name directly from the **Search GA** field.). **DPT** is optional if you've imported the ETS file, otherwise you must specify it, for example '1.001'. |
|
|
840
852
|
| setGAValue (string GA, any value, optional string DPT) | Set the specified GA's value. The GA con be wrote for example **'1/0/1'**, or also **'1/0/1 Bed table light'** (All text after a blank space will be ignored by the function. This is useful if you want to add the GA name as a reminder. With the ETS file imported, you can also copy and paste the GA and GA Name directly from the **Search GA** field.). The **value** is mandatory, can be a boolean or number or string, **DPT** is optional if you've imported the ETS file, otherwise you must specify it, for example '1.001'. |
|
|
841
853
|
| self (any value) | Set the currend node's value and sends the value to the KNX BUS as well. For example, *self(false)*. Caution using **self** function in the *From KNX BUS to node's OUTPUT PIN* code, because the code will be executed everytime a KNX telegram is received, so you coud have recurrency loops. |
|
|
842
|
-
| toggle (
|
|
854
|
+
| toggle () | Toggle the currend node's value and sends the value to the KNX BUS as well. For example, *toggle()*. Caution using **toggle** function in the *From KNX BUS to node's OUTPUT PIN* code, because the code will be executed everytime a KNX telegram is received, so you coud have recurrency loops. |
|
|
843
855
|
| node (object) | The node object. |
|
|
844
856
|
| RED (Node-Red object) | The Node-Red's RED object. |
|
|
845
857
|
| return (msg) | Mandatory `return msg;`, if you want to emit the message. Otherwise, using `return;` will not emit any message. |
|
package/nodes/knxUltimate.js
CHANGED
|
@@ -121,7 +121,7 @@ module.exports = function (RED) {
|
|
|
121
121
|
node.inputmessage = {}; // Stores the input message to be passed through
|
|
122
122
|
node.timerTTLInputMessage = null; // The stored node.inputmessage has a ttl.
|
|
123
123
|
try {
|
|
124
|
-
node.sysLogger = new loggerClass({ loglevel: node.serverKNX.loglevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
|
|
124
|
+
node.sysLogger = new loggerClass({ loglevel: node.serverKNX.loglevel || 'error', setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
|
|
125
125
|
} catch (error) { console.log(error.stack) }
|
|
126
126
|
node.sendMsgToKNXCode = config.sendMsgToKNXCode || undefined;
|
|
127
127
|
node.receiveMsgFromKNXCode = config.receiveMsgFromKNXCode || undefined;
|
|
@@ -35,7 +35,7 @@ module.exports = function (RED) {
|
|
|
35
35
|
function knxUltimateAutoResponder(config) {
|
|
36
36
|
RED.nodes.createNode(this, config)
|
|
37
37
|
const node = this
|
|
38
|
-
node.serverKNX = RED.nodes.getNode(config.server)
|
|
38
|
+
node.serverKNX = RED.nodes.getNode(config.server)
|
|
39
39
|
node.topic = node.name
|
|
40
40
|
node.name = config.name === undefined ? 'Auto responder' : config.name
|
|
41
41
|
node.outputtopic = node.name
|
|
@@ -50,6 +50,9 @@ module.exports = function (RED) {
|
|
|
50
50
|
node.inputRBE = 'false' // Apply or not RBE to the input (Messages coming from BUS)
|
|
51
51
|
node.exposedGAs = [];
|
|
52
52
|
node.commandText = []; // Raw list Respond To
|
|
53
|
+
node.timerSaveExposedGAs = null;
|
|
54
|
+
if (node.serverKNX === null) { node.status({ fill: 'red', shape: 'dot', text: '[NO GATEWAY SELECTED]' }); return; }
|
|
55
|
+
|
|
53
56
|
try {
|
|
54
57
|
node.sysLogger = new loggerClass({ loglevel: node.serverKNX.loglevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
|
|
55
58
|
} catch (error) { console.log(error.stack) }
|
|
@@ -66,7 +69,7 @@ module.exports = function (RED) {
|
|
|
66
69
|
// }
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
node.saveExposedGAs = () => {
|
|
72
|
+
node.saveExposedGAs = async () => {
|
|
70
73
|
const sFile = path.join(node.serverKNX.userDir, "knxpersistvalues", "knxpersist" + node.id + ".json");
|
|
71
74
|
try {
|
|
72
75
|
if (node.exposedGAs.length > 0) {
|
|
@@ -77,6 +80,7 @@ module.exports = function (RED) {
|
|
|
77
80
|
if (node.sysLogger !== undefined && node.sysLogger !== null) node.sysLogger.error("knxUltimateAutoResponder: unable to write peristent values to the file " + sFile + " " + err.message);
|
|
78
81
|
}
|
|
79
82
|
}
|
|
83
|
+
|
|
80
84
|
node.loadExposedGAs = () => {
|
|
81
85
|
const sFile = path.join(node.serverKNX.userDir, "knxpersistvalues", "knxpersist" + node.id + ".json");
|
|
82
86
|
try {
|
|
@@ -94,10 +98,14 @@ module.exports = function (RED) {
|
|
|
94
98
|
node.exposedGAs.forEach(element => {
|
|
95
99
|
element.enabled = false;
|
|
96
100
|
})
|
|
101
|
+
if (node.timerSaveExposedGAs !== null) clearInterval(node.timerSaveExposedGAs);
|
|
102
|
+
node.sysLogger?.info("Started timerSaveExposedGAs with array lenght ", node.exposedGAs?.length);
|
|
103
|
+
node.timerSaveExposedGAs = setInterval(async () => {
|
|
104
|
+
await node.saveExposedGAs();
|
|
105
|
+
}, 5000);
|
|
97
106
|
} catch (error) {
|
|
98
107
|
}
|
|
99
108
|
|
|
100
|
-
|
|
101
109
|
// Add the ETS CSV file list to exposedGAs
|
|
102
110
|
if (node.serverKNX.csv === undefined || node.serverKNX.csv === '' || node.serverKNX.csv.length === 0) {
|
|
103
111
|
node.status({ fill: 'grey', shape: 'ring', text: 'No ETS file imported', payload: '', dpt: '', devicename: '' });
|
|
@@ -219,6 +227,7 @@ module.exports = function (RED) {
|
|
|
219
227
|
|
|
220
228
|
node.on('close', function (done) {
|
|
221
229
|
try {
|
|
230
|
+
if (node.timerSaveExposedGAs !== null) clearInterval(node.timerSaveExposedGAs);
|
|
222
231
|
node.saveExposedGAs();
|
|
223
232
|
} catch (error) {
|
|
224
233
|
}
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=20.18.1"
|
|
5
5
|
},
|
|
6
|
-
"version": "3.3.
|
|
6
|
+
"version": "3.3.40",
|
|
7
7
|
"description": "Control your KNX 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",
|
|
@@ -41,4 +41,25 @@ return msg`;
|
|
|
41
41
|
const KNXFunctionSnippetThree = `// @ts-nocheck
|
|
42
42
|
// The current msg contains the internal temperature in the "msg.payload" property, but we want to emit the external temperature as well.
|
|
43
43
|
msg.externalTemperature = getGAValue('0/0/10 Garden temperature sensor'); // In case the ETS file is missing, you must specify the dpt as well: getGAValue('0/0/10','9.001')
|
|
44
|
+
return msg;`;
|
|
45
|
+
|
|
46
|
+
const KNXFunctionSnippetFour = `// @ts-nocheck
|
|
47
|
+
// After 5000 milliseconds, toggle.
|
|
48
|
+
setTimeout(function() {
|
|
49
|
+
toggle();
|
|
50
|
+
}, 5000);
|
|
51
|
+
return msg;`;
|
|
52
|
+
|
|
53
|
+
const KNXFunctionSnippetFive = `// @ts-nocheck
|
|
54
|
+
// After 5000 milliseconds, send false.
|
|
55
|
+
setTimeout(function () {
|
|
56
|
+
self(false);
|
|
57
|
+
}, 5000);
|
|
58
|
+
return msg;`;
|
|
59
|
+
|
|
60
|
+
const KNXFunctionSnippetSix = `// @ts-nocheck
|
|
61
|
+
// Send 20% to the GA 1/0/1 having DPT 5.001
|
|
62
|
+
if (msg.payload === true){
|
|
63
|
+
setGAValue('1/0/1',20,'5.001')
|
|
64
|
+
}
|
|
44
65
|
return msg;`;
|
|
File without changes
|