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,1765 +0,0 @@
|
|
|
1
|
-
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
|
|
2
|
-
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
|
|
3
|
-
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/hueControllerEditorSelection.js"></script>
|
|
4
|
-
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/hueControllerProfiles.js"></script>
|
|
5
|
-
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/hueControllerMigration.js"></script>
|
|
6
|
-
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/flowMigrationBackup.js"></script>
|
|
7
|
-
<script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/hueControllerMigrationDialog.js"></script>
|
|
8
|
-
|
|
9
|
-
<script type="text/javascript">
|
|
10
|
-
(function () {
|
|
11
|
-
// Editor architecture
|
|
12
|
-
// -------------------
|
|
13
|
-
// HUE Controller is registered once, but hosts fifteen private editors. The
|
|
14
|
-
// resource loaded above owns their JavaScript, HTML and translations; this
|
|
15
|
-
// wrapper only selects a profile and bridges its lifecycle to one Node-RED
|
|
16
|
-
// dialog. In particular, nothing below queries RED.nodes for a legacy type.
|
|
17
|
-
//
|
|
18
|
-
// Keep this browser-facing catalog aligned with the canonical build catalog
|
|
19
|
-
// in scripts/hue-controller-profiles/catalog.js. Tests guard that alignment,
|
|
20
|
-
// including the independent runtime map.
|
|
21
|
-
const PROFILE_TYPES = Object.freeze({
|
|
22
|
-
light: { nodeType: 'knxUltimateHueLight', label: 'HUE Light / grouped light' },
|
|
23
|
-
plug: { nodeType: 'knxUltimateHuePlug', label: 'HUE Plug / outlet' },
|
|
24
|
-
button: { nodeType: 'knxUltimateHueButton', label: 'HUE Button' },
|
|
25
|
-
relative_rotary: { nodeType: 'knxUltimateHueTapDial', label: 'HUE Tap dial' },
|
|
26
|
-
motion: { nodeType: 'knxUltimateHueMotion', label: 'HUE Motion' },
|
|
27
|
-
area_motion: { nodeType: 'knxUltimateHueAreaMotion', label: 'HUE Area motion' },
|
|
28
|
-
camera_motion: { nodeType: 'knxUltimateHueCameraMotion', label: 'HUE Camera motion' },
|
|
29
|
-
contact: { nodeType: 'knxUltimateHueContactSensor', label: 'HUE Contact' },
|
|
30
|
-
light_level: { nodeType: 'knxUltimateHueLightSensor', label: 'HUE Light level' },
|
|
31
|
-
temperature: { nodeType: 'knxUltimateHueTemperatureSensor', label: 'HUE Temperature' },
|
|
32
|
-
humidity: { nodeType: 'knxUltimateHueHumiditySensor', label: 'HUE Humidity' },
|
|
33
|
-
scene: { nodeType: 'knxUltimateHueScene', label: 'HUE Scene' },
|
|
34
|
-
device_power: { nodeType: 'knxUltimateHueBattery', label: 'HUE Battery' },
|
|
35
|
-
zigbee_connectivity: { nodeType: 'knxUltimateHueZigbeeConnectivity', label: 'HUE Zigbee connectivity' },
|
|
36
|
-
device_software_update: { nodeType: 'knxUltimateHuedevice_software_update', label: 'HUE Device software update' }
|
|
37
|
-
});
|
|
38
|
-
// Node-RED 4.x uses `_ADD_` both for the visible "none" option (when
|
|
39
|
-
// gateways exist) and for "Add new..." (when none exist).
|
|
40
|
-
const KNX_EMPTY_SERVER_VALUES = new Set(['', 'none', '_add_', '__none__']);
|
|
41
|
-
const HUE_EMPTY_SERVER_VALUES = new Set(['', 'none', '_add_', '__none__']);
|
|
42
|
-
const normalizeKnxServerSelection = (value) => {
|
|
43
|
-
const normalized = value === undefined || value === null ? '' : String(value).trim();
|
|
44
|
-
return KNX_EMPTY_SERVER_VALUES.has(normalized.toLowerCase()) ? '' : normalized;
|
|
45
|
-
};
|
|
46
|
-
const normalizeHueServerSelection = (value) => {
|
|
47
|
-
const normalized = value === undefined || value === null ? '' : String(value).trim();
|
|
48
|
-
return HUE_EMPTY_SERVER_VALUES.has(normalized.toLowerCase()) ? '' : normalized;
|
|
49
|
-
};
|
|
50
|
-
const TUTORIALS_URL = 'https://www.youtube.com/playlist?list=PL9Yh1bjbLAYrU8PsVhW4xzEug2WtVFv3E';
|
|
51
|
-
const profileBundle = window.KNXUltimateHueControllerProfiles;
|
|
52
|
-
const editorSelection = window.KNXUltimateHueControllerEditorSelection;
|
|
53
|
-
const shouldPreserveStoredSelection = editorSelection && typeof editorSelection.shouldPreserveStoredSelection === 'function'
|
|
54
|
-
? editorSelection.shouldPreserveStoredSelection
|
|
55
|
-
: (event, nextValue, storedValue, emptyValues) => {
|
|
56
|
-
const programmaticChange = !event || !event.originalEvent;
|
|
57
|
-
const normalizedNext = nextValue === undefined || nextValue === null ? '' : String(nextValue).trim().toLowerCase();
|
|
58
|
-
const normalizedStored = storedValue === undefined || storedValue === null ? '' : String(storedValue).trim().toLowerCase();
|
|
59
|
-
return programmaticChange && emptyValues.has(normalizedNext) && !emptyValues.has(normalizedStored);
|
|
60
|
-
};
|
|
61
|
-
const resolveSelectedOrStoredSelection = editorSelection && typeof editorSelection.resolveSelectedOrStoredSelection === 'function'
|
|
62
|
-
? editorSelection.resolveSelectedOrStoredSelection
|
|
63
|
-
: (selectedValue, storedValue, emptyValues) => {
|
|
64
|
-
const selected = selectedValue === undefined || selectedValue === null ? '' : String(selectedValue).trim();
|
|
65
|
-
const stored = storedValue === undefined || storedValue === null ? '' : String(storedValue).trim();
|
|
66
|
-
return emptyValues.has(selected.toLowerCase())
|
|
67
|
-
? (emptyValues.has(stored.toLowerCase()) ? '' : stored)
|
|
68
|
-
: selected;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
const getProfileDefinition = (controllerType) => {
|
|
72
|
-
// The bundle captures a private definition through a RED facade. It does
|
|
73
|
-
// not register that definition and its presentation metadata is inert.
|
|
74
|
-
if (!profileBundle || typeof profileBundle.getDefinition !== 'function') return undefined;
|
|
75
|
-
return profileBundle.getDefinition(controllerType, RED);
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const focusProfileHelp = (controllerType) => {
|
|
79
|
-
// Node-RED renders localized help asynchronously after opening the dialog.
|
|
80
|
-
// A few bounded retries focus the matching function without leaving a
|
|
81
|
-
// timer running for the lifetime of the editor.
|
|
82
|
-
const anchorId = `hue-controller-help-${controllerType}`;
|
|
83
|
-
let attempts = 0;
|
|
84
|
-
const focus = () => {
|
|
85
|
-
const marker = document.getElementById(anchorId);
|
|
86
|
-
if (marker && typeof marker.scrollIntoView === 'function') {
|
|
87
|
-
marker.scrollIntoView({ block: 'start' });
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
attempts += 1;
|
|
91
|
-
if (attempts < 4) setTimeout(focus, 100);
|
|
92
|
-
};
|
|
93
|
-
setTimeout(focus, 0);
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
const buildDefaults = () => {
|
|
97
|
-
// Node-RED persists only keys declared at registration time. Build the
|
|
98
|
-
// union once so changing function inside the dialog never drops fields
|
|
99
|
-
// belonging to the newly selected profile.
|
|
100
|
-
const defaults = {
|
|
101
|
-
// Keep config-node references explicit. Node-RED must see their `type`
|
|
102
|
-
// while this node is registered or it renders plain text inputs instead
|
|
103
|
-
// of managed config-node selectors.
|
|
104
|
-
server: { value: '', type: 'knxUltimate-config', required: false },
|
|
105
|
-
serverHue: { value: '', type: 'hue-config', required: true },
|
|
106
|
-
name: { value: '' },
|
|
107
|
-
hueControllerType: { value: 'light', required: true },
|
|
108
|
-
inputs: { value: 0 },
|
|
109
|
-
outputs: { value: 0 }
|
|
110
|
-
};
|
|
111
|
-
Object.keys(PROFILE_TYPES).forEach((controllerType) => {
|
|
112
|
-
const definition = getProfileDefinition(controllerType);
|
|
113
|
-
Object.entries(definition?.defaults || {}).forEach(([key, property]) => {
|
|
114
|
-
// HUE Controller starts as a light, so the first profile wins for
|
|
115
|
-
// shared keys. Clone the descriptor because Node-RED may decorate it.
|
|
116
|
-
if (!Object.prototype.hasOwnProperty.call(defaults, key)) defaults[key] = { ...property };
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
// Dynamic pins must always be persisted by this node, regardless of whether
|
|
120
|
-
// the selected legacy editor originally used fixed or configurable pins.
|
|
121
|
-
defaults.inputs = { value: 0 };
|
|
122
|
-
defaults.outputs = { value: 0 };
|
|
123
|
-
return defaults;
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
const setFieldValue = ($field, value) => {
|
|
127
|
-
// Property keys come from the private definition, never from CSS classes:
|
|
128
|
-
// jQuery UI mutates classes when it upgrades fields into widgets.
|
|
129
|
-
if (!$field.length) return;
|
|
130
|
-
if ($field.is(':checkbox')) {
|
|
131
|
-
$field.prop('checked', value === true || value === 'true' || value === 'yes');
|
|
132
|
-
} else if ($field.is(':radio')) {
|
|
133
|
-
$field.filter(`[value="${String(value).replace(/"/g, '\\"')}"]`).prop('checked', true);
|
|
134
|
-
} else if (value !== undefined && value !== null) {
|
|
135
|
-
$field.val(typeof value === 'object' ? JSON.stringify(value) : value);
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const readFieldValue = ($field, currentValue) => {
|
|
140
|
-
// Mirror setFieldValue for the untouched-save round trip. Missing elements
|
|
141
|
-
// retain their current value instead of silently becoming undefined.
|
|
142
|
-
if (!$field.length) return currentValue;
|
|
143
|
-
if ($field.is(':checkbox')) return $field.prop('checked');
|
|
144
|
-
if ($field.is(':radio')) return $field.filter(':checked').val();
|
|
145
|
-
const value = $field.val();
|
|
146
|
-
// DPT options are loaded asynchronously by the mounted profile. A select
|
|
147
|
-
// can therefore temporarily have no selected option even though the node
|
|
148
|
-
// has a valid saved value. Preserve that value when Save is pressed while
|
|
149
|
-
// the request is still in flight instead of persisting null.
|
|
150
|
-
if ($field.is('select') && (value === undefined || value === null)) {
|
|
151
|
-
return currentValue;
|
|
152
|
-
}
|
|
153
|
-
return value;
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
const translateProfileEditor = ($container, controllerType, nodeType) => {
|
|
157
|
-
// Injected fragments miss Node-RED's initial i18n pass and belong to the
|
|
158
|
-
// original profile namespace. Resolve them against the private dictionaries;
|
|
159
|
-
// the bundle applies the active-locale, English and RED._ fallbacks.
|
|
160
|
-
$container.find('[data-i18n]').each(function () {
|
|
161
|
-
const $element = $(this);
|
|
162
|
-
const translationSpec = String($element.attr('data-i18n') || '').trim();
|
|
163
|
-
if (!translationSpec) return;
|
|
164
|
-
|
|
165
|
-
const attributeMatch = translationSpec.match(/^\[([^\]]+)](.+)$/);
|
|
166
|
-
const attributeName = attributeMatch ? attributeMatch[1] : undefined;
|
|
167
|
-
const translationKey = attributeMatch ? attributeMatch[2] : translationSpec;
|
|
168
|
-
const qualifiedKey = translationKey.includes(':')
|
|
169
|
-
? translationKey
|
|
170
|
-
: `node-red-contrib-knx-ultimate/${nodeType}:${translationKey}`;
|
|
171
|
-
let translated;
|
|
172
|
-
try {
|
|
173
|
-
translated = profileBundle && typeof profileBundle.translate === 'function'
|
|
174
|
-
? profileBundle.translate(controllerType, qualifiedKey, RED)
|
|
175
|
-
: RED._(qualifiedKey);
|
|
176
|
-
} catch (error) { /* empty */ }
|
|
177
|
-
if (!translated || translated === qualifiedKey || translated === translationKey) return;
|
|
178
|
-
|
|
179
|
-
if (attributeName) $element.attr(attributeName, translated);
|
|
180
|
-
else $element.text(translated);
|
|
181
|
-
// The fragment belongs to the selected legacy node namespace. Removing
|
|
182
|
-
// the marker prevents the controller namespace from blanking it later.
|
|
183
|
-
$element.removeAttr('data-i18n');
|
|
184
|
-
});
|
|
185
|
-
};
|
|
186
|
-
|
|
187
|
-
const ensureControllerEditorStyle = () => {
|
|
188
|
-
// Styles are scoped to the mounted fragment so no legacy editor or other
|
|
189
|
-
// Node-RED dialog is affected. Insert them once per browser page.
|
|
190
|
-
if ($('#knxUltimateHueControllerEditorStyle').length) return;
|
|
191
|
-
$('head').append(`
|
|
192
|
-
<style id="knxUltimateHueControllerEditorStyle">
|
|
193
|
-
/* Migration is an occasional but important action, so give it a
|
|
194
|
-
strong warning-orange treatment that remains legible in both the
|
|
195
|
-
light and dark Node-RED editor themes. */
|
|
196
|
-
#hue-controller-migrate-legacy-flow.red-ui-button {
|
|
197
|
-
background: #d97706 !important;
|
|
198
|
-
border-color: #b45309 !important;
|
|
199
|
-
color: #ffffff !important;
|
|
200
|
-
font-weight: 700;
|
|
201
|
-
box-shadow: 0 2px 7px rgba(146, 64, 14, 0.35);
|
|
202
|
-
}
|
|
203
|
-
#hue-controller-migrate-legacy-flow.red-ui-button:hover {
|
|
204
|
-
background: #b45309 !important;
|
|
205
|
-
border-color: #92400e !important;
|
|
206
|
-
}
|
|
207
|
-
#hue-controller-migrate-legacy-flow.red-ui-button:active {
|
|
208
|
-
background: #92400e !important;
|
|
209
|
-
}
|
|
210
|
-
#hue-controller-migrate-legacy-flow.red-ui-button:focus-visible {
|
|
211
|
-
outline: 3px solid #fbbf24;
|
|
212
|
-
outline-offset: 2px;
|
|
213
|
-
}
|
|
214
|
-
#hue-controller-profile-editor.hue-controller-light-profile.hue-controller-no-knx #tabs {
|
|
215
|
-
display: none !important;
|
|
216
|
-
}
|
|
217
|
-
#hue-controller-profile-editor:not(.hue-controller-light-profile).hue-controller-no-knx .hue-knx-section {
|
|
218
|
-
display: none !important;
|
|
219
|
-
}
|
|
220
|
-
#hue-controller-profile-editor .hue-controller-knx-flow-only-notice {
|
|
221
|
-
box-sizing: border-box;
|
|
222
|
-
padding: 9px 12px;
|
|
223
|
-
margin: 0 0 12px;
|
|
224
|
-
border-left: 4px solid #d79b00;
|
|
225
|
-
background: #fff8df;
|
|
226
|
-
color: #4d3a00;
|
|
227
|
-
}
|
|
228
|
-
/* Every profile inherited slightly different fixed KNX widths. Mark
|
|
229
|
-
actual DPT rows after mounting and compact only their DPT/Name
|
|
230
|
-
controls. No wrapping keeps one mapping on one visual line, while the
|
|
231
|
-
small flex allowance lets Name contract on narrow editor trays. */
|
|
232
|
-
#hue-controller-profile-editor .hue-controller-knx-mapping-row {
|
|
233
|
-
display: flex;
|
|
234
|
-
align-items: center;
|
|
235
|
-
flex-wrap: nowrap !important;
|
|
236
|
-
}
|
|
237
|
-
#hue-controller-profile-editor .hue-controller-knx-mapping-row > label {
|
|
238
|
-
flex-shrink: 0;
|
|
239
|
-
}
|
|
240
|
-
#hue-controller-profile-editor .hue-controller-knx-mapping-row > select[id^="node-input-dpt"] {
|
|
241
|
-
box-sizing: border-box;
|
|
242
|
-
width: 105px !important;
|
|
243
|
-
min-width: 90px !important;
|
|
244
|
-
max-width: 105px !important;
|
|
245
|
-
flex: 0 1 105px !important;
|
|
246
|
-
}
|
|
247
|
-
#hue-controller-profile-editor .hue-controller-knx-mapping-row > input[type="text"][id^="node-input-name"] {
|
|
248
|
-
box-sizing: border-box;
|
|
249
|
-
width: 115px !important;
|
|
250
|
-
min-width: 70px !important;
|
|
251
|
-
max-width: 115px !important;
|
|
252
|
-
flex: 0 1 115px !important;
|
|
253
|
-
}
|
|
254
|
-
</style>
|
|
255
|
-
`);
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
const controllerMessage = (key, values) => {
|
|
259
|
-
try {
|
|
260
|
-
const messageKey = `node-red-contrib-knx-ultimate/knxUltimateHueController:knxUltimateHueController.${key}`;
|
|
261
|
-
const translated = RED._(messageKey, values);
|
|
262
|
-
if (translated && translated !== messageKey) return translated;
|
|
263
|
-
} catch (error) { /* empty */ }
|
|
264
|
-
return undefined;
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
const migrationText = (_node, key, fallback, values) => {
|
|
268
|
-
const translated = controllerMessage(key, values);
|
|
269
|
-
if (translated) return translated;
|
|
270
|
-
return fallback;
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
const editorContainsLegacyHueNodes = () => {
|
|
274
|
-
// This read-only scan controls visibility. The shared migration resource
|
|
275
|
-
// later converts each matching node entirely inside the editor.
|
|
276
|
-
const migrationApi = window.KNXUltimateHueControllerMigration;
|
|
277
|
-
if (!migrationApi || typeof migrationApi.isLegacyHueNode !== 'function') return false;
|
|
278
|
-
if (!RED.nodes || typeof RED.nodes.eachNode !== 'function') return false;
|
|
279
|
-
let found = false;
|
|
280
|
-
try {
|
|
281
|
-
RED.nodes.eachNode((node) => {
|
|
282
|
-
if (!found && migrationApi.isLegacyHueNode(node)) found = true;
|
|
283
|
-
});
|
|
284
|
-
} catch (error) {
|
|
285
|
-
// If an older/custom editor cannot enumerate nodes, hide the action:
|
|
286
|
-
// showing it without evidence of a migration target would be noisier.
|
|
287
|
-
return false;
|
|
288
|
-
}
|
|
289
|
-
return found;
|
|
290
|
-
};
|
|
291
|
-
|
|
292
|
-
const openLegacyMigrationDialog = (node) => {
|
|
293
|
-
const dialogApi = window.KNXUltimateHueControllerMigrationDialog;
|
|
294
|
-
if (!dialogApi || typeof dialogApi.open !== 'function') {
|
|
295
|
-
RED.notify(migrationText(node, 'migration_unavailable', 'The HUE migration tool is unavailable. Restart Node-RED after updating the package.'), 'error');
|
|
296
|
-
return () => { };
|
|
297
|
-
}
|
|
298
|
-
return dialogApi.open({
|
|
299
|
-
RED,
|
|
300
|
-
$,
|
|
301
|
-
windowObject: window,
|
|
302
|
-
documentObject: document,
|
|
303
|
-
translate: (key, fallback, values) => migrationText(node, key, fallback, values)
|
|
304
|
-
});
|
|
305
|
-
};
|
|
306
|
-
|
|
307
|
-
RED.nodes.registerType('knxUltimateHueController', {
|
|
308
|
-
category: 'KNX Ultimate',
|
|
309
|
-
color: '#C0C7E9',
|
|
310
|
-
defaults: buildDefaults(),
|
|
311
|
-
// catalogDefaults is consumed by the Cerebrum Ultimate catalog. It intentionally
|
|
312
|
-
// describes only the stable public surface; the real persistence contract
|
|
313
|
-
// remains the complete `defaults` union above.
|
|
314
|
-
catalogDefaults: {
|
|
315
|
-
server: { type: 'knxUltimate-config' },
|
|
316
|
-
serverHue: { type: 'hue-config' },
|
|
317
|
-
name: {},
|
|
318
|
-
hueControllerType: {},
|
|
319
|
-
hueDevice: {},
|
|
320
|
-
enableNodePINS: {},
|
|
321
|
-
inputs: {},
|
|
322
|
-
outputs: {}
|
|
323
|
-
},
|
|
324
|
-
inputs: 0,
|
|
325
|
-
outputs: 0,
|
|
326
|
-
icon: 'node-hue-icon.svg',
|
|
327
|
-
label() {
|
|
328
|
-
const profile = PROFILE_TYPES[this.hueControllerType] || PROFILE_TYPES.light;
|
|
329
|
-
let typeLabel = profile.label;
|
|
330
|
-
try {
|
|
331
|
-
const translationKey = `node-red-contrib-knx-ultimate/knxUltimateHueController:knxUltimateHueController.types.${this.hueControllerType || 'light'}`;
|
|
332
|
-
const translated = RED._(translationKey);
|
|
333
|
-
if (translated && translated !== translationKey) typeLabel = translated;
|
|
334
|
-
} catch (error) { /* use catalog fallback */ }
|
|
335
|
-
return this.name || `HUE Controller · ${typeLabel}`;
|
|
336
|
-
},
|
|
337
|
-
paletteLabel: 'HUE Controller',
|
|
338
|
-
oneditprepare() {
|
|
339
|
-
try { RED.sidebar.show('help'); } catch (error) { /* empty */ }
|
|
340
|
-
ensureControllerEditorStyle();
|
|
341
|
-
const controllerNode = this;
|
|
342
|
-
// activeProfile/legacyContext describe the currently mounted function.
|
|
343
|
-
// Drafts preserve unsaved edits when the user switches away and back;
|
|
344
|
-
// the migration closer prevents detached jQuery dialogs and handlers.
|
|
345
|
-
let activeProfile;
|
|
346
|
-
let legacyContext;
|
|
347
|
-
let closeMigrationDialog = () => { };
|
|
348
|
-
const profileDrafts = {};
|
|
349
|
-
let cachedHueResources = [];
|
|
350
|
-
let selectedHueResource;
|
|
351
|
-
let activeHueServerId;
|
|
352
|
-
let hueDevicePickerMouseDown = false;
|
|
353
|
-
let hueCatalogReady = false;
|
|
354
|
-
let hueReadinessTimer;
|
|
355
|
-
let hueUnreachableTimer;
|
|
356
|
-
let hueReadinessAttempts = 0;
|
|
357
|
-
let hueReadinessErrorShown = false;
|
|
358
|
-
let hueBridgeUnreachable = false;
|
|
359
|
-
let hueEditorClosed = false;
|
|
360
|
-
const HUE_READINESS_INTERVAL_MS = 2000;
|
|
361
|
-
const HUE_READINESS_MAX_ATTEMPTS = 60;
|
|
362
|
-
const HUE_UNREACHABLE_TIMEOUT_MS = 15000;
|
|
363
|
-
const defaultHueDevicePlaceholder = $('#node-input-name').attr('placeholder') || '';
|
|
364
|
-
|
|
365
|
-
const hasLegacyHueNodes = editorContainsLegacyHueNodes();
|
|
366
|
-
const $migrationButton = $('#hue-controller-migrate-legacy-flow');
|
|
367
|
-
$('#hue-controller-migrate-legacy-flow-row').toggle(hasLegacyHueNodes);
|
|
368
|
-
$migrationButton.off('.knxUltimateHueControllerMigration');
|
|
369
|
-
if (hasLegacyHueNodes) {
|
|
370
|
-
$migrationButton.on('click.knxUltimateHueControllerMigration', () => {
|
|
371
|
-
closeMigrationDialog();
|
|
372
|
-
closeMigrationDialog = openLegacyMigrationDialog(controllerNode);
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const cloneEditorValue = (value) => {
|
|
377
|
-
// Profile defaults may contain arrays or objects. Clone them before
|
|
378
|
-
// drafting so editing one function cannot mutate shared definitions.
|
|
379
|
-
if (value === undefined || value === null || typeof value !== 'object') return value;
|
|
380
|
-
try { return JSON.parse(JSON.stringify(value)); } catch (error) { return value; }
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
// Several profile editors update the live node object while the dialog
|
|
384
|
-
// is open so switching device functions can mount the correct fields.
|
|
385
|
-
// Node-RED cannot roll those direct mutations back by itself on Cancel,
|
|
386
|
-
// therefore retain the complete persisted defaults before editing.
|
|
387
|
-
const originalEditorState = {};
|
|
388
|
-
Object.keys(buildDefaults()).forEach((key) => {
|
|
389
|
-
originalEditorState[key] = {
|
|
390
|
-
present: Object.prototype.hasOwnProperty.call(controllerNode, key),
|
|
391
|
-
value: cloneEditorValue(controllerNode[key])
|
|
392
|
-
};
|
|
393
|
-
});
|
|
394
|
-
const restoreOriginalEditorState = () => {
|
|
395
|
-
Object.entries(originalEditorState).forEach(([key, snapshot]) => {
|
|
396
|
-
if (snapshot.present) controllerNode[key] = cloneEditorValue(snapshot.value);
|
|
397
|
-
else delete controllerNode[key];
|
|
398
|
-
});
|
|
399
|
-
};
|
|
400
|
-
|
|
401
|
-
const collectCurrentEditor = () => {
|
|
402
|
-
// Collect before unmounting. Exact keys come from the selected private
|
|
403
|
-
// definition, avoiding broad DOM scans and widget-added CSS classes.
|
|
404
|
-
if (!activeProfile || !legacyContext) return;
|
|
405
|
-
const definition = getProfileDefinition(controllerNode.hueControllerType);
|
|
406
|
-
const draft = {};
|
|
407
|
-
Object.keys(definition?.defaults || {}).forEach((key) => {
|
|
408
|
-
const fieldValue = readFieldValue($(`#node-input-${key}`), controllerNode[key]);
|
|
409
|
-
let value = fieldValue;
|
|
410
|
-
if (key === 'server') {
|
|
411
|
-
value = resolveSelectedOrStoredSelection(fieldValue, controllerNode.server, KNX_EMPTY_SERVER_VALUES);
|
|
412
|
-
} else if (key === 'serverHue') {
|
|
413
|
-
value = resolveSelectedOrStoredSelection(fieldValue, controllerNode.serverHue, HUE_EMPTY_SERVER_VALUES);
|
|
414
|
-
}
|
|
415
|
-
controllerNode[key] = value;
|
|
416
|
-
legacyContext[key] = value;
|
|
417
|
-
draft[key] = cloneEditorValue(value);
|
|
418
|
-
});
|
|
419
|
-
profileDrafts[controllerNode.hueControllerType] = draft;
|
|
420
|
-
if (Number.isFinite(Number(legacyContext.inputs))) controllerNode.inputs = Number(legacyContext.inputs);
|
|
421
|
-
if (Number.isFinite(Number(legacyContext.outputs))) controllerNode.outputs = Number(legacyContext.outputs);
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
const disposeCurrentEditor = () => {
|
|
425
|
-
// A profile can attach handlers or allocate editor-only state. Reuse
|
|
426
|
-
// its cancel hook when changing function, then remove the two handler
|
|
427
|
-
// namespaces that belong specifically to this wrapper.
|
|
428
|
-
if (!activeProfile || !legacyContext) return;
|
|
429
|
-
$('#node-input-server').off('.knxUltimateHueControllerLightVisibility');
|
|
430
|
-
$(document).off('change.knxUltimateHueControllerKnxVisibility', '#node-input-server');
|
|
431
|
-
const definition = getProfileDefinition(controllerNode.hueControllerType);
|
|
432
|
-
if (definition && typeof definition.oneditcancel === 'function') {
|
|
433
|
-
definition.oneditcancel.call(legacyContext);
|
|
434
|
-
}
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
const prepareProfileValues = (controllerType, definition) => {
|
|
438
|
-
// Returning to a profile restores its in-dialog draft. First visits use
|
|
439
|
-
// that profile's defaults, except shared gateway selections which must
|
|
440
|
-
// survive every function change.
|
|
441
|
-
const draft = profileDrafts[controllerType];
|
|
442
|
-
Object.entries(definition?.defaults || {}).forEach(([key, property]) => {
|
|
443
|
-
if (draft && Object.prototype.hasOwnProperty.call(draft, key)) {
|
|
444
|
-
controllerNode[key] = cloneEditorValue(draft[key]);
|
|
445
|
-
} else if (key !== 'server' && key !== 'serverHue') {
|
|
446
|
-
controllerNode[key] = cloneEditorValue(property.value);
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
};
|
|
450
|
-
|
|
451
|
-
const controllerText = (key, fallback) => {
|
|
452
|
-
const translated = controllerMessage(key);
|
|
453
|
-
if (translated) return translated;
|
|
454
|
-
return fallback;
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
const resolveHueServerId = ({ allowStored = false } = {}) => {
|
|
458
|
-
const domValue = $('#node-input-serverHue').val();
|
|
459
|
-
if (domValue !== undefined && domValue !== null) {
|
|
460
|
-
const normalized = String(domValue).trim();
|
|
461
|
-
if (normalized !== '' && !HUE_EMPTY_SERVER_VALUES.has(normalized.toLowerCase())) return normalized;
|
|
462
|
-
}
|
|
463
|
-
if (allowStored && controllerNode.serverHue !== undefined && controllerNode.serverHue !== null) {
|
|
464
|
-
const stored = String(controllerNode.serverHue).trim();
|
|
465
|
-
if (stored !== '' && !HUE_EMPTY_SERVER_VALUES.has(stored.toLowerCase())) return stored;
|
|
466
|
-
}
|
|
467
|
-
return '';
|
|
468
|
-
};
|
|
469
|
-
|
|
470
|
-
const getHueDeviceValue = () => {
|
|
471
|
-
const domValue = $('#node-input-hueDevice').val();
|
|
472
|
-
if (domValue !== undefined && domValue !== null && String(domValue).trim() !== '') return String(domValue).trim();
|
|
473
|
-
return controllerNode.hueDevice === undefined || controllerNode.hueDevice === null
|
|
474
|
-
? ''
|
|
475
|
-
: String(controllerNode.hueDevice).trim();
|
|
476
|
-
};
|
|
477
|
-
|
|
478
|
-
const getRawHueResourceId = (value) => String(value || '').split('#')[0];
|
|
479
|
-
|
|
480
|
-
const updateSelectedDevicePresentation = (controllerType = controllerNode.hueControllerType) => {
|
|
481
|
-
// A persisted device remains visible while its Hue Bridge is offline.
|
|
482
|
-
// Catalog readiness controls discovery and editing of the device
|
|
483
|
-
// selection, not whether saved mappings remain usable in the editor.
|
|
484
|
-
const hueServerSelected = resolveHueServerId({ allowStored: true }) !== '';
|
|
485
|
-
const hasDevice = hueServerSelected && getHueDeviceValue() !== '';
|
|
486
|
-
const profile = PROFILE_TYPES[controllerType] || PROFILE_TYPES.light;
|
|
487
|
-
const typeLabel = controllerText(`types.${controllerType}`, profile.label);
|
|
488
|
-
$('#hue-controller-selected-device-type-value').text(typeLabel);
|
|
489
|
-
$('#hue-controller-selected-device-type').toggle(hasDevice);
|
|
490
|
-
$('#hue-controller-locate-device').toggle(hasDevice && controllerType === 'light');
|
|
491
|
-
$('#hue-controller-profile-editor').toggle(hasDevice);
|
|
492
|
-
$('#node-input-hueControllerType').val(controllerType);
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
const updateHueDeviceControlVisibility = () => {
|
|
496
|
-
const hueServerSelected = resolveHueServerId({ allowStored: true }) !== '';
|
|
497
|
-
const hasPersistedDevice = getHueDeviceValue() !== '';
|
|
498
|
-
const deviceControlVisible = hueServerSelected && (hueCatalogReady || hasPersistedDevice);
|
|
499
|
-
const deviceCatalogPending = hueServerSelected && !hueCatalogReady;
|
|
500
|
-
$('#hue-controller-device-row').toggle(deviceControlVisible);
|
|
501
|
-
$('#node-input-name').prop('disabled', hueServerSelected && !hueCatalogReady);
|
|
502
|
-
$('#hue-controller-devices-loading').toggle(deviceCatalogPending);
|
|
503
|
-
$('#hue-controller-devices-waiting').toggle(!hueBridgeUnreachable);
|
|
504
|
-
$('#hue-controller-devices-unreachable').toggle(hueBridgeUnreachable);
|
|
505
|
-
if (!deviceControlVisible) {
|
|
506
|
-
$('#hue-controller-selected-device-type').hide();
|
|
507
|
-
$('#hue-controller-locate-device').hide();
|
|
508
|
-
$('#hue-controller-profile-editor').hide();
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
updateSelectedDevicePresentation();
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
const filterHueResources = (term) => {
|
|
515
|
-
const search = String(term || '').replace(/exactmatch/gi, '').trim().toLowerCase();
|
|
516
|
-
return cachedHueResources.filter((item) => {
|
|
517
|
-
if (search === '') return true;
|
|
518
|
-
return String(item.name || item.id || '').toLowerCase().includes(search);
|
|
519
|
-
}).map((item) => ({
|
|
520
|
-
...item,
|
|
521
|
-
value: item.name || item.id,
|
|
522
|
-
label: item.name || item.id
|
|
523
|
-
}));
|
|
524
|
-
};
|
|
525
|
-
|
|
526
|
-
const reconcileSavedHueResource = () => {
|
|
527
|
-
const savedDevice = getHueDeviceValue();
|
|
528
|
-
if (savedDevice === '') return;
|
|
529
|
-
const rawId = getRawHueResourceId(savedDevice);
|
|
530
|
-
const match = cachedHueResources.find((item) => item.hueDevice === savedDevice)
|
|
531
|
-
|| cachedHueResources.find((item) => item.id === rawId && item.controllerType === controllerNode.hueControllerType)
|
|
532
|
-
|| cachedHueResources.find((item) => item.id === rawId);
|
|
533
|
-
if (!match) {
|
|
534
|
-
updateSelectedDevicePresentation();
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
selectedHueResource = match;
|
|
538
|
-
if (!$('#node-input-name').val()) $('#node-input-name').val(match.name || match.id);
|
|
539
|
-
if (match.controllerType !== controllerNode.hueControllerType) {
|
|
540
|
-
applyHueResourceSelection(match);
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
543
|
-
updateSelectedDevicePresentation(match.controllerType);
|
|
544
|
-
};
|
|
545
|
-
|
|
546
|
-
const fetchHueResources = (term, response, { forceRefresh = false } = {}) => {
|
|
547
|
-
const reply = typeof response === 'function' ? response : () => { };
|
|
548
|
-
const hueServerId = resolveHueServerId({ allowStored: true });
|
|
549
|
-
if (hueServerId === '') {
|
|
550
|
-
hueCatalogReady = false;
|
|
551
|
-
updateHueDeviceControlVisibility();
|
|
552
|
-
reply([]);
|
|
553
|
-
return;
|
|
554
|
-
}
|
|
555
|
-
if (!forceRefresh && cachedHueResources.length > 0) {
|
|
556
|
-
hueCatalogReady = true;
|
|
557
|
-
updateHueDeviceControlVisibility();
|
|
558
|
-
reply(filterHueResources(term));
|
|
559
|
-
return;
|
|
560
|
-
}
|
|
561
|
-
const refreshQuery = forceRefresh ? '&forceRefresh=1' : '';
|
|
562
|
-
$.getJSON(`KNXUltimateGetResourcesHUE?rtype=hue_controller&serverId=${encodeURIComponent(hueServerId)}${refreshQuery}&_=${Date.now()}`, (data) => {
|
|
563
|
-
if (hueEditorClosed) return;
|
|
564
|
-
if (resolveHueServerId({ allowStored: true }) !== hueServerId) {
|
|
565
|
-
reply([]);
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
const devices = Array.isArray(data) ? data : (Array.isArray(data?.devices) ? data.devices : []);
|
|
569
|
-
cachedHueResources = devices.filter((item) => item && PROFILE_TYPES[item.controllerType] && item.id && item.hueDevice);
|
|
570
|
-
hueCatalogReady = data?.ready === true;
|
|
571
|
-
$('#node-input-name').attr('placeholder', cachedHueResources.length > 0
|
|
572
|
-
? defaultHueDevicePlaceholder
|
|
573
|
-
: controllerText('no_devices', 'No Hue resources found. Check the Hue Bridge and press refresh.'));
|
|
574
|
-
updateHueDeviceControlVisibility();
|
|
575
|
-
if (hueCatalogReady) reconcileSavedHueResource();
|
|
576
|
-
reply(filterHueResources(term));
|
|
577
|
-
}).fail(() => {
|
|
578
|
-
if (hueEditorClosed) return;
|
|
579
|
-
cachedHueResources = [];
|
|
580
|
-
hueCatalogReady = false;
|
|
581
|
-
updateHueDeviceControlVisibility();
|
|
582
|
-
$('#node-input-name').attr('placeholder', controllerText('no_devices', 'No Hue resources found. Check the Hue Bridge and press refresh.'));
|
|
583
|
-
reply([]);
|
|
584
|
-
});
|
|
585
|
-
};
|
|
586
|
-
|
|
587
|
-
const clearHueReadinessTimer = () => {
|
|
588
|
-
if (hueReadinessTimer !== undefined) clearTimeout(hueReadinessTimer);
|
|
589
|
-
hueReadinessTimer = undefined;
|
|
590
|
-
};
|
|
591
|
-
|
|
592
|
-
const clearHueUnreachableTimer = () => {
|
|
593
|
-
if (hueUnreachableTimer !== undefined) clearTimeout(hueUnreachableTimer);
|
|
594
|
-
hueUnreachableTimer = undefined;
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
const probeHueBridgeReadiness = ({ reset = false, openPicker = false } = {}) => {
|
|
598
|
-
clearHueReadinessTimer();
|
|
599
|
-
if (reset) {
|
|
600
|
-
hueReadinessAttempts = 0;
|
|
601
|
-
hueReadinessErrorShown = false;
|
|
602
|
-
hueBridgeUnreachable = false;
|
|
603
|
-
clearHueUnreachableTimer();
|
|
604
|
-
}
|
|
605
|
-
const expectedServerId = resolveHueServerId({ allowStored: true });
|
|
606
|
-
if (expectedServerId === '') {
|
|
607
|
-
clearHueUnreachableTimer();
|
|
608
|
-
hueCatalogReady = false;
|
|
609
|
-
updateHueDeviceControlVisibility();
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
if (reset) {
|
|
613
|
-
hueUnreachableTimer = setTimeout(() => {
|
|
614
|
-
if (hueEditorClosed) return;
|
|
615
|
-
if (resolveHueServerId({ allowStored: true }) !== expectedServerId || hueCatalogReady) return;
|
|
616
|
-
hueBridgeUnreachable = true;
|
|
617
|
-
updateHueDeviceControlVisibility();
|
|
618
|
-
}, HUE_UNREACHABLE_TIMEOUT_MS);
|
|
619
|
-
}
|
|
620
|
-
updateHueDeviceControlVisibility();
|
|
621
|
-
hueReadinessAttempts += 1;
|
|
622
|
-
fetchHueResources('', (items) => {
|
|
623
|
-
if (resolveHueServerId({ allowStored: true }) !== expectedServerId) return;
|
|
624
|
-
if (hueCatalogReady) {
|
|
625
|
-
clearHueUnreachableTimer();
|
|
626
|
-
hueBridgeUnreachable = false;
|
|
627
|
-
updateHueDeviceControlVisibility();
|
|
628
|
-
if (openPicker && items.length) $('#node-input-name').autocomplete('search', '');
|
|
629
|
-
return;
|
|
630
|
-
}
|
|
631
|
-
if (hueReadinessAttempts >= HUE_READINESS_MAX_ATTEMPTS) {
|
|
632
|
-
if (!hueReadinessErrorShown) {
|
|
633
|
-
hueReadinessErrorShown = true;
|
|
634
|
-
updateHueDeviceControlVisibility();
|
|
635
|
-
RED.notify(controllerText(
|
|
636
|
-
'hue_bridge_not_ready',
|
|
637
|
-
'The Hue Bridge did not become ready. Check its connection and reopen the editor.'
|
|
638
|
-
), { type: 'error', fixed: true });
|
|
639
|
-
}
|
|
640
|
-
return;
|
|
641
|
-
}
|
|
642
|
-
hueReadinessTimer = setTimeout(() => {
|
|
643
|
-
probeHueBridgeReadiness({ openPicker });
|
|
644
|
-
}, HUE_READINESS_INTERVAL_MS);
|
|
645
|
-
}, { forceRefresh: true });
|
|
646
|
-
};
|
|
647
|
-
|
|
648
|
-
const configureUnifiedDeviceControl = () => {
|
|
649
|
-
const $deviceName = $('#node-input-name');
|
|
650
|
-
if (!$deviceName.length) return;
|
|
651
|
-
$deviceName.autocomplete({
|
|
652
|
-
minLength: 0,
|
|
653
|
-
source(request, response) {
|
|
654
|
-
if (!hueCatalogReady) {
|
|
655
|
-
response([]);
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
fetchHueResources(request.term, response);
|
|
659
|
-
},
|
|
660
|
-
select(event, ui) {
|
|
661
|
-
applyHueResourceSelection(ui.item);
|
|
662
|
-
return false;
|
|
663
|
-
},
|
|
664
|
-
change(event, ui) {
|
|
665
|
-
if (ui.item || selectedHueResource?.name === $deviceName.val()) return;
|
|
666
|
-
selectedHueResource = undefined;
|
|
667
|
-
controllerNode.hueDevice = '';
|
|
668
|
-
$('#node-input-hueDevice').val('');
|
|
669
|
-
updateSelectedDevicePresentation();
|
|
670
|
-
}
|
|
671
|
-
});
|
|
672
|
-
$deviceName.off('.knxUltimateHueControllerDevice')
|
|
673
|
-
.on('mousedown.knxUltimateHueControllerDevice', () => {
|
|
674
|
-
hueDevicePickerMouseDown = true;
|
|
675
|
-
})
|
|
676
|
-
.on('focus.knxUltimateHueControllerDevice', function () {
|
|
677
|
-
if (!hueDevicePickerMouseDown) $(this).autocomplete('search', '');
|
|
678
|
-
})
|
|
679
|
-
.on('click.knxUltimateHueControllerDevice', function () {
|
|
680
|
-
hueDevicePickerMouseDown = false;
|
|
681
|
-
const input = this;
|
|
682
|
-
setTimeout(() => $(input).autocomplete('search', ''), 0);
|
|
683
|
-
})
|
|
684
|
-
.on('blur.knxUltimateHueControllerDevice', () => {
|
|
685
|
-
hueDevicePickerMouseDown = false;
|
|
686
|
-
});
|
|
687
|
-
};
|
|
688
|
-
|
|
689
|
-
const applyHueResourceSelection = (item) => {
|
|
690
|
-
if (!item || !PROFILE_TYPES[item.controllerType] || !item.hueDevice) return;
|
|
691
|
-
const nextType = item.controllerType;
|
|
692
|
-
const typeChanged = nextType !== controllerNode.hueControllerType;
|
|
693
|
-
collectCurrentEditor();
|
|
694
|
-
if (typeChanged) prepareProfileValues(nextType, getProfileDefinition(nextType));
|
|
695
|
-
selectedHueResource = item;
|
|
696
|
-
controllerNode.hueControllerType = nextType;
|
|
697
|
-
controllerNode.name = item.name || item.id;
|
|
698
|
-
controllerNode.hueDevice = item.hueDevice;
|
|
699
|
-
if (item.deviceObject) controllerNode.hueDeviceObject = cloneEditorValue(item.deviceObject);
|
|
700
|
-
const nextDefinition = getProfileDefinition(nextType);
|
|
701
|
-
controllerNode.inputs = Number(nextDefinition?.inputs || 0);
|
|
702
|
-
controllerNode.outputs = Number(nextDefinition?.outputs || 0);
|
|
703
|
-
$('#node-input-name').val(controllerNode.name);
|
|
704
|
-
$('#node-input-hueDevice').val(controllerNode.hueDevice);
|
|
705
|
-
$('#node-input-hueControllerType').val(nextType);
|
|
706
|
-
renderProfileEditor(nextType, true);
|
|
707
|
-
updateSelectedDevicePresentation(nextType);
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
const renderProfileEditor = (controllerType, skipCollect) => {
|
|
711
|
-
// Controlled lifecycle transition:
|
|
712
|
-
// collect old -> dispose old -> mount private HTML -> translate ->
|
|
713
|
-
// restore values -> execute the selected profile's oneditprepare.
|
|
714
|
-
if (skipCollect !== true) collectCurrentEditor();
|
|
715
|
-
disposeCurrentEditor();
|
|
716
|
-
const profile = PROFILE_TYPES[controllerType] || PROFILE_TYPES.light;
|
|
717
|
-
const definition = getProfileDefinition(controllerType);
|
|
718
|
-
const template = profileBundle && typeof profileBundle.getTemplate === 'function'
|
|
719
|
-
? profileBundle.getTemplate(controllerType)
|
|
720
|
-
: undefined;
|
|
721
|
-
const $container = $('#hue-controller-profile-editor');
|
|
722
|
-
$container.toggleClass('hue-controller-light-profile', controllerType === 'light');
|
|
723
|
-
|
|
724
|
-
if (!definition || !template) {
|
|
725
|
-
$container.html($('<div class="hue-controller-editor-error"></div>').text(
|
|
726
|
-
controllerText('editor_unavailable', 'The selected Hue editor is unavailable. Restart Node-RED after updating the package.')
|
|
727
|
-
));
|
|
728
|
-
return;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
activeProfile = profile;
|
|
732
|
-
controllerNode.hueControllerType = controllerType;
|
|
733
|
-
// Some dedicated definitions used fixed pins, others persisted them.
|
|
734
|
-
// Normalize both forms into per-instance numeric Controller pins.
|
|
735
|
-
if (!definition.defaults?.inputs) controllerNode.inputs = Number(definition.inputs || 0);
|
|
736
|
-
if (!definition.defaults?.outputs) controllerNode.outputs = Number(definition.outputs || 0);
|
|
737
|
-
controllerNode.inputs = Number.isFinite(Number(controllerNode.inputs))
|
|
738
|
-
? Number(controllerNode.inputs)
|
|
739
|
-
: Number(definition.inputs || 0);
|
|
740
|
-
controllerNode.outputs = Number.isFinite(Number(controllerNode.outputs))
|
|
741
|
-
? Number(controllerNode.outputs)
|
|
742
|
-
: Number(definition.outputs || 0);
|
|
743
|
-
|
|
744
|
-
const $profileContent = $('<div></div>').html(template);
|
|
745
|
-
// The unified editor owns the single playlist link at the top.
|
|
746
|
-
$profileContent.find(`a[href="${TUTORIALS_URL}"]`).each(function () {
|
|
747
|
-
$(this).closest('.form-row').remove();
|
|
748
|
-
});
|
|
749
|
-
// This notice belongs only to the dedicated legacy node editor. The
|
|
750
|
-
// current editor is already HUE Controller, so do not repeat it here.
|
|
751
|
-
$profileContent.find('.hue-legacy-controller-notice').remove();
|
|
752
|
-
// Configuration-node fields must exist before oneditprepare so Node-RED
|
|
753
|
-
// can turn them into its managed selectors. The unified template owns
|
|
754
|
-
// those two fixed fields; remove the duplicate legacy rows.
|
|
755
|
-
$profileContent.find('#node-input-server, #node-input-serverHue').each(function () {
|
|
756
|
-
$(this).closest('.form-row').remove();
|
|
757
|
-
});
|
|
758
|
-
// Device selection belongs to the unified wrapper. Remove the private
|
|
759
|
-
// profile's duplicate row/hidden value while keeping the static fields
|
|
760
|
-
// available to its mature lifecycle callbacks.
|
|
761
|
-
$profileContent.find('#node-input-name').each(function () {
|
|
762
|
-
$(this).closest('.form-row').remove();
|
|
763
|
-
});
|
|
764
|
-
$profileContent.find('#node-input-hueDevice').remove();
|
|
765
|
-
$container.empty().append($profileContent.contents());
|
|
766
|
-
// Node-RED translates the static dialog before oneditprepare. This
|
|
767
|
-
// fragment belongs to another node type, so qualify every key with the
|
|
768
|
-
// selected profile's namespace instead of the controller namespace.
|
|
769
|
-
translateProfileEditor($container, controllerType, profile.nodeType);
|
|
770
|
-
// A row containing a DPT selector is a KNX mapping row regardless of
|
|
771
|
-
// which private profile supplied it. Tagging by the strict field ID
|
|
772
|
-
// avoids coupling the Controller layout to legacy CSS class names.
|
|
773
|
-
$container.find('select[id^="node-input-dpt"]').each(function () {
|
|
774
|
-
$(this).closest('.form-row').addClass('hue-controller-knx-mapping-row');
|
|
775
|
-
});
|
|
776
|
-
Object.keys(definition.defaults || {}).forEach((key) => {
|
|
777
|
-
setFieldValue($(`#node-input-${key}`), controllerNode[key]);
|
|
778
|
-
});
|
|
779
|
-
|
|
780
|
-
// The inherited context lets mature callbacks read the Controller's
|
|
781
|
-
// properties while isolating their temporary mutations. Never assign
|
|
782
|
-
// `legacyContext.type`: that could save the node under a legacy type.
|
|
783
|
-
legacyContext = Object.create(controllerNode);
|
|
784
|
-
legacyContext._ = definition._;
|
|
785
|
-
legacyContext.inputs = controllerNode.inputs;
|
|
786
|
-
legacyContext.outputs = controllerNode.outputs;
|
|
787
|
-
// Light deliberately receives the real Hue config-node selection.
|
|
788
|
-
// Its private editor owns the bounded readiness poll and displays the
|
|
789
|
-
// hourglass until the bridge resources are available or it times out.
|
|
790
|
-
// The Light editor completes asynchronously and installs its historic
|
|
791
|
-
// light-only autocomplete inside Go(). Give it an explicit callback
|
|
792
|
-
// that restores the Controller-wide catalog after that late setup.
|
|
793
|
-
controllerNode.__configureHueControllerDeviceControl = configureUnifiedDeviceControl;
|
|
794
|
-
if (typeof definition.oneditprepare === 'function') {
|
|
795
|
-
definition.oneditprepare.call(legacyContext);
|
|
796
|
-
}
|
|
797
|
-
configureUnifiedDeviceControl();
|
|
798
|
-
// Profile guidance is already available in the node help. Keeping it
|
|
799
|
-
// out of the embedded editor makes every device profile more compact.
|
|
800
|
-
$container.find('.form-tips').remove();
|
|
801
|
-
|
|
802
|
-
const $knxFlowOnlyNotice = $container.find('.hue-controller-knx-flow-only-notice');
|
|
803
|
-
const $lightTabs = $container.find('#tabs');
|
|
804
|
-
let knxFlowOnlyNoticeText = 'To display the group-address mappings, select a KNX gateway. Without one, this node can only be controlled by input messages from the flow.';
|
|
805
|
-
try {
|
|
806
|
-
const noticeKey = 'node-red-contrib-knx-ultimate/knxUltimateHueController:knxUltimateHueController.knx_gateway_required_for_mappings';
|
|
807
|
-
const translatedNotice = RED._(noticeKey);
|
|
808
|
-
if (translatedNotice && translatedNotice !== noticeKey) knxFlowOnlyNoticeText = translatedNotice;
|
|
809
|
-
} catch (error) { /* use English fallback */ }
|
|
810
|
-
$knxFlowOnlyNotice.text(knxFlowOnlyNoticeText);
|
|
811
|
-
|
|
812
|
-
const updateControllerKnxVisibility = () => {
|
|
813
|
-
// Node-RED has used several sentinel values for an empty config-node
|
|
814
|
-
// selector. During editor bootstrap the DOM can temporarily expose
|
|
815
|
-
// one of them even though the node has a persisted gateway, so use
|
|
816
|
-
// the stored reference as a fallback before hiding the Light tabs.
|
|
817
|
-
const serverValue = $('#node-input-server').val();
|
|
818
|
-
const normalizedServerValue = serverValue === undefined || serverValue === null
|
|
819
|
-
? ''
|
|
820
|
-
: String(serverValue).trim().toLowerCase();
|
|
821
|
-
const storedServerValue = controllerNode.server === undefined || controllerNode.server === null
|
|
822
|
-
? ''
|
|
823
|
-
: String(controllerNode.server).trim().toLowerCase();
|
|
824
|
-
const hasDomServer = !KNX_EMPTY_SERVER_VALUES.has(normalizedServerValue);
|
|
825
|
-
const hasStoredServer = !KNX_EMPTY_SERVER_VALUES.has(storedServerValue);
|
|
826
|
-
const knxDisabled = !hasDomServer && !hasStoredServer;
|
|
827
|
-
$container.toggleClass('hue-controller-no-knx', knxDisabled);
|
|
828
|
-
$knxFlowOnlyNotice.toggle(controllerType === 'light' && knxDisabled);
|
|
829
|
-
if (controllerType === 'light' && $lightTabs.length) {
|
|
830
|
-
// Device availability controls the outer profile container;
|
|
831
|
-
// KNX selection alone controls the nested mapping tabs.
|
|
832
|
-
const shouldShowLightTabs = !knxDisabled;
|
|
833
|
-
// The mature Light editor also manages this inline style. Make
|
|
834
|
-
// the wrapper authoritative after every lifecycle transition so
|
|
835
|
-
// a transient bootstrap value cannot leave display:none behind
|
|
836
|
-
// after the saved/selected KNX gateway has been restored.
|
|
837
|
-
$lightTabs.css('display', shouldShowLightTabs ? 'flex' : 'none');
|
|
838
|
-
if (shouldShowLightTabs) {
|
|
839
|
-
try { $lightTabs.tabs('refresh'); } catch (error) { /* raw tabs remain visible */ }
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
};
|
|
843
|
-
const handleControllerKnxSelection = function (event) {
|
|
844
|
-
// An explicit user choice must supersede the persisted bootstrap
|
|
845
|
-
// fallback. Node-RED can represent "none" as `_ADD_`, so normalize
|
|
846
|
-
// it before both editors recalculate their visibility.
|
|
847
|
-
const selectedValue = $(this).val();
|
|
848
|
-
if (shouldPreserveStoredSelection(event, selectedValue, controllerNode.server, KNX_EMPTY_SERVER_VALUES)) {
|
|
849
|
-
updateControllerKnxVisibility();
|
|
850
|
-
return;
|
|
851
|
-
}
|
|
852
|
-
const selectedServer = normalizeKnxServerSelection(selectedValue);
|
|
853
|
-
controllerNode.server = selectedServer;
|
|
854
|
-
if (legacyContext) legacyContext.server = selectedServer;
|
|
855
|
-
updateControllerKnxVisibility();
|
|
856
|
-
};
|
|
857
|
-
updateControllerKnxVisibility();
|
|
858
|
-
$(document)
|
|
859
|
-
.off('change.knxUltimateHueControllerKnxVisibility', '#node-input-server')
|
|
860
|
-
.on('change.knxUltimateHueControllerKnxVisibility', '#node-input-server', handleControllerKnxSelection);
|
|
861
|
-
updateSelectedDevicePresentation(controllerType);
|
|
862
|
-
focusProfileHelp(controllerType);
|
|
863
|
-
};
|
|
864
|
-
|
|
865
|
-
const selectedType = PROFILE_TYPES[this.hueControllerType] ? this.hueControllerType : 'light';
|
|
866
|
-
$('#node-input-hueControllerType').val(selectedType);
|
|
867
|
-
|
|
868
|
-
activeHueServerId = resolveHueServerId({ allowStored: true });
|
|
869
|
-
$('#hue-controller-refresh-devices')
|
|
870
|
-
.off('.knxUltimateHueControllerDevice')
|
|
871
|
-
.on('click.knxUltimateHueControllerDevice', () => {
|
|
872
|
-
cachedHueResources = [];
|
|
873
|
-
hueCatalogReady = false;
|
|
874
|
-
probeHueBridgeReadiness({ reset: true, openPicker: true });
|
|
875
|
-
});
|
|
876
|
-
$(document)
|
|
877
|
-
.off('change.knxUltimateHueControllerHueServer', '#node-input-serverHue')
|
|
878
|
-
.on('change.knxUltimateHueControllerHueServer', '#node-input-serverHue', (event) => {
|
|
879
|
-
const selectedValue = $('#node-input-serverHue').val();
|
|
880
|
-
if (shouldPreserveStoredSelection(event, selectedValue, controllerNode.serverHue, HUE_EMPTY_SERVER_VALUES)) {
|
|
881
|
-
updateHueDeviceControlVisibility();
|
|
882
|
-
updateSelectedDevicePresentation();
|
|
883
|
-
return;
|
|
884
|
-
}
|
|
885
|
-
const nextServerId = normalizeHueServerSelection(selectedValue);
|
|
886
|
-
if (nextServerId === activeHueServerId) return;
|
|
887
|
-
activeHueServerId = nextServerId;
|
|
888
|
-
controllerNode.serverHue = nextServerId;
|
|
889
|
-
if (legacyContext) legacyContext.serverHue = nextServerId;
|
|
890
|
-
clearHueReadinessTimer();
|
|
891
|
-
clearHueUnreachableTimer();
|
|
892
|
-
cachedHueResources = [];
|
|
893
|
-
hueCatalogReady = false;
|
|
894
|
-
hueReadinessErrorShown = false;
|
|
895
|
-
hueBridgeUnreachable = false;
|
|
896
|
-
selectedHueResource = undefined;
|
|
897
|
-
controllerNode.name = '';
|
|
898
|
-
controllerNode.hueDevice = '';
|
|
899
|
-
$('#node-input-name, #node-input-hueDevice').val('');
|
|
900
|
-
updateHueDeviceControlVisibility();
|
|
901
|
-
updateSelectedDevicePresentation();
|
|
902
|
-
if (nextServerId !== '') probeHueBridgeReadiness({ reset: true });
|
|
903
|
-
});
|
|
904
|
-
|
|
905
|
-
this._hueControllerCollectEditor = collectCurrentEditor;
|
|
906
|
-
this._hueControllerGetLegacyContext = () => legacyContext;
|
|
907
|
-
this._hueControllerGetProfile = () => activeProfile;
|
|
908
|
-
this._hueControllerCloseMigration = () => closeMigrationDialog();
|
|
909
|
-
this._hueControllerRestoreOriginalState = restoreOriginalEditorState;
|
|
910
|
-
this._hueControllerCleanupDevice = () => {
|
|
911
|
-
hueEditorClosed = true;
|
|
912
|
-
clearHueReadinessTimer();
|
|
913
|
-
clearHueUnreachableTimer();
|
|
914
|
-
$('#hue-controller-refresh-devices, #node-input-serverHue, #node-input-name').off('.knxUltimateHueControllerDevice');
|
|
915
|
-
$(document).off('change.knxUltimateHueControllerHueServer', '#node-input-serverHue');
|
|
916
|
-
$(document).off('change.knxUltimateHueControllerKnxVisibility', '#node-input-server');
|
|
917
|
-
delete controllerNode.__configureHueControllerDeviceControl;
|
|
918
|
-
};
|
|
919
|
-
renderProfileEditor(selectedType);
|
|
920
|
-
updateHueDeviceControlVisibility();
|
|
921
|
-
probeHueBridgeReadiness({ reset: true });
|
|
922
|
-
},
|
|
923
|
-
oneditsave() {
|
|
924
|
-
// Preserve lifecycle order: close auxiliary UI, collect mounted fields,
|
|
925
|
-
// let the profile normalize them, then copy values and dynamic pins back
|
|
926
|
-
// onto the actual node that Node-RED will serialize.
|
|
927
|
-
if (typeof this._hueControllerCloseMigration === 'function') this._hueControllerCloseMigration();
|
|
928
|
-
if (typeof this._hueControllerCollectEditor === 'function') this._hueControllerCollectEditor();
|
|
929
|
-
const profile = typeof this._hueControllerGetProfile === 'function'
|
|
930
|
-
? this._hueControllerGetProfile()
|
|
931
|
-
: undefined;
|
|
932
|
-
const legacyContext = typeof this._hueControllerGetLegacyContext === 'function'
|
|
933
|
-
? this._hueControllerGetLegacyContext()
|
|
934
|
-
: undefined;
|
|
935
|
-
const definition = profile ? getProfileDefinition(this.hueControllerType) : undefined;
|
|
936
|
-
if (definition && typeof definition.oneditsave === 'function') {
|
|
937
|
-
definition.oneditsave.call(legacyContext || this);
|
|
938
|
-
}
|
|
939
|
-
if (legacyContext) {
|
|
940
|
-
Object.keys(definition?.defaults || {}).forEach((key) => {
|
|
941
|
-
if (Object.prototype.hasOwnProperty.call(legacyContext, key)) this[key] = legacyContext[key];
|
|
942
|
-
});
|
|
943
|
-
if (Number.isFinite(Number(legacyContext.inputs))) this.inputs = Number(legacyContext.inputs);
|
|
944
|
-
if (Number.isFinite(Number(legacyContext.outputs))) this.outputs = Number(legacyContext.outputs);
|
|
945
|
-
}
|
|
946
|
-
if (typeof this._hueControllerCleanupDevice === 'function') this._hueControllerCleanupDevice();
|
|
947
|
-
delete this._hueControllerCollectEditor;
|
|
948
|
-
delete this._hueControllerGetLegacyContext;
|
|
949
|
-
delete this._hueControllerGetProfile;
|
|
950
|
-
delete this._hueControllerCloseMigration;
|
|
951
|
-
delete this._hueControllerRestoreOriginalState;
|
|
952
|
-
delete this._hueControllerCleanupDevice;
|
|
953
|
-
},
|
|
954
|
-
oneditcancel() {
|
|
955
|
-
// Cancel releases profile-owned editor state and restores the snapshot
|
|
956
|
-
// taken before device/profile previews mutated the live node object.
|
|
957
|
-
if (typeof this._hueControllerCloseMigration === 'function') this._hueControllerCloseMigration();
|
|
958
|
-
const profile = typeof this._hueControllerGetProfile === 'function'
|
|
959
|
-
? this._hueControllerGetProfile()
|
|
960
|
-
: undefined;
|
|
961
|
-
const legacyContext = typeof this._hueControllerGetLegacyContext === 'function'
|
|
962
|
-
? this._hueControllerGetLegacyContext()
|
|
963
|
-
: undefined;
|
|
964
|
-
const definition = profile ? getProfileDefinition(this.hueControllerType) : undefined;
|
|
965
|
-
if (definition && typeof definition.oneditcancel === 'function') {
|
|
966
|
-
definition.oneditcancel.call(legacyContext || this);
|
|
967
|
-
}
|
|
968
|
-
if (typeof this._hueControllerCleanupDevice === 'function') this._hueControllerCleanupDevice();
|
|
969
|
-
if (typeof this._hueControllerRestoreOriginalState === 'function') this._hueControllerRestoreOriginalState();
|
|
970
|
-
delete this._hueControllerCollectEditor;
|
|
971
|
-
delete this._hueControllerGetLegacyContext;
|
|
972
|
-
delete this._hueControllerGetProfile;
|
|
973
|
-
delete this._hueControllerCloseMigration;
|
|
974
|
-
delete this._hueControllerRestoreOriginalState;
|
|
975
|
-
delete this._hueControllerCleanupDevice;
|
|
976
|
-
}
|
|
977
|
-
});
|
|
978
|
-
}());
|
|
979
|
-
</script>
|
|
980
|
-
|
|
981
|
-
<script type="text/html" data-template-name="knxUltimateHueController">
|
|
982
|
-
<div class="form-row knx-ultimate-v8-upgrade-row">
|
|
983
|
-
<button type="button" class="red-ui-button knx-ultimate-v8-upgrade-button" data-i18n="[title]node-red-contrib-knx-ultimate/knxUltimateUtility:knxUltimateUtility.v8_upgrade.button_title">
|
|
984
|
-
<i class="fa fa-arrow-circle-up" aria-hidden="true"></i>
|
|
985
|
-
<span data-i18n="node-red-contrib-knx-ultimate/knxUltimateUtility:knxUltimateUtility.v8_upgrade.button"></span>
|
|
986
|
-
</button>
|
|
987
|
-
</div>
|
|
988
|
-
<div class="form-row" style="margin-bottom:14px;">
|
|
989
|
-
<span style="color:#ff0000"><i class="fa fa-youtube"></i></span>
|
|
990
|
-
<a target="_blank" rel="noopener noreferrer" href="https://www.youtube.com/playlist?list=PL9Yh1bjbLAYrU8PsVhW4xzEug2WtVFv3E"><b data-i18n="knxUltimateHueController.tutorials_link"></b></a>
|
|
991
|
-
</div>
|
|
992
|
-
<div class="form-row" id="hue-controller-migrate-legacy-flow-row" style="display:none; margin-bottom:14px;">
|
|
993
|
-
<a class="hue-legacy-migration-video" href="https://youtu.be/f0Evf2QFI7c" target="_blank" rel="noopener noreferrer" style="display:inline-flex; align-items:center; gap:5px; margin-right:10px;" data-i18n="[title]knxUltimateHueController.migration_video_title">
|
|
994
|
-
<i class="fa fa-youtube-play" aria-hidden="true" style="color:#ff0000;"></i>
|
|
995
|
-
<span data-i18n="knxUltimateHueController.migration_video"></span>
|
|
996
|
-
</a>
|
|
997
|
-
<button type="button" id="hue-controller-migrate-legacy-flow" class="red-ui-button" data-i18n="[title]knxUltimateHueController.migration_button_title">
|
|
998
|
-
<i class="fa fa-exchange"></i>
|
|
999
|
-
<span data-i18n="knxUltimateHueController.migration_button"></span>
|
|
1000
|
-
</button>
|
|
1001
|
-
<div class="form-tips hue-controller-migration-disclaimer" style="margin-top:8px;" data-i18n="knxUltimateHueController.migration_disclaimer"></div>
|
|
1002
|
-
</div>
|
|
1003
|
-
<div class="form-row">
|
|
1004
|
-
<label for="node-input-server">
|
|
1005
|
-
<i class="fa fa-server"></i>
|
|
1006
|
-
<span data-i18n="common.knx_gw"></span>
|
|
1007
|
-
</label>
|
|
1008
|
-
<input type="text" id="node-input-server">
|
|
1009
|
-
</div>
|
|
1010
|
-
<div class="form-row">
|
|
1011
|
-
<label for="node-input-serverHue">
|
|
1012
|
-
<i class="fa fa-circle"></i>
|
|
1013
|
-
<span data-i18n="common.hue_bridge"></span>
|
|
1014
|
-
</label>
|
|
1015
|
-
<input type="text" id="node-input-serverHue">
|
|
1016
|
-
</div>
|
|
1017
|
-
<div class="form-row" id="hue-controller-devices-loading" style="display:none; color:#666;">
|
|
1018
|
-
<label></label>
|
|
1019
|
-
<span id="hue-controller-devices-waiting">
|
|
1020
|
-
<i class="fa fa-circle-notch fa-spin" style="color:#1b7d33;"></i>
|
|
1021
|
-
<span data-i18n="knxUltimateHueController.loading_hue_devices"></span>
|
|
1022
|
-
</span>
|
|
1023
|
-
<span id="hue-controller-devices-unreachable" style="display:none; color:#b45309;">
|
|
1024
|
-
<i class="fa fa-exclamation-triangle"></i>
|
|
1025
|
-
<span data-i18n="knxUltimateHueController.hue_bridge_unreachable"></span>
|
|
1026
|
-
</span>
|
|
1027
|
-
</div>
|
|
1028
|
-
<div class="form-row" id="hue-controller-device-row" style="display:none;">
|
|
1029
|
-
<label for="node-input-name">
|
|
1030
|
-
<i class="fa fa-play-circle"></i>
|
|
1031
|
-
<span data-i18n="knxUltimateHueController.hue_device"></span>
|
|
1032
|
-
</label>
|
|
1033
|
-
<input type="text" id="node-input-name" data-i18n="[placeholder]knxUltimateHueController.hue_device_placeholder"
|
|
1034
|
-
style="flex:1 1 240px; min-width:240px; max-width:240px;">
|
|
1035
|
-
<button type="button" id="hue-controller-refresh-devices" class="red-ui-button"
|
|
1036
|
-
style="margin-left:6px; color:#1b7d33; border-color:#1b7d33;" data-i18n="[title]knxUltimateHueController.refresh_devices">
|
|
1037
|
-
<i class="fa fa-sync"></i>
|
|
1038
|
-
</button>
|
|
1039
|
-
<button type="button" id="hue-controller-locate-device" class="red-ui-button hue-locate-device"
|
|
1040
|
-
style="display:none; margin-left:6px; color:#ff9800; border-color:#ff9800;" data-i18n="[title]knxUltimateHueController.locate_device">
|
|
1041
|
-
<i class="fa fa-play"></i>
|
|
1042
|
-
</button>
|
|
1043
|
-
<span id="hue-controller-selected-device-type" style="display:none; margin-left:10px; color:#666; white-space:nowrap;">
|
|
1044
|
-
<i class="fa fa-cubes"></i>
|
|
1045
|
-
<span data-i18n="knxUltimateHueController.device_type"></span>:
|
|
1046
|
-
<span id="hue-controller-selected-device-type-value" style="font-weight:600;"></span>
|
|
1047
|
-
</span>
|
|
1048
|
-
<input type="hidden" id="node-input-hueDevice">
|
|
1049
|
-
<input type="hidden" id="node-input-hueControllerType">
|
|
1050
|
-
</div>
|
|
1051
|
-
<div id="hue-controller-profile-editor"></div>
|
|
1052
|
-
<br/>
|
|
1053
|
-
<br/>
|
|
1054
|
-
<br/>
|
|
1055
|
-
<br/>
|
|
1056
|
-
</script>
|
|
1057
|
-
|
|
1058
|
-
<script type="text/markdown" data-help-name="knxUltimateHueController">
|
|
1059
|
-
### Upgrade to KNX Ultimate 8
|
|
1060
|
-
|
|
1061
|
-
Version 7 shows a compact **Upgrade to v8** button at the top of this editor. It downloads a flow backup, installs the required HUE/Matter packages, converts compatible nodes, performs a full Deploy, verifies the saved flows and installs version 8. Restart the Node-RED service when prompted; reloading only the browser is not enough. Legacy KNX AI nodes stop the automatic operation.
|
|
1062
|
-
|
|
1063
|
-
[Full upgrade guide](https://supergiovane.github.io/node-red-contrib-knx-ultimate/wiki/Upgrade-to-v8)
|
|
1064
|
-
|
|
1065
|
-
<br/>
|
|
1066
|
-
|
|
1067
|
-
# HUE Controller
|
|
1068
|
-
|
|
1069
|
-
[**KNX-Ultimate video tutorials (YouTube playlist)**](https://www.youtube.com/playlist?list=PL9Yh1bjbLAYrU8PsVhW4xzEug2WtVFv3E)
|
|
1070
|
-
|
|
1071
|
-
The unified controller for Hue API v2 resources. Choose a Hue device or resource; its device type is detected automatically and the matching KNX mapping, behaviour and node pins are then displayed.
|
|
1072
|
-
|
|
1073
|
-
Clicking or focusing the Hue device field always opens the complete resource list, even when a device is already selected. Typing continues to filter the list.
|
|
1074
|
-
|
|
1075
|
-
The Hue device picker remains hidden until the selected Hue Bridge is connected and its resource catalog is ready. A loading indicator is shown while the editor waits; selecting `none` hides the indicator and device controls.
|
|
1076
|
-
|
|
1077
|
-
If the node already has a saved Hue device, its picker and KNX mapping tabs remain available while the selected bridge is offline. Resource discovery continues in the background and a fixed red error appears if the bridge does not become ready.
|
|
1078
|
-
|
|
1079
|
-
For Light resources without a KNX gateway, the editor shows a flow-only notice in place of the duplicate “Philips HUE” heading.
|
|
1080
|
-
|
|
1081
|
-
The controller supports lights and grouped lights, plugs, buttons, Tap dial, motion resources, contacts, light level, temperature, humidity, scenes, battery, Zigbee connectivity, and device software update resources.
|
|
1082
|
-
|
|
1083
|
-
## Convert a legacy HUE flow
|
|
1084
|
-
|
|
1085
|
-
Use **Convert legacy HUE flow** in HUE Controller or the conversion button in a legacy HUE editor. After confirmation, the browser automatically starts downloading a dated JSON backup of all current editor flows, including tabs, subflows, configuration nodes, groups and wires. The backup uses the standard Node-RED export format and excludes declared credentials. Your browser may ask where to save the file. If the backup cannot be created or its download cannot be started, no nodes are converted.
|
|
1086
|
-
|
|
1087
|
-
The current editor then closes and discards unsaved form edits. Conversion runs locally in the editor and preserves node IDs, settings, configuration references, positions, groups and wiring. A single Undo restores the original nodes. Review the converted flows and click **Deploy** yourself; conversion does not deploy automatically.
|
|
1088
|
-
|
|
1089
|
-
## Compatibility and loop protection
|
|
1090
|
-
|
|
1091
|
-
Each function uses its private mature runtime contract. Hue events remain status updates and are never reflected to Hue or KNX as new commands unless the selected function explicitly maps them to a KNX output. The Controller owns its Light implementation without modifying the original legacy Hue Light node.
|
|
1092
|
-
|
|
1093
|
-
Dedicated legacy HUE nodes remain registered for existing flows, but are frozen and receive no new features or maintenance updates. Node-RED hides their special `deprecated` category from the palette, while existing instances remain editable, deployable, lighter than HUE Controller and visibly marked `(deprecated)` on the canvas. They also show a migration notice at the top of their editor. Before starting, [watch the explanatory migration video on YouTube](https://youtu.be/f0Evf2QFI7c). Use HUE Controller for new work or migrate them with the fully local conversion button; afterwards, the browser opens only an editable usage email draft without navigating away from Node-RED. The email is never sent automatically. Before Deploy, inspect every modified HUE node and verify its function, configuration references, pins and wiring. A fixed Node-RED completion message remains visible until you click **OK** and offers an optional support button; the donation page opens only when that button is clicked.
|
|
1094
|
-
|
|
1095
|
-
When no **KNX Gateway** is selected (including **none** and **Add new...**), only the Light mapping tabs are hidden. Their mounted GA, DPT and Name fields remain unchanged and reappear immediately with the correct vertical tab layout when the gateway is selected again. Hue resource selection and flow-only options remain available.
|
|
1096
|
-
|
|
1097
|
-
Temporary placeholder values emitted programmatically by Node-RED while the KNX and Hue configuration selectors initialize do not replace saved gateways. Only an explicit user selection of **none** hides the Light mapping tabs.
|
|
1098
|
-
|
|
1099
|
-
The Light mapping tabs contain only configuration controls; the decorative Dim, Tunable White and RGB images have been removed.
|
|
1100
|
-
|
|
1101
|
-
For a single light, the **Dim**, **Tunable White**, **RGB/HSV**, and native-effects sections are enabled from the live capabilities reported by the selected Hue API v2 light resource. A light that exposes `dimming`, `color_temperature`, or `color` therefore shows the corresponding KNX mappings automatically.
|
|
1102
|
-
|
|
1103
|
-
The Light editor renders saved mappings immediately without waiting for the runtime Hue resource cache. Current capabilities load in the background; if that request fails, the saved mappings and pin selector remain available and a fixed red Node-RED error reports the failure.
|
|
1104
|
-
|
|
1105
|
-
Locate and the Light mapping container initialize before optional Effects and tab widgets. A saved KNX gateway remains valid if Node-RED temporarily exposes an empty selector while the editor starts. Browser-side failures and a rejected initial Locate command produce a fixed red Node-RED error with the technical detail instead of leaving the editor silent.
|
|
1106
|
-
|
|
1107
|
-
Changing the selected **Hue device** automatically changes the detected **Device type**, visible editor and node pin layout. After saving, reopen the node to verify the selected resource and mappings.
|
|
1108
|
-
|
|
1109
|
-
KNX mapping rows keep GA, DPT and Name on one line. DPT selectors use a compact fixed range, while Name fields are shorter and may contract further on a narrow editor tray without changing their stored text. Saved DPT values are retained while selector options load asynchronously.
|
|
1110
|
-
|
|
1111
|
-
<!-- HUE_CONTROLLER_PROFILE_HELP_START -->
|
|
1112
|
-
|
|
1113
|
-
## Device function
|
|
1114
|
-
|
|
1115
|
-
- [Light / grouped light (`light`)](#hue-controller-help-light)
|
|
1116
|
-
- [Plug / outlet (`plug`)](#hue-controller-help-plug)
|
|
1117
|
-
- [Button (`button`)](#hue-controller-help-button)
|
|
1118
|
-
- [Tap dial (`relative_rotary`)](#hue-controller-help-relative_rotary)
|
|
1119
|
-
- [Motion (`motion`)](#hue-controller-help-motion)
|
|
1120
|
-
- [Area motion (`area_motion`)](#hue-controller-help-area_motion)
|
|
1121
|
-
- [Camera motion (`camera_motion`)](#hue-controller-help-camera_motion)
|
|
1122
|
-
- [Contact (`contact`)](#hue-controller-help-contact)
|
|
1123
|
-
- [Light level (`light_level`)](#hue-controller-help-light_level)
|
|
1124
|
-
- [Temperature (`temperature`)](#hue-controller-help-temperature)
|
|
1125
|
-
- [Humidity (`humidity`)](#hue-controller-help-humidity)
|
|
1126
|
-
- [Scene (`scene`)](#hue-controller-help-scene)
|
|
1127
|
-
- [Battery (`device_power`)](#hue-controller-help-device_power)
|
|
1128
|
-
- [Zigbee connectivity (`zigbee_connectivity`)](#hue-controller-help-zigbee_connectivity)
|
|
1129
|
-
- [Device software update (`device_software_update`)](#hue-controller-help-device_software_update)
|
|
1130
|
-
|
|
1131
|
-
<span id="hue-controller-help-light" data-hue-controller-type="light"></span>
|
|
1132
|
-
|
|
1133
|
-
## Light / grouped light (`light`)
|
|
1134
|
-
|
|
1135
|
-
<p>This node controls Philips Hue lights (single or grouped) and maps their commands/states to KNX.</p>
|
|
1136
|
-
|
|
1137
|
-
**General**
|
|
1138
|
-
|
|
1139
|
-
|Property|Description|
|
|
1140
|
-
|--|--|
|
|
1141
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1142
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1143
|
-
| Name | Hue light or grouped light to use (autocomplete while typing).|
|
|
1144
|
-
|
|
1145
|
-
<br/>
|
|
1146
|
-
|
|
1147
|
-
**Locate device**
|
|
1148
|
-
|
|
1149
|
-
Use the `Locate` button (play icon) to start a Hue identify session for the selected resource. While the session is active the button switches to a stop icon and the bridge makes the light — or every light in the grouped resource — blink once per second. Press the button again to stop immediately; otherwise the session ends automatically after 10 minutes.
|
|
1150
|
-
|
|
1151
|
-
<br/>
|
|
1152
|
-
|
|
1153
|
-
**OPTIONS**
|
|
1154
|
-
|
|
1155
|
-
Here you can link KNX Group Addresses to the available Hue commands/states.<br/>
|
|
1156
|
-
Start typing in the GA field (name or Group Address); suggestions appear while you type.
|
|
1157
|
-
|
|
1158
|
-
**Switch**
|
|
1159
|
-
|
|
1160
|
-
|Property|Description|
|
|
1161
|
-
|--|--|
|
|
1162
|
-
| Control | This GA is used to turn on/off the Hue light via a boolean KNX value true/false|
|
|
1163
|
-
| Status | Link this to the light's switch status group address|
|
|
1164
|
-
|
|
1165
|
-
<br/>
|
|
1166
|
-
|
|
1167
|
-
**Dim**
|
|
1168
|
-
|
|
1169
|
-
|Property|Description|
|
|
1170
|
-
|--|--|
|
|
1171
|
-
| Control dim | Relative DIM of the Hue light. You can set the dimming speed in the **Behaviour** tab. |
|
|
1172
|
-
| Control % | Changes the absolute Hue light's brightness (0-100%)|
|
|
1173
|
-
| Status % | Link this to the light's brightness status KNX group address |
|
|
1174
|
-
| Dim Speed (ms) | Dimming speed in milliseconds. Applies to both the light brightness and the tunable-white datapoints. Calculated over the 0%→100% range. |
|
|
1175
|
-
| Min Dim brightness | Tha Minimum brightness that the lamp can reach. For example, if you are dimming the light down, the light will stop dimming at the specified brightness %. |
|
|
1176
|
-
| Max Dim brightness | Tha Maximum brightness that the lamp can reach. For example, if you are dimming the light up, the light will stop dimming at the specified brightness %. |
|
|
1177
|
-
|
|
1178
|
-
<br/>
|
|
1179
|
-
|
|
1180
|
-
**Tunable White**
|
|
1181
|
-
|
|
1182
|
-
|Property|Description|
|
|
1183
|
-
|--|--|
|
|
1184
|
-
| Control dim | Change white temperature using DPT 3.007 dimming. Speed is set in the **Behaviour** tab.|
|
|
1185
|
-
| Control % | Change white temperature using DPT 5.001. 0 = full warm, 100 = full cold.|
|
|
1186
|
-
| Status %| Temperature status GA. DPT 5.001 absolute value: 0 = full warm, 100 = full cold.|
|
|
1187
|
-
| Control kelvin | **DPT 7.600: ** set temperature in Kelvin using the KNX range 2000-6535 (converted to Hue mirek).<br/>**DPT 9.002:** set temperature using Hue range 2000-6535 K (Ambiance starts at 2200 K). Conversions may introduce small deviations.|
|
|
1188
|
-
| Status kelvin | **DPT 7.600: ** read temperature in Kelvin using KNX range 2000-6535 (converted from Hue).<br/>**DPT 9.002:** read temperature using Hue range 2000-6535 K (Ambiance starts at 2200 K). Conversions may introduce small deviations. |
|
|
1189
|
-
| Invert dim direction | Inverts the DIM direction. |
|
|
1190
|
-
<br/>
|
|
1191
|
-
|
|
1192
|
-
**RGB/HSV**
|
|
1193
|
-
|
|
1194
|
-
|Property|Description|
|
|
1195
|
-
|--|--|
|
|
1196
|
-
| **RGB section** ||
|
|
1197
|
-
| Control rgb| Change color using RGB triplet (r,g,b). Gamut correction is handled. Sending a color turns the light on and sets color/brightness (perceptual). Sending r,g,b = 0 turns the light off. |
|
|
1198
|
-
| Status rgb | The light's color status group address. Accepted datapoint is RGB triplet (r,g,b)|
|
|
1199
|
-
| **HSV section** ||
|
|
1200
|
-
| Color H dim | Cycle through HSV hue using DPT 3.007 dimming. Speed is set in the **Behaviour** tab.|
|
|
1201
|
-
| Status H %| Status of the HSV chromatic circle.|
|
|
1202
|
-
| Control S dim | Changes the light's color saturation, using DPT 3.007 dimming. You can set the dimming speed in the **_Behaviour_** tab.|
|
|
1203
|
-
| Status S %| The light color saturation status group address.|
|
|
1204
|
-
| Dim Speed (ms) | The dimming speed, in Milliseconds, from bottom to top scale. |
|
|
1205
|
-
|
|
1206
|
-
For controlling the HSV "V” (brightness), use the standard controls under the **Dim** tab.
|
|
1207
|
-
|
|
1208
|
-
<br/>
|
|
1209
|
-
|
|
1210
|
-
**Effects**
|
|
1211
|
-
|
|
1212
|
-
_Non-Hue basic effects_
|
|
1213
|
-
|
|
1214
|
-
|Property|Description|
|
|
1215
|
-
|--|--|
|
|
1216
|
-
| Blink | _true_ Blink the light, _false_ Stop blinking. Blinks the light on and off. Useful for signalling. Works with all Hue lights. |
|
|
1217
|
-
| Color Cycle | _true_ start cycle, _false_ Stop cycle. Randomly changes the Hue light's color at regular interval. Works with all Hue lights having color capabilities. The color effect will start 10 seconds after set. |
|
|
1218
|
-
|
|
1219
|
-
_Hue native effects_
|
|
1220
|
-
|
|
1221
|
-
Use the **Hue native effects** table to map your KNX values to the effects supported by the selected light (for example `candle`, `fireplace`, `prism`). Each row links a KNX value (boolean, numeric or textual, depending on the datapoint you pick) with a Hue effect. On the KNX side you can:
|
|
1222
|
-
|
|
1223
|
-
- send the mapped value to activate that effect;
|
|
1224
|
-
- optionally provide a status Group Address: the node emits the mapped value whenever the Hue bridge reports an effect change; if no mapping exists the raw effect name is sent (requires a textual DPT such as 16.xxx).
|
|
1225
|
-
|
|
1226
|
-
<br/>
|
|
1227
|
-
|
|
1228
|
-
**Behaviour**
|
|
1229
|
-
|
|
1230
|
-
| Property | Description |
|
|
1231
|
-
| ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
1232
|
-
| Read status at startup | Read the Hue light status at node-red's startup or node-red's full deploy, and send that status to the KNX BUS |
|
|
1233
|
-
| KNX Brightness Status | Updates the KNX brightness group address status, whenever the Hue lamp is switched ON/OFF. The options are **When Hue light is Off send 0%. When Hue On, restore previous value (Default KNX behaviour) ** and**Leave as is (default Hue behaviour) ** . If you have KNX dimmer with brightness status, like MDT, the suggested option is _**When Hue light is Off send 0%. When Hue On, restore previous value (Default KNX behaviour)** _ |
|
|
1234
|
-
| Update local cached Hue state from KNX bus writes | Advanced option, enabled by default. When enabled, writes arriving from the KNX bus also update the node's local cached Hue state immediately, without waiting for feedback/events from the Hue bridge. This gives faster local reactions and more consistent immediate KNX read responses, especially while the light or grouped light is OFF. Disable it if you prefer the cache to follow only real feedback/events from the Hue bridge. |
|
|
1235
|
-
| Switch on behaviour | It sets the behaviour of your lights when switched on. You can choose from differents behaviours.<br/> **Select color: ** the light will be switched on with the color of your choice. To change color, just CLICK on the color selector (under the _Select color_ control).<br/>**Select temperature and brightness: ** the light will be switched on with the temperature (Kelvin) and brightness (0-100) of your choice.<br/>**None:** the light will retain its last status. In case you've enable the night lighting, after the night time ends, the lamp will resume the color/temperature/brightness state set at day time. |
|
|
1236
|
-
| Night Lighting | It allows to set a particular light color/brightness at nighttime. The options are the same as the daytime. You could select either a temperature/brightness or color. A cozy temperature of 2700 Kelvin, with a brightness of 10% or 20%, is a good choice for bathroom's night light.|
|
|
1237
|
-
| Day/Night | Select the group address used to set the day/night behaviour. The group address value is _true_ if daytime, _false_ if nighttime. |
|
|
1238
|
-
| Invert day/night value | Invert the values of _Day/Night_ group address. Default value is **unchecked** . |
|
|
1239
|
-
| Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
|
|
1240
|
-
| Force day mode | You can force the day mode by manually switching the light as described here: **Switch to DAY mode by rapid switching the ligth off then on (This light only) ** does what described and acts only on this light.**Switch to DAY mode by rapid switching the ligth off then on (apply yo ALL light nodes)** acts to ALL Light nodes, by setting the Day/Night group address to Day mode. |
|
|
1241
|
-
| Node Input/Output PINs | Hide or show the input/output PINs. Input/output PINS allow the node to accept msg input from the flow and send msg output to the flow. Input msg must follow the Hue API v.2 Standards. This is an example msg, that turns on the light: <code>msg.on = {"on":true}</code>. Please refer to the [official Hue Api page](https://developers.meethue.com/develop/hue-api-v2/api-reference/#resource_light__id__put) |
|
|
1242
|
-
|
|
1243
|
-
##### Note
|
|
1244
|
-
|
|
1245
|
-
The Dimming function works in **KNX mode `start` and`stop` ** . To start dimming, send only one "start" KNX telegram. To stop dimming, send a "stop" KNX telegram. Please**remember that** , when you set your wall swiches properties.
|
|
1246
|
-
|
|
1247
|
-
<br/>
|
|
1248
|
-
|
|
1249
|
-
---
|
|
1250
|
-
|
|
1251
|
-
<span id="hue-controller-help-plug" data-hue-controller-type="plug"></span>
|
|
1252
|
-
|
|
1253
|
-
## Plug / outlet (`plug`)
|
|
1254
|
-
|
|
1255
|
-
### Hue Plug / Outlet
|
|
1256
|
-
|
|
1257
|
-
#### Overview
|
|
1258
|
-
|
|
1259
|
-
The Hue Plug node links a Philips Hue smart plug (service `plug`) with KNX group addresses so you can control power and track the state directly from the BUS.
|
|
1260
|
-
|
|
1261
|
-
- Supports **on/off control** and **status feedback**.
|
|
1262
|
-
- Optional mapping of the Hue `power_state` (on / standby).
|
|
1263
|
-
- Can expose Node-RED input/output pins to forward Hue events to flows or send advanced API payloads.
|
|
1264
|
-
|
|
1265
|
-
#### Configuration
|
|
1266
|
-
|
|
1267
|
-
|Field|Description|
|
|
1268
|
-
|--|--|
|
|
1269
|
-
| KNX GW | KNX gateway used for telegrams |
|
|
1270
|
-
| Hue Bridge | Configured Hue Bridge |
|
|
1271
|
-
| Name | Select the Hue plug from the autocomplete list |
|
|
1272
|
-
| Control | KNX GA for on/off commands (boolean DPT) |
|
|
1273
|
-
| Status | GA for the on/off feedback coming from Hue |
|
|
1274
|
-
| Power state | Optional GA mirroring Hue `power_state` (boolean/text) |
|
|
1275
|
-
| Read status at startup | When enabled, the node emits the current plug state on deploy/connection |
|
|
1276
|
-
| Node Input/Output PINs | Enable Node-RED input/output pins. Input expects Hue API payloads (e.g. `{ on: { on: true } }`). Output forwards every Hue event. |
|
|
1277
|
-
|
|
1278
|
-
#### KNX Mapping Tips
|
|
1279
|
-
|
|
1280
|
-
- Use a boolean datapoint (e.g. DPT 1.001) for both command and status.
|
|
1281
|
-
- If you expose `power_state`, map it to a boolean GA (true = `on`, false = `standby`).
|
|
1282
|
-
- For read requests (`GroupValue_Read`) the node returns the last cached Hue value.
|
|
1283
|
-
|
|
1284
|
-
#### Flow Integration
|
|
1285
|
-
|
|
1286
|
-
When _Node I/O pins_ are enabled:
|
|
1287
|
-
|
|
1288
|
-
- **Input:** send Hue v2 payloads to perform advanced actions (e.g. `msg.on = { on: true }`).
|
|
1289
|
-
- **Output:** receive an event object `{ payload: boolean, on, power_state, rawEvent }` whenever Hue reports a change.
|
|
1290
|
-
|
|
1291
|
-
#### Hue API Reference
|
|
1292
|
-
|
|
1293
|
-
The node uses `/resource/plug/{id}` over HTTPS. Status changes are delivered via the Hue event stream and cached for KNX read responses.
|
|
1294
|
-
|
|
1295
|
-
---
|
|
1296
|
-
|
|
1297
|
-
<span id="hue-controller-help-button" data-hue-controller-type="button"></span>
|
|
1298
|
-
|
|
1299
|
-
## Button (`button`)
|
|
1300
|
-
|
|
1301
|
-
<p>The Hue Button node maps Hue button events to KNX group addresses and exposes the same events on its flow output via <code>button.button_report.event</code>.</p>
|
|
1302
|
-
|
|
1303
|
-
Start typing in the GA field (name or Group Address) to link the KNX GA; devices appear while you type.
|
|
1304
|
-
|
|
1305
|
-
**General**
|
|
1306
|
-
|
|
1307
|
-
|Property|Description|
|
|
1308
|
-
|--|--|
|
|
1309
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1310
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1311
|
-
| Hue Button | Hue button to be used (autocomplete while typing) |
|
|
1312
|
-
|
|
1313
|
-
**Switch**
|
|
1314
|
-
|
|
1315
|
-
|Property|Description|
|
|
1316
|
-
|--|--|
|
|
1317
|
-
| Switch | GA triggered by <code>short\_release</code> (quick press/release). |
|
|
1318
|
-
| Status GA | Optional feedback GA when <em>Toggle values</em> is enabled to keep the internal toggle state aligned with other actuators. |
|
|
1319
|
-
|
|
1320
|
-
**Dim**
|
|
1321
|
-
|
|
1322
|
-
|Property|Description|
|
|
1323
|
-
|--|--|
|
|
1324
|
-
| Dim | GA used during <code>long\_press</code>/<code>repeat</code> events for dimming (typically DPT 3.007). |
|
|
1325
|
-
|
|
1326
|
-
**Behaviour**
|
|
1327
|
-
|
|
1328
|
-
|Property|Description|
|
|
1329
|
-
|--|--|
|
|
1330
|
-
| Toggle values on each event | If enabled, the node alternates between <code>true/false</code> and up/down dimming payloads. |
|
|
1331
|
-
| Switch payload | Payload sent to KNX/flow when Toggle values is disabled. |
|
|
1332
|
-
| Dim payload | Direction sent to KNX/flow when Toggle values is disabled. |
|
|
1333
|
-
|
|
1334
|
-
##### Outputs
|
|
1335
|
-
|
|
1336
|
-
1. Standard output
|
|
1337
|
-
: `msg.payload` carries the boolean (or dim object) sent to KNX; `msg.event` is the Hue event string (e.g. `short_release`, `repeat`).
|
|
1338
|
-
|
|
1339
|
-
##### Details
|
|
1340
|
-
|
|
1341
|
-
`msg.event` mirrors `button.button_report.event`. The original Hue event is exposed in `msg.rawEvent`. Use the optional Status GA to keep the toggle state in sync with wall switches or other controllers.
|
|
1342
|
-
|
|
1343
|
-
---
|
|
1344
|
-
|
|
1345
|
-
<span id="hue-controller-help-relative_rotary" data-hue-controller-type="relative_rotary"></span>
|
|
1346
|
-
|
|
1347
|
-
## Tap dial (`relative_rotary`)
|
|
1348
|
-
|
|
1349
|
-
The **Hue Tap Dial** node maps the rotary service of the Hue Tap Dial to KNX and forwards the raw Hue events to your flow. Use the refresh icon beside the device field after pairing a new dial on the bridge.
|
|
1350
|
-
|
|
1351
|
-
##### Tabs
|
|
1352
|
-
|
|
1353
|
-
- **Mapping** - select the KNX GA and DPT used for the rotation events. Supported datapoints: DPT 3.007 (relative dim), DPT 5.001 (absolute level 0-100 %) and DPT 232.600 (vendor colour control).
|
|
1354
|
-
- **Behaviour** - show or hide the Node-RED output pin. When no KNX gateway is configured the output is kept enabled so Hue events still reach the flow.
|
|
1355
|
-
|
|
1356
|
-
##### General settings
|
|
1357
|
-
|
|
1358
|
-
|Property|Description|
|
|
1359
|
-
|--|--|
|
|
1360
|
-
| KNX GW | KNX gateway used for GA autocomplete. |
|
|
1361
|
-
| Hue Bridge | Hue Bridge hosting the Tap Dial. |
|
|
1362
|
-
| Hue Tap Dial | Rotary device to control (autocomplete; refresh button reloads the list). |
|
|
1363
|
-
|
|
1364
|
-
##### Mapping tab
|
|
1365
|
-
|
|
1366
|
-
|Property|Description|
|
|
1367
|
-
|--|--|
|
|
1368
|
-
| Rotate GA | KNX GA receiving rotation events (supports DPT 3.007, 5.001, 232.600). |
|
|
1369
|
-
| Name | Friendly label for the GA. |
|
|
1370
|
-
|
|
1371
|
-
##### Outputs
|
|
1372
|
-
|
|
1373
|
-
|#|Port|Payload|
|
|
1374
|
-
|--|--|--|
|
|
1375
|
-
|1|Standard output|`msg.payload` (object) Raw Hue event emitted by the Tap Dial.|
|
|
1376
|
-
|
|
1377
|
-
> ℹ️ KNX-specific widgets appear only after selecting a KNX gateway; the Mapping tab stays hidden until both the bridge and the gateway are configured.
|
|
1378
|
-
|
|
1379
|
-
---
|
|
1380
|
-
|
|
1381
|
-
<span id="hue-controller-help-motion" data-hue-controller-type="motion"></span>
|
|
1382
|
-
|
|
1383
|
-
## Motion (`motion`)
|
|
1384
|
-
|
|
1385
|
-
<p>This node listens to a Hue motion sensor and mirrors the events to KNX and/or your Node-RED flow.</p>
|
|
1386
|
-
|
|
1387
|
-
Start typing the KNX device name or Group Address in the GA field; suggestions appear while you type. Hit the refresh button next to "Hue sensor” to reload the device list from the bridge if you add new sensors.
|
|
1388
|
-
|
|
1389
|
-
**General**
|
|
1390
|
-
|
|
1391
|
-
|Property|Description|
|
|
1392
|
-
|--|--|
|
|
1393
|
-
| KNX GW | KNX gateway that receives the motion updates (required before KNX mapping fields appear). |
|
|
1394
|
-
| Hue Bridge | Hue Bridge to query. |
|
|
1395
|
-
| Hue motion sensor | Hue motion sensor (supports autocomplete and refresh). |
|
|
1396
|
-
|
|
1397
|
-
**Mapping**
|
|
1398
|
-
|
|
1399
|
-
|Property|Description|
|
|
1400
|
-
|--|--|
|
|
1401
|
-
| Motion | KNX GA that receives `true` when motion is detected and `false` when the area is clear. Recommended DPT: <b>1.001</b>. |
|
|
1402
|
-
|
|
1403
|
-
**Behaviour**
|
|
1404
|
-
|
|
1405
|
-
|Property|Description|
|
|
1406
|
-
|--|--|
|
|
1407
|
-
| Node output pin | Show or hide the Node-RED output. When no KNX gateway is selected the output pin stays enabled so Hue motion events still reach your flow. |
|
|
1408
|
-
|
|
1409
|
-
> ℹ️ KNX widgets remain hidden until you select a KNX gateway, making it easy to use the node purely as a Hue → Node-RED listener.
|
|
1410
|
-
|
|
1411
|
-
##### Output
|
|
1412
|
-
|
|
1413
|
-
1. Standard output — `msg.payload` (boolean)
|
|
1414
|
-
: `true` on motion, `false` when motion ends.
|
|
1415
|
-
|
|
1416
|
-
---
|
|
1417
|
-
|
|
1418
|
-
<span id="hue-controller-help-area_motion" data-hue-controller-type="area_motion"></span>
|
|
1419
|
-
|
|
1420
|
-
## Area motion (`area_motion`)
|
|
1421
|
-
|
|
1422
|
-
<p>The Hue Motion Area node listens to MotionAware area motion events (Hue Bridge Pro) and mirrors the aggregated detected/not-detected state to KNX or your Node-RED flow.</p>
|
|
1423
|
-
|
|
1424
|
-
Start typing in the GA field (name or Group Address) to link the KNX GA; devices appear while you type.
|
|
1425
|
-
|
|
1426
|
-
**General**
|
|
1427
|
-
|
|
1428
|
-
|Property|Description|
|
|
1429
|
-
|--|--|
|
|
1430
|
-
| KNX GW | Select the KNX gateway to be used. |
|
|
1431
|
-
| HUE Bridge | Select the Hue Bridge Pro to be used. |
|
|
1432
|
-
| HUE Area | MotionAware area (convenience or security) to monitor (autocomplete while typing). |
|
|
1433
|
-
| Read status at startup | On startup/reconnect, read the current value and send it to KNX (default: yes). |
|
|
1434
|
-
|
|
1435
|
-
**Mapping**
|
|
1436
|
-
|
|
1437
|
-
|Property|Description|
|
|
1438
|
-
|--|--|
|
|
1439
|
-
| Motion | KNX GA for the area motion state (boolean). Recommended DPT: <b>1.001</b>. |
|
|
1440
|
-
|
|
1441
|
-
**Behaviour**
|
|
1442
|
-
|
|
1443
|
-
|Property|Description|
|
|
1444
|
-
|--|--|
|
|
1445
|
-
| Node output pin | Show or hide the Node-RED output. When no KNX gateway is selected the output pin stays enabled so MotionAware events still reach your flow. |
|
|
1446
|
-
|
|
1447
|
-
##### Outputs
|
|
1448
|
-
|
|
1449
|
-
1. Standard output
|
|
1450
|
-
: `msg.payload` (boolean): `true` when motion is detected in the area, otherwise `false`.
|
|
1451
|
-
|
|
1452
|
-
##### Details
|
|
1453
|
-
|
|
1454
|
-
`msg.payload` carries the latest MotionAware area motion status (aggregated from the underlying sensors).
|
|
1455
|
-
|
|
1456
|
-
---
|
|
1457
|
-
|
|
1458
|
-
<span id="hue-controller-help-camera_motion" data-hue-controller-type="camera_motion"></span>
|
|
1459
|
-
|
|
1460
|
-
## Camera motion (`camera_motion`)
|
|
1461
|
-
|
|
1462
|
-
<p>The Hue Camera Motion node listens to Philips Hue camera motion services and mirrors the detected/not detected state to KNX.</p>
|
|
1463
|
-
|
|
1464
|
-
Start typing in the GA field (name or Group Address) to link the KNX GA; devices appear while you type.
|
|
1465
|
-
|
|
1466
|
-
**General**
|
|
1467
|
-
|
|
1468
|
-
|Property|Description|
|
|
1469
|
-
|--|--|
|
|
1470
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1471
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1472
|
-
| Hue Camera Motion | Hue camera motion sensor (autocomplete while typing) |
|
|
1473
|
-
| Read status at startup | On startup/reconnect, read the current value and send it to KNX (default: no) |
|
|
1474
|
-
|
|
1475
|
-
**Mapping**
|
|
1476
|
-
|
|
1477
|
-
|Property|Description|
|
|
1478
|
-
|--|--|
|
|
1479
|
-
| Motion | KNX GA for camera motion (boolean). Recommended DPT: <b>1.001</b> |
|
|
1480
|
-
|
|
1481
|
-
##### Outputs
|
|
1482
|
-
|
|
1483
|
-
1. Standard output
|
|
1484
|
-
: `msg.payload` (boolean): `true` when motion is detected; otherwise `false`
|
|
1485
|
-
|
|
1486
|
-
##### Details
|
|
1487
|
-
|
|
1488
|
-
`msg.payload` carries the latest motion status reported by the Hue camera service.
|
|
1489
|
-
|
|
1490
|
-
---
|
|
1491
|
-
|
|
1492
|
-
<span id="hue-controller-help-contact" data-hue-controller-type="contact"></span>
|
|
1493
|
-
|
|
1494
|
-
## Contact (`contact`)
|
|
1495
|
-
|
|
1496
|
-
<p>This node forwards events from a Hue contact sensor and maps them to KNX group addresses.</p>
|
|
1497
|
-
|
|
1498
|
-
Start typing in the GA field, the name or group address of your KNX device, the avaiable devices start showing up while you're typing.
|
|
1499
|
-
|
|
1500
|
-
**General**
|
|
1501
|
-
|
|
1502
|
-
|Property|Description|
|
|
1503
|
-
|--|--|
|
|
1504
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1505
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1506
|
-
| Hue Contact Sensor | Hue contact sensor to be used (autocomplete while typing).|
|
|
1507
|
-
|
|
1508
|
-
| Property | Description |
|
|
1509
|
-
|--|--|
|
|
1510
|
-
| Contact | When the contact opens/closes, send KNX value: _true_ on active/open, otherwise _false_. |
|
|
1511
|
-
|
|
1512
|
-
##### Outputs
|
|
1513
|
-
|
|
1514
|
-
1. Standard output
|
|
1515
|
-
: payload (boolean) : the standard output of the command.
|
|
1516
|
-
|
|
1517
|
-
##### Details
|
|
1518
|
-
|
|
1519
|
-
`msg.payload` carries the raw Hue event (boolean/object). Use it for custom logic if needed.
|
|
1520
|
-
|
|
1521
|
-
---
|
|
1522
|
-
|
|
1523
|
-
<span id="hue-controller-help-light_level" data-hue-controller-type="light_level"></span>
|
|
1524
|
-
|
|
1525
|
-
## Light level (`light_level`)
|
|
1526
|
-
|
|
1527
|
-
<p>This node reads lux events from a Hue Light Sensor and maps them to KNX.</p>
|
|
1528
|
-
|
|
1529
|
-
It emits the ambient illuminance (lux) each time it changes. Start typing in the GA field (name or Group Address) to link the KNX GA; devices appear while you type.
|
|
1530
|
-
|
|
1531
|
-
**General**
|
|
1532
|
-
|
|
1533
|
-
|Property|Description|
|
|
1534
|
-
|--|--|
|
|
1535
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1536
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1537
|
-
| Hue Light Sensor | Hue Light Sensor to use (autocomplete while typing).|
|
|
1538
|
-
| Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
|
|
1539
|
-
|
|
1540
|
-
**Mapping**
|
|
1541
|
-
|
|
1542
|
-
| Property | Description |
|
|
1543
|
-
|--|--|
|
|
1544
|
-
| Lux | KNX GA that receives the lux value. |
|
|
1545
|
-
|
|
1546
|
-
##### Outputs
|
|
1547
|
-
|
|
1548
|
-
1. Standard output
|
|
1549
|
-
: payload (number): current lux value.
|
|
1550
|
-
|
|
1551
|
-
##### Details
|
|
1552
|
-
|
|
1553
|
-
`msg.payload` carries the numeric lux value. Use it for custom logic if needed.
|
|
1554
|
-
|
|
1555
|
-
---
|
|
1556
|
-
|
|
1557
|
-
<span id="hue-controller-help-temperature" data-hue-controller-type="temperature"></span>
|
|
1558
|
-
|
|
1559
|
-
## Temperature (`temperature`)
|
|
1560
|
-
|
|
1561
|
-
<p>This node reads temperature (°C) from a Hue temperature sensor and maps it to KNX.</p>
|
|
1562
|
-
|
|
1563
|
-
Start typing in the GA field (name or Group Address) to link the KNX GA; devices appear while you type.
|
|
1564
|
-
|
|
1565
|
-
**General**
|
|
1566
|
-
|
|
1567
|
-
|Property|Description|
|
|
1568
|
-
|--|--|
|
|
1569
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1570
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1571
|
-
| Hue temperature sensor | Hue temperature sensor (autocomplete while typing) |
|
|
1572
|
-
| Read status at startup | On startup/reconnect, read current value and send it to KNX (default: no) |
|
|
1573
|
-
|
|
1574
|
-
**Mapping**
|
|
1575
|
-
|
|
1576
|
-
|Property|Description|
|
|
1577
|
-
|--|--|
|
|
1578
|
-
| Temp | KNX GA for temperature in Celsius. Recommended DPT: <b>9.001</b> |
|
|
1579
|
-
|
|
1580
|
-
##### Outputs
|
|
1581
|
-
|
|
1582
|
-
1. Standard output
|
|
1583
|
-
: `msg.payload` (number): current temperature in °C
|
|
1584
|
-
|
|
1585
|
-
##### Details
|
|
1586
|
-
|
|
1587
|
-
`msg.payload` carries the numeric temperature value.
|
|
1588
|
-
|
|
1589
|
-
---
|
|
1590
|
-
|
|
1591
|
-
<span id="hue-controller-help-humidity" data-hue-controller-type="humidity"></span>
|
|
1592
|
-
|
|
1593
|
-
## Humidity (`humidity`)
|
|
1594
|
-
|
|
1595
|
-
<p>This node reads relative humidity (%) from a Hue humidity sensor and maps it to KNX.</p>
|
|
1596
|
-
|
|
1597
|
-
Start typing in the GA field (name or Group Address) to link the KNX GA; devices appear while you type.
|
|
1598
|
-
|
|
1599
|
-
**General**
|
|
1600
|
-
|
|
1601
|
-
|Property|Description|
|
|
1602
|
-
|--|--|
|
|
1603
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1604
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1605
|
-
| Hue Sensor | Hue humidity sensor (autocomplete while typing) |
|
|
1606
|
-
| Read status at startup | On startup/reconnect, read current value and send it to KNX (default: no) |
|
|
1607
|
-
|
|
1608
|
-
**Mapping**
|
|
1609
|
-
|
|
1610
|
-
|Property|Description|
|
|
1611
|
-
|--|--|
|
|
1612
|
-
| Humidity | KNX GA for relative humidity %. Recommended DPT: <b>9.007</b> |
|
|
1613
|
-
|
|
1614
|
-
##### Outputs
|
|
1615
|
-
|
|
1616
|
-
1. Standard output
|
|
1617
|
-
: `msg.payload` (number): current relative humidity in %
|
|
1618
|
-
|
|
1619
|
-
##### Details
|
|
1620
|
-
|
|
1621
|
-
`msg.payload` carries the numeric humidity value (percentage).
|
|
1622
|
-
|
|
1623
|
-
---
|
|
1624
|
-
|
|
1625
|
-
<span id="hue-controller-help-scene" data-hue-controller-type="scene"></span>
|
|
1626
|
-
|
|
1627
|
-
## Scene (`scene`)
|
|
1628
|
-
|
|
1629
|
-
The **Hue Scene** node exposes Hue scenes to KNX and can forward the raw Hue events to a Node-RED flow. The scene field supports autocomplete; use the refresh icon after adding scenes on the bridge so the list stays up to date.
|
|
1630
|
-
|
|
1631
|
-
##### Tabs at a glance
|
|
1632
|
-
|
|
1633
|
-
- **Mapping** - link KNX group addresses to the selected Hue scene. DPT 1.xxx performs boolean recall, while DPT 18.xxx sends a KNX scene number.
|
|
1634
|
-
- **Multi scene** - build a rule list that associates KNX scene numbers with different Hue scenes and chooses whether each scene is recalled as _active_, _dynamic\_palette_ or _static_.
|
|
1635
|
-
- **Behaviour** - toggle the Node-RED output pin. When no KNX gateway is configured the pin remains enabled so bridge events still reach the flow.
|
|
1636
|
-
|
|
1637
|
-
##### General settings
|
|
1638
|
-
|
|
1639
|
-
|Property|Description|
|
|
1640
|
-
|--|--|
|
|
1641
|
-
| KNX GW | KNX gateway supplying the address catalogue used for autocomplete. |
|
|
1642
|
-
| Hue Bridge | Hue Bridge that hosts the scenes. |
|
|
1643
|
-
| Hue Scene | Scene to recall (autocomplete; refresh button reloads the bridge catalogue). |
|
|
1644
|
-
|
|
1645
|
-
##### Mapping tab
|
|
1646
|
-
|
|
1647
|
-
|Property|Description|
|
|
1648
|
-
|--|--|
|
|
1649
|
-
| Recall | KNX group address that recalls the scene. Use DPT 1.xxx for boolean control or DPT 18.xxx to transmit a KNX scene number. |
|
|
1650
|
-
| DPT | Datapoint used with the recall GA (1.xxx or 18.001). |
|
|
1651
|
-
| Name | Friendly label for the recall GA. |
|
|
1652
|
-
| # | Appears when a KNX scene DPT is chosen; select the KNX scene number to send. |
|
|
1653
|
-
| Status GA | Optional boolean GA that mirrors whether the scene is currently active. |
|
|
1654
|
-
|
|
1655
|
-
##### Multi scene tab
|
|
1656
|
-
|
|
1657
|
-
|Property|Description|
|
|
1658
|
-
|--|--|
|
|
1659
|
-
| Recall | KNX GA (DPT 18.001) that selects scenes by number. |
|
|
1660
|
-
| Scene selector | Editable list that maps KNX scene numbers to Hue scenes with the desired recall mode. Drag handles reorder entries. |
|
|
1661
|
-
|
|
1662
|
-
> ℹ️ KNX-specific widgets only appear after a KNX gateway is selected. The Mapping tabs remain hidden until both the bridge and the gateway are configured.
|
|
1663
|
-
|
|
1664
|
-
---
|
|
1665
|
-
|
|
1666
|
-
<span id="hue-controller-help-device_power" data-hue-controller-type="device_power"></span>
|
|
1667
|
-
|
|
1668
|
-
## Battery (`device_power`)
|
|
1669
|
-
|
|
1670
|
-
<p>This node exposes the battery level of a Hue device to KNX and raises an event whenever the value changes.</p>
|
|
1671
|
-
|
|
1672
|
-
Start typing the KNX device name or Group Address in the GA field; matching entries appear while you type. Use the refresh icon next to <q>Hue sensor</q> to reload the list from the Hue bridge after adding new devices.
|
|
1673
|
-
|
|
1674
|
-
**General**
|
|
1675
|
-
|
|
1676
|
-
|Property|Description|
|
|
1677
|
-
|--|--|
|
|
1678
|
-
| KNX GW | KNX gateway used to publish the battery level (required before KNX mapping fields appear). |
|
|
1679
|
-
| Hue Bridge | Hue Bridge that hosts the device. |
|
|
1680
|
-
| Hue battery sensor | Hue device/sensor providing the battery level (supports autocomplete and refresh). |
|
|
1681
|
-
|
|
1682
|
-
**Mapping**
|
|
1683
|
-
|
|
1684
|
-
|Property|Description|
|
|
1685
|
-
|--|--|
|
|
1686
|
-
| Level | KNX GA for the battery percentage (0-100%). Recommended DPT: <b>5.001</b>. |
|
|
1687
|
-
|
|
1688
|
-
**Behaviour**
|
|
1689
|
-
|
|
1690
|
-
|Property|Description|
|
|
1691
|
-
|--|--|
|
|
1692
|
-
| Read status at startup | On deploy/reconnect read the current battery value and publish it to KNX. Default: "yes”. |
|
|
1693
|
-
| Node output pin | Show or hide the Node-RED output. When no KNX gateway is selected the output stays enabled so Hue events continue to reach the flow. |
|
|
1694
|
-
|
|
1695
|
-
> ℹ️ KNX mapping widgets remain hidden until a KNX gateway is selected. This keeps the editor tidy when the node is used only to forward Hue events into Node-RED.
|
|
1696
|
-
|
|
1697
|
-
---
|
|
1698
|
-
|
|
1699
|
-
<span id="hue-controller-help-zigbee_connectivity" data-hue-controller-type="zigbee_connectivity"></span>
|
|
1700
|
-
|
|
1701
|
-
## Zigbee connectivity (`zigbee_connectivity`)
|
|
1702
|
-
|
|
1703
|
-
<p>This node retrieves the Zigbee connectivity status from a Hue device and exposes it to KNX.</p>
|
|
1704
|
-
|
|
1705
|
-
Start typing the KNX device name or Group Address in the GA field; suggestions appear while you type.
|
|
1706
|
-
|
|
1707
|
-
**General**
|
|
1708
|
-
|
|
1709
|
-
|Property|Description|
|
|
1710
|
-
|--|--|
|
|
1711
|
-
| KNX GW | KNX gateway used to publish the status. |
|
|
1712
|
-
| Hue Bridge | Hue Bridge to query. |
|
|
1713
|
-
| Hue zigbee connectivity | Hue sensor/device providing the Zigbee connectivity info. Autocomplete while typing. |
|
|
1714
|
-
|
|
1715
|
-
**Mapping**
|
|
1716
|
-
|
|
1717
|
-
|Property|Description|
|
|
1718
|
-
|--|--|
|
|
1719
|
-
| Status | KNX Group Address that reflects Zigbee connectivity. Becomes _true_ when connected, otherwise _false_. |
|
|
1720
|
-
| Read status at startup | Reads current status at editor start/reconnection and emits to KNX. Default: "yes”. |
|
|
1721
|
-
|
|
1722
|
-
##### Outputs
|
|
1723
|
-
|
|
1724
|
-
1. Standard output
|
|
1725
|
-
: payload (boolean): connectivity state.
|
|
1726
|
-
|
|
1727
|
-
##### Details
|
|
1728
|
-
|
|
1729
|
-
`msg.payload` carries the boolean state (true/false).\
|
|
1730
|
-
`msg.status` contains a textual status: one of **connected, disconnected, connectivity\_issue, unidirectional\_incoming** .
|
|
1731
|
-
|
|
1732
|
-
---
|
|
1733
|
-
|
|
1734
|
-
<span id="hue-controller-help-device_software_update" data-hue-controller-type="device_software_update"></span>
|
|
1735
|
-
|
|
1736
|
-
## Device software update (`device_software_update`)
|
|
1737
|
-
|
|
1738
|
-
<p>This node monitors whether a selected Hue device has a software update available and publishes the status to KNX.</p>
|
|
1739
|
-
|
|
1740
|
-
Start typing the name or group address of your KNX device in the GA field, the avaiable devices start showing up while
|
|
1741
|
-
you're typing.
|
|
1742
|
-
|
|
1743
|
-
**General**
|
|
1744
|
-
|
|
1745
|
-
|Property|Description|
|
|
1746
|
-
|--|--|
|
|
1747
|
-
| KNX GW | Select the KNX gateway to be used |
|
|
1748
|
-
| Hue Bridge | Select the Hue Bridge to be used |
|
|
1749
|
-
| Hue device | Hue device to monitor for software updates (autocomplete while typing).|
|
|
1750
|
-
|
|
1751
|
-
**Mapping**
|
|
1752
|
-
|
|
1753
|
-
| Property | Description |
|
|
1754
|
-
|--|--|
|
|
1755
|
-
| Status | KNX GA reflecting update status. _true_ if an update is available/ready/being installed, otherwise _false_. |
|
|
1756
|
-
| Read status at startup | Read current status at startup/reconnection and emit to KNX (default "yes”). |
|
|
1757
|
-
|
|
1758
|
-
##### Outputs
|
|
1759
|
-
|
|
1760
|
-
1. Standard output
|
|
1761
|
-
: payload (boolean): update flag.
|
|
1762
|
-
: status (string): one of **no\_update, update\_pending, ready\_to\_install, installing** .
|
|
1763
|
-
|
|
1764
|
-
<!-- HUE_CONTROLLER_PROFILE_HELP_END -->
|
|
1765
|
-
</script>
|