node-red-contrib-knx-ultimate 8.0.4 → 8.0.6

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,15 @@
6
6
 
7
7
  # CHANGELOG
8
8
 
9
+ **Version 8.0.6** - September 2026
10
+
11
+ - Updated the KNX engine to `knxultimate` 6.0.8 to restore reception of authenticated Data Secure status telegrams from gateways such as Apricum that omit the outer KNX/IP wrapper.
12
+ - Secure status nodes now update after group writes while MAC validation and replay protection remain enabled.
13
+
14
+ **Version 8.0.5** - September 2026
15
+
16
+ - Added the KNX Ultimate 7-to-8 migration video to the package README, migration guide and all localized documentation pages.
17
+
9
18
  **Version 8.0.4** - September 2026
10
19
 
11
20
  - Automatic migration now validates only the HUE, Matter and KNX Utility nodes it converts. Invalid nodes from unrelated packages no longer block the upgrade.
package/MIGRATION.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Version 8 contains the current KNX nodes and gateway. HUE and Matter are provided by `node-red-contrib-hue-ultimate` and `node-red-contrib-matter-ultimate`; the old dedicated KNX utility nodes are replaced by KNX Utility.
4
4
 
5
+ > ▶️ [Watch the KNX Ultimate 7 → 8 migration video](https://youtu.be/fpNNi1jZZSc) *(Italian)*
6
+
5
7
  ## Recommended path from version 7
6
8
 
7
9
  Install KNX Ultimate 7.1.4 first, open any KNX Ultimate node and press **Upgrade to v8**. The guided operation backs up the flows, installs the required HUE/Matter packages, converts compatible nodes, performs and verifies a full Deploy, and installs version 8. Restart the Node-RED service when requested.
package/README.md CHANGED
@@ -22,6 +22,8 @@ The palette contains KNX Device, KNX Utility, KNX Viewer, KNX IoT Bridge, KNX Mu
22
22
  >
23
23
  > If version 8 was installed directly from an older v7, restart Node-RED and open the editor: the built-in recovery bridge offers the same protected backup, package installation, conversion and Deploy. Legacy KNX AI nodes still require manual replacement or removal.
24
24
  >
25
+ > ▶️ **[Watch the KNX Ultimate 7 → 8 migration video](https://youtu.be/fpNNi1jZZSc)** *(Italian)*
26
+ >
25
27
  > **Follow the [upgrade steps](https://supergiovane.github.io/node-red-contrib-knx-ultimate/wiki/Migration-8) to keep your flows working.**
26
28
 
27
29
  ### Native seamless integrations
@@ -1,3 +1,4 @@
1
+ <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/editorNotifications.js"></script>
1
2
  <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/flowMigrationBackup.js"></script>
2
3
  <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/hueControllerMigration.js"></script>
3
4
  <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/knxUtilityMigration.js"></script>
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "engines": {
4
4
  "node": ">=20.18.1"
5
5
  },
6
- "version": "8.0.4",
6
+ "version": "8.0.6",
7
7
  "description": "KNX integration for Node-RED with KNX/IP and KNX Secure, ETS import, routing, diagnostics, automation utilities, MQTT and Modbus adapters. Optional Hue Ultimate and Matter Ultimate packages connect through the KNX gateway.",
8
8
  "files": [
9
9
  "nodes/",
@@ -19,7 +19,7 @@
19
19
  "scripts/check-legacy-flows.js"
20
20
  ],
21
21
  "dependencies": {
22
- "knxultimate": "6.0.6",
22
+ "knxultimate": "6.0.8",
23
23
  "lodash": "4.18.1",
24
24
  "mqtt": "^5.15.2",
25
25
  "ping": "0.4.4",
@@ -0,0 +1,101 @@
1
+ /* global RED */
2
+ /* eslint-disable no-undef */
3
+
4
+ ;(function (root, factory) {
5
+ const api = factory()
6
+ if (typeof module === 'object' && module.exports) module.exports = api
7
+ if (root) root.UltimateEditorNotifications = api
8
+ try {
9
+ const editor = typeof RED !== 'undefined' ? RED : (root && root.RED)
10
+ if (editor) api.install(editor)
11
+ } catch (error) { /* Node-RED will call install when the resource loads again. */ }
12
+ }(typeof globalThis !== 'undefined' ? globalThis : this, function () {
13
+ 'use strict'
14
+
15
+ const PATCH_MARKER = '__ultimateCloseButtonPatched'
16
+ const CLOSE_BUTTON_CLASS = 'ultimate-notification-close'
17
+
18
+ const closeLabel = (RED) => {
19
+ const key = 'common.label.close'
20
+ try {
21
+ const translated = RED && typeof RED._ === 'function' ? RED._(key) : undefined
22
+ if (translated && translated !== key) return translated
23
+ } catch (error) { /* use the language-neutral fallback below */ }
24
+ return 'Close'
25
+ }
26
+
27
+ const normalizeOptions = (options, fixed, timeout) => {
28
+ if (options && typeof options === 'object') return { ...options }
29
+ const normalized = {}
30
+ if (options !== undefined && options !== null) normalized.type = options
31
+ if (fixed !== undefined) normalized.fixed = fixed
32
+ if (timeout !== undefined) normalized.timeout = timeout
33
+ return normalized
34
+ }
35
+
36
+ const closesNotification = (button) => {
37
+ if (!button || typeof button !== 'object') return false
38
+ if (String(button.class || '').split(/\s+/).includes(CLOSE_BUTTON_CLASS)) return true
39
+ if (typeof button.click !== 'function') return false
40
+
41
+ // Existing project buttons close either the notification directly or a
42
+ // named close/dismiss helper. Recognising them avoids duplicate buttons.
43
+ const source = Function.prototype.toString.call(button.click)
44
+ return /\.close\s*\(|\.dialog\s*\(\s*['"]close['"]|\b(?:close|dismiss)\w*\s*\(/i.test(source)
45
+ }
46
+
47
+ const withCloseButton = (RED, options, getNotification) => {
48
+ const normalized = { ...options }
49
+ const buttons = Array.isArray(normalized.buttons) ? normalized.buttons.slice() : []
50
+ if (!buttons.some(closesNotification)) {
51
+ buttons.push({
52
+ text: closeLabel(RED),
53
+ class: CLOSE_BUTTON_CLASS,
54
+ click: function () {
55
+ const notification = getNotification()
56
+ if (notification && typeof notification.close === 'function') notification.close()
57
+ }
58
+ })
59
+ }
60
+ normalized.buttons = buttons
61
+ return normalized
62
+ }
63
+
64
+ const install = (RED) => {
65
+ if (!RED || typeof RED.notify !== 'function') return false
66
+ if (RED.notify[PATCH_MARKER]) return true
67
+
68
+ const originalNotify = RED.notify
69
+ const notifyWithClose = function (message, options, fixed, timeout) {
70
+ const notificationRef = { current: null }
71
+ const normalized = withCloseButton(
72
+ RED,
73
+ normalizeOptions(options, fixed, timeout),
74
+ () => notificationRef.current
75
+ )
76
+ notificationRef.current = originalNotify.call(this, message, normalized)
77
+ const notification = notificationRef.current
78
+
79
+ if (notification && typeof notification.update === 'function' && !notification.update[PATCH_MARKER]) {
80
+ const originalUpdate = notification.update
81
+ const updateWithClose = function (updatedMessage, updatedOptions) {
82
+ const options = typeof updatedOptions === 'number'
83
+ ? { timeout: updatedOptions }
84
+ : normalizeOptions(updatedOptions)
85
+ return originalUpdate.call(this, updatedMessage, withCloseButton(RED, options, () => notification))
86
+ }
87
+ Object.defineProperty(updateWithClose, PATCH_MARKER, { value: true })
88
+ notification.update = updateWithClose
89
+ }
90
+
91
+ return notification
92
+ }
93
+
94
+ Object.defineProperty(notifyWithClose, PATCH_MARKER, { value: true })
95
+ Object.defineProperty(notifyWithClose, '__ultimateOriginalNotify', { value: originalNotify })
96
+ RED.notify = notifyWithClose
97
+ return true
98
+ }
99
+
100
+ return Object.freeze({ install })
101
+ }))