node-red-contrib-knx-ultimate 4.0.8 → 4.0.9

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,7 +6,7 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
- **Version 4.0.8** - September 2025<br/>
9
+ **Version 4.0.9** - September 2025<br/>
10
10
  - KNX Config node: now the ethernet interface is automatically selected, based on the KNX Gateway's IP subnet.<br/>
11
11
  - Added the details of keyring in clear text, when the loglevel is set to "debug".<br/>
12
12
 
@@ -393,17 +393,87 @@ module.exports = (RED) => {
393
393
  sequenceNumber: typeof device.sequenceNumber === "number" ? device.sequenceNumber : "",
394
394
  serialNumber: device.serialNumber || "",
395
395
  }));
396
- const keyringDump = {
397
- rawXML: node.keyringFileXML,
398
- password: node.credentials?.keyringFilePassword || "",
399
- createdBy: kr.getCreatedBy?.() || "",
400
- created: kr.getCreated?.() || "",
401
- interfaces,
402
- backbones,
403
- groupAddresses,
404
- devices,
405
- };
406
- node.sysLogger?.debug("KNX Secure keyring debug dump:", JSON.stringify(keyringDump, null, 2));
396
+ const lines = [];
397
+ lines.push("================ KNX Secure keyring debug dump ================");
398
+ lines.push(`Node: ${node.name || node.id || ""}`);
399
+ lines.push(`Created By: ${kr.getCreatedBy?.() || ""}`);
400
+ lines.push(`Created On: ${kr.getCreated?.() || ""}`);
401
+ lines.push(`Password (node credentials): ${node.credentials?.keyringFilePassword || ""}`);
402
+ lines.push("");
403
+
404
+ lines.push("Interfaces:");
405
+ if (interfaces.length === 0) {
406
+ lines.push(" (none)");
407
+ } else {
408
+ interfaces.forEach((iface, idx) => {
409
+ lines.push(` [${idx + 1}] ${iface.individualAddress || "(unknown)"} (${iface.type || ""})`);
410
+ lines.push(` Host: ${iface.host || ""}`);
411
+ lines.push(` User ID: ${iface.userId === "" ? "" : iface.userId}`);
412
+ lines.push(` Password (encoded): ${iface.password || ""}`);
413
+ lines.push(` Password (decoded): ${iface.decryptedPassword || ""}`);
414
+ lines.push(` Authentication (encoded): ${iface.authentication || ""}`);
415
+ lines.push(` Authentication (decoded): ${iface.decryptedAuthentication || ""}`);
416
+ if (!iface.groupAddresses || iface.groupAddresses.length === 0) {
417
+ lines.push(" Group Addresses: (none)");
418
+ } else {
419
+ lines.push(" Group Addresses:");
420
+ iface.groupAddresses.forEach((ga) => {
421
+ const senders = ga.senders && ga.senders.length > 0 ? ga.senders.join(", ") : "(none)";
422
+ lines.push(` - ${ga.address}: senders ${senders}`);
423
+ });
424
+ }
425
+ lines.push("");
426
+ });
427
+ }
428
+
429
+ lines.push("Backbones:");
430
+ if (backbones.length === 0) {
431
+ lines.push(" (none)");
432
+ } else {
433
+ backbones.forEach((backbone, idx) => {
434
+ lines.push(` [${idx + 1}] Multicast: ${backbone.multicastAddress || ""}`);
435
+ lines.push(` Latency: ${backbone.latency === "" ? "" : backbone.latency}`);
436
+ lines.push(` Key (encoded): ${backbone.key || ""}`);
437
+ lines.push(` Key (decoded hex): ${backbone.decryptedKey || ""}`);
438
+ lines.push("");
439
+ });
440
+ }
441
+
442
+ lines.push("Group Addresses:");
443
+ if (groupAddresses.length === 0) {
444
+ lines.push(" (none)");
445
+ } else {
446
+ groupAddresses.forEach((group, idx) => {
447
+ lines.push(` [${idx + 1}] ${group.address || ""}`);
448
+ lines.push(` Key (encoded): ${group.key || ""}`);
449
+ lines.push(` Key (decoded hex): ${group.decryptedKey || ""}`);
450
+ lines.push("");
451
+ });
452
+ }
453
+
454
+ lines.push("Devices:");
455
+ if (devices.length === 0) {
456
+ lines.push(" (none)");
457
+ } else {
458
+ devices.forEach((device, idx) => {
459
+ lines.push(` [${idx + 1}] ${device.individualAddress || ""}`);
460
+ lines.push(` Tool Key (encoded): ${device.toolKey || ""}`);
461
+ lines.push(` Tool Key (decoded hex): ${device.decryptedToolKey || ""}`);
462
+ lines.push(` Management Password (encoded): ${device.managementPassword || ""}`);
463
+ lines.push(` Management Password (decoded): ${device.decryptedManagementPassword || ""}`);
464
+ lines.push(` Authentication (encoded): ${device.authentication || ""}`);
465
+ lines.push(` Authentication (decoded): ${device.decryptedAuthentication || ""}`);
466
+ lines.push(` Sequence Number: ${device.sequenceNumber === "" ? "" : device.sequenceNumber}`);
467
+ lines.push(` Serial Number: ${device.serialNumber || ""}`);
468
+ lines.push("");
469
+ });
470
+ }
471
+
472
+ lines.push("Raw keyring (XML/base64 as provided):");
473
+ lines.push(node.keyringFileXML || "(empty)");
474
+ lines.push("================ End of keyring debug dump ================");
475
+
476
+ node.sysLogger?.debug(lines.join("\n"));
407
477
  } catch (dumpError) {
408
478
  node.sysLogger?.error("KNX Secure: unable to log keyring details: " + dumpError.message);
409
479
  }
