node-red-contrib-knx-ultimate 6.3.13 → 6.3.14
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 +4 -0
- package/nodes/knxUltimateMatterBridge.html +19 -2
- package/nodes/knxUltimateMatterBridge.js +18 -3
- package/nodes/locales/de/knxUltimateMatterBridge.html +3 -1
- package/nodes/locales/de/knxUltimateMatterBridge.json +5 -1
- package/nodes/locales/en/knxUltimateMatterBridge.html +3 -1
- package/nodes/locales/en/knxUltimateMatterBridge.json +5 -1
- package/nodes/locales/es/knxUltimateMatterBridge.html +3 -1
- package/nodes/locales/es/knxUltimateMatterBridge.json +5 -1
- package/nodes/locales/fr/knxUltimateMatterBridge.html +3 -1
- package/nodes/locales/fr/knxUltimateMatterBridge.json +5 -1
- package/nodes/locales/it/knxUltimateMatterBridge.html +3 -1
- package/nodes/locales/it/knxUltimateMatterBridge.json +5 -1
- package/nodes/locales/zh-CN/knxUltimateMatterBridge.html +3 -1
- package/nodes/locales/zh-CN/knxUltimateMatterBridge.json +5 -1
- package/nodes/utils/matterBridgeDeviceFactory.mjs +130 -65
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,10 @@
|
|
|
6
6
|
|
|
7
7
|
# CHANGELOG
|
|
8
8
|
|
|
9
|
+
**Version 6.3.14** - August 2026<br/>
|
|
10
|
+
|
|
11
|
+
- **Expose KNX to Matter — Room Air Conditioner and Door Lock**: added native Matter **Room Air Conditioner** (`0x0072`) and **Door Lock** (`0x000A`) profiles. A room AC combines On/Off, current temperature, heating/cooling setpoints and fan speed in one endpoint; a door lock maps separate Lock/Unlock command and Locked/Unlocked status GAs. Both profiles support KNX or flow-backed state updates without feedback loops, with editor help and documentation in EN/IT/DE/FR/ES/zh-CN.<br/>
|
|
12
|
+
|
|
9
13
|
**Version 6.3.13** - August 2026<br/>
|
|
10
14
|
|
|
11
15
|
- **Matter**: promoted Matter Controller, Matter Bridge and Expose KNX to Matter from BETA to production-ready status; removed BETA labels and experimental warnings from the palette, editor help, examples and multilingual documentation while retaining pairing, backup and endpoint-structure safety guidance.<br/>
|
|
@@ -54,6 +54,21 @@
|
|
|
54
54
|
{ key: 'CoolingSetpoint', labelKey: 'fn_coolingsetpoint_cmd', dptPrefix: '9.', fallbackDpt: '9.001' },
|
|
55
55
|
{ key: 'CoolingSetpointStatus', labelKey: 'fn_coolingsetpoint_status', dptPrefix: '9.', fallbackDpt: '9.001' }
|
|
56
56
|
],
|
|
57
|
+
roomairconditioner: [
|
|
58
|
+
{ key: 'OnOff', labelKey: 'fn_onoff_cmd', dptPrefix: '1.', fallbackDpt: '1.001' },
|
|
59
|
+
{ key: 'OnOffStatus', labelKey: 'fn_onoff_status', dptPrefix: '1.', fallbackDpt: '1.001' },
|
|
60
|
+
{ key: 'CurrentTemp', labelKey: 'fn_currenttemp', dptPrefix: '9.', fallbackDpt: '9.001' },
|
|
61
|
+
{ key: 'Setpoint', labelKey: 'fn_setpoint_cmd', dptPrefix: '9.', fallbackDpt: '9.001' },
|
|
62
|
+
{ key: 'SetpointStatus', labelKey: 'fn_setpoint_status', dptPrefix: '9.', fallbackDpt: '9.001' },
|
|
63
|
+
{ key: 'CoolingSetpoint', labelKey: 'fn_coolingsetpoint_cmd', dptPrefix: '9.', fallbackDpt: '9.001' },
|
|
64
|
+
{ key: 'CoolingSetpointStatus', labelKey: 'fn_coolingsetpoint_status', dptPrefix: '9.', fallbackDpt: '9.001' },
|
|
65
|
+
{ key: 'FanSpeed', labelKey: 'fn_fanspeed_cmd', dptPrefix: '5.', fallbackDpt: '5.001' },
|
|
66
|
+
{ key: 'FanSpeedStatus', labelKey: 'fn_fanspeed_status', dptPrefix: '5.', fallbackDpt: '5.001' }
|
|
67
|
+
],
|
|
68
|
+
doorlock: [
|
|
69
|
+
{ key: 'Lock', labelKey: 'fn_lock_cmd', dptPrefix: '1.', fallbackDpt: '1.001' },
|
|
70
|
+
{ key: 'LockStatus', labelKey: 'fn_lock_status', dptPrefix: '1.', fallbackDpt: '1.001' }
|
|
71
|
+
],
|
|
57
72
|
smokecoalarm: [
|
|
58
73
|
{ key: 'Smoke', labelKey: 'fn_smoke_ga', dptPrefix: '1.', fallbackDpt: '1.005' },
|
|
59
74
|
{ key: 'CO', labelKey: 'fn_co_ga', dptPrefix: '1.', fallbackDpt: '1.005' }
|
|
@@ -66,7 +81,7 @@
|
|
|
66
81
|
],
|
|
67
82
|
robotvacuum: [] // Flow-only: no GA fields, controlled via the node PINs
|
|
68
83
|
};
|
|
69
|
-
const TYPE_ORDER = ['onofflight', 'dimmablelight', 'rgblight', 'colortemperaturelight', 'onoffplug', 'windowcovering', 'thermostat', 'fan', 'temperaturesensor', 'humiditysensor', 'lightsensor', 'occupancysensor', 'contactsensor', 'smokecoalarm', 'waterleakdetector', 'airqualitysensor', 'robotvacuum'];
|
|
84
|
+
const TYPE_ORDER = ['onofflight', 'dimmablelight', 'rgblight', 'colortemperaturelight', 'onoffplug', 'windowcovering', 'thermostat', 'roomairconditioner', 'fan', 'doorlock', 'temperaturesensor', 'humiditysensor', 'lightsensor', 'occupancysensor', 'contactsensor', 'smokecoalarm', 'waterleakdetector', 'airqualitysensor', 'robotvacuum'];
|
|
70
85
|
const FLOW_HELP = {
|
|
71
86
|
onofflight: { input: [['onoff', true]], output: [['onoff', true]] },
|
|
72
87
|
onoffplug: { input: [['onoff', true]], output: [['onoff', true]] },
|
|
@@ -80,6 +95,8 @@
|
|
|
80
95
|
contactsensor: { input: [['contact', true]], output: [] },
|
|
81
96
|
windowcovering: { input: [['position', 35]], output: [['updown', false], ['position', 35], ['stop', true]] },
|
|
82
97
|
thermostat: { input: [['currenttemp', 21.5], ['setpoint', 21], ['coolingsetpoint', 24]], output: [['setpoint', 21], ['coolingsetpoint', 24]] },
|
|
98
|
+
roomairconditioner: { input: [['onoff', true], ['currenttemp', 25.5], ['setpoint', 21], ['coolingsetpoint', 24], ['fanspeed', 60]], output: [['onoff', true], ['setpoint', 21], ['coolingsetpoint', 24], ['fanspeed', 60]] },
|
|
99
|
+
doorlock: { input: [['lock', true]], output: [['lock', true]] },
|
|
83
100
|
smokecoalarm: { input: [['smoke', true], ['co', true]], output: [] },
|
|
84
101
|
waterleakdetector: { input: [['leak', true]], output: [] },
|
|
85
102
|
airqualitysensor: { input: [['co2', 850]], output: [] },
|
|
@@ -379,7 +396,7 @@
|
|
|
379
396
|
const isCover = selected === 'windowcovering';
|
|
380
397
|
// The Alexa duplicate-command dedup applies to any device that emits On/Off or
|
|
381
398
|
// level commands (plain on/off lights and plugs included), not just dimmers.
|
|
382
|
-
const hasCommand = selected === 'onofflight' || selected === 'onoffplug' || hasLevel;
|
|
399
|
+
const hasCommand = selected === 'onofflight' || selected === 'onoffplug' || selected === 'roomairconditioner' || hasLevel;
|
|
383
400
|
$advancedRows.toggle(hasCommand || isCover);
|
|
384
401
|
$commandAdvancedRows.toggle(hasCommand);
|
|
385
402
|
$dimmerAdvancedRows.toggle(hasLevel);
|
|
@@ -55,6 +55,21 @@ module.exports = function (RED) {
|
|
|
55
55
|
{ fn: 'coolingsetpoint', direction: 'command', ga: 'gaCoolingSetpoint', dpt: 'dptCoolingSetpoint', fallbackDpt: '9.001' },
|
|
56
56
|
{ fn: 'coolingsetpoint', direction: 'status', ga: 'gaCoolingSetpointStatus', dpt: 'dptCoolingSetpointStatus', fallbackDpt: '9.001' }
|
|
57
57
|
],
|
|
58
|
+
roomairconditioner: [
|
|
59
|
+
{ fn: 'onoff', direction: 'command', ga: 'gaOnOff', dpt: 'dptOnOff', fallbackDpt: '1.001' },
|
|
60
|
+
{ fn: 'onoff', direction: 'status', ga: 'gaOnOffStatus', dpt: 'dptOnOffStatus', fallbackDpt: '1.001' },
|
|
61
|
+
{ fn: 'currenttemp', direction: 'status', ga: 'gaCurrentTemp', dpt: 'dptCurrentTemp', fallbackDpt: '9.001' },
|
|
62
|
+
{ fn: 'setpoint', direction: 'command', ga: 'gaSetpoint', dpt: 'dptSetpoint', fallbackDpt: '9.001' },
|
|
63
|
+
{ fn: 'setpoint', direction: 'status', ga: 'gaSetpointStatus', dpt: 'dptSetpointStatus', fallbackDpt: '9.001' },
|
|
64
|
+
{ fn: 'coolingsetpoint', direction: 'command', ga: 'gaCoolingSetpoint', dpt: 'dptCoolingSetpoint', fallbackDpt: '9.001' },
|
|
65
|
+
{ fn: 'coolingsetpoint', direction: 'status', ga: 'gaCoolingSetpointStatus', dpt: 'dptCoolingSetpointStatus', fallbackDpt: '9.001' },
|
|
66
|
+
{ fn: 'fanspeed', direction: 'command', ga: 'gaFanSpeed', dpt: 'dptFanSpeed', fallbackDpt: '5.001' },
|
|
67
|
+
{ fn: 'fanspeed', direction: 'status', ga: 'gaFanSpeedStatus', dpt: 'dptFanSpeedStatus', fallbackDpt: '5.001' }
|
|
68
|
+
],
|
|
69
|
+
doorlock: [
|
|
70
|
+
{ fn: 'lock', direction: 'command', ga: 'gaLock', dpt: 'dptLock', fallbackDpt: '1.001' },
|
|
71
|
+
{ fn: 'lock', direction: 'status', ga: 'gaLockStatus', dpt: 'dptLockStatus', fallbackDpt: '1.001' }
|
|
72
|
+
],
|
|
58
73
|
smokecoalarm: [
|
|
59
74
|
{ fn: 'smoke', direction: 'status', ga: 'gaSmoke', dpt: 'dptSmoke', fallbackDpt: '1.005' },
|
|
60
75
|
{ fn: 'co', direction: 'status', ga: 'gaCO', dpt: 'dptCO', fallbackDpt: '1.005' }
|
|
@@ -275,9 +290,9 @@ module.exports = function (RED) {
|
|
|
275
290
|
coverSliderDebounceMs: node.coverSliderDebounceMs,
|
|
276
291
|
commandDedupMs: node.commandDedupMs,
|
|
277
292
|
coverUpdateMode: node.coverUpdateMode,
|
|
278
|
-
// Thermostat
|
|
279
|
-
// configured, so the bridge engine can build a Heating-only,
|
|
280
|
-
// ThermostatServer without a dedicated
|
|
293
|
+
// Thermostat/Room Air Conditioner: whether a heating/cooling setpoint GA (command
|
|
294
|
+
// or status) was configured, so the bridge engine can build a Heating-only,
|
|
295
|
+
// Cooling-only or dual ThermostatServer without a dedicated mode dropdown.
|
|
281
296
|
hasHeatingSetpoint: devConfigValue('gaSetpoint') !== '' || devConfigValue('gaSetpointStatus') !== '',
|
|
282
297
|
hasCoolingSetpoint: devConfigValue('gaCoolingSetpoint') !== '' || devConfigValue('gaCoolingSetpointStatus') !== ''
|
|
283
298
|
})
|
|
@@ -27,7 +27,9 @@ Das Ändern des Gerätetyps nach der Kopplung der Bridge verändert die Matter-E
|
|
|
27
27
|
| Tunable-White-Licht | + Farbtemperatur Befehls-/Status-GA in Kelvin (DPT 7.600) |
|
|
28
28
|
| Rollladen / Jalousie | Auf/Ab (DPT 1.008), Stopp (DPT 1.017), Position % Befehl/Status (DPT 5.001), optionale Positionsumkehr |
|
|
29
29
|
| Thermostat (Heizung und/oder Kühlung) | GA aktuelle Temperatur, Sollwert Befehls-/Status-GA (DPT 9.001). Mit zusätzlichem Kühl-Sollwert Befehls-/Status-GA wird auch der Kühlmodus (Doppel-Sollwert) bereitgestellt |
|
|
30
|
+
| Raumklimagerät | Ein Matter-Gerät kombiniert Ein/Aus (DPT 1.001), aktuelle Temperatur und Heiz-/Kühl-Sollwerte (DPT 9.001) sowie Lüftergeschwindigkeit % (DPT 5.001), jeweils als Befehls-/Status-GA |
|
|
30
31
|
| Ventilator / Lüftung | Geschwindigkeit % Befehls-/Status-GA (DPT 5.001) |
|
|
32
|
+
| Türschloss | Verriegeln/Entriegeln Befehls-GA und Verriegelt/Entriegelt Status-GA (DPT 1.001; `true` = verriegelt) |
|
|
31
33
|
| Sensoren (Temperatur, Feuchte, Licht, Präsenz, Kontakt) | Je eine Status-GA |
|
|
32
34
|
| Rauch-/CO-Melder | Rauchalarm Status-GA + optionale CO-Alarm Status-GA (DPT 1.005): kritische Benachrichtigungen auf dem Telefon |
|
|
33
35
|
| Wasserleckmelder | Leckage Status-GA (DPT 1.005) |
|
|
@@ -45,7 +47,7 @@ Diese Optionen werden nur angezeigt, wenn sie zum gewählten Typ passen. Dimmbar
|
|
|
45
47
|
|
|
46
48
|
Der PIN-Selektor befindet sich außerhalb der Editor-Tabs. Nach dem Aktivieren erscheint direkt darunter ein kontextbezogener Bereich **Flow-Eingang/-Ausgang** mit kopierbaren Beispielen für den ausgewählten Gerätetyp:
|
|
47
49
|
|
|
48
|
-
- **Input**: aktualisiere den Matter-Zustand aus dem Flow, ohne den KNX-Bus: `msg.payload = { function: "onoff", value: true }` (`function` ist eine von `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `fanspeed`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Nützlich, um im Flow berechnete Werte (z.B. einen virtuellen Sensor) für Alexa & Co. bereitzustellen.
|
|
50
|
+
- **Input**: aktualisiere den Matter-Zustand aus dem Flow, ohne den KNX-Bus: `msg.payload = { function: "onoff", value: true }` (`function` ist eine von `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `coolingsetpoint`, `fanspeed`, `lock`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Nützlich, um im Flow berechnete Werte (z.B. einen virtuellen Sensor) für Alexa & Co. bereitzustellen.
|
|
49
51
|
- **Output**: Jeder von einem Matter-Controller empfangene Befehl wird an den Flow weitergeleitet: `msg.topic` = Gerätename, `msg.payload` = Wert, `msg.matter` = der rohe Befehl. Ein Gerät ohne Befehls-GAs wird zum **Nur-Flow-Gerät**.
|
|
50
52
|
|
|
51
53
|
## Hinweise
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
"fn_leak_ga": "Leckage Status-GA",
|
|
75
75
|
"fn_co2_ga": "CO2 Status-GA (ppm, DPT 9.008)",
|
|
76
76
|
"fn_fanspeed_cmd": "Lüftergeschwindigkeit % Befehls-GA",
|
|
77
|
-
"fn_fanspeed_status": "Lüftergeschwindigkeit % Status-GA"
|
|
77
|
+
"fn_fanspeed_status": "Lüftergeschwindigkeit % Status-GA",
|
|
78
|
+
"fn_lock_cmd": "Verriegeln/Entriegeln Befehls-GA",
|
|
79
|
+
"fn_lock_status": "Verriegelt/Entriegelt Status-GA"
|
|
78
80
|
},
|
|
79
81
|
"types": {
|
|
80
82
|
"onofflight": "Ein/Aus-Licht",
|
|
@@ -89,7 +91,9 @@
|
|
|
89
91
|
"contactsensor": "Kontaktsensor",
|
|
90
92
|
"windowcovering": "Rollladen / Jalousie",
|
|
91
93
|
"thermostat": "Thermostat (Heizung)",
|
|
94
|
+
"roomairconditioner": "Raumklimagerät",
|
|
92
95
|
"fan": "Ventilator / Lüftung",
|
|
96
|
+
"doorlock": "Türschloss",
|
|
93
97
|
"smokecoalarm": "Rauch-/CO-Melder",
|
|
94
98
|
"waterleakdetector": "Wasserleckmelder",
|
|
95
99
|
"airqualitysensor": "Luftqualitätssensor (CO2)",
|
|
@@ -27,7 +27,9 @@ Changing the device type after the bridge has been paired changes the Matter end
|
|
|
27
27
|
| Tunable white light | + Color temperature command/status GA in Kelvin (DPT 7.600) |
|
|
28
28
|
| Cover / Shutter | Up/Down (DPT 1.008), Stop (DPT 1.017), Position % command/status (DPT 5.001), optional position inversion |
|
|
29
29
|
| Thermostat (heating and/or cooling) | Current temperature GA, Setpoint command/status GA (DPT 9.001). Optionally add a Cooling setpoint command/status GA to also expose a Cool mode (dual-setpoint) |
|
|
30
|
+
| Room air conditioner | One Matter device combining On/Off (DPT 1.001), current temperature and heating/cooling setpoints (DPT 9.001), and fan speed % (DPT 5.001) command/status GAs |
|
|
30
31
|
| Fan / Ventilation | Fan speed % command/status GA (DPT 5.001) |
|
|
32
|
+
| Door lock | Lock/Unlock command GA and Locked/Unlocked status GA (DPT 1.001; `true` = locked) |
|
|
31
33
|
| Sensors (temperature, humidity, light, occupancy, contact) | One status GA each |
|
|
32
34
|
| Smoke/CO alarm | Smoke alarm status GA + optional CO alarm status GA (DPT 1.005): critical notifications on the phone |
|
|
33
35
|
| Water leak detector | Leak status GA (DPT 1.005) |
|
|
@@ -45,7 +47,7 @@ These options are hidden unless they apply to the selected type. Dimmable device
|
|
|
45
47
|
|
|
46
48
|
The PIN selector is outside the editor tabs. Enabling it reveals a contextual **Flow input/output** section directly below, with copyable examples filtered to the selected device type:
|
|
47
49
|
|
|
48
|
-
- **Input**: update the Matter state from the flow, without the KNX bus: `msg.payload = { function: "onoff", value: true }` (`function` is one of `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `fanspeed`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Useful to expose flow-computed values (e.g. a virtual sensor) to Alexa & Co.
|
|
50
|
+
- **Input**: update the Matter state from the flow, without the KNX bus: `msg.payload = { function: "onoff", value: true }` (`function` is one of `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `coolingsetpoint`, `fanspeed`, `lock`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Useful to expose flow-computed values (e.g. a virtual sensor) to Alexa & Co.
|
|
49
51
|
- **Output**: every command received from a Matter controller is forwarded to the flow: `msg.topic` = device name, `msg.payload` = value, `msg.matter` = the raw command. A device without command GAs becomes a **flow-only device**.
|
|
50
52
|
|
|
51
53
|
## Notes
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
"fn_leak_ga": "Leak status GA",
|
|
75
75
|
"fn_co2_ga": "CO2 status GA (ppm, DPT 9.008)",
|
|
76
76
|
"fn_fanspeed_cmd": "Fan speed % command GA",
|
|
77
|
-
"fn_fanspeed_status": "Fan speed % status GA"
|
|
77
|
+
"fn_fanspeed_status": "Fan speed % status GA",
|
|
78
|
+
"fn_lock_cmd": "Lock/Unlock command GA",
|
|
79
|
+
"fn_lock_status": "Locked/Unlocked status GA"
|
|
78
80
|
},
|
|
79
81
|
"types": {
|
|
80
82
|
"onofflight": "On/Off light",
|
|
@@ -89,7 +91,9 @@
|
|
|
89
91
|
"contactsensor": "Contact sensor",
|
|
90
92
|
"windowcovering": "Cover / Shutter",
|
|
91
93
|
"thermostat": "Thermostat (heating)",
|
|
94
|
+
"roomairconditioner": "Room air conditioner",
|
|
92
95
|
"fan": "Fan / Ventilation",
|
|
96
|
+
"doorlock": "Door lock",
|
|
93
97
|
"smokecoalarm": "Smoke/CO alarm",
|
|
94
98
|
"waterleakdetector": "Water leak detector",
|
|
95
99
|
"airqualitysensor": "Air quality sensor (CO2)",
|
|
@@ -27,7 +27,9 @@ Cambiar el tipo de dispositivo después de emparejar el bridge modifica la estru
|
|
|
27
27
|
| Luz blanco dinámico | + GA comando/estado temperatura de color en Kelvin (DPT 7.600) |
|
|
28
28
|
| Persiana / Cortina | Subir/Bajar (DPT 1.008), Stop (DPT 1.017), posición % comando/estado (DPT 5.001), inversión de posición opcional |
|
|
29
29
|
| Termostato (calefacción y/o refrigeración) | GA temperatura actual, GA comando/estado consigna (DPT 9.001). Añadiendo también la GA comando/estado consigna de refrigeración se expone también el modo Cool (doble consigna) |
|
|
30
|
+
| Aire acondicionado de habitación | Un dispositivo Matter combina GA comando/estado On/Off (DPT 1.001), temperatura actual y consignas de calefacción/refrigeración (DPT 9.001), y velocidad del ventilador % (DPT 5.001) |
|
|
30
31
|
| Ventilador / VMC | GA comando/estado velocidad % (DPT 5.001) |
|
|
32
|
+
| Cerradura de puerta | GA comando bloqueo/desbloqueo y GA estado bloqueado/desbloqueado (DPT 1.001; `true` = bloqueada) |
|
|
31
33
|
| Sensores (temperatura, humedad, luz, presencia, contacto) | Una GA de estado cada uno |
|
|
32
34
|
| Alarma humo/CO | GA estado alarma de humo + GA estado alarma CO opcional (DPT 1.005): notificaciones críticas en el teléfono |
|
|
33
35
|
| Detector de fugas de agua | GA estado fuga (DPT 1.005) |
|
|
@@ -45,7 +47,7 @@ Estas opciones solo aparecen cuando tienen sentido para el tipo seleccionado. Lo
|
|
|
45
47
|
|
|
46
48
|
El selector de PINes está fuera de las pestañas del editor. Al activarlo aparece justo debajo una sección contextual **Entrada/salida del flow**, con ejemplos copiables filtrados según el tipo de dispositivo:
|
|
47
49
|
|
|
48
|
-
- **Entrada**: actualiza el estado Matter desde el flow, sin pasar por el bus KNX: `msg.payload = { function: "onoff", value: true }` (`function` es una de `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `fanspeed`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Útil para exponer a Alexa y cía. valores calculados en el flow (p.ej. un sensor virtual).
|
|
50
|
+
- **Entrada**: actualiza el estado Matter desde el flow, sin pasar por el bus KNX: `msg.payload = { function: "onoff", value: true }` (`function` es una de `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `coolingsetpoint`, `fanspeed`, `lock`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Útil para exponer a Alexa y cía. valores calculados en el flow (p.ej. un sensor virtual).
|
|
49
51
|
- **Salida**: cada comando recibido de un controlador Matter se reenvía al flow: `msg.topic` = nombre del dispositivo, `msg.payload` = valor, `msg.matter` = el comando en bruto. Un dispositivo sin GA de comando se convierte en un **dispositivo solo-flow**.
|
|
50
52
|
|
|
51
53
|
## Notas
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
"fn_leak_ga": "GA estado fuga de agua",
|
|
75
75
|
"fn_co2_ga": "GA estado CO2 (ppm, DPT 9.008)",
|
|
76
76
|
"fn_fanspeed_cmd": "GA comando velocidad ventilador %",
|
|
77
|
-
"fn_fanspeed_status": "GA estado velocidad ventilador %"
|
|
77
|
+
"fn_fanspeed_status": "GA estado velocidad ventilador %",
|
|
78
|
+
"fn_lock_cmd": "GA comando bloqueo/desbloqueo",
|
|
79
|
+
"fn_lock_status": "GA estado bloqueado/desbloqueado"
|
|
78
80
|
},
|
|
79
81
|
"types": {
|
|
80
82
|
"onofflight": "Luz On/Off",
|
|
@@ -89,7 +91,9 @@
|
|
|
89
91
|
"contactsensor": "Sensor de contacto",
|
|
90
92
|
"windowcovering": "Persiana / Cortina",
|
|
91
93
|
"thermostat": "Termostato (calefacción)",
|
|
94
|
+
"roomairconditioner": "Aire acondicionado de habitación",
|
|
92
95
|
"fan": "Ventilador / VMC",
|
|
96
|
+
"doorlock": "Cerradura de puerta",
|
|
93
97
|
"smokecoalarm": "Alarma humo/CO",
|
|
94
98
|
"waterleakdetector": "Detector de fugas de agua",
|
|
95
99
|
"airqualitysensor": "Sensor de calidad del aire (CO2)",
|
|
@@ -27,7 +27,9 @@ Changer le type d'appareil après l'appairage du bridge modifie la structure de
|
|
|
27
27
|
| Lumière blanc dynamique | + GA commande/état température de couleur en Kelvin (DPT 7.600) |
|
|
28
28
|
| Volet / Store | Monter/Descendre (DPT 1.008), Stop (DPT 1.017), position % commande/état (DPT 5.001), inversion de position optionnelle |
|
|
29
29
|
| Thermostat (chauffage et/ou rafraîchissement) | GA température actuelle, GA commande/état consigne (DPT 9.001). En ajoutant aussi la GA commande/état consigne rafraîchissement, le mode Cool (double consigne) est également exposé |
|
|
30
|
+
| Climatiseur individuel | Un appareil Matter combine les GA commande/état On/Off (DPT 1.001), température actuelle et consignes chauffage/rafraîchissement (DPT 9.001), et vitesse ventilateur % (DPT 5.001) |
|
|
30
31
|
| Ventilateur / VMC | GA commande/état vitesse % (DPT 5.001) |
|
|
32
|
+
| Serrure de porte | GA commande verrouillage/déverrouillage et GA état verrouillé/déverrouillé (DPT 1.001 ; `true` = verrouillée) |
|
|
31
33
|
| Capteurs (température, humidité, lumière, présence, contact) | Une GA d'état chacun |
|
|
32
34
|
| Détecteur fumée/CO | GA état alarme fumée + GA état alarme CO optionnelle (DPT 1.005) : notifications critiques sur le téléphone |
|
|
33
35
|
| Détecteur de fuite d'eau | GA état fuite (DPT 1.005) |
|
|
@@ -45,7 +47,7 @@ Ces options ne s'affichent que lorsqu'elles s'appliquent au type sélectionné.
|
|
|
45
47
|
|
|
46
48
|
Le sélecteur de PIN se trouve hors des onglets de l'éditeur. Son activation affiche juste dessous une section contextuelle **Entrée/sortie du flow**, avec des exemples copiables filtrés selon le type d'appareil :
|
|
47
49
|
|
|
48
|
-
- **Entrée** : mettez à jour l'état Matter depuis le flux, sans passer par le bus KNX : `msg.payload = { function: "onoff", value: true }` (`function` est l'une de `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `fanspeed`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Utile pour exposer à Alexa & Co. des valeurs calculées dans le flux (ex. un capteur virtuel).
|
|
50
|
+
- **Entrée** : mettez à jour l'état Matter depuis le flux, sans passer par le bus KNX : `msg.payload = { function: "onoff", value: true }` (`function` est l'une de `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `coolingsetpoint`, `fanspeed`, `lock`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Utile pour exposer à Alexa & Co. des valeurs calculées dans le flux (ex. un capteur virtuel).
|
|
49
51
|
- **Sortie** : chaque commande reçue d'un contrôleur Matter est transmise au flux : `msg.topic` = nom de l'appareil, `msg.payload` = valeur, `msg.matter` = la commande brute. Un appareil sans GA de commande devient un **appareil flow uniquement**.
|
|
50
52
|
|
|
51
53
|
## Notes
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
"fn_leak_ga": "GA état fuite d'eau",
|
|
75
75
|
"fn_co2_ga": "GA état CO2 (ppm, DPT 9.008)",
|
|
76
76
|
"fn_fanspeed_cmd": "GA commande vitesse ventilateur %",
|
|
77
|
-
"fn_fanspeed_status": "GA état vitesse ventilateur %"
|
|
77
|
+
"fn_fanspeed_status": "GA état vitesse ventilateur %",
|
|
78
|
+
"fn_lock_cmd": "GA commande verrouillage/déverrouillage",
|
|
79
|
+
"fn_lock_status": "GA état verrouillé/déverrouillé"
|
|
78
80
|
},
|
|
79
81
|
"types": {
|
|
80
82
|
"onofflight": "Lumière On/Off",
|
|
@@ -89,7 +91,9 @@
|
|
|
89
91
|
"contactsensor": "Capteur de contact",
|
|
90
92
|
"windowcovering": "Volet / Store",
|
|
91
93
|
"thermostat": "Thermostat (chauffage)",
|
|
94
|
+
"roomairconditioner": "Climatiseur individuel",
|
|
92
95
|
"fan": "Ventilateur / VMC",
|
|
96
|
+
"doorlock": "Serrure de porte",
|
|
93
97
|
"smokecoalarm": "Détecteur fumée/CO",
|
|
94
98
|
"waterleakdetector": "Détecteur de fuite d'eau",
|
|
95
99
|
"airqualitysensor": "Capteur de qualité d'air (CO2)",
|
|
@@ -27,7 +27,9 @@ Cambiare il tipo dispositivo dopo l'abbinamento del bridge modifica la struttura
|
|
|
27
27
|
| Luce bianco dinamico | + GA comando/stato temperatura colore in Kelvin (DPT 7.600) |
|
|
28
28
|
| Tapparella / Tenda | Su/Giù (DPT 1.008), Stop (DPT 1.017), posizione % comando/stato (DPT 5.001), inversione posizione opzionale |
|
|
29
29
|
| Termostato (riscaldamento e/o raffrescamento) | GA temperatura attuale, GA comando/stato setpoint (DPT 9.001). Aggiungendo anche il GA comando/stato setpoint raffrescamento si espone anche la modalità Cool (doppio setpoint) |
|
|
30
|
+
| Condizionatore ambiente | Un unico dispositivo Matter che combina GA comando/stato On/Off (DPT 1.001), temperatura attuale e setpoint caldo/freddo (DPT 9.001), e velocità ventola % (DPT 5.001) |
|
|
30
31
|
| Ventola / VMC | GA comando/stato velocità % (DPT 5.001) |
|
|
32
|
+
| Serratura porta | GA comando blocco/sblocco e GA stato bloccato/sbloccato (DPT 1.001; `true` = bloccata) |
|
|
31
33
|
| Sensori (temperatura, umidità, luminosità, presenza, contatto) | Un GA di stato ciascuno |
|
|
32
34
|
| Rilevatore fumo/CO | GA stato allarme fumo + GA stato allarme CO opzionale (DPT 1.005): notifiche critiche sul telefono |
|
|
33
35
|
| Rilevatore allagamento | GA stato allagamento (DPT 1.005) |
|
|
@@ -45,7 +47,7 @@ Queste opzioni sono nascoste finché non servono al tipo selezionato. I disposit
|
|
|
45
47
|
|
|
46
48
|
Il selettore dei PIN si trova fuori dalle TAB dell'editor. Abilitandolo compare subito sotto una sezione contestuale **Input/output del flow**, con esempi copiabili filtrati per il tipo di dispositivo selezionato:
|
|
47
49
|
|
|
48
|
-
- **Input**: aggiorna lo stato Matter dal flow, senza passare dal bus KNX: `msg.payload = { function: "onoff", value: true }` (`function` è una tra `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `fanspeed`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Utile per esporre ad Alexa & Co. valori calcolati nel flow (es. un sensore virtuale).
|
|
50
|
+
- **Input**: aggiorna lo stato Matter dal flow, senza passare dal bus KNX: `msg.payload = { function: "onoff", value: true }` (`function` è una tra `onoff`, `level`, `rgb`, `colortemp`, `position`, `temperature`, `humidity`, `illuminance`, `occupancy`, `contact`, `currenttemp`, `setpoint`, `coolingsetpoint`, `fanspeed`, `lock`, `smoke`, `co`, `leak`, `co2`, `rvcstate`, `rvcmode`). Utile per esporre ad Alexa & Co. valori calcolati nel flow (es. un sensore virtuale).
|
|
49
51
|
- **Output**: ogni comando ricevuto da un controller Matter viene inoltrato al flow: `msg.topic` = nome del dispositivo, `msg.payload` = valore, `msg.matter` = il comando grezzo. Un dispositivo senza GA di comando diventa un **dispositivo solo-flow**.
|
|
50
52
|
|
|
51
53
|
## Note
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
"fn_leak_ga": "GA stato allagamento",
|
|
75
75
|
"fn_co2_ga": "GA stato CO2 (ppm, DPT 9.008)",
|
|
76
76
|
"fn_fanspeed_cmd": "GA comando velocità ventola %",
|
|
77
|
-
"fn_fanspeed_status": "GA stato velocità ventola %"
|
|
77
|
+
"fn_fanspeed_status": "GA stato velocità ventola %",
|
|
78
|
+
"fn_lock_cmd": "GA comando blocco/sblocco",
|
|
79
|
+
"fn_lock_status": "GA stato bloccato/sbloccato"
|
|
78
80
|
},
|
|
79
81
|
"types": {
|
|
80
82
|
"onofflight": "Luce On/Off",
|
|
@@ -89,7 +91,9 @@
|
|
|
89
91
|
"contactsensor": "Sensore contatto",
|
|
90
92
|
"windowcovering": "Tapparella / Tenda",
|
|
91
93
|
"thermostat": "Termostato (riscaldamento)",
|
|
94
|
+
"roomairconditioner": "Condizionatore ambiente",
|
|
92
95
|
"fan": "Ventola / VMC",
|
|
96
|
+
"doorlock": "Serratura porta",
|
|
93
97
|
"smokecoalarm": "Rilevatore fumo/CO",
|
|
94
98
|
"waterleakdetector": "Rilevatore allagamento",
|
|
95
99
|
"airqualitysensor": "Sensore qualità aria (CO2)",
|
|
@@ -27,7 +27,9 @@
|
|
|
27
27
|
| 色温灯 | + 色温命令/状态 GA,开尔文 (DPT 7.600) |
|
|
28
28
|
| 窗帘/卷帘 | 上/下 (DPT 1.008)、停止 (DPT 1.017)、位置 % 命令/状态 (DPT 5.001)、可选位置反转 |
|
|
29
29
|
| 温控器(采暖和/或制冷) | 当前温度 GA、设定点命令/状态 GA (DPT 9.001)。如再配置制冷设定点命令/状态 GA,则同时提供 Cool 模式(双设定点) |
|
|
30
|
+
| 房间空调 | 一个 Matter 设备组合开/关命令/状态 GA (DPT 1.001)、当前温度与采暖/制冷设定点 (DPT 9.001),以及风扇速度 % 命令/状态 GA (DPT 5.001) |
|
|
30
31
|
| 风扇/新风 | 速度 % 命令/状态 GA (DPT 5.001) |
|
|
32
|
+
| 门锁 | 锁定/解锁命令 GA 和锁定/解锁状态 GA (DPT 1.001;`true` = 已锁定) |
|
|
31
33
|
| 传感器(温度、湿度、光照、人体、门磁) | 各一个状态 GA |
|
|
32
34
|
| 烟雾/CO 报警器 | 烟雾报警状态 GA + 可选 CO 报警状态 GA (DPT 1.005):手机上的紧急通知 |
|
|
33
35
|
| 漏水探测器 | 漏水状态 GA (DPT 1.005) |
|
|
@@ -45,7 +47,7 @@
|
|
|
45
47
|
|
|
46
48
|
引脚选择器位于编辑器选项卡之外。启用后,其下方会显示与所选设备类型匹配的 **Flow 输入/输出** 区域,并提供可复制示例:
|
|
47
49
|
|
|
48
|
-
- **输入**:从 Flow 更新 Matter 状态,无需经过 KNX 总线:`msg.payload = { function: "onoff", value: true }`(`function` 为 `onoff`、`level`、`rgb`、`colortemp`、`position`、`temperature`、`humidity`、`illuminance`、`occupancy`、`contact`、`currenttemp`、`setpoint`、`fanspeed`、`smoke`、`co`、`leak`、`co2`、`rvcstate`、`rvcmode` 之一)。适合把 Flow 中计算的值(如虚拟传感器)公开给 Alexa 等。
|
|
50
|
+
- **输入**:从 Flow 更新 Matter 状态,无需经过 KNX 总线:`msg.payload = { function: "onoff", value: true }`(`function` 为 `onoff`、`level`、`rgb`、`colortemp`、`position`、`temperature`、`humidity`、`illuminance`、`occupancy`、`contact`、`currenttemp`、`setpoint`、`coolingsetpoint`、`fanspeed`、`lock`、`smoke`、`co`、`leak`、`co2`、`rvcstate`、`rvcmode` 之一)。适合把 Flow 中计算的值(如虚拟传感器)公开给 Alexa 等。
|
|
49
51
|
- **输出**:从 Matter 控制器收到的每个命令都转发到 Flow:`msg.topic` = 设备名称,`msg.payload` = 值,`msg.matter` = 原始命令。没有命令 GA 的设备成为**纯 Flow 设备**。
|
|
50
52
|
|
|
51
53
|
## 说明
|
|
@@ -74,7 +74,9 @@
|
|
|
74
74
|
"fn_leak_ga": "漏水状态 GA",
|
|
75
75
|
"fn_co2_ga": "CO2 状态 GA(ppm,DPT 9.008)",
|
|
76
76
|
"fn_fanspeed_cmd": "风扇速度 % 命令 GA",
|
|
77
|
-
"fn_fanspeed_status": "风扇速度 % 状态 GA"
|
|
77
|
+
"fn_fanspeed_status": "风扇速度 % 状态 GA",
|
|
78
|
+
"fn_lock_cmd": "锁定/解锁 命令 GA",
|
|
79
|
+
"fn_lock_status": "锁定/解锁 状态 GA"
|
|
78
80
|
},
|
|
79
81
|
"types": {
|
|
80
82
|
"onofflight": "开关灯",
|
|
@@ -89,7 +91,9 @@
|
|
|
89
91
|
"contactsensor": "门磁传感器",
|
|
90
92
|
"windowcovering": "窗帘 / 卷帘",
|
|
91
93
|
"thermostat": "温控器(采暖)",
|
|
94
|
+
"roomairconditioner": "房间空调",
|
|
92
95
|
"fan": "风扇 / 新风",
|
|
96
|
+
"doorlock": "门锁",
|
|
93
97
|
"smokecoalarm": "烟雾/CO 报警器",
|
|
94
98
|
"waterleakdetector": "漏水探测器",
|
|
95
99
|
"airqualitysensor": "空气质量传感器 (CO2)",
|
|
@@ -28,6 +28,11 @@ import { AirQualitySensorDevice } from '@matter/main/devices/air-quality-sensor'
|
|
|
28
28
|
import { AirQualityServer } from '@matter/main/behaviors/air-quality'
|
|
29
29
|
import { CarbonDioxideConcentrationMeasurementServer } from '@matter/main/behaviors/carbon-dioxide-concentration-measurement'
|
|
30
30
|
import { FanDevice } from '@matter/main/devices/fan'
|
|
31
|
+
import { FanControlServer } from '@matter/main/behaviors/fan-control'
|
|
32
|
+
import { RoomAirConditionerDevice } from '@matter/main/devices/room-air-conditioner'
|
|
33
|
+
import { DoorLockDevice } from '@matter/main/devices/door-lock'
|
|
34
|
+
import { DoorLockServer } from '@matter/main/behaviors/door-lock'
|
|
35
|
+
import { DoorLock } from '@matter/main/clusters/door-lock'
|
|
31
36
|
import { RoboticVacuumCleanerDevice } from '@matter/main/devices/robotic-vacuum-cleaner'
|
|
32
37
|
import { RvcRunModeServer } from '@matter/main/behaviors/rvc-run-mode'
|
|
33
38
|
import { RvcOperationalStateServer } from '@matter/main/behaviors/rvc-operational-state'
|
|
@@ -53,6 +58,8 @@ const BRIDGE_TYPES = {
|
|
|
53
58
|
// Custom construction (dedicated server behaviors), handled in createBridgedEndpoint
|
|
54
59
|
windowcovering: { device: null, functions: ['position'], commandFunctions: [] },
|
|
55
60
|
thermostat: { device: null, functions: ['currenttemp', 'setpoint', 'coolingsetpoint'], commandFunctions: [] },
|
|
61
|
+
roomairconditioner: { device: null, functions: ['onoff', 'currenttemp', 'setpoint', 'coolingsetpoint', 'fanspeed'], commandFunctions: [] },
|
|
62
|
+
doorlock: { device: null, functions: ['lock'], commandFunctions: [] },
|
|
56
63
|
rgblight: { device: null, functions: ['onoff', 'level', 'rgb'], commandFunctions: ['onoff', 'level'] },
|
|
57
64
|
colortemperaturelight: { device: null, functions: ['onoff', 'level', 'colortemp'], commandFunctions: ['onoff', 'level'] },
|
|
58
65
|
smokecoalarm: { device: null, functions: ['smoke', 'co'], commandFunctions: [] },
|
|
@@ -124,6 +131,8 @@ function knxValueToMatterPatch (def, fn, value) {
|
|
|
124
131
|
}
|
|
125
132
|
case 'onoff':
|
|
126
133
|
return { onOff: { onOff: truthy(value) } }
|
|
134
|
+
case 'lock':
|
|
135
|
+
return { doorLock: { lockState: truthy(value) ? DoorLock.LockState.Locked : DoorLock.LockState.Unlocked } }
|
|
127
136
|
case 'level': {
|
|
128
137
|
const percent = Number(value)
|
|
129
138
|
if (Number.isNaN(percent)) return undefined
|
|
@@ -281,6 +290,76 @@ function createRawColorControlServer (def, onCommand) {
|
|
|
281
290
|
return { RawColorControlServer, attachLevelTracker }
|
|
282
291
|
}
|
|
283
292
|
|
|
293
|
+
function configureThermostatState (initialState, def, fallbackMode) {
|
|
294
|
+
let hasHeating = def.hasHeatingSetpoint === true
|
|
295
|
+
let hasCooling = def.hasCoolingSetpoint === true
|
|
296
|
+
// The Thermostat cluster cannot be composed without at least one operating feature.
|
|
297
|
+
// Preserve the historical heating default for the standalone Thermostat; a Room Air
|
|
298
|
+
// Conditioner with no setpoint GA configured defaults to cooling, its primary use case.
|
|
299
|
+
if (!hasHeating && !hasCooling) {
|
|
300
|
+
hasHeating = fallbackMode === 'heating'
|
|
301
|
+
hasCooling = fallbackMode === 'cooling'
|
|
302
|
+
}
|
|
303
|
+
const features = []
|
|
304
|
+
if (hasHeating) features.push('Heating')
|
|
305
|
+
if (hasCooling) features.push('Cooling')
|
|
306
|
+
initialState.thermostat = {
|
|
307
|
+
localTemperature: null,
|
|
308
|
+
// CoolingOnly=0, HeatingOnly=2, CoolingAndHeating=4 (ControlSequenceOfOperation).
|
|
309
|
+
controlSequenceOfOperation: hasHeating && hasCooling ? 4 : (hasCooling ? 0 : 2),
|
|
310
|
+
// Cool=3, Heat=4 (SystemMode). A dual-mode device starts in Heat.
|
|
311
|
+
systemMode: hasCooling && !hasHeating ? 3 : 4
|
|
312
|
+
}
|
|
313
|
+
if (hasHeating) initialState.thermostat.occupiedHeatingSetpoint = 2000 // 20°C
|
|
314
|
+
if (hasCooling) initialState.thermostat.occupiedCoolingSetpoint = 2400 // 24°C
|
|
315
|
+
return { features, hasHeating, hasCooling }
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function attachThermostatCommandHandlers (endpoint, def, onCommand, capabilities) {
|
|
319
|
+
// Absolute thermostat targets are Matter attribute writes, not commands. The offline
|
|
320
|
+
// context marks KNX/flow state synchronization and prevents a feedback write to KNX.
|
|
321
|
+
if (capabilities.hasHeating) {
|
|
322
|
+
endpoint.events.thermostat.occupiedHeatingSetpoint$Changed.on((value, oldValue, context) => {
|
|
323
|
+
try {
|
|
324
|
+
if (context?.offline === true || value === null || value === undefined) return
|
|
325
|
+
onCommand({ deviceId: def.id, fn: 'setpoint', value: Math.round(Number(value)) / 100 })
|
|
326
|
+
} catch (error) { /* empty */ }
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
if (capabilities.hasCooling) {
|
|
330
|
+
endpoint.events.thermostat.occupiedCoolingSetpoint$Changed.on((value, oldValue, context) => {
|
|
331
|
+
try {
|
|
332
|
+
if (context?.offline === true || value === null || value === undefined) return
|
|
333
|
+
onCommand({ deviceId: def.id, fn: 'coolingsetpoint', value: Math.round(Number(value)) / 100 })
|
|
334
|
+
} catch (error) { /* empty */ }
|
|
335
|
+
})
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function configureFanState (initialState) {
|
|
340
|
+
initialState.fanControl = {
|
|
341
|
+
fanMode: 0, // Off
|
|
342
|
+
fanModeSequence: 0, // Off/Low/Med/High (Auto requires the AUT feature)
|
|
343
|
+
percentSetting: 0,
|
|
344
|
+
percentCurrent: 0
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function attachFanCommandHandlers (endpoint, def, onCommand) {
|
|
349
|
+
endpoint.events.fanControl.percentSetting$Changed.on((value, oldValue, context) => {
|
|
350
|
+
try {
|
|
351
|
+
if (context?.offline === true || value === null || value === undefined) return
|
|
352
|
+
onCommand({ deviceId: def.id, fn: 'fanspeed', value: clamp(Math.round(Number(value)), 0, 100) })
|
|
353
|
+
} catch (error) { /* empty */ }
|
|
354
|
+
})
|
|
355
|
+
endpoint.events.fanControl.fanMode$Changed.on((value, oldValue, context) => {
|
|
356
|
+
try {
|
|
357
|
+
if (context?.offline === true) return
|
|
358
|
+
if (Number(value) === 0) onCommand({ deviceId: def.id, fn: 'fanspeed', value: 0 })
|
|
359
|
+
} catch (error) { /* empty */ }
|
|
360
|
+
})
|
|
361
|
+
}
|
|
362
|
+
|
|
284
363
|
/**
|
|
285
364
|
* Creates the bridged Matter endpoint for a virtual device definition.
|
|
286
365
|
* @param {object} def - { id, type, name }
|
|
@@ -353,7 +432,9 @@ function createBridgedEndpoint (def, serialPrefix, onCommand) {
|
|
|
353
432
|
return false
|
|
354
433
|
}
|
|
355
434
|
|
|
356
|
-
const RawOnOffBase = def.type === 'onoffplug'
|
|
435
|
+
const RawOnOffBase = def.type === 'onoffplug'
|
|
436
|
+
? OnOffServer
|
|
437
|
+
: def.type === 'roomairconditioner' ? OnOffServer.with('DeadFrontBehavior') : OnOffServer.with('Lighting')
|
|
357
438
|
class RawOnOffServer extends RawOnOffBase {
|
|
358
439
|
async on () {
|
|
359
440
|
await super.on()
|
|
@@ -505,57 +586,58 @@ function createBridgedEndpoint (def, serialPrefix, onCommand) {
|
|
|
505
586
|
// Heating/Cooling capability is auto-detected from which setpoint GA(s) the KNX node
|
|
506
587
|
// has configured (see knxUltimateMatterBridge.js#getMatterDef). Leaving both flags
|
|
507
588
|
// unset keeps the original heating-only behavior, so existing flows are unaffected.
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (hasHeating) features.push('Heating')
|
|
512
|
-
if (hasCooling) features.push('Cooling')
|
|
513
|
-
if (features.length === 0) features.push('Heating') // never build a thermostat with neither mode
|
|
514
|
-
|
|
515
|
-
initialState.thermostat = {
|
|
516
|
-
localTemperature: null,
|
|
517
|
-
// CoolingOnly=0, HeatingOnly=2, CoolingAndHeating=4 (Matter ControlSequenceOfOperation enum)
|
|
518
|
-
controlSequenceOfOperation: hasHeating && hasCooling ? 4 : (hasCooling ? 0 : 2),
|
|
519
|
-
// Cool=3, Heat=4 (Matter SystemMode enum). Dual-mode starts in Heat; the controller can
|
|
520
|
-
// switch it, same as any physical dual thermostat without an auto/deadband mode.
|
|
521
|
-
systemMode: hasCooling && !hasHeating ? 3 : 4
|
|
522
|
-
}
|
|
523
|
-
if (hasHeating) initialState.thermostat.occupiedHeatingSetpoint = 2000 // 20°C
|
|
524
|
-
if (hasCooling) initialState.thermostat.occupiedCoolingSetpoint = 2400 // 24°C
|
|
525
|
-
|
|
526
|
-
endpoint = new Endpoint(ThermostatDevice.with(ThermostatServer.with(...features), BridgedDeviceBasicInformationServer), initialState)
|
|
527
|
-
|
|
528
|
-
// Setpoint changes from a Matter controller. Unlike OnOff/LevelControl/WindowCovering/
|
|
529
|
-
// ColorControl, an absolute setpoint has no cluster COMMAND to intercept - Thermostat
|
|
530
|
-
// only exposes SetpointRaiseLower (a *relative* command) and SetActivePresetRequest;
|
|
531
|
-
// controllers set an absolute target via a plain attribute write. matter.js only fires
|
|
532
|
-
// $Changing/$Changed when the value actually differs (verified in @matter/node's
|
|
533
|
-
// Datasource#preCommit), so a duplicate setpoint (same value sent twice) cannot be
|
|
534
|
-
// forwarded raw here - there is no lower-level hook to capture it at.
|
|
535
|
-
if (hasHeating) {
|
|
536
|
-
endpoint.events.thermostat.occupiedHeatingSetpoint$Changed.on((value, oldValue, context) => {
|
|
537
|
-
try {
|
|
538
|
-
if (context?.offline === true) return
|
|
539
|
-
if (value === null || value === undefined) return
|
|
540
|
-
onCommand({ deviceId: def.id, fn: 'setpoint', value: Math.round(Number(value)) / 100 }) // centi-°C -> °C
|
|
541
|
-
} catch (error) { /* empty */ }
|
|
542
|
-
})
|
|
543
|
-
}
|
|
544
|
-
if (hasCooling) {
|
|
545
|
-
endpoint.events.thermostat.occupiedCoolingSetpoint$Changed.on((value, oldValue, context) => {
|
|
546
|
-
try {
|
|
547
|
-
if (context?.offline === true) return
|
|
548
|
-
if (value === null || value === undefined) return
|
|
549
|
-
onCommand({ deviceId: def.id, fn: 'coolingsetpoint', value: Math.round(Number(value)) / 100 }) // centi-°C -> °C
|
|
550
|
-
} catch (error) { /* empty */ }
|
|
551
|
-
})
|
|
552
|
-
}
|
|
589
|
+
const thermostat = configureThermostatState(initialState, def, 'heating')
|
|
590
|
+
endpoint = new Endpoint(ThermostatDevice.with(ThermostatServer.with(...thermostat.features), BridgedDeviceBasicInformationServer), initialState)
|
|
591
|
+
attachThermostatCommandHandlers(endpoint, def, onCommand, thermostat)
|
|
553
592
|
// NOTE: SystemMode (Heat/Cool/Off/Auto) changes from a controller are accepted by the
|
|
554
593
|
// cluster but not forwarded to KNX yet: there is no single KNX DPT for HVAC mode that
|
|
555
594
|
// fits every actuator. Track it via the node's optional input PIN if you need it today.
|
|
556
595
|
return endpoint
|
|
557
596
|
}
|
|
558
597
|
|
|
598
|
+
if (def.type === 'roomairconditioner') {
|
|
599
|
+
// Matter Room Air Conditioner (0x0072) requires OnOff with DeadFrontBehavior and a
|
|
600
|
+
// feature-selected Thermostat server. FanControl is optional in the specification,
|
|
601
|
+
// but included here so the former on/off + thermostat + fan trio becomes one endpoint.
|
|
602
|
+
const thermostat = configureThermostatState(initialState, def, 'cooling')
|
|
603
|
+
configureFanState(initialState)
|
|
604
|
+
endpoint = new Endpoint(RoomAirConditionerDevice.with(
|
|
605
|
+
RawOnOffServer,
|
|
606
|
+
ThermostatServer.with(...thermostat.features),
|
|
607
|
+
FanControlServer,
|
|
608
|
+
BridgedDeviceBasicInformationServer
|
|
609
|
+
), initialState)
|
|
610
|
+
attachThermostatCommandHandlers(endpoint, def, onCommand, thermostat)
|
|
611
|
+
attachFanCommandHandlers(endpoint, def, onCommand)
|
|
612
|
+
return endpoint
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (def.type === 'doorlock') {
|
|
616
|
+
initialState.doorLock = {
|
|
617
|
+
lockState: DoorLock.LockState.Unlocked,
|
|
618
|
+
lockType: DoorLock.LockType.Other,
|
|
619
|
+
actuatorEnabled: true,
|
|
620
|
+
operatingMode: DoorLock.OperatingMode.Normal,
|
|
621
|
+
// matter.js currently defaults these constrained base attributes to 0, which is
|
|
622
|
+
// outside their Matter-defined 1..255 range and prevents endpoint initialization.
|
|
623
|
+
wrongCodeEntryLimit: 3,
|
|
624
|
+
userCodeTemporaryDisableTime: 10
|
|
625
|
+
}
|
|
626
|
+
class KnxDoorLockServer extends DoorLockServer {
|
|
627
|
+
async lockDoor (request) {
|
|
628
|
+
await super.lockDoor(request)
|
|
629
|
+
onCommand({ deviceId: def.id, fn: 'lock', value: true, matterCommand: { cluster: 'DoorLock', command: 'lockDoor' } })
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
async unlockDoor (request) {
|
|
633
|
+
await super.unlockDoor(request)
|
|
634
|
+
onCommand({ deviceId: def.id, fn: 'lock', value: false, matterCommand: { cluster: 'DoorLock', command: 'unlockDoor' } })
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
endpoint = new Endpoint(DoorLockDevice.with(KnxDoorLockServer, BridgedDeviceBasicInformationServer), initialState)
|
|
638
|
+
return endpoint
|
|
639
|
+
}
|
|
640
|
+
|
|
559
641
|
if (def.type === 'occupancysensor') {
|
|
560
642
|
// The OccupancySensing cluster is not added by default: the sensor type must be chosen (we expose it as PIR)
|
|
561
643
|
endpoint = new Endpoint(OccupancySensorDevice.with(OccupancySensingServer.with('PassiveInfrared'), BridgedDeviceBasicInformationServer), initialState)
|
|
@@ -620,30 +702,13 @@ function createBridgedEndpoint (def, serialPrefix, onCommand) {
|
|
|
620
702
|
BridgedDeviceBasicInformationServer
|
|
621
703
|
), initialState)
|
|
622
704
|
} else if (def.type === 'fan') {
|
|
623
|
-
initialState
|
|
624
|
-
fanMode: 0, // Off
|
|
625
|
-
fanModeSequence: 0, // Off/Low/Med/High (Auto requires the AUT feature)
|
|
626
|
-
percentSetting: 0,
|
|
627
|
-
percentCurrent: 0
|
|
628
|
-
}
|
|
705
|
+
configureFanState(initialState)
|
|
629
706
|
endpoint = new Endpoint(FanDevice.with(BridgedDeviceBasicInformationServer), initialState)
|
|
630
707
|
// Speed changes from the controller (percent write or fan mode change). Like the
|
|
631
708
|
// Thermostat setpoints above, FanControlServer exposes no command to intercept for
|
|
632
709
|
// percentSetting (@matter/node's FanControlServer overrides nothing beyond
|
|
633
710
|
// initialize()) - it is attribute-write only, so this cannot be made "raw" either.
|
|
634
|
-
endpoint
|
|
635
|
-
try {
|
|
636
|
-
if (context?.offline === true) return
|
|
637
|
-
if (value === null || value === undefined) return
|
|
638
|
-
onCommand({ deviceId: def.id, fn: 'fanspeed', value: clamp(Math.round(Number(value)), 0, 100) })
|
|
639
|
-
} catch (error) { /* empty */ }
|
|
640
|
-
})
|
|
641
|
-
endpoint.events.fanControl.fanMode$Changed.on((value, oldValue, context) => {
|
|
642
|
-
try {
|
|
643
|
-
if (context?.offline === true) return
|
|
644
|
-
if (Number(value) === 0) onCommand({ deviceId: def.id, fn: 'fanspeed', value: 0 })
|
|
645
|
-
} catch (error) { /* empty */ }
|
|
646
|
-
})
|
|
711
|
+
attachFanCommandHandlers(endpoint, def, onCommand)
|
|
647
712
|
} else if (def.type === 'robotvacuum') {
|
|
648
713
|
// Flow-only device: run mode changes and operational commands are forwarded to the flow
|
|
649
714
|
// (node PINs); the flow reports the state back through the input PIN.
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"engines": {
|
|
4
4
|
"node": ">=20.18.1"
|
|
5
5
|
},
|
|
6
|
-
"version": "6.3.
|
|
6
|
+
"version": "6.3.14",
|
|
7
7
|
"description": "KNX Ultimate is the most advanced KNX integration for Node-RED, providing secure KNX/IP communication, routing, ETS project import, Philips Hue, Matter Controller and Matter Bridge (control matter device via KNX and expose KNX GA via Matter), MQTT, diagnostics with AI, virtual devices, and powerful automation nodes. Build professional, reliable, and scalable smart home and building automation projects with minimal effort.",
|
|
8
8
|
"files": [
|
|
9
9
|
"nodes/",
|