node-red-contrib-knx-ultimate 5.2.4 → 6.0.0

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.
Files changed (79) hide show
  1. package/CHANGELOG.md +21 -8
  2. package/README.md +10 -3
  3. package/img/readmemain.png +0 -0
  4. package/nodes/commonFunctions.js +40 -3
  5. package/nodes/knxUltimate-config.js +379 -335
  6. package/nodes/knxUltimate.html +8 -9
  7. package/nodes/knxUltimate.js +5 -5
  8. package/nodes/knxUltimateAI.js +1 -1
  9. package/nodes/knxUltimateHueLight.html +3 -3
  10. package/nodes/knxUltimateHueLight.js +1 -1
  11. package/nodes/knxUltimateMatterBridge.html +321 -247
  12. package/nodes/knxUltimateMatterBridge.js +48 -1
  13. package/nodes/knxUltimateMatterControllerDevice.html +2119 -0
  14. package/nodes/knxUltimateMatterControllerDevice.js +1701 -0
  15. package/nodes/locales/de/knxUltimateMatterBridge.html +6 -2
  16. package/nodes/locales/de/knxUltimateMatterBridge.json +14 -1
  17. package/nodes/locales/de/knxUltimateMatterControllerDevice.html +27 -0
  18. package/nodes/locales/de/knxUltimateMatterControllerDevice.json +97 -0
  19. package/nodes/locales/de/matter-config.json +5 -1
  20. package/nodes/locales/de/matterbridge-config.json +1 -0
  21. package/nodes/locales/en/knxUltimateMatterBridge.html +6 -2
  22. package/nodes/locales/en/knxUltimateMatterBridge.json +14 -1
  23. package/nodes/locales/en/knxUltimateMatterControllerDevice.html +27 -0
  24. package/nodes/locales/en/knxUltimateMatterControllerDevice.json +97 -0
  25. package/nodes/locales/en/matter-config.json +6 -1
  26. package/nodes/locales/en/matterbridge-config.json +1 -0
  27. package/nodes/locales/es/knxUltimateMatterBridge.html +6 -2
  28. package/nodes/locales/es/knxUltimateMatterBridge.json +14 -1
  29. package/nodes/locales/es/knxUltimateMatterControllerDevice.html +27 -0
  30. package/nodes/locales/es/knxUltimateMatterControllerDevice.json +97 -0
  31. package/nodes/locales/es/matter-config.json +5 -1
  32. package/nodes/locales/es/matterbridge-config.json +1 -0
  33. package/nodes/locales/fr/knxUltimateMatterBridge.html +6 -2
  34. package/nodes/locales/fr/knxUltimateMatterBridge.json +14 -1
  35. package/nodes/locales/fr/knxUltimateMatterControllerDevice.html +27 -0
  36. package/nodes/locales/fr/knxUltimateMatterControllerDevice.json +89 -0
  37. package/nodes/locales/fr/matter-config.json +5 -1
  38. package/nodes/locales/fr/matterbridge-config.json +1 -0
  39. package/nodes/locales/it/knxUltimateMatterBridge.html +6 -2
  40. package/nodes/locales/it/knxUltimateMatterBridge.json +14 -1
  41. package/nodes/locales/it/knxUltimateMatterControllerDevice.html +27 -0
  42. package/nodes/locales/it/knxUltimateMatterControllerDevice.json +97 -0
  43. package/nodes/locales/it/matter-config.json +6 -1
  44. package/nodes/locales/it/matterbridge-config.json +1 -0
  45. package/nodes/locales/zh-CN/knxUltimateMatterBridge.html +6 -2
  46. package/nodes/locales/zh-CN/knxUltimateMatterBridge.json +14 -1
  47. package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.html +27 -0
  48. package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.json +89 -0
  49. package/nodes/locales/zh-CN/matter-config.json +5 -1
  50. package/nodes/locales/zh-CN/matterbridge-config.json +1 -0
  51. package/nodes/matter-config.html +58 -6
  52. package/nodes/matter-config.js +7 -2
  53. package/nodes/matterbridge-config.html +1 -0
  54. package/nodes/utils/lightEngines/canonicalLight.js +75 -0
  55. package/nodes/utils/lightEngines/hueLightEngine.js +51 -0
  56. package/nodes/utils/lightEngines/index.js +25 -0
  57. package/nodes/utils/lightEngines/knxLightCommand.js +79 -0
  58. package/nodes/utils/lightEngines/lightEngine.js +46 -0
  59. package/nodes/utils/lightEngines/matterHueShim.js +59 -0
  60. package/nodes/utils/lightEngines/matterLightEngine.js +117 -0
  61. package/nodes/utils/matterEngine.mjs +185 -14
  62. package/nodes/utils/matterKnxConverter.js +1 -1
  63. package/package.json +21 -3
  64. package/resources/KNXSendSnippets.js +53 -53
  65. package/resources/htmlUtils.js +6 -4
  66. package/nodes/knxUltimateMatterDevice.html +0 -632
  67. package/nodes/knxUltimateMatterDevice.js +0 -308
  68. package/nodes/locales/de/knxUltimateMatterDevice.html +0 -56
  69. package/nodes/locales/de/knxUltimateMatterDevice.json +0 -109
  70. package/nodes/locales/en/knxUltimateMatterDevice.html +0 -56
  71. package/nodes/locales/en/knxUltimateMatterDevice.json +0 -109
  72. package/nodes/locales/es/knxUltimateMatterDevice.html +0 -56
  73. package/nodes/locales/es/knxUltimateMatterDevice.json +0 -109
  74. package/nodes/locales/fr/knxUltimateMatterDevice.html +0 -56
  75. package/nodes/locales/fr/knxUltimateMatterDevice.json +0 -109
  76. package/nodes/locales/it/knxUltimateMatterDevice.html +0 -56
  77. package/nodes/locales/it/knxUltimateMatterDevice.json +0 -109
  78. package/nodes/locales/zh-CN/knxUltimateMatterDevice.html +0 -56
  79. package/nodes/locales/zh-CN/knxUltimateMatterDevice.json +0 -109