@@ -121,7 +121,8 @@ 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 || 'error', setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
124
+ const baseLogLevel = (node.serverKNX && node.serverKNX.loglevel) ? node.serverKNX.loglevel : 'error';
125
+ node.sysLogger = new loggerClass({ loglevel: baseLogLevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
125
126
  } catch (error) { console.log(error.stack) }
126
127
  node.sendMsgToKNXCode = config.sendMsgToKNXCode || undefined;
127
128
  node.receiveMsgFromKNXCode = config.receiveMsgFromKNXCode || undefined;
@@ -54,7 +54,8 @@ module.exports = function (RED) {
54
54
  if (node.serverKNX === null) { node.status({ fill: 'red', shape: 'dot', text: '[NO GATEWAY SELECTED]' }); return; }
55
55
 
56
56
  try {
57
- node.sysLogger = new loggerClass({ loglevel: node.serverKNX.loglevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
57
+ const baseLogLevel = (node.serverKNX && node.serverKNX.loglevel) ? node.serverKNX.loglevel : 'error';
58
+ node.sysLogger = new loggerClass({ loglevel: baseLogLevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
58
59
  } catch (error) { console.log(error.stack) }
59
60
  // Used to call the status update from the config node.
60
61
  node.setNodeStatus = ({ fill, shape, text, payload, GA, dpt, devicename }) => {
@@ -29,7 +29,8 @@ module.exports = function (RED) {
29
29
  node.hueDevice = config.hueDevice;
30
30
  node.initializingAtStart = false;
31
31
  try {
32
- node.sysLogger = new loggerClass({ loglevel: node.serverKNX.loglevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
32
+ const baseLogLevel = (node.serverKNX && node.serverKNX.loglevel) ? node.serverKNX.loglevel : 'error';
33
+ node.sysLogger = new loggerClass({ loglevel: baseLogLevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
33
34
  } catch (error) { console.log(error.stack) }
34
35
  // Multi scene
35
36
  config.GAsceneMulti = config.GAsceneMulti === undefined ? '' : config.GAsceneMulti;
@@ -38,7 +38,8 @@ module.exports = function (RED) {
38
38
  node.totalWatt = 0 // Current total watt consumption
39
39
  node.wattLimit = config.wattLimit === undefined ? 3000 : Number(config.wattLimit)
40
40
  try {
41
- node.sysLogger = new loggerClass({ loglevel: node.serverKNX.loglevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
41
+ const baseLogLevel = (node.serverKNX && node.serverKNX.loglevel) ? node.serverKNX.loglevel : 'error';
42
+ node.sysLogger = new loggerClass({ loglevel: baseLogLevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
42
43
  } catch (error) { console.log(error.stack) }
43
44
  node.deviceList = []
44
45
  for (let index = 1; index < 6; index++) {
@@ -29,7 +29,8 @@ module.exports = function (RED) {
29
29
  node.isSceneController = true // Signal to config node, that this is a node scene controller
30
30
  node.userDir = path.join(RED.settings.userDir, 'knxultimatestorage') // 09/03/2020 Storage of ttsultimate (otherwise, at each upgrade to a newer version, the node path is wiped out and recreated, loosing all custom files)
31
31
  try {
32
- node.sysLogger = new loggerClass({ loglevel: node.serverKNX.loglevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
32
+ const baseLogLevel = (node.serverKNX && node.serverKNX.loglevel) ? node.serverKNX.loglevel : 'error';
33
+ node.sysLogger = new loggerClass({ loglevel: baseLogLevel, setPrefix: node.type + " <" + (node.name || node.id || '') + ">" });
33
34
  } catch (error) { console.log(error.stack) }
34
35
  node.timerWait = null
35
36
  node.icountMessageInWindow = 0
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=20.18.1"
5
5
  },
6
- "version": "4.0.8",
6
+ "version": "4.0.9",
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",