node-red-contrib-knx-ultimate 7.1.4 → 8.0.2
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 +20 -10
- package/MIGRATION.md +40 -0
- package/README.md +32 -6
- package/docs/README.md +34 -0
- package/docs/assets/brand/made-in-italy.svg +12 -0
- package/examples/Alerter - Device Alert Aggregation.json +5 -2
- package/examples/Auto Responder - Read Request Defaults.json +5 -2
- package/examples/Garage - Door Controller.json +5 -2
- package/examples/Global Context - Expose KNX Values.json +5 -2
- package/examples/KNX DateTime - Set Date and Time to Bus.json +111 -89
- package/examples/Load Control - Manual Shedding Mode.json +5 -2
- package/examples/Logger ETS File and Telegram Count.json +10 -2
- package/examples/Scene Controller Recall and Save.json +33 -6
- package/examples/Staircase - Timer, Override and Block.json +5 -2
- package/examples/WatchDog Connect Disconnect.json +98 -70
- package/nodes/commonFunctions.js +0 -587
- package/nodes/knxUltimate-config.html +0 -14
- package/nodes/knxUltimate-config.js +1 -18
- package/nodes/knxUltimate.html +1 -6
- package/nodes/knxUltimateIoTBridge.html +0 -14
- package/nodes/knxUltimateLegacyMigration.js +75 -0
- package/nodes/knxUltimateMultiRouting.html +1 -7
- package/nodes/knxUltimateRouterFilter.html +1 -7
- package/nodes/knxUltimateUtility.html +0 -6
- package/nodes/knxUltimateViewer.html +0 -6
- package/nodes/locales/de/knxUltimate-config.html +0 -8
- package/nodes/locales/de/knxUltimate.html +0 -8
- package/nodes/locales/de/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/de/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/de/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/de/knxUltimateUtility.html +0 -8
- package/nodes/locales/de/knxUltimateUtility.json +16 -1
- package/nodes/locales/de/knxUltimateViewer.html +0 -8
- package/nodes/locales/en/knxUltimate-config.html +0 -8
- package/nodes/locales/en/knxUltimate.html +0 -8
- package/nodes/locales/en/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/en/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/en/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/en/knxUltimateUtility.html +0 -8
- package/nodes/locales/en/knxUltimateUtility.json +16 -1
- package/nodes/locales/en/knxUltimateViewer.html +0 -8
- package/nodes/locales/es/knxUltimate-config.html +0 -8
- package/nodes/locales/es/knxUltimate.html +0 -8
- package/nodes/locales/es/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/es/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/es/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/es/knxUltimateUtility.html +0 -8
- package/nodes/locales/es/knxUltimateUtility.json +17 -2
- package/nodes/locales/es/knxUltimateViewer.html +0 -8
- package/nodes/locales/fr/knxUltimate-config.html +0 -8
- package/nodes/locales/fr/knxUltimate.html +0 -8
- package/nodes/locales/fr/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/fr/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/fr/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/fr/knxUltimateUtility.html +0 -8
- package/nodes/locales/fr/knxUltimateUtility.json +16 -1
- package/nodes/locales/fr/knxUltimateViewer.html +0 -8
- package/nodes/locales/it/knxUltimate-config.html +0 -8
- package/nodes/locales/it/knxUltimate.html +0 -8
- package/nodes/locales/it/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/it/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/it/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/it/knxUltimateUtility.html +0 -8
- package/nodes/locales/it/knxUltimateUtility.json +16 -1
- package/nodes/locales/it/knxUltimateViewer.html +0 -8
- package/nodes/locales/zh-CN/knxUltimate-config.html +0 -8
- package/nodes/locales/zh-CN/knxUltimate.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateIoTBridge.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateMultiRouting.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateRouterFilter.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateUtility.html +0 -8
- package/nodes/locales/zh-CN/knxUltimateUtility.json +16 -1
- package/nodes/locales/zh-CN/knxUltimateViewer.html +0 -8
- package/nodes/plugins/knxUltimate-v8-migration-recovery-plugin.html +140 -0
- package/package.json +22 -69
- package/resources/11f26b4500.js +2 -2
- package/resources/KNXAIChatAdapterMappings.js +2 -416
- package/resources/configNodeEditorSelection.js +2 -32
- package/resources/hueControllerEditorSelection.js +2 -32
- package/resources/hueControllerMigrationDialog.js +2 -254
- package/resources/hueControllerProfiles.js +2 -9319
- package/resources/knxUtilityProfiles.js +2041 -2082
- package/resources/legacyMigrationNotice.js +23 -111
- package/resources/matterQrScanner.js +2 -98
- package/resources/upgradeToV8.js +94 -26
- package/scripts/check-legacy-flows.js +142 -0
- package/examples/Hue Area Motion - Zone Presence.json +0 -77
- package/examples/Hue Battery - Level Status.json +0 -77
- package/examples/Hue Button - Short and Dim Commands.json +0 -83
- package/examples/Hue Camera Motion - Presence.json +0 -77
- package/examples/Hue Config - Bridge Template.json +0 -27
- package/examples/Hue Contact Sensor - Open Closed.json +0 -75
- package/examples/Hue Device Software Update - Availability.json +0 -77
- package/examples/Hue Humidity Sensor - Relative Humidity.json +0 -77
- package/examples/Hue Light - Switch and Brightness.json +0 -67
- package/examples/Hue Light Sensor - Lux to KNX.json +0 -77
- package/examples/Hue Motion - Presence Sensor.json +0 -76
- package/examples/Hue Plug - Switch and State.json +0 -63
- package/examples/Hue Scene - Recall from KNX.json +0 -63
- package/examples/Hue Tap Dial - Relative Dimming.json +0 -76
- package/examples/Hue Temperature Sensor - Celsius to KNX.json +0 -77
- package/examples/Hue Zigbee Connectivity - Online Status.json +0 -77
- package/examples/Matter Controller - Semantic Flow Input.json +0 -248
- package/nodes/hue-config.html +0 -378
- package/nodes/hue-config.js +0 -846
- package/nodes/icons/node-alerter-icon.png +0 -0
- package/nodes/icons/node-homekit-icon.png +0 -0
- package/nodes/icons/node-homekit-icon.svg +0 -10
- package/nodes/icons/node-hue-icon.svg +0 -10
- package/nodes/icons/node-knx-icon.png +0 -0
- package/nodes/icons/node-logger-icon.png +0 -0
- package/nodes/icons/node-logger2-icon.png +0 -0
- package/nodes/icons/node-logger2-icon.svg +0 -32
- package/nodes/icons/node-matter-bridge-icon.svg +0 -6
- package/nodes/icons/node-matter-controller-icon.svg +0 -6
- package/nodes/icons/node-matter-icon.svg +0 -12
- package/nodes/icons/node-scene-icon.png +0 -0
- package/nodes/icons/node-watchdog-icon.png +0 -0
- package/nodes/knxUltimateAI.html +0 -1826
- package/nodes/knxUltimateAI.js +0 -16797
- package/nodes/knxUltimateAIHomeAssistant.html +0 -54
- package/nodes/knxUltimateAIHomeAssistant.js +0 -152
- package/nodes/knxUltimateAlerter.html +0 -267
- package/nodes/knxUltimateAlerter.js +0 -300
- package/nodes/knxUltimateAutoResponder.html +0 -128
- package/nodes/knxUltimateAutoResponder.js +0 -264
- package/nodes/knxUltimateDateTime.html +0 -579
- package/nodes/knxUltimateDateTime.js +0 -282
- package/nodes/knxUltimateGarage.html +0 -337
- package/nodes/knxUltimateGarage.js +0 -504
- package/nodes/knxUltimateGlobalContext.html +0 -145
- package/nodes/knxUltimateGlobalContext.js +0 -208
- package/nodes/knxUltimateHATranslator.html +0 -85
- package/nodes/knxUltimateHATranslator.js +0 -83
- package/nodes/knxUltimateHueAreaMotion.html +0 -670
- package/nodes/knxUltimateHueAreaMotion.js +0 -218
- package/nodes/knxUltimateHueBattery.html +0 -646
- package/nodes/knxUltimateHueBattery.js +0 -182
- package/nodes/knxUltimateHueButton.html +0 -804
- package/nodes/knxUltimateHueButton.js +0 -292
- package/nodes/knxUltimateHueCameraMotion.html +0 -671
- package/nodes/knxUltimateHueCameraMotion.js +0 -218
- package/nodes/knxUltimateHueContactSensor.html +0 -609
- package/nodes/knxUltimateHueContactSensor.js +0 -188
- package/nodes/knxUltimateHueController.html +0 -1765
- package/nodes/knxUltimateHueController.js +0 -28
- package/nodes/knxUltimateHueHumiditySensor.html +0 -641
- package/nodes/knxUltimateHueHumiditySensor.js +0 -201
- package/nodes/knxUltimateHueLight.html +0 -2516
- package/nodes/knxUltimateHueLight.js +0 -1582
- package/nodes/knxUltimateHueLightSensor.html +0 -636
- package/nodes/knxUltimateHueLightSensor.js +0 -177
- package/nodes/knxUltimateHueMotion.html +0 -634
- package/nodes/knxUltimateHueMotion.js +0 -182
- package/nodes/knxUltimateHuePlug.html +0 -576
- package/nodes/knxUltimateHuePlug.js +0 -341
- package/nodes/knxUltimateHueScene.html +0 -967
- package/nodes/knxUltimateHueScene.js +0 -349
- package/nodes/knxUltimateHueTapDial.html +0 -640
- package/nodes/knxUltimateHueTapDial.js +0 -268
- package/nodes/knxUltimateHueTemperatureSensor.html +0 -639
- package/nodes/knxUltimateHueTemperatureSensor.js +0 -184
- package/nodes/knxUltimateHueZigbeeConnectivity.html +0 -648
- package/nodes/knxUltimateHueZigbeeConnectivity.js +0 -182
- package/nodes/knxUltimateHuedevice_software_update.html +0 -650
- package/nodes/knxUltimateHuedevice_software_update.js +0 -182
- package/nodes/knxUltimateLoadControl.html +0 -425
- package/nodes/knxUltimateLoadControl.js +0 -443
- package/nodes/knxUltimateLogger.html +0 -197
- package/nodes/knxUltimateLogger.js +0 -224
- package/nodes/knxUltimateMatterBridge.html +0 -689
- package/nodes/knxUltimateMatterBridge.js +0 -464
- package/nodes/knxUltimateMatterControllerDevice.html +0 -2851
- package/nodes/knxUltimateMatterControllerDevice.js +0 -1747
- package/nodes/knxUltimateSceneController.html +0 -529
- package/nodes/knxUltimateSceneController.js +0 -437
- package/nodes/knxUltimateStaircase.html +0 -346
- package/nodes/knxUltimateStaircase.js +0 -463
- package/nodes/knxUltimateWatchDog.html +0 -241
- package/nodes/knxUltimateWatchDog.js +0 -230
- package/nodes/locales/de/hue-config.html +0 -33
- package/nodes/locales/de/hue-config.json +0 -21
- package/nodes/locales/de/knxUltimateAI.html +0 -13
- package/nodes/locales/de/knxUltimateAI.json +0 -231
- package/nodes/locales/de/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/de/knxUltimateAlerter.html +0 -159
- package/nodes/locales/de/knxUltimateAlerter.json +0 -27
- package/nodes/locales/de/knxUltimateAutoResponder.html +0 -96
- package/nodes/locales/de/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/de/knxUltimateDateTime.html +0 -45
- package/nodes/locales/de/knxUltimateDateTime.json +0 -32
- package/nodes/locales/de/knxUltimateGarage.html +0 -79
- package/nodes/locales/de/knxUltimateGarage.json +0 -51
- package/nodes/locales/de/knxUltimateGlobalContext.html +0 -76
- package/nodes/locales/de/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/de/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/de/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/de/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/de/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/de/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/de/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/de/knxUltimateHueButton.html +0 -52
- package/nodes/locales/de/knxUltimateHueButton.json +0 -34
- package/nodes/locales/de/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/de/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/de/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/de/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/de/knxUltimateHueController.html +0 -690
- package/nodes/locales/de/knxUltimateHueController.json +0 -64
- package/nodes/locales/de/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/de/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/de/knxUltimateHueLight.html +0 -121
- package/nodes/locales/de/knxUltimateHueLight.json +0 -94
- package/nodes/locales/de/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/de/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/de/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/de/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/de/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/de/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/de/knxUltimateHueScene.html +0 -45
- package/nodes/locales/de/knxUltimateHueScene.json +0 -41
- package/nodes/locales/de/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/de/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/de/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/de/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/de/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/de/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/de/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/de/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/de/knxUltimateLoadControl.html +0 -69
- package/nodes/locales/de/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/de/knxUltimateLogger.html +0 -126
- package/nodes/locales/de/knxUltimateLogger.json +0 -31
- package/nodes/locales/de/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/de/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/de/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/de/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/de/knxUltimateSceneController.html +0 -98
- package/nodes/locales/de/knxUltimateSceneController.json +0 -32
- package/nodes/locales/de/knxUltimateStaircase.html +0 -77
- package/nodes/locales/de/knxUltimateStaircase.json +0 -62
- package/nodes/locales/de/knxUltimateWatchDog.html +0 -178
- package/nodes/locales/de/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/de/matter-config.html +0 -47
- package/nodes/locales/de/matter-config.json +0 -47
- package/nodes/locales/de/matterbridge-config.html +0 -45
- package/nodes/locales/de/matterbridge-config.json +0 -25
- package/nodes/locales/en/hue-config.html +0 -31
- package/nodes/locales/en/hue-config.json +0 -21
- package/nodes/locales/en/knxUltimateAI.html +0 -13
- package/nodes/locales/en/knxUltimateAI.json +0 -234
- package/nodes/locales/en/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/en/knxUltimateAlerter.html +0 -164
- package/nodes/locales/en/knxUltimateAlerter.json +0 -27
- package/nodes/locales/en/knxUltimateAutoResponder.html +0 -94
- package/nodes/locales/en/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/en/knxUltimateDateTime.html +0 -67
- package/nodes/locales/en/knxUltimateDateTime.json +0 -32
- package/nodes/locales/en/knxUltimateGarage.html +0 -79
- package/nodes/locales/en/knxUltimateGarage.json +0 -51
- package/nodes/locales/en/knxUltimateGlobalContext.html +0 -124
- package/nodes/locales/en/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/en/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/en/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/en/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/en/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/en/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/en/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/en/knxUltimateHueButton.html +0 -52
- package/nodes/locales/en/knxUltimateHueButton.json +0 -34
- package/nodes/locales/en/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/en/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/en/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/en/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/en/knxUltimateHueController.html +0 -691
- package/nodes/locales/en/knxUltimateHueController.json +0 -64
- package/nodes/locales/en/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/en/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/en/knxUltimateHueLight.html +0 -124
- package/nodes/locales/en/knxUltimateHueLight.json +0 -94
- package/nodes/locales/en/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/en/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/en/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/en/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/en/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/en/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/en/knxUltimateHueScene.html +0 -45
- package/nodes/locales/en/knxUltimateHueScene.json +0 -41
- package/nodes/locales/en/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/en/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/en/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/en/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/en/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/en/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/en/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/en/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/en/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/en/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/en/knxUltimateLogger.html +0 -161
- package/nodes/locales/en/knxUltimateLogger.json +0 -31
- package/nodes/locales/en/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/en/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/en/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/en/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/en/knxUltimateSceneController.html +0 -117
- package/nodes/locales/en/knxUltimateSceneController.json +0 -32
- package/nodes/locales/en/knxUltimateStaircase.html +0 -77
- package/nodes/locales/en/knxUltimateStaircase.json +0 -62
- package/nodes/locales/en/knxUltimateWatchDog.html +0 -244
- package/nodes/locales/en/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/en/matter-config.html +0 -47
- package/nodes/locales/en/matter-config.json +0 -48
- package/nodes/locales/en/matterbridge-config.html +0 -45
- package/nodes/locales/en/matterbridge-config.json +0 -25
- package/nodes/locales/es/hue-config.html +0 -31
- package/nodes/locales/es/hue-config.json +0 -21
- package/nodes/locales/es/knxUltimateAI.html +0 -13
- package/nodes/locales/es/knxUltimateAI.json +0 -231
- package/nodes/locales/es/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/es/knxUltimateAlerter.html +0 -164
- package/nodes/locales/es/knxUltimateAlerter.json +0 -27
- package/nodes/locales/es/knxUltimateAutoResponder.html +0 -81
- package/nodes/locales/es/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/es/knxUltimateDateTime.html +0 -45
- package/nodes/locales/es/knxUltimateDateTime.json +0 -32
- package/nodes/locales/es/knxUltimateGarage.html +0 -79
- package/nodes/locales/es/knxUltimateGarage.json +0 -51
- package/nodes/locales/es/knxUltimateGlobalContext.html +0 -128
- package/nodes/locales/es/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/es/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/es/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/es/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/es/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/es/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/es/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/es/knxUltimateHueButton.html +0 -52
- package/nodes/locales/es/knxUltimateHueButton.json +0 -34
- package/nodes/locales/es/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/es/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/es/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/es/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/es/knxUltimateHueController.html +0 -691
- package/nodes/locales/es/knxUltimateHueController.json +0 -64
- package/nodes/locales/es/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/es/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/es/knxUltimateHueLight.html +0 -124
- package/nodes/locales/es/knxUltimateHueLight.json +0 -94
- package/nodes/locales/es/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/es/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/es/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/es/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/es/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/es/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/es/knxUltimateHueScene.html +0 -45
- package/nodes/locales/es/knxUltimateHueScene.json +0 -41
- package/nodes/locales/es/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/es/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/es/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/es/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/es/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/es/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/es/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/es/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/es/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/es/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/es/knxUltimateLogger.html +0 -162
- package/nodes/locales/es/knxUltimateLogger.json +0 -31
- package/nodes/locales/es/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/es/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/es/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/es/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/es/knxUltimateSceneController.html +0 -115
- package/nodes/locales/es/knxUltimateSceneController.json +0 -32
- package/nodes/locales/es/knxUltimateStaircase.html +0 -77
- package/nodes/locales/es/knxUltimateStaircase.json +0 -62
- package/nodes/locales/es/knxUltimateWatchDog.html +0 -230
- package/nodes/locales/es/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/es/matter-config.html +0 -47
- package/nodes/locales/es/matter-config.json +0 -47
- package/nodes/locales/es/matterbridge-config.html +0 -45
- package/nodes/locales/es/matterbridge-config.json +0 -25
- package/nodes/locales/fr/hue-config.html +0 -31
- package/nodes/locales/fr/hue-config.json +0 -21
- package/nodes/locales/fr/knxUltimateAI.html +0 -13
- package/nodes/locales/fr/knxUltimateAI.json +0 -231
- package/nodes/locales/fr/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/fr/knxUltimateAlerter.html +0 -164
- package/nodes/locales/fr/knxUltimateAlerter.json +0 -27
- package/nodes/locales/fr/knxUltimateAutoResponder.html +0 -92
- package/nodes/locales/fr/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/fr/knxUltimateDateTime.html +0 -45
- package/nodes/locales/fr/knxUltimateDateTime.json +0 -32
- package/nodes/locales/fr/knxUltimateGarage.html +0 -79
- package/nodes/locales/fr/knxUltimateGarage.json +0 -51
- package/nodes/locales/fr/knxUltimateGlobalContext.html +0 -122
- package/nodes/locales/fr/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/fr/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/fr/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/fr/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/fr/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/fr/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/fr/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/fr/knxUltimateHueButton.html +0 -52
- package/nodes/locales/fr/knxUltimateHueButton.json +0 -34
- package/nodes/locales/fr/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/fr/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/fr/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/fr/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/fr/knxUltimateHueController.html +0 -691
- package/nodes/locales/fr/knxUltimateHueController.json +0 -64
- package/nodes/locales/fr/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/fr/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/fr/knxUltimateHueLight.html +0 -124
- package/nodes/locales/fr/knxUltimateHueLight.json +0 -86
- package/nodes/locales/fr/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/fr/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/fr/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/fr/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/fr/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/fr/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/fr/knxUltimateHueScene.html +0 -45
- package/nodes/locales/fr/knxUltimateHueScene.json +0 -41
- package/nodes/locales/fr/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/fr/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/fr/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/fr/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/fr/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/fr/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/fr/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/fr/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/fr/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/fr/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/fr/knxUltimateLogger.html +0 -160
- package/nodes/locales/fr/knxUltimateLogger.json +0 -31
- package/nodes/locales/fr/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/fr/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/fr/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/fr/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/fr/knxUltimateSceneController.html +0 -117
- package/nodes/locales/fr/knxUltimateSceneController.json +0 -32
- package/nodes/locales/fr/knxUltimateStaircase.html +0 -77
- package/nodes/locales/fr/knxUltimateStaircase.json +0 -62
- package/nodes/locales/fr/knxUltimateWatchDog.html +0 -228
- package/nodes/locales/fr/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/fr/matter-config.html +0 -47
- package/nodes/locales/fr/matter-config.json +0 -47
- package/nodes/locales/fr/matterbridge-config.html +0 -45
- package/nodes/locales/fr/matterbridge-config.json +0 -25
- package/nodes/locales/it/hue-config.html +0 -33
- package/nodes/locales/it/hue-config.json +0 -21
- package/nodes/locales/it/knxUltimateAI.html +0 -13
- package/nodes/locales/it/knxUltimateAI.json +0 -234
- package/nodes/locales/it/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/it/knxUltimateAlerter.html +0 -159
- package/nodes/locales/it/knxUltimateAlerter.json +0 -27
- package/nodes/locales/it/knxUltimateAutoResponder.html +0 -96
- package/nodes/locales/it/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/it/knxUltimateDateTime.html +0 -67
- package/nodes/locales/it/knxUltimateDateTime.json +0 -32
- package/nodes/locales/it/knxUltimateGarage.html +0 -79
- package/nodes/locales/it/knxUltimateGarage.json +0 -51
- package/nodes/locales/it/knxUltimateGlobalContext.html +0 -81
- package/nodes/locales/it/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/it/knxUltimateHATranslator.html +0 -24
- package/nodes/locales/it/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/it/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/it/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/it/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/it/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/it/knxUltimateHueButton.html +0 -52
- package/nodes/locales/it/knxUltimateHueButton.json +0 -34
- package/nodes/locales/it/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/it/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/it/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/it/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/it/knxUltimateHueController.html +0 -690
- package/nodes/locales/it/knxUltimateHueController.json +0 -64
- package/nodes/locales/it/knxUltimateHueHumiditySensor 2.html +0 -11
- package/nodes/locales/it/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/it/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/it/knxUltimateHueLight.html +0 -124
- package/nodes/locales/it/knxUltimateHueLight.json +0 -94
- package/nodes/locales/it/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/it/knxUltimateHueLightSensor.json +0 -19
- package/nodes/locales/it/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/it/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/it/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/it/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/it/knxUltimateHueScene.html +0 -45
- package/nodes/locales/it/knxUltimateHueScene.json +0 -41
- package/nodes/locales/it/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/it/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/it/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/it/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/it/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/it/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/it/knxUltimateHuedevice_software_update.html +0 -35
- package/nodes/locales/it/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/it/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/it/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/it/knxUltimateLogger.html +0 -132
- package/nodes/locales/it/knxUltimateLogger.json +0 -31
- package/nodes/locales/it/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/it/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/it/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/it/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/it/knxUltimateSceneController.html +0 -101
- package/nodes/locales/it/knxUltimateSceneController.json +0 -32
- package/nodes/locales/it/knxUltimateStaircase.html +0 -77
- package/nodes/locales/it/knxUltimateStaircase.json +0 -62
- package/nodes/locales/it/knxUltimateWatchDog.html +0 -194
- package/nodes/locales/it/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/it/matter-config.html +0 -47
- package/nodes/locales/it/matter-config.json +0 -48
- package/nodes/locales/it/matterbridge-config.html +0 -45
- package/nodes/locales/it/matterbridge-config.json +0 -25
- package/nodes/locales/zh-CN/hue-config.html +0 -33
- package/nodes/locales/zh-CN/hue-config.json +0 -21
- package/nodes/locales/zh-CN/knxUltimateAI.html +0 -13
- package/nodes/locales/zh-CN/knxUltimateAI.json +0 -231
- package/nodes/locales/zh-CN/knxUltimateAIHomeAssistant.html +0 -11
- package/nodes/locales/zh-CN/knxUltimateAlerter.html +0 -159
- package/nodes/locales/zh-CN/knxUltimateAlerter.json +0 -27
- package/nodes/locales/zh-CN/knxUltimateAutoResponder.html +0 -94
- package/nodes/locales/zh-CN/knxUltimateAutoResponder.json +0 -8
- package/nodes/locales/zh-CN/knxUltimateDateTime.html +0 -45
- package/nodes/locales/zh-CN/knxUltimateDateTime.json +0 -32
- package/nodes/locales/zh-CN/knxUltimateGarage.html +0 -79
- package/nodes/locales/zh-CN/knxUltimateGarage.json +0 -51
- package/nodes/locales/zh-CN/knxUltimateGlobalContext.html +0 -77
- package/nodes/locales/zh-CN/knxUltimateGlobalContext.json +0 -24
- package/nodes/locales/zh-CN/knxUltimateHATranslator.html +0 -25
- package/nodes/locales/zh-CN/knxUltimateHATranslator.json +0 -8
- package/nodes/locales/zh-CN/knxUltimateHueAreaMotion.html +0 -44
- package/nodes/locales/zh-CN/knxUltimateHueAreaMotion.json +0 -31
- package/nodes/locales/zh-CN/knxUltimateHueBattery.html +0 -37
- package/nodes/locales/zh-CN/knxUltimateHueBattery.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueButton.html +0 -52
- package/nodes/locales/zh-CN/knxUltimateHueButton.json +0 -34
- package/nodes/locales/zh-CN/knxUltimateHueCameraMotion.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueCameraMotion.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueContactSensor.html +0 -35
- package/nodes/locales/zh-CN/knxUltimateHueContactSensor.json +0 -26
- package/nodes/locales/zh-CN/knxUltimateHueController.html +0 -693
- package/nodes/locales/zh-CN/knxUltimateHueController.json +0 -64
- package/nodes/locales/zh-CN/knxUltimateHueHumiditySensor.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueHumiditySensor.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueLight.html +0 -126
- package/nodes/locales/zh-CN/knxUltimateHueLight.json +0 -86
- package/nodes/locales/zh-CN/knxUltimateHueLightSensor.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueLightSensor.json +0 -9
- package/nodes/locales/zh-CN/knxUltimateHueMotion.html +0 -41
- package/nodes/locales/zh-CN/knxUltimateHueMotion.json +0 -27
- package/nodes/locales/zh-CN/knxUltimateHuePlug.html +0 -50
- package/nodes/locales/zh-CN/knxUltimateHuePlug.json +0 -33
- package/nodes/locales/zh-CN/knxUltimateHueScene.html +0 -45
- package/nodes/locales/zh-CN/knxUltimateHueScene.json +0 -41
- package/nodes/locales/zh-CN/knxUltimateHueTapDial.html +0 -40
- package/nodes/locales/zh-CN/knxUltimateHueTapDial.json +0 -28
- package/nodes/locales/zh-CN/knxUltimateHueTemperatureSensor.html +0 -38
- package/nodes/locales/zh-CN/knxUltimateHueTemperatureSensor.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHueZigbeeConnectivity.html +0 -39
- package/nodes/locales/zh-CN/knxUltimateHueZigbeeConnectivity.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateHuedevice_software_update.html +0 -36
- package/nodes/locales/zh-CN/knxUltimateHuedevice_software_update.json +0 -30
- package/nodes/locales/zh-CN/knxUltimateLoadControl.html +0 -76
- package/nodes/locales/zh-CN/knxUltimateLoadControl.json +0 -28
- package/nodes/locales/zh-CN/knxUltimateLogger.html +0 -126
- package/nodes/locales/zh-CN/knxUltimateLogger.json +0 -31
- package/nodes/locales/zh-CN/knxUltimateMatterBridge.html +0 -65
- package/nodes/locales/zh-CN/knxUltimateMatterBridge.json +0 -123
- package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.html +0 -57
- package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.json +0 -146
- package/nodes/locales/zh-CN/knxUltimateSceneController.html +0 -98
- package/nodes/locales/zh-CN/knxUltimateSceneController.json +0 -32
- package/nodes/locales/zh-CN/knxUltimateStaircase.html +0 -77
- package/nodes/locales/zh-CN/knxUltimateStaircase.json +0 -62
- package/nodes/locales/zh-CN/knxUltimateWatchDog.html +0 -178
- package/nodes/locales/zh-CN/knxUltimateWatchDog.json +0 -27
- package/nodes/locales/zh-CN/matter-config.html +0 -47
- package/nodes/locales/zh-CN/matter-config.json +0 -47
- package/nodes/locales/zh-CN/matterbridge-config.html +0 -45
- package/nodes/locales/zh-CN/matterbridge-config.json +0 -25
- package/nodes/matter-config.html +0 -578
- package/nodes/matter-config.js +0 -387
- package/nodes/matterbridge-config.html +0 -198
- package/nodes/matterbridge-config.js +0 -261
- package/nodes/plugins/knxUltimate-cerebrum-runtime-plugin.js +0 -79
- package/nodes/plugins/knxUltimate-migration-notice-plugin.html +0 -44
- package/nodes/plugins/knxUltimateAI-vue/assets/app.css +0 -1
- package/nodes/plugins/knxUltimateAI-vue/assets/app.js +0 -13
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-html2canvas.esm.js +0 -5
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-index.es.js +0 -5
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-jspdf.es.min.js +0 -79
- package/nodes/plugins/knxUltimateAI-vue/assets/chunk-purify.es.js +0 -3
- package/nodes/plugins/knxUltimateAI-vue/index.html +0 -13
- package/nodes/utils/HueEventStream.mjs +0 -176
- package/nodes/utils/colorManipulators/XYFromRGB_Supergiovane.js +0 -113
- package/nodes/utils/colorManipulators/hueColorConverter.js +0 -521
- package/nodes/utils/http.js +0 -291
- package/nodes/utils/hueControllerProfileAdapter.js +0 -104
- package/nodes/utils/hueControllerProfiles/runtime/area_motion.js +0 -221
- package/nodes/utils/hueControllerProfiles/runtime/button.js +0 -295
- package/nodes/utils/hueControllerProfiles/runtime/camera_motion.js +0 -221
- package/nodes/utils/hueControllerProfiles/runtime/contact.js +0 -191
- package/nodes/utils/hueControllerProfiles/runtime/device_power.js +0 -185
- package/nodes/utils/hueControllerProfiles/runtime/device_software_update.js +0 -185
- package/nodes/utils/hueControllerProfiles/runtime/humidity.js +0 -204
- package/nodes/utils/hueControllerProfiles/runtime/light.js +0 -1585
- package/nodes/utils/hueControllerProfiles/runtime/light_level.js +0 -180
- package/nodes/utils/hueControllerProfiles/runtime/motion.js +0 -185
- package/nodes/utils/hueControllerProfiles/runtime/plug.js +0 -344
- package/nodes/utils/hueControllerProfiles/runtime/relative_rotary.js +0 -271
- package/nodes/utils/hueControllerProfiles/runtime/scene.js +0 -352
- package/nodes/utils/hueControllerProfiles/runtime/temperature.js +0 -187
- package/nodes/utils/hueControllerProfiles/runtime/zigbee_connectivity.js +0 -185
- package/nodes/utils/hueControllerResourceCatalog.js +0 -71
- package/nodes/utils/hueEngine.mjs +0 -469
- package/nodes/utils/knxAiCamera.js +0 -302
- package/nodes/utils/knxAiCatalogRetrieval.js +0 -349
- package/nodes/utils/knxAiCerebrum.js +0 -406
- package/nodes/utils/knxAiChatContext.js +0 -496
- package/nodes/utils/knxAiEventHistory.js +0 -521
- package/nodes/utils/knxAiHomeMemory.js +0 -1021
- package/nodes/utils/knxAiScheduler.js +0 -445
- package/nodes/utils/knxAiSemanticContext.js +0 -662
- package/nodes/utils/knxAiTelegramVoice.js +0 -545
- package/nodes/utils/knxAiWebAccess.js +0 -631
- package/nodes/utils/lightEngines/canonicalLight.js +0 -75
- package/nodes/utils/lightEngines/hueLightEngine.js +0 -51
- package/nodes/utils/lightEngines/index.js +0 -25
- package/nodes/utils/lightEngines/knxLightCommand.js +0 -79
- package/nodes/utils/lightEngines/lightEngine.js +0 -46
- package/nodes/utils/lightEngines/matterHueShim.js +0 -59
- package/nodes/utils/lightEngines/matterLightEngine.js +0 -117
- package/nodes/utils/matterBridgeDeviceFactory.mjs +0 -780
- package/nodes/utils/matterBridgeEngine.mjs +0 -297
- package/nodes/utils/matterControllerCommandGate.js +0 -47
- package/nodes/utils/matterControllerProfiles/doorLock.js +0 -258
- package/nodes/utils/matterControllerProfiles/fan.js +0 -19
- package/nodes/utils/matterControllerProfiles/index.js +0 -34
- package/nodes/utils/matterControllerProfiles/mappedEndpoint.js +0 -217
- package/nodes/utils/matterControllerProfiles/switch.js +0 -13
- package/nodes/utils/matterControllerProfiles/thermostat.js +0 -19
- package/nodes/utils/matterControllerProfiles/universal.js +0 -462
- package/nodes/utils/matterControllerProfiles/windowCovering.js +0 -19
- package/nodes/utils/matterControllerSemanticInput.js +0 -212
- package/nodes/utils/matterEngine.mjs +0 -894
- package/nodes/utils/matterEnvironmentLock.mjs +0 -32
- package/nodes/utils/matterKnxConverter.js +0 -204
- package/nodes/utils/matterStorageBackup.js +0 -100
- package/resources/HA-icon.png +0 -0
- package/resources/dim.png +0 -0
- package/resources/rgb.png +0 -0
- package/resources/tunablewhite.png +0 -0
- package/resources/zxing-browser-0.2.0.min.js +0 -1
- package/resources/zxing-browser-LICENSE.txt +0 -21
|
@@ -1,780 +0,0 @@
|
|
|
1
|
-
/* eslint-disable max-len */
|
|
2
|
-
// Factory of the bridged Matter endpoints exposed by knxUltimateMatterBridge.
|
|
3
|
-
// Each KNX "virtual device" definition becomes a Matter endpoint under the aggregator.
|
|
4
|
-
import { Endpoint } from '@matter/main'
|
|
5
|
-
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information'
|
|
6
|
-
import { OnOffServer } from '@matter/main/behaviors/on-off'
|
|
7
|
-
import { LevelControlServer } from '@matter/main/behaviors/level-control'
|
|
8
|
-
import { OnOffLightDevice } from '@matter/main/devices/on-off-light'
|
|
9
|
-
import { DimmableLightDevice } from '@matter/main/devices/dimmable-light'
|
|
10
|
-
import { OnOffPlugInUnitDevice } from '@matter/main/devices/on-off-plug-in-unit'
|
|
11
|
-
import { TemperatureSensorDevice } from '@matter/main/devices/temperature-sensor'
|
|
12
|
-
import { HumiditySensorDevice } from '@matter/main/devices/humidity-sensor'
|
|
13
|
-
import { LightSensorDevice } from '@matter/main/devices/light-sensor'
|
|
14
|
-
import { OccupancySensorDevice } from '@matter/main/devices/occupancy-sensor'
|
|
15
|
-
import { OccupancySensingServer } from '@matter/main/behaviors/occupancy-sensing'
|
|
16
|
-
import { ContactSensorDevice } from '@matter/main/devices/contact-sensor'
|
|
17
|
-
import { WindowCoveringDevice } from '@matter/main/devices/window-covering'
|
|
18
|
-
import { MovementDirection, MovementType, WindowCoveringServer } from '@matter/main/behaviors/window-covering'
|
|
19
|
-
import { ThermostatDevice } from '@matter/main/devices/thermostat'
|
|
20
|
-
import { ThermostatServer } from '@matter/main/behaviors/thermostat'
|
|
21
|
-
import { ExtendedColorLightDevice } from '@matter/main/devices/extended-color-light'
|
|
22
|
-
import { ColorTemperatureLightDevice } from '@matter/main/devices/color-temperature-light'
|
|
23
|
-
import { ColorControlServer } from '@matter/main/behaviors/color-control'
|
|
24
|
-
import { SmokeCoAlarmDevice } from '@matter/main/devices/smoke-co-alarm'
|
|
25
|
-
import { SmokeCoAlarmServer } from '@matter/main/behaviors/smoke-co-alarm'
|
|
26
|
-
import { WaterLeakDetectorDevice } from '@matter/main/devices/water-leak-detector'
|
|
27
|
-
import { AirQualitySensorDevice } from '@matter/main/devices/air-quality-sensor'
|
|
28
|
-
import { AirQualityServer } from '@matter/main/behaviors/air-quality'
|
|
29
|
-
import { CarbonDioxideConcentrationMeasurementServer } from '@matter/main/behaviors/carbon-dioxide-concentration-measurement'
|
|
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'
|
|
36
|
-
import { RoboticVacuumCleanerDevice } from '@matter/main/devices/robotic-vacuum-cleaner'
|
|
37
|
-
import { RvcRunModeServer } from '@matter/main/behaviors/rvc-run-mode'
|
|
38
|
-
import { RvcOperationalStateServer } from '@matter/main/behaviors/rvc-operational-state'
|
|
39
|
-
import { ModeUtils } from '@matter/main/behaviors/mode-base'
|
|
40
|
-
import hueColorConverter from './colorManipulators/hueColorConverter.js'
|
|
41
|
-
|
|
42
|
-
const { ColorConverter } = hueColorConverter
|
|
43
|
-
const clamp = (v, min, max) => Math.min(max, Math.max(min, v))
|
|
44
|
-
const truthy = (v) => v === true || v === 1 || v === '1' || v === 'true' || v === 'on'
|
|
45
|
-
|
|
46
|
-
// Catalog of the supported virtual device types.
|
|
47
|
-
// - functions: the abstract functions the KNX node can feed/receive ('onoff', 'level', 'temperature', ...)
|
|
48
|
-
// - commandFunctions: the subset that flows Matter -> KNX (commands from Alexa & Co.)
|
|
49
|
-
const BRIDGE_TYPES = {
|
|
50
|
-
onofflight: { device: OnOffLightDevice, functions: ['onoff'], commandFunctions: ['onoff'] },
|
|
51
|
-
onoffplug: { device: OnOffPlugInUnitDevice, functions: ['onoff'], commandFunctions: ['onoff'] },
|
|
52
|
-
dimmablelight: { device: DimmableLightDevice, functions: ['onoff', 'level'], commandFunctions: ['onoff', 'level'] },
|
|
53
|
-
temperaturesensor: { device: TemperatureSensorDevice, functions: ['temperature'], commandFunctions: [] },
|
|
54
|
-
humiditysensor: { device: HumiditySensorDevice, functions: ['humidity'], commandFunctions: [] },
|
|
55
|
-
lightsensor: { device: LightSensorDevice, functions: ['illuminance'], commandFunctions: [] },
|
|
56
|
-
occupancysensor: { device: OccupancySensorDevice, functions: ['occupancy'], commandFunctions: [] },
|
|
57
|
-
contactsensor: { device: ContactSensorDevice, functions: ['contact'], commandFunctions: [] },
|
|
58
|
-
// Custom construction (dedicated server behaviors), handled in createBridgedEndpoint
|
|
59
|
-
windowcovering: { device: null, functions: ['position'], commandFunctions: [] },
|
|
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: [] },
|
|
63
|
-
rgblight: { device: null, functions: ['onoff', 'level', 'rgb'], commandFunctions: ['onoff', 'level'] },
|
|
64
|
-
colortemperaturelight: { device: null, functions: ['onoff', 'level', 'colortemp'], commandFunctions: ['onoff', 'level'] },
|
|
65
|
-
smokecoalarm: { device: null, functions: ['smoke', 'co'], commandFunctions: [] },
|
|
66
|
-
waterleakdetector: { device: WaterLeakDetectorDevice, functions: ['leak'], commandFunctions: [] },
|
|
67
|
-
airqualitysensor: { device: null, functions: ['co2'], commandFunctions: [] },
|
|
68
|
-
fan: { device: null, functions: ['fanspeed'], commandFunctions: [] },
|
|
69
|
-
robotvacuum: { device: null, functions: ['rvcstate', 'rvcmode'], commandFunctions: [] } // Flow-only (node PINs)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
// CO2 ppm -> Matter AirQuality classification (1 Good ... 6 ExtremelyPoor)
|
|
73
|
-
function co2ToAirQuality (ppm) {
|
|
74
|
-
if (ppm < 800) return 1
|
|
75
|
-
if (ppm < 1000) return 2
|
|
76
|
-
if (ppm < 1400) return 3
|
|
77
|
-
if (ppm < 2000) return 4
|
|
78
|
-
if (ppm < 3000) return 5
|
|
79
|
-
return 6
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// RVC operational states (Matter enum values, incl. the RVC specific ones)
|
|
83
|
-
const RVC_OP_STATES = { stopped: 0, running: 1, paused: 2, error: 3, seekingcharger: 0x40, charging: 0x41, docked: 0x42 }
|
|
84
|
-
|
|
85
|
-
// KNX payload (decoded DPT value) -> Matter attribute patch for endpoint.set()
|
|
86
|
-
function knxValueToMatterPatch (def, fn, value) {
|
|
87
|
-
switch (fn) {
|
|
88
|
-
case 'position': {
|
|
89
|
-
// KNX 5.001 position: 0% = open, 100% = closed (invert flag flips it).
|
|
90
|
-
// Matter lift percent100ths: 0 = open, 10000 = closed.
|
|
91
|
-
let percent = Number(value)
|
|
92
|
-
if (Number.isNaN(percent)) return undefined
|
|
93
|
-
const invert = (def.invertPosition === true) !== (def.coverSwapOpenClose === true)
|
|
94
|
-
if (invert) percent = 100 - percent
|
|
95
|
-
return { windowCovering: { currentPositionLiftPercent100ths: clamp(Math.round(percent * 100), 0, 10000) } }
|
|
96
|
-
}
|
|
97
|
-
case 'rgb': {
|
|
98
|
-
// KNX DPT 232.600 payload: { red, green, blue } 0-255 -> Matter hue/saturation (0-254)
|
|
99
|
-
if (value === null || typeof value !== 'object') return undefined
|
|
100
|
-
const red = Number(value.red); const green = Number(value.green); const blue = Number(value.blue)
|
|
101
|
-
if (Number.isNaN(red) || Number.isNaN(green) || Number.isNaN(blue)) return undefined
|
|
102
|
-
const hsv = ColorConverter.rgbToHsv(clamp(red, 0, 255), clamp(green, 0, 255), clamp(blue, 0, 255)) // h,s,v in percent 0-100
|
|
103
|
-
return {
|
|
104
|
-
colorControl: {
|
|
105
|
-
currentHue: clamp(Math.round(hsv.h * 254 / 100), 0, 254),
|
|
106
|
-
currentSaturation: clamp(Math.round(hsv.s * 254 / 100), 0, 254)
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
case 'colortemp': {
|
|
111
|
-
// KNX DPT 7.600 carries Kelvin -> Matter mireds (accept mireds too for values < 1000)
|
|
112
|
-
const numeric = Number(value)
|
|
113
|
-
if (Number.isNaN(numeric) || numeric <= 0) return undefined
|
|
114
|
-
const mireds = numeric >= 1000 ? Math.round(1000000 / numeric) : Math.round(numeric)
|
|
115
|
-
return { colorControl: { colorTemperatureMireds: clamp(mireds, 153, 500) } }
|
|
116
|
-
}
|
|
117
|
-
case 'currenttemp': {
|
|
118
|
-
const t = Number(value)
|
|
119
|
-
if (Number.isNaN(t)) return undefined
|
|
120
|
-
return { thermostat: { localTemperature: Math.round(t * 100) } }
|
|
121
|
-
}
|
|
122
|
-
case 'setpoint': {
|
|
123
|
-
const t = Number(value)
|
|
124
|
-
if (Number.isNaN(t)) return undefined
|
|
125
|
-
return { thermostat: { occupiedHeatingSetpoint: clamp(Math.round(t * 100), 700, 3000) } } // 7-30°C
|
|
126
|
-
}
|
|
127
|
-
case 'coolingsetpoint': {
|
|
128
|
-
const t = Number(value)
|
|
129
|
-
if (Number.isNaN(t)) return undefined
|
|
130
|
-
return { thermostat: { occupiedCoolingSetpoint: clamp(Math.round(t * 100), 1600, 3200) } } // 16-32°C
|
|
131
|
-
}
|
|
132
|
-
case 'onoff':
|
|
133
|
-
return { onOff: { onOff: truthy(value) } }
|
|
134
|
-
case 'lock':
|
|
135
|
-
return { doorLock: { lockState: truthy(value) ? DoorLock.LockState.Locked : DoorLock.LockState.Unlocked } }
|
|
136
|
-
case 'level': {
|
|
137
|
-
const percent = Number(value)
|
|
138
|
-
if (Number.isNaN(percent)) return undefined
|
|
139
|
-
// KNX 0-100% -> Matter level 1-254 (0 is not a valid "on" level for lighting)
|
|
140
|
-
const level = clamp(Math.round(percent * 254 / 100), 1, 254)
|
|
141
|
-
return { levelControl: { currentLevel: level } }
|
|
142
|
-
}
|
|
143
|
-
case 'temperature': {
|
|
144
|
-
const t = Number(value)
|
|
145
|
-
if (Number.isNaN(t)) return undefined
|
|
146
|
-
return { temperatureMeasurement: { measuredValue: Math.round(t * 100) } } // °C -> centi-°C
|
|
147
|
-
}
|
|
148
|
-
case 'humidity': {
|
|
149
|
-
const h = Number(value)
|
|
150
|
-
if (Number.isNaN(h)) return undefined
|
|
151
|
-
return { relativeHumidityMeasurement: { measuredValue: clamp(Math.round(h * 100), 0, 10000) } }
|
|
152
|
-
}
|
|
153
|
-
case 'illuminance': {
|
|
154
|
-
const lux = Number(value)
|
|
155
|
-
if (Number.isNaN(lux)) return undefined
|
|
156
|
-
// Matter: measuredValue = 10000 * log10(lux) + 1 (0 = "too low to measure")
|
|
157
|
-
const measured = lux <= 0 ? 0 : clamp(Math.round(10000 * Math.log10(lux) + 1), 0, 65534)
|
|
158
|
-
return { illuminanceMeasurement: { measuredValue: measured } }
|
|
159
|
-
}
|
|
160
|
-
case 'occupancy':
|
|
161
|
-
return { occupancySensing: { occupancy: { occupied: truthy(value) } } }
|
|
162
|
-
case 'contact':
|
|
163
|
-
return { booleanState: { stateValue: truthy(value) } }
|
|
164
|
-
case 'leak':
|
|
165
|
-
return { booleanState: { stateValue: truthy(value) } } // true = leak detected
|
|
166
|
-
case 'smoke': {
|
|
167
|
-
const alarm = truthy(value)
|
|
168
|
-
return { smokeCoAlarm: { smokeState: alarm ? 2 : 0, expressedState: alarm ? 1 : 0 } } // 2 = critical
|
|
169
|
-
}
|
|
170
|
-
case 'co': {
|
|
171
|
-
const alarm = truthy(value)
|
|
172
|
-
return { smokeCoAlarm: { coState: alarm ? 2 : 0, expressedState: alarm ? 2 : 0 } }
|
|
173
|
-
}
|
|
174
|
-
case 'co2': {
|
|
175
|
-
const ppm = Number(value)
|
|
176
|
-
if (Number.isNaN(ppm) || ppm < 0) return undefined
|
|
177
|
-
return {
|
|
178
|
-
carbonDioxideConcentrationMeasurement: { measuredValue: Math.round(ppm) },
|
|
179
|
-
airQuality: { airQuality: co2ToAirQuality(ppm) }
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
case 'fanspeed': {
|
|
183
|
-
const percent = Number(value)
|
|
184
|
-
if (Number.isNaN(percent)) return undefined
|
|
185
|
-
const p = clamp(Math.round(percent), 0, 100)
|
|
186
|
-
return { fanControl: { percentCurrent: p, percentSetting: p, fanMode: p > 0 ? 3 : 0 } } // 3 = High, 0 = Off
|
|
187
|
-
}
|
|
188
|
-
case 'rvcstate': {
|
|
189
|
-
// 'docked' | 'charging' | 'running' | 'paused' | 'stopped' | 'seekingcharger' | 'error' (or the numeric Matter value)
|
|
190
|
-
const key = value !== null && value !== undefined ? value.toString().toLowerCase().trim() : ''
|
|
191
|
-
const state = RVC_OP_STATES[key] !== undefined ? RVC_OP_STATES[key] : Number(value)
|
|
192
|
-
if (Number.isNaN(state)) return undefined
|
|
193
|
-
return { rvcOperationalState: { operationalState: state } }
|
|
194
|
-
}
|
|
195
|
-
case 'rvcmode': {
|
|
196
|
-
const key = value !== null && value !== undefined ? value.toString().toLowerCase().trim() : ''
|
|
197
|
-
if (key !== 'idle' && key !== 'cleaning') return undefined
|
|
198
|
-
return { rvcRunMode: { currentMode: key === 'cleaning' ? 1 : 0 } }
|
|
199
|
-
}
|
|
200
|
-
default:
|
|
201
|
-
return undefined
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Builds a ColorControlServer that captures color commands AT THE COMMAND BOUNDARY
|
|
206
|
-
// (like RawOnOffServer/RawLevelControlServer), instead of listening for attribute
|
|
207
|
-
// changes: repeated commands (e.g. "set to red" twice) are still forwarded every time,
|
|
208
|
-
// not just the first. This is possible for color because Matter controllers always
|
|
209
|
-
// change color via cluster COMMANDS (MoveToHue, MoveToSaturation, MoveToHueAndSaturation,
|
|
210
|
-
// MoveToColor) - unlike e.g. Thermostat/FanControl, where absolute values are set via a
|
|
211
|
-
// plain ATTRIBUTE WRITE with no command-level hook to intercept (verified against
|
|
212
|
-
// @matter/node's ThermostatServer/FanControlServer: only relative Move/Step-style
|
|
213
|
-
// commands exist there, not the absolute "set to X" interaction voice assistants use).
|
|
214
|
-
//
|
|
215
|
-
// Controllers set the color as hue+saturation OR as X+Y, sometimes as two separate
|
|
216
|
-
// commands (MoveToHue then MoveToSaturation): a short debounce merges those two into a
|
|
217
|
-
// single KNX RGB command. A combined MoveToHueAndSaturation/MoveToColor command already
|
|
218
|
-
// carries both values, so it flushes immediately with no debounce.
|
|
219
|
-
function createRawColorControlServer (def, onCommand) {
|
|
220
|
-
const tracker = { hue: 0, sat: 0, x: undefined, y: undefined, mode: 0, level: 254, timer: null }
|
|
221
|
-
|
|
222
|
-
const flush = () => {
|
|
223
|
-
if (tracker.timer !== null) { clearTimeout(tracker.timer); tracker.timer = null }
|
|
224
|
-
try {
|
|
225
|
-
const v01 = clamp((tracker.level === null || tracker.level === undefined ? 254 : Number(tracker.level)) / 254, 0, 1)
|
|
226
|
-
let rgb
|
|
227
|
-
if (tracker.mode === 1 && tracker.x !== undefined && tracker.y !== undefined) {
|
|
228
|
-
// XY color mode (Matter x/y are 0..65536 for 0..1)
|
|
229
|
-
rgb = ColorConverter.xyBriToRgb(tracker.x / 65536, tracker.y / 65536, Math.max(1, Math.round(v01 * 100)))
|
|
230
|
-
} else {
|
|
231
|
-
// Hue/Saturation mode (Matter 0..254 -> 0..1)
|
|
232
|
-
rgb = ColorConverter.hsvToRgb(clamp(tracker.hue / 254, 0, 1), clamp(tracker.sat / 254, 0, 1), Math.max(0.01, v01))
|
|
233
|
-
}
|
|
234
|
-
if (!rgb) return
|
|
235
|
-
onCommand({
|
|
236
|
-
deviceId: def.id,
|
|
237
|
-
fn: 'rgb',
|
|
238
|
-
value: { red: clamp(Math.round(rgb.r), 0, 255), green: clamp(Math.round(rgb.g), 0, 255), blue: clamp(Math.round(rgb.b), 0, 255) }
|
|
239
|
-
})
|
|
240
|
-
} catch (error) { /* empty */ }
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
const schedule = () => {
|
|
244
|
-
if (tracker.timer !== null) clearTimeout(tracker.timer)
|
|
245
|
-
tracker.timer = setTimeout(flush, 250)
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
class RawColorControlServer extends ColorControlServer.with('HueSaturation', 'Xy') {
|
|
249
|
-
async moveToHue (request) {
|
|
250
|
-
await super.moveToHue(request)
|
|
251
|
-
tracker.hue = Number(request.hue)
|
|
252
|
-
tracker.mode = 0
|
|
253
|
-
schedule()
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async moveToSaturation (request) {
|
|
257
|
-
await super.moveToSaturation(request)
|
|
258
|
-
tracker.sat = Number(request.saturation)
|
|
259
|
-
tracker.mode = 0
|
|
260
|
-
schedule()
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async moveToHueAndSaturation (request) {
|
|
264
|
-
await super.moveToHueAndSaturation(request)
|
|
265
|
-
tracker.hue = Number(request.hue)
|
|
266
|
-
tracker.sat = Number(request.saturation)
|
|
267
|
-
tracker.mode = 0
|
|
268
|
-
flush() // atomic: both values already known, no need to wait for a second command
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
async moveToColor (request) {
|
|
272
|
-
await super.moveToColor(request)
|
|
273
|
-
tracker.x = Number(request.colorX)
|
|
274
|
-
tracker.y = Number(request.colorY)
|
|
275
|
-
tracker.mode = 1
|
|
276
|
-
flush()
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Track the brightness (for the RGB computation only: the level command has its own GA).
|
|
281
|
-
// Passive bookkeeping, not a command to forward raw, so an attribute listener is fine here.
|
|
282
|
-
const attachLevelTracker = (endpoint) => {
|
|
283
|
-
endpoint.events.levelControl.currentLevel$Changed.on((value) => {
|
|
284
|
-
try {
|
|
285
|
-
if (value !== null && value !== undefined) tracker.level = Number(value)
|
|
286
|
-
} catch (error) { /* empty */ }
|
|
287
|
-
})
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
return { RawColorControlServer, attachLevelTracker }
|
|
291
|
-
}
|
|
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
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Creates the bridged Matter endpoint for a virtual device definition.
|
|
365
|
-
* @param {object} def - { id, type, name }
|
|
366
|
-
* @param {string} serialPrefix - stable prefix for serial numbers
|
|
367
|
-
* @param {function} onCommand - callback({ deviceId, fn, value }) for commands coming from Matter controllers.
|
|
368
|
-
* 'value' is already KNX friendly (boolean for onoff, 0-100 for level).
|
|
369
|
-
* @returns {Endpoint}
|
|
370
|
-
*/
|
|
371
|
-
function createBridgedEndpoint (def, serialPrefix, onCommand) {
|
|
372
|
-
const typeInfo = BRIDGE_TYPES[def.type]
|
|
373
|
-
if (typeInfo === undefined) throw new Error(`Unsupported Matter bridge device type: ${def.type}`)
|
|
374
|
-
const name = (def.name || def.type).toString().slice(0, 32)
|
|
375
|
-
|
|
376
|
-
const stableSerial = `${serialPrefix}-${def.id}`.slice(0, 32)
|
|
377
|
-
const initialState = {
|
|
378
|
-
id: `knx-${def.id}`.slice(0, 32),
|
|
379
|
-
bridgedDeviceBasicInformation: {
|
|
380
|
-
nodeLabel: name, // This is the name Alexa/Google/Apple show and use
|
|
381
|
-
productName: name,
|
|
382
|
-
productLabel: name,
|
|
383
|
-
serialNumber: stableSerial,
|
|
384
|
-
// Optional but recommended: some controllers (notably Apple Home) use UniqueID,
|
|
385
|
-
// rather than the endpoint number alone, as the stable cross-reset device identity.
|
|
386
|
-
// It never changes for a given def.id, matching the endpoint's own persisted 'id'.
|
|
387
|
-
uniqueId: stableSerial,
|
|
388
|
-
reachable: true
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
// Non nullable attributes need a sane initial value
|
|
392
|
-
if (def.type === 'contactsensor') initialState.booleanState = { stateValue: false }
|
|
393
|
-
if (def.type === 'occupancysensor') initialState.occupancySensing = { occupancy: { occupied: false } }
|
|
394
|
-
// Although Matter permits an unknown (null) position, some controllers (including
|
|
395
|
-
// Alexa) then expose only Open/Close instead of percentage positioning. Start with
|
|
396
|
-
// a valid position; KNX or flow feedback replaces it as soon as it is available.
|
|
397
|
-
if (def.type === 'windowcovering') {
|
|
398
|
-
initialState.windowCovering = {
|
|
399
|
-
currentPositionLiftPercent100ths: 0,
|
|
400
|
-
targetPositionLiftPercent100ths: 0
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
let endpoint
|
|
405
|
-
|
|
406
|
-
// Emit controller commands at the command boundary instead of observing attribute
|
|
407
|
-
// changes. This makes the node output raw: a controller re-sending a command (for
|
|
408
|
-
// example Off while already off) is still forwarded, unlike attribute-change tracking
|
|
409
|
-
// which would swallow the no-op.
|
|
410
|
-
//
|
|
411
|
-
// The one exception is a DUPLICATE burst from a single request. Just like the
|
|
412
|
-
// WindowCovering RangeController quirk handled below, Alexa maps lights to its generic
|
|
413
|
-
// Alexa.PowerController / Alexa.BrightnessController and a single "turn on" / "set to
|
|
414
|
-
// 50%" voice request can arrive here as up to two IDENTICAL cluster commands (two On, or
|
|
415
|
-
// moveToLevelWithOnOff + moveToLevel with the same level) instead of one - which made the
|
|
416
|
-
// node emit duplicate raw msgs, discussions/516. A short leading-edge dedup collapses
|
|
417
|
-
// that: the FIRST command is forwarded immediately (no added latency, unlike the cover's
|
|
418
|
-
// trailing debounce - lights must react instantly), and a command identical to the one
|
|
419
|
-
// just emitted for the same function is dropped only if it lands within the window. Any
|
|
420
|
-
// change of value (a real On->Off, or a different brightness) always passes through at
|
|
421
|
-
// once, so this suppresses only the spurious duplicate, never a genuine command.
|
|
422
|
-
// Configurable per device via the editor's Advanced tab (def.commandDedupMs): 0 disables
|
|
423
|
-
// it entirely (every command forwarded raw), a missing value uses the 1200ms default.
|
|
424
|
-
const rawDedupMs = Number(def.commandDedupMs)
|
|
425
|
-
const COMMAND_DEDUP_MS = Number.isFinite(rawDedupMs) && rawDedupMs >= 0 ? rawDedupMs : 1200
|
|
426
|
-
const lastEmittedCommand = new Map() // fn -> { value, at }
|
|
427
|
-
const isDuplicateCommand = (fn, value) => {
|
|
428
|
-
const now = Date.now()
|
|
429
|
-
const prev = lastEmittedCommand.get(fn)
|
|
430
|
-
if (prev !== undefined && prev.value === value && (now - prev.at) < COMMAND_DEDUP_MS) return true
|
|
431
|
-
lastEmittedCommand.set(fn, { value, at: now })
|
|
432
|
-
return false
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
const RawOnOffBase = def.type === 'onoffplug'
|
|
436
|
-
? OnOffServer
|
|
437
|
-
: def.type === 'roomairconditioner' ? OnOffServer.with('DeadFrontBehavior') : OnOffServer.with('Lighting')
|
|
438
|
-
class RawOnOffServer extends RawOnOffBase {
|
|
439
|
-
async on () {
|
|
440
|
-
await super.on()
|
|
441
|
-
if (isDuplicateCommand('onoff', true)) return
|
|
442
|
-
onCommand({ deviceId: def.id, fn: 'onoff', value: true, matterCommand: { cluster: 'OnOff', command: 'on' } })
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
async off () {
|
|
446
|
-
await super.off()
|
|
447
|
-
if (isDuplicateCommand('onoff', false)) return
|
|
448
|
-
onCommand({ deviceId: def.id, fn: 'onoff', value: false, matterCommand: { cluster: 'OnOff', command: 'off' } })
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
class RawLevelControlServer extends LevelControlServer.with('Lighting', 'OnOff') {
|
|
453
|
-
async moveToLevel (request) {
|
|
454
|
-
await super.moveToLevel(request)
|
|
455
|
-
const value = clamp(Math.round(Number(request.level) * 100 / 254), 0, 100)
|
|
456
|
-
if (isDuplicateCommand('level', value)) return
|
|
457
|
-
onCommand({ deviceId: def.id, fn: 'level', value, matterCommand: { cluster: 'LevelControl', command: 'moveToLevel', request } })
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
async moveToLevelWithOnOff (request) {
|
|
461
|
-
await super.moveToLevelWithOnOff(request)
|
|
462
|
-
const value = clamp(Math.round(Number(request.level) * 100 / 254), 0, 100)
|
|
463
|
-
if (isDuplicateCommand('level', value)) return
|
|
464
|
-
onCommand({ deviceId: def.id, fn: 'level', value, matterCommand: { cluster: 'LevelControl', command: 'moveToLevelWithOnOff', request } })
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
if (def.type === 'windowcovering') {
|
|
469
|
-
// The WindowCoveringServer requires the movement logic: we forward it to the KNX bus.
|
|
470
|
-
// Position feedback comes back from the KNX status GA, so we do NOT call the default
|
|
471
|
-
// implementation (which would fake the movement by jumping to the target).
|
|
472
|
-
// KNX DPT 5.001 already follows Matter's cover convention. `invertPosition`
|
|
473
|
-
// provides the Home Assistant/Alexa-friendly opposite percentage convention;
|
|
474
|
-
// swapping Open/Close also reverses percentage commands and reports, symmetrically.
|
|
475
|
-
const swapOpenClose = def.coverSwapOpenClose === true
|
|
476
|
-
const invert = (def.invertPosition === true) !== swapOpenClose
|
|
477
|
-
|
|
478
|
-
// Alexa DOES support the Matter WindowCovering device type - per Amazon's own docs
|
|
479
|
-
// (developer.amazon.com/.../supported-matter-device-categories.html, Closure category) -
|
|
480
|
-
// but maps it to its generic Alexa.RangeController interface, not a dedicated cover
|
|
481
|
-
// controller (unlike lights, which get Alexa.ColorController, or locks, which get
|
|
482
|
-
// Alexa.LockController). RangeController's generic "set/adjust range value" directive
|
|
483
|
-
// model plausibly explains why a single "open/close the blind" voice request can arrive
|
|
484
|
-
// here as a BURST of several GoToLiftPercentage commands stepping toward the final target,
|
|
485
|
-
// instead of one UpOrOpen/DownOrClose/GoToLiftPercentage(final) call. Forwarding every
|
|
486
|
-
// step to KNX makes the physical cover move in jerky stop-start motion. A short debounce -
|
|
487
|
-
// the same coalescing technique already used for RGB colors elsewhere in this file, and
|
|
488
|
-
// the fix independently validated in production by a very similar bridge - collapses a
|
|
489
|
-
// burst into one KNX command using only the LAST target. This adds an imperceptible delay
|
|
490
|
-
// for a single legitimate command (covers take many seconds to physically travel), and
|
|
491
|
-
// StopMotion always bypasses it below.
|
|
492
|
-
// https://github.com/Luligu/matterbridge-hass/issues/196
|
|
493
|
-
// Match Home Assistant Matter Hub's cover slider handling: the first command in a
|
|
494
|
-
// sequence waits 400 ms and subsequent rapid updates wait 150 ms. A per-node value
|
|
495
|
-
// above zero replaces both windows. `movementDebounceMs` remains as a test/backward
|
|
496
|
-
// compatibility alias for definitions created outside the Node-RED editor.
|
|
497
|
-
const configuredDebounce = Number(def.coverSliderDebounceMs) > 0
|
|
498
|
-
? Number(def.coverSliderDebounceMs)
|
|
499
|
-
: Number(def.movementDebounceMs) > 0 ? Number(def.movementDebounceMs) : 0
|
|
500
|
-
const DEBOUNCE_INITIAL_MS = 400
|
|
501
|
-
const DEBOUNCE_SUBSEQUENT_MS = 150
|
|
502
|
-
const COMMAND_SEQUENCE_THRESHOLD_MS = 600
|
|
503
|
-
let lastMovementCommandAt = 0
|
|
504
|
-
let movementTimer = null
|
|
505
|
-
let pendingMovementCommand = null
|
|
506
|
-
const flushMovement = () => {
|
|
507
|
-
movementTimer = null
|
|
508
|
-
if (pendingMovementCommand === null) return
|
|
509
|
-
const command = pendingMovementCommand
|
|
510
|
-
pendingMovementCommand = null
|
|
511
|
-
onCommand(command)
|
|
512
|
-
}
|
|
513
|
-
const scheduleMovement = (command) => {
|
|
514
|
-
const now = Date.now()
|
|
515
|
-
const firstInSequence = now - lastMovementCommandAt > COMMAND_SEQUENCE_THRESHOLD_MS
|
|
516
|
-
lastMovementCommandAt = now
|
|
517
|
-
const debounceMs = configuredDebounce > 0
|
|
518
|
-
? configuredDebounce
|
|
519
|
-
: firstInSequence ? DEBOUNCE_INITIAL_MS : DEBOUNCE_SUBSEQUENT_MS
|
|
520
|
-
pendingMovementCommand = command
|
|
521
|
-
if (movementTimer !== null) clearTimeout(movementTimer)
|
|
522
|
-
movementTimer = setTimeout(flushMovement, debounceMs)
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
class KnxCoverServer extends WindowCoveringServer.with('Lift', 'PositionAwareLift') {
|
|
526
|
-
async handleMovement (type, reversed, direction, targetPercent100ths) {
|
|
527
|
-
try {
|
|
528
|
-
if (type !== MovementType.Lift) return
|
|
529
|
-
const matterDiagnostic = {
|
|
530
|
-
handler: 'handleMovement',
|
|
531
|
-
movementType: type,
|
|
532
|
-
reversed: reversed === true,
|
|
533
|
-
direction,
|
|
534
|
-
directionName: direction === MovementDirection.DefinedByPosition
|
|
535
|
-
? 'DefinedByPosition'
|
|
536
|
-
: direction === MovementDirection.Open ? 'Open' : direction === MovementDirection.Close ? 'Close' : 'Unknown',
|
|
537
|
-
targetPercent100ths: targetPercent100ths ?? null
|
|
538
|
-
}
|
|
539
|
-
if (targetPercent100ths === undefined || targetPercent100ths === null) return
|
|
540
|
-
// NOTE: 'direction' is NOT a usable signal here. matter.js's WindowCoveringServer
|
|
541
|
-
// resolves MovementDirection.DefinedByPosition (the direction goToLiftPercentage()
|
|
542
|
-
// actually passes) into a concrete Open/Close BEFORE calling handleMovement,
|
|
543
|
-
// by comparing targetPercent100ths against the current position (see
|
|
544
|
-
// #prepareMovement in @matter/node's WindowCoveringServer.ts). Since this bridge
|
|
545
|
-
// always starts with a known (non-null) position, handleMovement never receives
|
|
546
|
-
// DefinedByPosition in practice - every percentage command looked exactly like a
|
|
547
|
-
// plain Open/Close command. targetPercent100ths, on the other hand, is always
|
|
548
|
-
// populated when PositionAwareLift is supported (0/10000 for plain Up/Down too),
|
|
549
|
-
// so classify on that instead. Credit: till69, github.com/Supergiovane/
|
|
550
|
-
// node-red-contrib-knx-ultimate/discussions/516#discussioncomment-17633430
|
|
551
|
-
const target = Number(targetPercent100ths)
|
|
552
|
-
if (target <= 0 || target >= 10000) {
|
|
553
|
-
// Full travel: KNX DPT 1.008 (0 = up/open, 1 = down/close). Not affected by
|
|
554
|
-
// invertPosition, which only rescales the percentage GA convention.
|
|
555
|
-
const downOrClose = target >= 10000
|
|
556
|
-
scheduleMovement({ deviceId: def.id, fn: 'updown', value: swapOpenClose ? !downOrClose : downOrClose, matterDiagnostic })
|
|
557
|
-
} else {
|
|
558
|
-
let percent = Math.round(target / 100)
|
|
559
|
-
if (invert) percent = 100 - percent
|
|
560
|
-
scheduleMovement({ deviceId: def.id, fn: 'position', value: clamp(percent, 0, 100), matterDiagnostic })
|
|
561
|
-
}
|
|
562
|
-
} catch (error) { /* empty */ }
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
async handleStopMovement () {
|
|
566
|
-
try {
|
|
567
|
-
// Stop is always immediate: drop any pending debounced movement so a stale queued
|
|
568
|
-
// command from before the stop cannot fire afterwards.
|
|
569
|
-
if (movementTimer !== null) { clearTimeout(movementTimer); movementTimer = null }
|
|
570
|
-
pendingMovementCommand = null
|
|
571
|
-
onCommand({
|
|
572
|
-
deviceId: def.id,
|
|
573
|
-
fn: 'stop',
|
|
574
|
-
value: true,
|
|
575
|
-
matterDiagnostic: { handler: 'handleStopMovement' }
|
|
576
|
-
})
|
|
577
|
-
} catch (error) { /* empty */ }
|
|
578
|
-
return super.handleStopMovement()
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
endpoint = new Endpoint(WindowCoveringDevice.with(KnxCoverServer, BridgedDeviceBasicInformationServer), initialState)
|
|
582
|
-
return endpoint
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (def.type === 'thermostat') {
|
|
586
|
-
// Heating/Cooling capability is auto-detected from which setpoint GA(s) the KNX node
|
|
587
|
-
// has configured (see knxUltimateMatterBridge.js#getMatterDef). Leaving both flags
|
|
588
|
-
// unset keeps the original heating-only behavior, so existing flows are unaffected.
|
|
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)
|
|
592
|
-
// NOTE: SystemMode (Heat/Cool/Off/Auto) changes from a controller are accepted by the
|
|
593
|
-
// cluster but not forwarded to KNX yet: there is no single KNX DPT for HVAC mode that
|
|
594
|
-
// fits every actuator. Track it via the node's optional input PIN if you need it today.
|
|
595
|
-
return endpoint
|
|
596
|
-
}
|
|
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
|
-
|
|
641
|
-
if (def.type === 'occupancysensor') {
|
|
642
|
-
// The OccupancySensing cluster is not added by default: the sensor type must be chosen (we expose it as PIR)
|
|
643
|
-
endpoint = new Endpoint(OccupancySensorDevice.with(OccupancySensingServer.with('PassiveInfrared'), BridgedDeviceBasicInformationServer), initialState)
|
|
644
|
-
} else if (def.type === 'rgblight') {
|
|
645
|
-
// colorMode/enhancedColorMode and the color attributes are mandatory initial values
|
|
646
|
-
initialState.colorControl = {
|
|
647
|
-
colorMode: 0, // CurrentHueAndCurrentSaturation
|
|
648
|
-
enhancedColorMode: 0,
|
|
649
|
-
currentHue: 0,
|
|
650
|
-
currentSaturation: 0,
|
|
651
|
-
currentX: Math.round(0.31 * 65536),
|
|
652
|
-
currentY: Math.round(0.33 * 65536)
|
|
653
|
-
}
|
|
654
|
-
const { RawColorControlServer, attachLevelTracker } = createRawColorControlServer(def, onCommand)
|
|
655
|
-
endpoint = new Endpoint(ExtendedColorLightDevice.with(RawOnOffServer, RawLevelControlServer, RawColorControlServer, BridgedDeviceBasicInformationServer), initialState)
|
|
656
|
-
attachLevelTracker(endpoint)
|
|
657
|
-
} else if (def.type === 'colortemperaturelight') {
|
|
658
|
-
initialState.colorControl = {
|
|
659
|
-
colorMode: 2, // ColorTemperatureMireds
|
|
660
|
-
enhancedColorMode: 2,
|
|
661
|
-
colorTempPhysicalMinMireds: 153, // 6500 K
|
|
662
|
-
colorTempPhysicalMaxMireds: 500, // 2000 K
|
|
663
|
-
colorTemperatureMireds: 250,
|
|
664
|
-
startUpColorTemperatureMireds: 250,
|
|
665
|
-
coupleColorTempToLevelMinMireds: 153
|
|
666
|
-
}
|
|
667
|
-
class RawColorTemperatureServer extends ColorControlServer.with('ColorTemperature') {
|
|
668
|
-
async moveToColorTemperature (request) {
|
|
669
|
-
await super.moveToColorTemperature(request)
|
|
670
|
-
const mireds = Number(request.colorTemperatureMireds)
|
|
671
|
-
if (Number.isNaN(mireds) || mireds <= 0) return
|
|
672
|
-
onCommand({ deviceId: def.id, fn: 'colortemp', value: Math.round(1000000 / mireds) }) // mireds -> Kelvin
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
endpoint = new Endpoint(ColorTemperatureLightDevice.with(RawOnOffServer, RawLevelControlServer, RawColorTemperatureServer, BridgedDeviceBasicInformationServer), initialState)
|
|
676
|
-
} else if (def.type === 'smokecoalarm') {
|
|
677
|
-
initialState.smokeCoAlarm = {
|
|
678
|
-
expressedState: 0, // Normal
|
|
679
|
-
smokeState: 0,
|
|
680
|
-
coState: 0,
|
|
681
|
-
batteryAlert: 0,
|
|
682
|
-
testInProgress: false,
|
|
683
|
-
hardwareFaultAlert: false,
|
|
684
|
-
endOfServiceAlert: 0
|
|
685
|
-
}
|
|
686
|
-
endpoint = new Endpoint(SmokeCoAlarmDevice.with(SmokeCoAlarmServer.with('SmokeAlarm', 'CoAlarm'), BridgedDeviceBasicInformationServer), initialState)
|
|
687
|
-
} else if (def.type === 'waterleakdetector') {
|
|
688
|
-
initialState.booleanState = { stateValue: false }
|
|
689
|
-
endpoint = new Endpoint(WaterLeakDetectorDevice.with(BridgedDeviceBasicInformationServer), initialState)
|
|
690
|
-
} else if (def.type === 'airqualitysensor') {
|
|
691
|
-
initialState.airQuality = { airQuality: 0 } // Unknown
|
|
692
|
-
initialState.carbonDioxideConcentrationMeasurement = {
|
|
693
|
-
measuredValue: null,
|
|
694
|
-
minMeasuredValue: null,
|
|
695
|
-
maxMeasuredValue: null,
|
|
696
|
-
measurementUnit: 0, // PPM
|
|
697
|
-
measurementMedium: 0 // Air
|
|
698
|
-
}
|
|
699
|
-
endpoint = new Endpoint(AirQualitySensorDevice.with(
|
|
700
|
-
AirQualityServer.with('Fair', 'Moderate', 'VeryPoor', 'ExtremelyPoor'),
|
|
701
|
-
CarbonDioxideConcentrationMeasurementServer.with('NumericMeasurement'),
|
|
702
|
-
BridgedDeviceBasicInformationServer
|
|
703
|
-
), initialState)
|
|
704
|
-
} else if (def.type === 'fan') {
|
|
705
|
-
configureFanState(initialState)
|
|
706
|
-
endpoint = new Endpoint(FanDevice.with(BridgedDeviceBasicInformationServer), initialState)
|
|
707
|
-
// Speed changes from the controller (percent write or fan mode change). Like the
|
|
708
|
-
// Thermostat setpoints above, FanControlServer exposes no command to intercept for
|
|
709
|
-
// percentSetting (@matter/node's FanControlServer overrides nothing beyond
|
|
710
|
-
// initialize()) - it is attribute-write only, so this cannot be made "raw" either.
|
|
711
|
-
attachFanCommandHandlers(endpoint, def, onCommand)
|
|
712
|
-
} else if (def.type === 'robotvacuum') {
|
|
713
|
-
// Flow-only device: run mode changes and operational commands are forwarded to the flow
|
|
714
|
-
// (node PINs); the flow reports the state back through the input PIN.
|
|
715
|
-
class KnxRvcRunModeServer extends RvcRunModeServer {
|
|
716
|
-
changeToMode ({ newMode }) {
|
|
717
|
-
try {
|
|
718
|
-
const result = ModeUtils.assertModeChange(this.state.supportedModes, this.state.currentMode, newMode)
|
|
719
|
-
if (result.status !== 0) return result
|
|
720
|
-
this.state.currentMode = newMode
|
|
721
|
-
return result
|
|
722
|
-
} catch (error) {
|
|
723
|
-
return { status: 2, statusText: error.message } // GenericFailure
|
|
724
|
-
}
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
class KnxRvcOperationalStateServer extends RvcOperationalStateServer {
|
|
728
|
-
async goHome () {
|
|
729
|
-
try { onCommand({ deviceId: def.id, fn: 'rvccommand', value: 'gohome' }) } catch (error) { /* empty */ }
|
|
730
|
-
return { commandResponseState: { errorStateId: 0 } }
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
async pause () {
|
|
734
|
-
try { onCommand({ deviceId: def.id, fn: 'rvccommand', value: 'pause' }) } catch (error) { /* empty */ }
|
|
735
|
-
return { commandResponseState: { errorStateId: 0 } }
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
async resume () {
|
|
739
|
-
try { onCommand({ deviceId: def.id, fn: 'rvccommand', value: 'resume' }) } catch (error) { /* empty */ }
|
|
740
|
-
return { commandResponseState: { errorStateId: 0 } }
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
initialState.rvcRunMode = {
|
|
744
|
-
supportedModes: [
|
|
745
|
-
{ label: 'Idle', mode: 0, modeTags: [{ value: 0x4000 }] }, // RvcRunMode.ModeTag.Idle
|
|
746
|
-
{ label: 'Cleaning', mode: 1, modeTags: [{ value: 0x4001 }] } // RvcRunMode.ModeTag.Cleaning
|
|
747
|
-
],
|
|
748
|
-
currentMode: 0
|
|
749
|
-
}
|
|
750
|
-
initialState.rvcOperationalState = {
|
|
751
|
-
operationalStateList: [
|
|
752
|
-
{ operationalStateId: RVC_OP_STATES.stopped },
|
|
753
|
-
{ operationalStateId: RVC_OP_STATES.running },
|
|
754
|
-
{ operationalStateId: RVC_OP_STATES.paused },
|
|
755
|
-
{ operationalStateId: RVC_OP_STATES.error },
|
|
756
|
-
{ operationalStateId: RVC_OP_STATES.seekingcharger },
|
|
757
|
-
{ operationalStateId: RVC_OP_STATES.charging },
|
|
758
|
-
{ operationalStateId: RVC_OP_STATES.docked }
|
|
759
|
-
],
|
|
760
|
-
operationalState: RVC_OP_STATES.docked
|
|
761
|
-
}
|
|
762
|
-
endpoint = new Endpoint(RoboticVacuumCleanerDevice.with(KnxRvcRunModeServer, KnxRvcOperationalStateServer, BridgedDeviceBasicInformationServer), initialState)
|
|
763
|
-
// Run mode changed by a controller ("Alexa, start cleaning")
|
|
764
|
-
endpoint.events.rvcRunMode.currentMode$Changed.on((value, oldValue, context) => {
|
|
765
|
-
try {
|
|
766
|
-
if (context?.offline === true) return
|
|
767
|
-
onCommand({ deviceId: def.id, fn: 'rvcmode', value: Number(value) === 1 ? 'cleaning' : 'idle' })
|
|
768
|
-
} catch (error) { /* empty */ }
|
|
769
|
-
})
|
|
770
|
-
} else {
|
|
771
|
-
let device = typeInfo.device
|
|
772
|
-
if (typeInfo.commandFunctions.includes('onoff')) device = device.with(RawOnOffServer)
|
|
773
|
-
if (typeInfo.commandFunctions.includes('level')) device = device.with(RawLevelControlServer)
|
|
774
|
-
endpoint = new Endpoint(device.with(BridgedDeviceBasicInformationServer), initialState)
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
return endpoint
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
export { BRIDGE_TYPES, createBridgedEndpoint, knxValueToMatterPatch }
|