@@ -1,308 +0,0 @@
1
- const dptlib = require('knxultimate').dptlib
2
- const matterKnxConverter = require('./utils/matterKnxConverter')
3
-
4
- module.exports = function (RED) {
5
- function knxUltimateMatterDevice (config) {
6
- RED.nodes.createNode(this, config)
7
- const node = this
8
- node.serverKNX = RED.nodes.getNode(config.server) || undefined
9
- node.serverMatter = RED.nodes.getNode(config.serverMatter) || undefined
10
-
11
- node.topic = node.name
12
- node.name = config.name === undefined || config.name === '' ? 'Matter Device (BETA)' : config.name
13
- node.dpt = ''
14
- node.notifyreadrequest = false
15
- node.notifyreadrequestalsorespondtobus = 'false'
16
- node.notifyreadrequestalsorespondtobusdefaultvalueifnotinitialized = ''
17
- node.notifyresponse = false
18
- node.notifywrite = true
19
- node.initialread = true
20
- node.listenallga = true // Don't remove
21
- node.outputtype = 'write'
22
- node.outputRBE = 'false'
23
- node.inputRBE = 'false'
24
- node.currentPayload = ''
25
- node.passthrough = 'no'
26
- node.formatmultiplyvalue = 1
27
- node.formatnegativevalue = 'leave'
28
- node.formatdecimalsvalue = 2
29
-
30
- node.matterNodeId = config.matterNodeId || ''
31
- node.mappings = []
32
- try {
33
- node.mappings = Array.isArray(config.mappings) ? config.mappings : JSON.parse(config.mappings || '[]')
34
- } catch (error) {
35
- node.mappings = []
36
- }
37
-
38
- node.initializingAtStart = config.readStatusAtStartup === undefined || config.readStatusAtStartup === 'yes'
39
- node.enableNodePINS = config.enableNodePINS === 'yes'
40
- node.inputs = node.enableNodePINS ? 1 : 0
41
- node.outputs = node.enableNodePINS ? 1 : 0
42
-
43
- let lastInitialReadTs = 0
44
-
45
- const pushStatus = (status) => {
46
- if (!status) return
47
- const provider = node.serverKNX
48
- if (provider && typeof provider.applyStatusUpdate === 'function') {
49
- provider.applyStatusUpdate(node, status)
50
- } else {
51
- node.status(status)
52
- }
53
- }
54
-
55
- const formatTs = (date) => {
56
- const d = date instanceof Date ? date : new Date(date)
57
- const provider = node.serverKNX
58
- if (provider && typeof provider.formatStatusTimestamp === 'function') return provider.formatStatusTimestamp(d)
59
- return `${d.getDate()}, ${d.toLocaleTimeString()}`
60
- }
61
-
62
- node.setNodeStatus = ({ fill, shape, text, payload }) => {
63
- try {
64
- if (payload === undefined) payload = ''
65
- const dDate = new Date()
66
- payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString()
67
- node.sKNXNodeStatusText = `|KNX: ${text} ${payload} (${formatTs(dDate)})`
68
- pushStatus({ fill, shape, text: (node.sMatterNodeStatusText || '') + ' ' + (node.sKNXNodeStatusText || '') })
69
- } catch (error) { /* empty */ }
70
- }
71
-
72
- node.setNodeStatusMatter = ({ fill, shape, text, payload }) => {
73
- try {
74
- if (payload === undefined) payload = ''
75
- const dDate = new Date()
76
- payload = typeof payload === 'object' ? JSON.stringify(payload) : payload.toString()
77
- node.sMatterNodeStatusText = `|Matter: ${text} ${payload} (${formatTs(dDate)})`
78
- pushStatus({ fill, shape, text: node.sMatterNodeStatusText + ' ' + (node.sKNXNodeStatusText || '') })
79
- } catch (error) { /* empty */ }
80
- }
81
-
82
- const safeSendToKNX = (telegram, context = 'write') => {
83
- try {
84
- if (!node.serverKNX || typeof node.serverKNX.sendKNXTelegramToKNXEngine !== 'function') {
85
- pushStatus({ fill: 'red', shape: 'dot', text: `KNX server missing (${context}) (${formatTs(new Date())})` })
86
- return
87
- }
88
- node.serverKNX.sendKNXTelegramToKNXEngine({ ...telegram, nodecallerid: node.id })
89
- } catch (error) {
90
- pushStatus({ fill: 'red', shape: 'dot', text: `KNX send error ${error.message}` })
91
- }
92
- }
93
-
94
- const sendMappingToKNX = (mapping, payload, outputtype = 'write') => {
95
- if (payload === undefined || mapping.ga === undefined || mapping.ga === '') return
96
- safeSendToKNX({
97
- grpaddr: mapping.ga,
98
- payload,
99
- dpt: mapping.dpt,
100
- outputtype
101
- }, outputtype)
102
- }
103
-
104
- const getMatterManager = () => {
105
- if (!node.serverMatter || node.serverMatter.matterManager === null || node.serverMatter.matterManager === undefined) return undefined
106
- return node.serverMatter.matterManager
107
- }
108
-
109
- // Send the cached Matter value of a status mapping to KNX
110
- const sendCachedStatusToKNX = (mapping, outputtype = 'write') => {
111
- try {
112
- const manager = getMatterManager()
113
- if (manager === undefined) return false
114
- const rawValue = manager.getCachedAttribute(node.matterNodeId, mapping.endpointId, mapping.clusterId, mapping.target)
115
- if (rawValue === undefined) return false
116
- const payload = matterKnxConverter.matterToKnx(mapping.clusterId, mapping.target, rawValue)
117
- if (payload === undefined) return false
118
- sendMappingToKNX(mapping, payload, outputtype)
119
- return true
120
- } catch (error) {
121
- node.setNodeStatusMatter({ fill: 'red', shape: 'dot', text: `Cached status error ${error.message}`, payload: '' })
122
- return false
123
- }
124
- }
125
-
126
- // KNX -> Matter
127
- node.handleSend = (msg) => {
128
- if (!msg || !msg.knx) return
129
- if (node.matterNodeId === '') {
130
- node.setNodeStatusMatter({ fill: 'red', shape: 'ring', text: 'Missing Matter device selection', payload: '' })
131
- return
132
- }
133
- try {
134
- if (!Array.isArray(node.mappings)) return
135
- if (msg.knx.event === 'GroupValue_Read') {
136
- // Respond to read requests with the cached Matter values
137
- node.mappings.filter((m) => m.direction === 'status' && m.ga === msg.knx.destination).forEach((mapping) => {
138
- if (sendCachedStatusToKNX(mapping, 'response')) {
139
- node.setNodeStatus({ fill: 'grey', shape: 'ring', text: 'Response', payload: mapping.ga })
140
- }
141
- })
142
- return
143
- }
144
- const manager = getMatterManager()
145
- node.mappings.filter((m) => m.direction === 'command' && m.ga === msg.knx.destination).forEach((mapping) => {
146
- const value = dptlib.fromBuffer(msg.knx.rawValue, dptlib.resolve(mapping.dpt))
147
- const matterAction = matterKnxConverter.knxToMatter(mapping, value)
148
- if (matterAction === null) return
149
- if (manager === undefined || node.serverMatter.linkStatus !== 'connected') {
150
- node.setNodeStatusMatter({ fill: 'red', shape: 'ring', text: 'Matter controller unavailable', payload: '' })
151
- return
152
- }
153
- manager.writeMatterQueueAdd({
154
- nodeId: node.matterNodeId,
155
- endpointId: mapping.endpointId,
156
- clusterId: mapping.clusterId,
157
- kind: matterAction.kind,
158
- name: matterAction.name,
159
- args: matterAction.args
160
- })
161
- node.setNodeStatusMatter({
162
- fill: 'green',
163
- shape: 'dot',
164
- text: `KNX->Matter ${mapping.clusterName || mapping.clusterId}.${matterAction.name}`,
165
- payload: value
166
- })
167
- })
168
- } catch (error) {
169
- node.setNodeStatusMatter({ fill: 'red', shape: 'dot', text: `KNX->Matter error ${error.message}`, payload: '' })
170
- }
171
- }
172
-
173
- // Matter -> KNX (attribute change reported by the subscription)
174
- node.handleSendMatter = (_event) => {
175
- try {
176
- if (_event === undefined) return
177
- if (_event.nodeId !== node.matterNodeId) return
178
- const matchingMappings = node.mappings.filter((m) => m.direction === 'status' &&
179
- Number(m.endpointId) === Number(_event.endpointId) &&
180
- Number(m.clusterId) === Number(_event.clusterId) &&
181
- m.targetKind === 'attribute' &&
182
- m.target === _event.attributeName)
183
- matchingMappings.forEach((mapping) => {
184
- const payload = matterKnxConverter.matterToKnx(_event.clusterId, _event.attributeName, _event.value)
185
- if (payload === undefined) return
186
- sendMappingToKNX(mapping, payload, 'write')
187
- node.setNodeStatusMatter({
188
- fill: 'blue',
189
- shape: 'dot',
190
- text: `Matter->KNX ${_event.attributeName}`,
191
- payload
192
- })
193
- })
194
- if (node.enableNodePINS) {
195
- node.send({
196
- topic: `${_event.clusterId}.${_event.attributeName}`,
197
- payload: _event.value,
198
- matter: _event
199
- })
200
- }
201
- } catch (error) {
202
- node.setNodeStatusMatter({ fill: 'red', shape: 'dot', text: `Matter->KNX error ${error.message}`, payload: '' })
203
- }
204
- }
205
-
206
- // Cluster events (e.g. switch presses). Forwarded to the flow only.
207
- node.handleMatterClusterEvent = (_event) => {
208
- try {
209
- if (_event === undefined || _event.nodeId !== node.matterNodeId) return
210
- if (node.enableNodePINS) {
211
- node.send({
212
- topic: `${_event.clusterId}.${_event.eventName}`,
213
- payload: _event.events,
214
- matter: _event
215
- })
216
- }
217
- } catch (error) { /* empty */ }
218
- }
219
-
220
- // Called by matter-config when the paired node completed its initial sync (or reconnected)
221
- node.handleMatterNodeInitialized = () => {
222
- try {
223
- if (!node.initializingAtStart) return
224
- if (node.matterNodeId === '') return
225
- const now = Date.now()
226
- if ((now - lastInitialReadTs) < 5000) return // Avoid duplicate bursts on reconnections
227
- let sentCount = 0
228
- node.mappings.filter((m) => m.direction === 'status' && m.targetKind === 'attribute').forEach((mapping) => {
229
- if (sendCachedStatusToKNX(mapping, 'write')) sentCount += 1
230
- })
231
- if (sentCount > 0) {
232
- lastInitialReadTs = now
233
- node.setNodeStatusMatter({ fill: 'green', shape: 'dot', text: `Initial read: ${sentCount} value(s) sent`, payload: '' })
234
- }
235
- } catch (error) {
236
- node.setNodeStatusMatter({ fill: 'red', shape: 'dot', text: `Initial read error ${error.message}`, payload: '' })
237
- }
238
- }
239
-
240
- if (node.serverKNX) {
241
- try {
242
- node.serverKNX.removeClient(node)
243
- node.serverKNX.addClient(node)
244
- } catch (error) {
245
- RED.log.error(`knxUltimateMatterDevice: register KNX client error ${error.message}`)
246
- }
247
- }
248
- if (node.serverMatter) {
249
- try {
250
- node.serverMatter.removeClient(node)
251
- node.serverMatter.addClient(node)
252
- } catch (error) {
253
- RED.log.error(`knxUltimateMatterDevice: register client error ${error.message}`)
254
- }
255
- }
256
-
257
- // Flow input pin: send raw Matter commands/attribute writes.
258
- // msg.payload = { endpointId, clusterId, command: 'on', args: {...} } or { endpointId, clusterId, attribute: 'onOff', value: true }
259
- node.on('input', (msg, send, done) => {
260
- if (!node.enableNodePINS) {
261
- if (done) done()
262
- return
263
- }
264
- try {
265
- const manager = getMatterManager()
266
- if (manager === undefined) throw new Error('Matter controller unavailable')
267
- const payload = msg.payload || {}
268
- if (payload.command !== undefined) {
269
- manager.writeMatterQueueAdd({
270
- nodeId: node.matterNodeId,
271
- endpointId: payload.endpointId,
272
- clusterId: payload.clusterId,
273
- kind: 'command',
274
- name: payload.command,
275
- args: payload.args
276
- })
277
- } else if (payload.attribute !== undefined) {
278
- manager.writeMatterQueueAdd({
279
- nodeId: node.matterNodeId,
280
- endpointId: payload.endpointId,
281
- clusterId: payload.clusterId,
282
- kind: 'attributeWrite',
283
- name: payload.attribute,
284
- args: payload.value
285
- })
286
- } else {
287
- throw new Error('msg.payload must contain "command" or "attribute"')
288
- }
289
- node.setNodeStatusMatter({ fill: 'green', shape: 'dot', text: 'Flow->Matter', payload })
290
- if (done) done()
291
- } catch (error) {
292
- node.setNodeStatusMatter({ fill: 'red', shape: 'dot', text: `Flow error ${error.message}`, payload: '' })
293
- if (done) done(error)
294
- }
295
- })
296
-
297
- node.on('close', () => {
298
- try {
299
- if (node.serverKNX) node.serverKNX.removeClient(node)
300
- } catch (error) { /* empty */ }
301
- try {
302
- if (node.serverMatter) node.serverMatter.removeClient(node)
303
- } catch (error) { /* empty */ }
304
- })
305
- }
306
-
307
- RED.nodes.registerType('knxUltimateMatterDevice', knxUltimateMatterDevice)
308
- }
@@ -1,56 +0,0 @@
1
- <script type="text/markdown" data-help-name="knxUltimateMatterDevice">
2
- # Matter-Gerät (BETA)
3
-
4
- > Dieser Node ist in **BETA**: Er funktioniert, aber Details können sich zwischen Releases noch ändern.
5
-
6
- ## Übersicht
7
-
8
- Der Matter Device Node verbindet ein **Matter-Gerät** mit **KNX-Gruppenadressen**. Der Node arbeitet über den Konfigurations-Node *Matter Controller*, der die Geräte in seine eigene Matter-Fabric kommissioniert.
9
-
10
- - **Steuere** jedes gekoppelte Matter-Gerät vom KNX-Bus aus (Ein/Aus, Dimmen, Rollläden, Thermostate, Schlösser, ...).
11
- - **Verfolge** jedes Attribut des Geräts auf KNX-Gruppenadressen (Statusmeldungen, Sensoren, Leistungsmessung, Batterie...).
12
- - Vollständig generisch: Die Zuordnungsliste wird aus den **realen Endpoints/Clustern** des Geräts aufgebaut.
13
-
14
- ## Konfiguration
15
-
16
- |Feld|Beschreibung|
17
- |--|--|
18
- | KNX GW | KNX-Gateway für die Telegramme |
19
- | Matter Ctrl | Der Matter-Controller-Konfigurations-Node (dort werden die Geräte gekoppelt) |
20
- | Gerät | Wähle das gekoppelte Matter-Gerät aus der Autovervollständigung |
21
- | Zuordnungen | Eine Zeile pro Zuordnung Gruppenadresse ↔ Matter-Cluster |
22
- | Status beim Start lesen | Wenn aktiviert, sendet der Node die aktuellen zwischengespeicherten Werte beim Deploy/Verbinden |
23
- | Node Input/Output PINs | Aktiviert die Node-RED-Pins für den rohen Matter-Zugriff |
24
-
25
- ## Zuordnungen
26
-
27
- Die Ziel-Liste zeigt die unterstützten Funktionen mit verständlichen Namen wie *"Ein/Aus-Schalter"* oder *"Momentanleistung (W)"*, gefiltert nach dem, was das Gerät wirklich bereitstellt, mit dem aktuellen Wert in eckigen Klammern.
28
-
29
- Jede Zuordnungszeile hat eine **Richtung**:
30
-
31
- - **KNX → Matter (Befehl)**: Ein Telegramm auf der Gruppenadresse ruft einen Matter-Cluster-Befehl auf oder schreibt ein Attribut. Beispiel: GA `1/1/1` DPT 1.001 → `OnOff.on/off` (der boolesche Wert wählt automatisch Ein oder Aus).
32
- - **Matter → KNX (Status)**: Wenn sich das abonnierte Matter-Attribut ändert, wird sein Wert konvertiert und auf die Gruppenadresse geschrieben. `GroupValue_Read`-Anfragen werden mit dem zwischengespeicherten Wert beantwortet.
33
-
34
- Die gängigen Cluster werden automatisch in KNX-freundliche Werte konvertiert:
35
-
36
- |Cluster|Konvertierung|
37
- |--|--|
38
- | OnOff | boolesch (DPT 1.001) |
39
- | LevelControl | 0-254 ↔ Prozent (DPT 5.001) |
40
- | WindowCovering | percent100ths ↔ Prozent (DPT 5.001), Auf/Ab (DPT 1.008) |
41
- | ColorControl | Mired ↔ Kelvin (DPT 7.600) |
42
- | Thermostat | Zenti-°C ↔ °C (DPT 9.001) |
43
- | Temperatur/Feuchte | Zenti-Einheiten ↔ Einheiten (DPT 9.001/9.007) |
44
- | Beleuchtungsstärke | Log-Skala ↔ Lux (DPT 9.004) |
45
- | PowerSource | Halb-Prozent ↔ Batterie-Prozent (DPT 5.001) |
46
- | Elektrische Leistung/Energie | mW ↔ W (DPT 14.056), mWh ↔ kWh (DPT 13.013) |
47
-
48
- Andere Cluster/Attribute werden unverändert durchgereicht; der gewählte DPT übernimmt die finale KNX-Kodierung.
49
-
50
- ## Node-PINs
51
-
52
- Wenn du die Node-PINs aktivierst:
53
-
54
- - **Input**: sende rohe Befehle: `msg.payload = { endpointId: 1, clusterId: 6, command: "toggle" }` oder Attribut-Schreibzugriffe: `msg.payload = { endpointId: 1, clusterId: 8, attribute: "onLevel", value: 128 }`
55
- - **Output**: empfängt jede Attributänderung (`msg.matter` enthält das komplette Ereignis) und jedes Cluster-Ereignis (Tastendrücke usw.).
56
- </script>
@@ -1,109 +0,0 @@
1
- {
2
- "knxUltimateMatterDevice": {
3
- "title": "Matter-Gerät (BETA)",
4
- "paletteLabel": "Matter Device (BETA)",
5
- "matter_controller": "Matter Ctrl",
6
- "matter_device": "Gerät",
7
- "device_placeholder": "Klicken, um ein gekoppeltes Matter-Gerät auszuwählen",
8
- "mapping_help": "Füge pro Zuordnung eine Zeile hinzu. \"KNX → Matter\" ruft einen Cluster-Befehl auf (oder schreibt ein Attribut), wenn ein Telegramm auf der Gruppenadresse eintrifft. \"Matter → KNX\" schreibt den Attributwert bei jeder Änderung auf die Gruppenadresse (Leseanfragen werden mit dem zwischengespeicherten Wert beantwortet).",
9
- "select_target": "-- Matter-Ziel auswählen --",
10
- "stored_target": "Gespeichert",
11
- "read_status_startup": "Status beim Start lesen",
12
- "opt_yes_emit": "Ja, und KNX-Telegramme senden.",
13
- "opt_no": "Nein",
14
- "node_pins": "Node Input/Output PINs",
15
- "node_pins_hide": "Ausblenden",
16
- "node_pins_show": "Input/Output-PINs anzeigen",
17
- "direction": {
18
- "command": "KNX → Matter (Befehl)",
19
- "status": "Matter → KNX (Status)"
20
- },
21
- "fields": {
22
- "direction": "Richtung",
23
- "target": "Matter Endpoint / Cluster / Ziel",
24
- "ga": "Gruppenadresse",
25
- "dpt": "DPT",
26
- "ganame": "Name"
27
- },
28
- "no_simple_targets": "Keine unterstützten Funktionen auf diesem Gerät gefunden (oder das Gerät ist noch nicht verbunden).",
29
- "endpoint": "Endpoint",
30
- "friendly": {
31
- "onoff_switch": "Ein/Aus-Schalter (ein-/ausschalten)",
32
- "onoff_toggle": "Umschalten (Toggle)",
33
- "onoff_state": "Ein/Aus-Status",
34
- "level_set": "Helligkeit / Stufe setzen (%)",
35
- "level_state": "Aktuelle Helligkeit / Stufe (%)",
36
- "colortemp_set": "Farbtemperatur setzen (Kelvin)",
37
- "colortemp_state": "Aktuelle Farbtemperatur (Kelvin)",
38
- "cover_updown": "Rollladen Auf/Ab",
39
- "cover_stop": "Rollladen Stopp",
40
- "cover_position_set": "Rollladen auf Position fahren (%)",
41
- "cover_position_state": "Aktuelle Rollladenposition (%)",
42
- "cover_tilt_set": "Lamellen neigen (%)",
43
- "cover_tilt_state": "Aktuelle Lamellenneigung (%)",
44
- "thermo_localtemp": "Raumtemperatur (°C)",
45
- "thermo_heatsp_set": "Heiz-Sollwert setzen (°C)",
46
- "thermo_coolsp_set": "Kühl-Sollwert setzen (°C)",
47
- "thermo_heatsp_state": "Heiz-Sollwert (°C)",
48
- "thermo_coolsp_state": "Kühl-Sollwert (°C)",
49
- "fan_speed_set": "Lüftergeschwindigkeit setzen (%)",
50
- "fan_speed_state": "Aktuelle Lüftergeschwindigkeit (%)",
51
- "lock_cmd": "Tür ver-/entriegeln",
52
- "lock_state": "Schlossstatus (verriegelt)",
53
- "temp_measured": "Gemessene Temperatur (°C)",
54
- "humidity_measured": "Relative Luftfeuchte (%)",
55
- "illuminance_measured": "Beleuchtungsstärke (Lux)",
56
- "occupancy_state": "Anwesenheit erkannt",
57
- "contact_state": "Kontaktstatus (geschlossen/offen)",
58
- "battery_percent": "Batteriestand (%)",
59
- "power_active": "Momentanleistung (W)",
60
- "power_voltage": "Spannung (V)",
61
- "power_current": "Strom (A)",
62
- "energy_imported": "Energieverbrauch (kWh)",
63
- "identify_cmd": "Gerät identifizieren (blinken)",
64
- "switch_position": "Tastenposition"
65
- },
66
- "devtype": {
67
- "onofflight": "Ein/Aus-Licht",
68
- "dimmablelight": "Dimmbares Licht",
69
- "colortemperaturelight": "Licht mit Farbtemperatur",
70
- "extendedcolorlight": "Farblicht",
71
- "onoffpluginunit": "Steckdose (Ein/Aus)",
72
- "dimmablepluginunit": "Steckdose (dimmbar)",
73
- "smartplug": "Smarte Steckdose",
74
- "contactsensor": "Kontaktsensor",
75
- "lightsensor": "Lichtsensor",
76
- "occupancysensor": "Präsenzsensor",
77
- "temperaturesensor": "Temperatursensor",
78
- "humiditysensor": "Feuchtesensor",
79
- "pressuresensor": "Drucksensor",
80
- "flowsensor": "Durchflusssensor",
81
- "doorlock": "Türschloss",
82
- "windowcovering": "Rollladen/Jalousie",
83
- "thermostat": "Thermostat",
84
- "fan": "Ventilator",
85
- "genericswitch": "Taster/Schalter",
86
- "airqualitysensor": "Luftqualitätssensor",
87
- "smokecoalarm": "Rauch-/CO-Melder",
88
- "waterleakdetector": "Wasserleckmelder",
89
- "roomairconditioner": "Klimagerät",
90
- "airpurifier": "Luftreiniger",
91
- "speaker": "Lautsprecher",
92
- "pumpcontroller": "Pumpe",
93
- "onofflightswitch": "Lichtschalter",
94
- "dimmerswitch": "Dimmerschalter",
95
- "colordimmerswitch": "Farbdimmerschalter",
96
- "powersource": "Stromversorgung",
97
- "electricalsensor": "Elektrischer Sensor",
98
- "bridgednode": "Bridged-Gerät",
99
- "aggregator": "Bridge/Aggregator",
100
- "rootnode": "Root-Node"
101
- }
102
- },
103
- "common": {
104
- "ga": "GA",
105
- "dpt": "DPT",
106
- "name": "Name",
107
- "knx_gw": "KNX GW"
108
- }
109
- }
@@ -1,56 +0,0 @@
1
- <script type="text/markdown" data-help-name="knxUltimateMatterDevice">
2
- # Matter Device (BETA)
3
-
4
- > This node is in **BETA**: it works, but details may still change between releases.
5
-
6
- ## Overview
7
-
8
- The Matter Device node bridges a **Matter device** to **KNX group addresses**. The node acts through the *Matter Controller* configuration node, which commissions (pairs) the devices into its own Matter fabric.
9
-
10
- - **Control** any commissioned Matter device from the KNX bus (on/off, dimming, covers, thermostats, locks, ...).
11
- - **Track** every attribute of the device on KNX group addresses (status feedback, sensors, power metering, battery...).
12
- - Fully generic: the mapping list is built from the **real endpoints/clusters** exposed by the device.
13
-
14
- ## Configuration
15
-
16
- |Field|Description|
17
- |--|--|
18
- | KNX GW | KNX gateway used for telegrams |
19
- | Matter Ctrl | The Matter Controller configuration node (where you pair the devices) |
20
- | Device | Pick the commissioned Matter device from the autocomplete list |
21
- | Mappings | One row per group address ↔ Matter cluster mapping |
22
- | Read status at startup | When enabled, the node emits the current cached values on deploy/connection |
23
- | Node Input/Output PINs | Enable Node-RED input/output pins for raw Matter access |
24
-
25
- ## Mappings
26
-
27
- The target list shows the supported functions with friendly names such as *"On/Off switch"* or *"Instantaneous power (W)"*, filtered on what the device really exposes and with the current value shown in brackets.
28
-
29
- Each mapping row has a **direction**:
30
-
31
- - **KNX → Matter (command)**: a telegram received on the group address invokes a Matter cluster command or writes an attribute. Example: GA `1/1/1` DPT 1.001 → `OnOff.on/off` (the boolean payload selects on or off automatically).
32
- - **Matter → KNX (status)**: whenever the subscribed Matter attribute changes, its value is converted and written to the group address. `GroupValue_Read` requests are answered with the cached value.
33
-
34
- Well-known clusters are converted automatically to KNX-friendly values:
35
-
36
- |Cluster|Conversion|
37
- |--|--|
38
- | OnOff | boolean (DPT 1.001) |
39
- | LevelControl | 0-254 ↔ percent (DPT 5.001) |
40
- | WindowCovering | percent100ths ↔ percent (DPT 5.001), up/down (DPT 1.008) |
41
- | ColorControl | mireds ↔ Kelvin (DPT 7.600) |
42
- | Thermostat | centi-°C ↔ °C (DPT 9.001) |
43
- | Temperature/Humidity | centi-units ↔ units (DPT 9.001/9.007) |
44
- | Illuminance | log scale ↔ Lux (DPT 9.004) |
45
- | PowerSource | half-percent ↔ percent battery (DPT 5.001) |
46
- | Electrical Power/Energy | mW ↔ W (DPT 14.056), mWh ↔ kWh (DPT 13.013) |
47
-
48
- Other clusters/attributes are passed through raw; the DPT you pick performs the final KNX encoding.
49
-
50
- ## Node PINs
51
-
52
- If you enable the node PINs:
53
-
54
- - **Input**: send raw commands: `msg.payload = { endpointId: 1, clusterId: 6, command: "toggle" }` or attribute writes: `msg.payload = { endpointId: 1, clusterId: 8, attribute: "onLevel", value: 128 }`
55
- - **Output**: receives every attribute change (`msg.matter` contains the full event) and every cluster event (button presses etc.).
56
- </script>
@@ -1,109 +0,0 @@
1
- {
2
- "knxUltimateMatterDevice": {
3
- "title": "Matter Device (BETA)",
4
- "paletteLabel": "Matter Device (BETA)",
5
- "matter_controller": "Matter Ctrl",
6
- "matter_device": "Device",
7
- "device_placeholder": "Click to pick a paired Matter device",
8
- "mapping_help": "Add one row per mapping. \"KNX → Matter\" invokes a cluster command (or writes an attribute) when a telegram arrives on the group address. \"Matter → KNX\" writes the attribute value to the group address whenever it changes (read requests are answered with the cached value).",
9
- "select_target": "-- select the Matter target --",
10
- "stored_target": "Stored",
11
- "read_status_startup": "Read status at startup",
12
- "opt_yes_emit": "Yes, and emit KNX telegrams.",
13
- "opt_no": "No",
14
- "node_pins": "Node Input/Output PINs",
15
- "node_pins_hide": "Hide",
16
- "node_pins_show": "Show node input/output PINs",
17
- "direction": {
18
- "command": "KNX → Matter (command)",
19
- "status": "Matter → KNX (status)"
20
- },
21
- "fields": {
22
- "direction": "Direction",
23
- "target": "Matter endpoint / cluster / target",
24
- "ga": "Group address",
25
- "dpt": "DPT",
26
- "ganame": "Name"
27
- },
28
- "no_simple_targets": "No supported functions found on this device (or the device is not connected yet).",
29
- "endpoint": "Endpoint",
30
- "friendly": {
31
- "onoff_switch": "On/Off switch (turn on/off)",
32
- "onoff_toggle": "Toggle (invert state)",
33
- "onoff_state": "On/Off state",
34
- "level_set": "Set brightness / level (%)",
35
- "level_state": "Current brightness / level (%)",
36
- "colortemp_set": "Set color temperature (Kelvin)",
37
- "colortemp_state": "Current color temperature (Kelvin)",
38
- "cover_updown": "Cover Up/Down",
39
- "cover_stop": "Cover Stop",
40
- "cover_position_set": "Move cover to position (%)",
41
- "cover_position_state": "Current cover position (%)",
42
- "cover_tilt_set": "Move slats to tilt (%)",
43
- "cover_tilt_state": "Current slat tilt (%)",
44
- "thermo_localtemp": "Room temperature (°C)",
45
- "thermo_heatsp_set": "Set heating setpoint (°C)",
46
- "thermo_coolsp_set": "Set cooling setpoint (°C)",
47
- "thermo_heatsp_state": "Heating setpoint (°C)",
48
- "thermo_coolsp_state": "Cooling setpoint (°C)",
49
- "fan_speed_set": "Set fan speed (%)",
50
- "fan_speed_state": "Current fan speed (%)",
51
- "lock_cmd": "Lock/Unlock door",
52
- "lock_state": "Lock state (locked)",
53
- "temp_measured": "Measured temperature (°C)",
54
- "humidity_measured": "Relative humidity (%)",
55
- "illuminance_measured": "Illuminance (Lux)",
56
- "occupancy_state": "Presence detected",
57
- "contact_state": "Contact state (closed/open)",
58
- "battery_percent": "Battery level (%)",
59
- "power_active": "Instantaneous power (W)",
60
- "power_voltage": "Voltage (V)",
61
- "power_current": "Current (A)",
62
- "energy_imported": "Energy consumed (kWh)",
63
- "identify_cmd": "Identify device (blink)",
64
- "switch_position": "Button position"
65
- },
66
- "devtype": {
67
- "onofflight": "On/Off light",
68
- "dimmablelight": "Dimmable light",
69
- "colortemperaturelight": "Color temperature light",
70
- "extendedcolorlight": "Color light",
71
- "onoffpluginunit": "Plug (on/off)",
72
- "dimmablepluginunit": "Plug (dimmable)",
73
- "smartplug": "Smart plug",
74
- "contactsensor": "Contact sensor",
75
- "lightsensor": "Light sensor",
76
- "occupancysensor": "Occupancy sensor",
77
- "temperaturesensor": "Temperature sensor",
78
- "humiditysensor": "Humidity sensor",
79
- "pressuresensor": "Pressure sensor",
80
- "flowsensor": "Flow sensor",
81
- "doorlock": "Door lock",
82
- "windowcovering": "Window covering",
83
- "thermostat": "Thermostat",
84
- "fan": "Fan",
85
- "genericswitch": "Button/Switch",
86
- "airqualitysensor": "Air quality sensor",
87
- "smokecoalarm": "Smoke/CO alarm",
88
- "waterleakdetector": "Water leak detector",
89
- "roomairconditioner": "Air conditioner",
90
- "airpurifier": "Air purifier",
91
- "speaker": "Speaker",
92
- "pumpcontroller": "Pump",
93
- "onofflightswitch": "Light switch",
94
- "dimmerswitch": "Dimmer switch",
95
- "colordimmerswitch": "Color dimmer switch",
96
- "powersource": "Power source",
97
- "electricalsensor": "Electrical sensor",
98
- "bridgednode": "Bridged device",
99
- "aggregator": "Bridge/Aggregator",
100
- "rootnode": "Root node"
101
- }
102
- },
103
- "common": {
104
- "ga": "GA",
105
- "dpt": "DPT",
106
- "name": "Name",
107
- "knx_gw": "KNX GW"
108
- }
109
- }