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.
Files changed (657) hide show
  1. package/CHANGELOG.md +20 -10
  2. package/MIGRATION.md +40 -0
  3. package/README.md +32 -6
  4. package/docs/README.md +34 -0
  5. package/docs/assets/brand/made-in-italy.svg +12 -0
  6. package/examples/Alerter - Device Alert Aggregation.json +5 -2
  7. package/examples/Auto Responder - Read Request Defaults.json +5 -2
  8. package/examples/Garage - Door Controller.json +5 -2
  9. package/examples/Global Context - Expose KNX Values.json +5 -2
  10. package/examples/KNX DateTime - Set Date and Time to Bus.json +111 -89
  11. package/examples/Load Control - Manual Shedding Mode.json +5 -2
  12. package/examples/Logger ETS File and Telegram Count.json +10 -2
  13. package/examples/Scene Controller Recall and Save.json +33 -6
  14. package/examples/Staircase - Timer, Override and Block.json +5 -2
  15. package/examples/WatchDog Connect Disconnect.json +98 -70
  16. package/nodes/commonFunctions.js +0 -587
  17. package/nodes/knxUltimate-config.html +0 -14
  18. package/nodes/knxUltimate-config.js +1 -18
  19. package/nodes/knxUltimate.html +1 -6
  20. package/nodes/knxUltimateIoTBridge.html +0 -14
  21. package/nodes/knxUltimateLegacyMigration.js +75 -0
  22. package/nodes/knxUltimateMultiRouting.html +1 -7
  23. package/nodes/knxUltimateRouterFilter.html +1 -7
  24. package/nodes/knxUltimateUtility.html +0 -6
  25. package/nodes/knxUltimateViewer.html +0 -6
  26. package/nodes/locales/de/knxUltimate-config.html +0 -8
  27. package/nodes/locales/de/knxUltimate.html +0 -8
  28. package/nodes/locales/de/knxUltimateIoTBridge.html +0 -8
  29. package/nodes/locales/de/knxUltimateMultiRouting.html +0 -8
  30. package/nodes/locales/de/knxUltimateRouterFilter.html +0 -8
  31. package/nodes/locales/de/knxUltimateUtility.html +0 -8
  32. package/nodes/locales/de/knxUltimateUtility.json +16 -1
  33. package/nodes/locales/de/knxUltimateViewer.html +0 -8
  34. package/nodes/locales/en/knxUltimate-config.html +0 -8
  35. package/nodes/locales/en/knxUltimate.html +0 -8
  36. package/nodes/locales/en/knxUltimateIoTBridge.html +0 -8
  37. package/nodes/locales/en/knxUltimateMultiRouting.html +0 -8
  38. package/nodes/locales/en/knxUltimateRouterFilter.html +0 -8
  39. package/nodes/locales/en/knxUltimateUtility.html +0 -8
  40. package/nodes/locales/en/knxUltimateUtility.json +16 -1
  41. package/nodes/locales/en/knxUltimateViewer.html +0 -8
  42. package/nodes/locales/es/knxUltimate-config.html +0 -8
  43. package/nodes/locales/es/knxUltimate.html +0 -8
  44. package/nodes/locales/es/knxUltimateIoTBridge.html +0 -8
  45. package/nodes/locales/es/knxUltimateMultiRouting.html +0 -8
  46. package/nodes/locales/es/knxUltimateRouterFilter.html +0 -8
  47. package/nodes/locales/es/knxUltimateUtility.html +0 -8
  48. package/nodes/locales/es/knxUltimateUtility.json +17 -2
  49. package/nodes/locales/es/knxUltimateViewer.html +0 -8
  50. package/nodes/locales/fr/knxUltimate-config.html +0 -8
  51. package/nodes/locales/fr/knxUltimate.html +0 -8
  52. package/nodes/locales/fr/knxUltimateIoTBridge.html +0 -8
  53. package/nodes/locales/fr/knxUltimateMultiRouting.html +0 -8
  54. package/nodes/locales/fr/knxUltimateRouterFilter.html +0 -8
  55. package/nodes/locales/fr/knxUltimateUtility.html +0 -8
  56. package/nodes/locales/fr/knxUltimateUtility.json +16 -1
  57. package/nodes/locales/fr/knxUltimateViewer.html +0 -8
  58. package/nodes/locales/it/knxUltimate-config.html +0 -8
  59. package/nodes/locales/it/knxUltimate.html +0 -8
  60. package/nodes/locales/it/knxUltimateIoTBridge.html +0 -8
  61. package/nodes/locales/it/knxUltimateMultiRouting.html +0 -8
  62. package/nodes/locales/it/knxUltimateRouterFilter.html +0 -8
  63. package/nodes/locales/it/knxUltimateUtility.html +0 -8
  64. package/nodes/locales/it/knxUltimateUtility.json +16 -1
  65. package/nodes/locales/it/knxUltimateViewer.html +0 -8
  66. package/nodes/locales/zh-CN/knxUltimate-config.html +0 -8
  67. package/nodes/locales/zh-CN/knxUltimate.html +0 -8
  68. package/nodes/locales/zh-CN/knxUltimateIoTBridge.html +0 -8
  69. package/nodes/locales/zh-CN/knxUltimateMultiRouting.html +0 -8
  70. package/nodes/locales/zh-CN/knxUltimateRouterFilter.html +0 -8
  71. package/nodes/locales/zh-CN/knxUltimateUtility.html +0 -8
  72. package/nodes/locales/zh-CN/knxUltimateUtility.json +16 -1
  73. package/nodes/locales/zh-CN/knxUltimateViewer.html +0 -8
  74. package/nodes/plugins/knxUltimate-v8-migration-recovery-plugin.html +140 -0
  75. package/package.json +22 -69
  76. package/resources/11f26b4500.js +2 -2
  77. package/resources/KNXAIChatAdapterMappings.js +2 -416
  78. package/resources/configNodeEditorSelection.js +2 -32
  79. package/resources/hueControllerEditorSelection.js +2 -32
  80. package/resources/hueControllerMigrationDialog.js +2 -254
  81. package/resources/hueControllerProfiles.js +2 -9319
  82. package/resources/knxUtilityProfiles.js +2041 -2082
  83. package/resources/legacyMigrationNotice.js +23 -111
  84. package/resources/matterQrScanner.js +2 -98
  85. package/resources/upgradeToV8.js +94 -26
  86. package/scripts/check-legacy-flows.js +142 -0
  87. package/examples/Hue Area Motion - Zone Presence.json +0 -77
  88. package/examples/Hue Battery - Level Status.json +0 -77
  89. package/examples/Hue Button - Short and Dim Commands.json +0 -83
  90. package/examples/Hue Camera Motion - Presence.json +0 -77
  91. package/examples/Hue Config - Bridge Template.json +0 -27
  92. package/examples/Hue Contact Sensor - Open Closed.json +0 -75
  93. package/examples/Hue Device Software Update - Availability.json +0 -77
  94. package/examples/Hue Humidity Sensor - Relative Humidity.json +0 -77
  95. package/examples/Hue Light - Switch and Brightness.json +0 -67
  96. package/examples/Hue Light Sensor - Lux to KNX.json +0 -77
  97. package/examples/Hue Motion - Presence Sensor.json +0 -76
  98. package/examples/Hue Plug - Switch and State.json +0 -63
  99. package/examples/Hue Scene - Recall from KNX.json +0 -63
  100. package/examples/Hue Tap Dial - Relative Dimming.json +0 -76
  101. package/examples/Hue Temperature Sensor - Celsius to KNX.json +0 -77
  102. package/examples/Hue Zigbee Connectivity - Online Status.json +0 -77
  103. package/examples/Matter Controller - Semantic Flow Input.json +0 -248
  104. package/nodes/hue-config.html +0 -378
  105. package/nodes/hue-config.js +0 -846
  106. package/nodes/icons/node-alerter-icon.png +0 -0
  107. package/nodes/icons/node-homekit-icon.png +0 -0
  108. package/nodes/icons/node-homekit-icon.svg +0 -10
  109. package/nodes/icons/node-hue-icon.svg +0 -10
  110. package/nodes/icons/node-knx-icon.png +0 -0
  111. package/nodes/icons/node-logger-icon.png +0 -0
  112. package/nodes/icons/node-logger2-icon.png +0 -0
  113. package/nodes/icons/node-logger2-icon.svg +0 -32
  114. package/nodes/icons/node-matter-bridge-icon.svg +0 -6
  115. package/nodes/icons/node-matter-controller-icon.svg +0 -6
  116. package/nodes/icons/node-matter-icon.svg +0 -12
  117. package/nodes/icons/node-scene-icon.png +0 -0
  118. package/nodes/icons/node-watchdog-icon.png +0 -0
  119. package/nodes/knxUltimateAI.html +0 -1826
  120. package/nodes/knxUltimateAI.js +0 -16797
  121. package/nodes/knxUltimateAIHomeAssistant.html +0 -54
  122. package/nodes/knxUltimateAIHomeAssistant.js +0 -152
  123. package/nodes/knxUltimateAlerter.html +0 -267
  124. package/nodes/knxUltimateAlerter.js +0 -300
  125. package/nodes/knxUltimateAutoResponder.html +0 -128
  126. package/nodes/knxUltimateAutoResponder.js +0 -264
  127. package/nodes/knxUltimateDateTime.html +0 -579
  128. package/nodes/knxUltimateDateTime.js +0 -282
  129. package/nodes/knxUltimateGarage.html +0 -337
  130. package/nodes/knxUltimateGarage.js +0 -504
  131. package/nodes/knxUltimateGlobalContext.html +0 -145
  132. package/nodes/knxUltimateGlobalContext.js +0 -208
  133. package/nodes/knxUltimateHATranslator.html +0 -85
  134. package/nodes/knxUltimateHATranslator.js +0 -83
  135. package/nodes/knxUltimateHueAreaMotion.html +0 -670
  136. package/nodes/knxUltimateHueAreaMotion.js +0 -218
  137. package/nodes/knxUltimateHueBattery.html +0 -646
  138. package/nodes/knxUltimateHueBattery.js +0 -182
  139. package/nodes/knxUltimateHueButton.html +0 -804
  140. package/nodes/knxUltimateHueButton.js +0 -292
  141. package/nodes/knxUltimateHueCameraMotion.html +0 -671
  142. package/nodes/knxUltimateHueCameraMotion.js +0 -218
  143. package/nodes/knxUltimateHueContactSensor.html +0 -609
  144. package/nodes/knxUltimateHueContactSensor.js +0 -188
  145. package/nodes/knxUltimateHueController.html +0 -1765
  146. package/nodes/knxUltimateHueController.js +0 -28
  147. package/nodes/knxUltimateHueHumiditySensor.html +0 -641
  148. package/nodes/knxUltimateHueHumiditySensor.js +0 -201
  149. package/nodes/knxUltimateHueLight.html +0 -2516
  150. package/nodes/knxUltimateHueLight.js +0 -1582
  151. package/nodes/knxUltimateHueLightSensor.html +0 -636
  152. package/nodes/knxUltimateHueLightSensor.js +0 -177
  153. package/nodes/knxUltimateHueMotion.html +0 -634
  154. package/nodes/knxUltimateHueMotion.js +0 -182
  155. package/nodes/knxUltimateHuePlug.html +0 -576
  156. package/nodes/knxUltimateHuePlug.js +0 -341
  157. package/nodes/knxUltimateHueScene.html +0 -967
  158. package/nodes/knxUltimateHueScene.js +0 -349
  159. package/nodes/knxUltimateHueTapDial.html +0 -640
  160. package/nodes/knxUltimateHueTapDial.js +0 -268
  161. package/nodes/knxUltimateHueTemperatureSensor.html +0 -639
  162. package/nodes/knxUltimateHueTemperatureSensor.js +0 -184
  163. package/nodes/knxUltimateHueZigbeeConnectivity.html +0 -648
  164. package/nodes/knxUltimateHueZigbeeConnectivity.js +0 -182
  165. package/nodes/knxUltimateHuedevice_software_update.html +0 -650
  166. package/nodes/knxUltimateHuedevice_software_update.js +0 -182
  167. package/nodes/knxUltimateLoadControl.html +0 -425
  168. package/nodes/knxUltimateLoadControl.js +0 -443
  169. package/nodes/knxUltimateLogger.html +0 -197
  170. package/nodes/knxUltimateLogger.js +0 -224
  171. package/nodes/knxUltimateMatterBridge.html +0 -689
  172. package/nodes/knxUltimateMatterBridge.js +0 -464
  173. package/nodes/knxUltimateMatterControllerDevice.html +0 -2851
  174. package/nodes/knxUltimateMatterControllerDevice.js +0 -1747
  175. package/nodes/knxUltimateSceneController.html +0 -529
  176. package/nodes/knxUltimateSceneController.js +0 -437
  177. package/nodes/knxUltimateStaircase.html +0 -346
  178. package/nodes/knxUltimateStaircase.js +0 -463
  179. package/nodes/knxUltimateWatchDog.html +0 -241
  180. package/nodes/knxUltimateWatchDog.js +0 -230
  181. package/nodes/locales/de/hue-config.html +0 -33
  182. package/nodes/locales/de/hue-config.json +0 -21
  183. package/nodes/locales/de/knxUltimateAI.html +0 -13
  184. package/nodes/locales/de/knxUltimateAI.json +0 -231
  185. package/nodes/locales/de/knxUltimateAIHomeAssistant.html +0 -11
  186. package/nodes/locales/de/knxUltimateAlerter.html +0 -159
  187. package/nodes/locales/de/knxUltimateAlerter.json +0 -27
  188. package/nodes/locales/de/knxUltimateAutoResponder.html +0 -96
  189. package/nodes/locales/de/knxUltimateAutoResponder.json +0 -8
  190. package/nodes/locales/de/knxUltimateDateTime.html +0 -45
  191. package/nodes/locales/de/knxUltimateDateTime.json +0 -32
  192. package/nodes/locales/de/knxUltimateGarage.html +0 -79
  193. package/nodes/locales/de/knxUltimateGarage.json +0 -51
  194. package/nodes/locales/de/knxUltimateGlobalContext.html +0 -76
  195. package/nodes/locales/de/knxUltimateGlobalContext.json +0 -24
  196. package/nodes/locales/de/knxUltimateHATranslator.html +0 -25
  197. package/nodes/locales/de/knxUltimateHATranslator.json +0 -8
  198. package/nodes/locales/de/knxUltimateHueAreaMotion.html +0 -44
  199. package/nodes/locales/de/knxUltimateHueAreaMotion.json +0 -31
  200. package/nodes/locales/de/knxUltimateHueBattery.html +0 -37
  201. package/nodes/locales/de/knxUltimateHueBattery.json +0 -30
  202. package/nodes/locales/de/knxUltimateHueButton.html +0 -52
  203. package/nodes/locales/de/knxUltimateHueButton.json +0 -34
  204. package/nodes/locales/de/knxUltimateHueCameraMotion.html +0 -38
  205. package/nodes/locales/de/knxUltimateHueCameraMotion.json +0 -30
  206. package/nodes/locales/de/knxUltimateHueContactSensor.html +0 -35
  207. package/nodes/locales/de/knxUltimateHueContactSensor.json +0 -26
  208. package/nodes/locales/de/knxUltimateHueController.html +0 -690
  209. package/nodes/locales/de/knxUltimateHueController.json +0 -64
  210. package/nodes/locales/de/knxUltimateHueHumiditySensor.html +0 -38
  211. package/nodes/locales/de/knxUltimateHueHumiditySensor.json +0 -30
  212. package/nodes/locales/de/knxUltimateHueLight.html +0 -121
  213. package/nodes/locales/de/knxUltimateHueLight.json +0 -94
  214. package/nodes/locales/de/knxUltimateHueLightSensor.html +0 -38
  215. package/nodes/locales/de/knxUltimateHueLightSensor.json +0 -19
  216. package/nodes/locales/de/knxUltimateHueMotion.html +0 -41
  217. package/nodes/locales/de/knxUltimateHueMotion.json +0 -27
  218. package/nodes/locales/de/knxUltimateHuePlug.html +0 -50
  219. package/nodes/locales/de/knxUltimateHuePlug.json +0 -33
  220. package/nodes/locales/de/knxUltimateHueScene.html +0 -45
  221. package/nodes/locales/de/knxUltimateHueScene.json +0 -41
  222. package/nodes/locales/de/knxUltimateHueTapDial.html +0 -40
  223. package/nodes/locales/de/knxUltimateHueTapDial.json +0 -28
  224. package/nodes/locales/de/knxUltimateHueTemperatureSensor.html +0 -38
  225. package/nodes/locales/de/knxUltimateHueTemperatureSensor.json +0 -30
  226. package/nodes/locales/de/knxUltimateHueZigbeeConnectivity.html +0 -39
  227. package/nodes/locales/de/knxUltimateHueZigbeeConnectivity.json +0 -30
  228. package/nodes/locales/de/knxUltimateHuedevice_software_update.html +0 -36
  229. package/nodes/locales/de/knxUltimateHuedevice_software_update.json +0 -30
  230. package/nodes/locales/de/knxUltimateLoadControl.html +0 -69
  231. package/nodes/locales/de/knxUltimateLoadControl.json +0 -28
  232. package/nodes/locales/de/knxUltimateLogger.html +0 -126
  233. package/nodes/locales/de/knxUltimateLogger.json +0 -31
  234. package/nodes/locales/de/knxUltimateMatterBridge.html +0 -65
  235. package/nodes/locales/de/knxUltimateMatterBridge.json +0 -123
  236. package/nodes/locales/de/knxUltimateMatterControllerDevice.html +0 -57
  237. package/nodes/locales/de/knxUltimateMatterControllerDevice.json +0 -146
  238. package/nodes/locales/de/knxUltimateSceneController.html +0 -98
  239. package/nodes/locales/de/knxUltimateSceneController.json +0 -32
  240. package/nodes/locales/de/knxUltimateStaircase.html +0 -77
  241. package/nodes/locales/de/knxUltimateStaircase.json +0 -62
  242. package/nodes/locales/de/knxUltimateWatchDog.html +0 -178
  243. package/nodes/locales/de/knxUltimateWatchDog.json +0 -27
  244. package/nodes/locales/de/matter-config.html +0 -47
  245. package/nodes/locales/de/matter-config.json +0 -47
  246. package/nodes/locales/de/matterbridge-config.html +0 -45
  247. package/nodes/locales/de/matterbridge-config.json +0 -25
  248. package/nodes/locales/en/hue-config.html +0 -31
  249. package/nodes/locales/en/hue-config.json +0 -21
  250. package/nodes/locales/en/knxUltimateAI.html +0 -13
  251. package/nodes/locales/en/knxUltimateAI.json +0 -234
  252. package/nodes/locales/en/knxUltimateAIHomeAssistant.html +0 -11
  253. package/nodes/locales/en/knxUltimateAlerter.html +0 -164
  254. package/nodes/locales/en/knxUltimateAlerter.json +0 -27
  255. package/nodes/locales/en/knxUltimateAutoResponder.html +0 -94
  256. package/nodes/locales/en/knxUltimateAutoResponder.json +0 -8
  257. package/nodes/locales/en/knxUltimateDateTime.html +0 -67
  258. package/nodes/locales/en/knxUltimateDateTime.json +0 -32
  259. package/nodes/locales/en/knxUltimateGarage.html +0 -79
  260. package/nodes/locales/en/knxUltimateGarage.json +0 -51
  261. package/nodes/locales/en/knxUltimateGlobalContext.html +0 -124
  262. package/nodes/locales/en/knxUltimateGlobalContext.json +0 -24
  263. package/nodes/locales/en/knxUltimateHATranslator.html +0 -25
  264. package/nodes/locales/en/knxUltimateHATranslator.json +0 -8
  265. package/nodes/locales/en/knxUltimateHueAreaMotion.html +0 -44
  266. package/nodes/locales/en/knxUltimateHueAreaMotion.json +0 -31
  267. package/nodes/locales/en/knxUltimateHueBattery.html +0 -37
  268. package/nodes/locales/en/knxUltimateHueBattery.json +0 -30
  269. package/nodes/locales/en/knxUltimateHueButton.html +0 -52
  270. package/nodes/locales/en/knxUltimateHueButton.json +0 -34
  271. package/nodes/locales/en/knxUltimateHueCameraMotion.html +0 -38
  272. package/nodes/locales/en/knxUltimateHueCameraMotion.json +0 -30
  273. package/nodes/locales/en/knxUltimateHueContactSensor.html +0 -35
  274. package/nodes/locales/en/knxUltimateHueContactSensor.json +0 -26
  275. package/nodes/locales/en/knxUltimateHueController.html +0 -691
  276. package/nodes/locales/en/knxUltimateHueController.json +0 -64
  277. package/nodes/locales/en/knxUltimateHueHumiditySensor.html +0 -38
  278. package/nodes/locales/en/knxUltimateHueHumiditySensor.json +0 -30
  279. package/nodes/locales/en/knxUltimateHueLight.html +0 -124
  280. package/nodes/locales/en/knxUltimateHueLight.json +0 -94
  281. package/nodes/locales/en/knxUltimateHueLightSensor.html +0 -38
  282. package/nodes/locales/en/knxUltimateHueLightSensor.json +0 -19
  283. package/nodes/locales/en/knxUltimateHueMotion.html +0 -41
  284. package/nodes/locales/en/knxUltimateHueMotion.json +0 -27
  285. package/nodes/locales/en/knxUltimateHuePlug.html +0 -50
  286. package/nodes/locales/en/knxUltimateHuePlug.json +0 -33
  287. package/nodes/locales/en/knxUltimateHueScene.html +0 -45
  288. package/nodes/locales/en/knxUltimateHueScene.json +0 -41
  289. package/nodes/locales/en/knxUltimateHueTapDial.html +0 -40
  290. package/nodes/locales/en/knxUltimateHueTapDial.json +0 -28
  291. package/nodes/locales/en/knxUltimateHueTemperatureSensor.html +0 -38
  292. package/nodes/locales/en/knxUltimateHueTemperatureSensor.json +0 -30
  293. package/nodes/locales/en/knxUltimateHueZigbeeConnectivity.html +0 -39
  294. package/nodes/locales/en/knxUltimateHueZigbeeConnectivity.json +0 -30
  295. package/nodes/locales/en/knxUltimateHuedevice_software_update.html +0 -36
  296. package/nodes/locales/en/knxUltimateHuedevice_software_update.json +0 -30
  297. package/nodes/locales/en/knxUltimateLoadControl.html +0 -76
  298. package/nodes/locales/en/knxUltimateLoadControl.json +0 -28
  299. package/nodes/locales/en/knxUltimateLogger.html +0 -161
  300. package/nodes/locales/en/knxUltimateLogger.json +0 -31
  301. package/nodes/locales/en/knxUltimateMatterBridge.html +0 -65
  302. package/nodes/locales/en/knxUltimateMatterBridge.json +0 -123
  303. package/nodes/locales/en/knxUltimateMatterControllerDevice.html +0 -57
  304. package/nodes/locales/en/knxUltimateMatterControllerDevice.json +0 -146
  305. package/nodes/locales/en/knxUltimateSceneController.html +0 -117
  306. package/nodes/locales/en/knxUltimateSceneController.json +0 -32
  307. package/nodes/locales/en/knxUltimateStaircase.html +0 -77
  308. package/nodes/locales/en/knxUltimateStaircase.json +0 -62
  309. package/nodes/locales/en/knxUltimateWatchDog.html +0 -244
  310. package/nodes/locales/en/knxUltimateWatchDog.json +0 -27
  311. package/nodes/locales/en/matter-config.html +0 -47
  312. package/nodes/locales/en/matter-config.json +0 -48
  313. package/nodes/locales/en/matterbridge-config.html +0 -45
  314. package/nodes/locales/en/matterbridge-config.json +0 -25
  315. package/nodes/locales/es/hue-config.html +0 -31
  316. package/nodes/locales/es/hue-config.json +0 -21
  317. package/nodes/locales/es/knxUltimateAI.html +0 -13
  318. package/nodes/locales/es/knxUltimateAI.json +0 -231
  319. package/nodes/locales/es/knxUltimateAIHomeAssistant.html +0 -11
  320. package/nodes/locales/es/knxUltimateAlerter.html +0 -164
  321. package/nodes/locales/es/knxUltimateAlerter.json +0 -27
  322. package/nodes/locales/es/knxUltimateAutoResponder.html +0 -81
  323. package/nodes/locales/es/knxUltimateAutoResponder.json +0 -8
  324. package/nodes/locales/es/knxUltimateDateTime.html +0 -45
  325. package/nodes/locales/es/knxUltimateDateTime.json +0 -32
  326. package/nodes/locales/es/knxUltimateGarage.html +0 -79
  327. package/nodes/locales/es/knxUltimateGarage.json +0 -51
  328. package/nodes/locales/es/knxUltimateGlobalContext.html +0 -128
  329. package/nodes/locales/es/knxUltimateGlobalContext.json +0 -24
  330. package/nodes/locales/es/knxUltimateHATranslator.html +0 -25
  331. package/nodes/locales/es/knxUltimateHATranslator.json +0 -8
  332. package/nodes/locales/es/knxUltimateHueAreaMotion.html +0 -44
  333. package/nodes/locales/es/knxUltimateHueAreaMotion.json +0 -31
  334. package/nodes/locales/es/knxUltimateHueBattery.html +0 -37
  335. package/nodes/locales/es/knxUltimateHueBattery.json +0 -30
  336. package/nodes/locales/es/knxUltimateHueButton.html +0 -52
  337. package/nodes/locales/es/knxUltimateHueButton.json +0 -34
  338. package/nodes/locales/es/knxUltimateHueCameraMotion.html +0 -38
  339. package/nodes/locales/es/knxUltimateHueCameraMotion.json +0 -30
  340. package/nodes/locales/es/knxUltimateHueContactSensor.html +0 -35
  341. package/nodes/locales/es/knxUltimateHueContactSensor.json +0 -26
  342. package/nodes/locales/es/knxUltimateHueController.html +0 -691
  343. package/nodes/locales/es/knxUltimateHueController.json +0 -64
  344. package/nodes/locales/es/knxUltimateHueHumiditySensor.html +0 -38
  345. package/nodes/locales/es/knxUltimateHueHumiditySensor.json +0 -30
  346. package/nodes/locales/es/knxUltimateHueLight.html +0 -124
  347. package/nodes/locales/es/knxUltimateHueLight.json +0 -94
  348. package/nodes/locales/es/knxUltimateHueLightSensor.html +0 -38
  349. package/nodes/locales/es/knxUltimateHueLightSensor.json +0 -19
  350. package/nodes/locales/es/knxUltimateHueMotion.html +0 -41
  351. package/nodes/locales/es/knxUltimateHueMotion.json +0 -27
  352. package/nodes/locales/es/knxUltimateHuePlug.html +0 -50
  353. package/nodes/locales/es/knxUltimateHuePlug.json +0 -33
  354. package/nodes/locales/es/knxUltimateHueScene.html +0 -45
  355. package/nodes/locales/es/knxUltimateHueScene.json +0 -41
  356. package/nodes/locales/es/knxUltimateHueTapDial.html +0 -40
  357. package/nodes/locales/es/knxUltimateHueTapDial.json +0 -28
  358. package/nodes/locales/es/knxUltimateHueTemperatureSensor.html +0 -38
  359. package/nodes/locales/es/knxUltimateHueTemperatureSensor.json +0 -30
  360. package/nodes/locales/es/knxUltimateHueZigbeeConnectivity.html +0 -39
  361. package/nodes/locales/es/knxUltimateHueZigbeeConnectivity.json +0 -30
  362. package/nodes/locales/es/knxUltimateHuedevice_software_update.html +0 -36
  363. package/nodes/locales/es/knxUltimateHuedevice_software_update.json +0 -30
  364. package/nodes/locales/es/knxUltimateLoadControl.html +0 -76
  365. package/nodes/locales/es/knxUltimateLoadControl.json +0 -28
  366. package/nodes/locales/es/knxUltimateLogger.html +0 -162
  367. package/nodes/locales/es/knxUltimateLogger.json +0 -31
  368. package/nodes/locales/es/knxUltimateMatterBridge.html +0 -65
  369. package/nodes/locales/es/knxUltimateMatterBridge.json +0 -123
  370. package/nodes/locales/es/knxUltimateMatterControllerDevice.html +0 -57
  371. package/nodes/locales/es/knxUltimateMatterControllerDevice.json +0 -146
  372. package/nodes/locales/es/knxUltimateSceneController.html +0 -115
  373. package/nodes/locales/es/knxUltimateSceneController.json +0 -32
  374. package/nodes/locales/es/knxUltimateStaircase.html +0 -77
  375. package/nodes/locales/es/knxUltimateStaircase.json +0 -62
  376. package/nodes/locales/es/knxUltimateWatchDog.html +0 -230
  377. package/nodes/locales/es/knxUltimateWatchDog.json +0 -27
  378. package/nodes/locales/es/matter-config.html +0 -47
  379. package/nodes/locales/es/matter-config.json +0 -47
  380. package/nodes/locales/es/matterbridge-config.html +0 -45
  381. package/nodes/locales/es/matterbridge-config.json +0 -25
  382. package/nodes/locales/fr/hue-config.html +0 -31
  383. package/nodes/locales/fr/hue-config.json +0 -21
  384. package/nodes/locales/fr/knxUltimateAI.html +0 -13
  385. package/nodes/locales/fr/knxUltimateAI.json +0 -231
  386. package/nodes/locales/fr/knxUltimateAIHomeAssistant.html +0 -11
  387. package/nodes/locales/fr/knxUltimateAlerter.html +0 -164
  388. package/nodes/locales/fr/knxUltimateAlerter.json +0 -27
  389. package/nodes/locales/fr/knxUltimateAutoResponder.html +0 -92
  390. package/nodes/locales/fr/knxUltimateAutoResponder.json +0 -8
  391. package/nodes/locales/fr/knxUltimateDateTime.html +0 -45
  392. package/nodes/locales/fr/knxUltimateDateTime.json +0 -32
  393. package/nodes/locales/fr/knxUltimateGarage.html +0 -79
  394. package/nodes/locales/fr/knxUltimateGarage.json +0 -51
  395. package/nodes/locales/fr/knxUltimateGlobalContext.html +0 -122
  396. package/nodes/locales/fr/knxUltimateGlobalContext.json +0 -24
  397. package/nodes/locales/fr/knxUltimateHATranslator.html +0 -25
  398. package/nodes/locales/fr/knxUltimateHATranslator.json +0 -8
  399. package/nodes/locales/fr/knxUltimateHueAreaMotion.html +0 -44
  400. package/nodes/locales/fr/knxUltimateHueAreaMotion.json +0 -31
  401. package/nodes/locales/fr/knxUltimateHueBattery.html +0 -37
  402. package/nodes/locales/fr/knxUltimateHueBattery.json +0 -30
  403. package/nodes/locales/fr/knxUltimateHueButton.html +0 -52
  404. package/nodes/locales/fr/knxUltimateHueButton.json +0 -34
  405. package/nodes/locales/fr/knxUltimateHueCameraMotion.html +0 -38
  406. package/nodes/locales/fr/knxUltimateHueCameraMotion.json +0 -30
  407. package/nodes/locales/fr/knxUltimateHueContactSensor.html +0 -35
  408. package/nodes/locales/fr/knxUltimateHueContactSensor.json +0 -26
  409. package/nodes/locales/fr/knxUltimateHueController.html +0 -691
  410. package/nodes/locales/fr/knxUltimateHueController.json +0 -64
  411. package/nodes/locales/fr/knxUltimateHueHumiditySensor.html +0 -38
  412. package/nodes/locales/fr/knxUltimateHueHumiditySensor.json +0 -30
  413. package/nodes/locales/fr/knxUltimateHueLight.html +0 -124
  414. package/nodes/locales/fr/knxUltimateHueLight.json +0 -86
  415. package/nodes/locales/fr/knxUltimateHueLightSensor.html +0 -38
  416. package/nodes/locales/fr/knxUltimateHueLightSensor.json +0 -19
  417. package/nodes/locales/fr/knxUltimateHueMotion.html +0 -41
  418. package/nodes/locales/fr/knxUltimateHueMotion.json +0 -27
  419. package/nodes/locales/fr/knxUltimateHuePlug.html +0 -50
  420. package/nodes/locales/fr/knxUltimateHuePlug.json +0 -33
  421. package/nodes/locales/fr/knxUltimateHueScene.html +0 -45
  422. package/nodes/locales/fr/knxUltimateHueScene.json +0 -41
  423. package/nodes/locales/fr/knxUltimateHueTapDial.html +0 -40
  424. package/nodes/locales/fr/knxUltimateHueTapDial.json +0 -28
  425. package/nodes/locales/fr/knxUltimateHueTemperatureSensor.html +0 -38
  426. package/nodes/locales/fr/knxUltimateHueTemperatureSensor.json +0 -30
  427. package/nodes/locales/fr/knxUltimateHueZigbeeConnectivity.html +0 -39
  428. package/nodes/locales/fr/knxUltimateHueZigbeeConnectivity.json +0 -30
  429. package/nodes/locales/fr/knxUltimateHuedevice_software_update.html +0 -36
  430. package/nodes/locales/fr/knxUltimateHuedevice_software_update.json +0 -30
  431. package/nodes/locales/fr/knxUltimateLoadControl.html +0 -76
  432. package/nodes/locales/fr/knxUltimateLoadControl.json +0 -28
  433. package/nodes/locales/fr/knxUltimateLogger.html +0 -160
  434. package/nodes/locales/fr/knxUltimateLogger.json +0 -31
  435. package/nodes/locales/fr/knxUltimateMatterBridge.html +0 -65
  436. package/nodes/locales/fr/knxUltimateMatterBridge.json +0 -123
  437. package/nodes/locales/fr/knxUltimateMatterControllerDevice.html +0 -57
  438. package/nodes/locales/fr/knxUltimateMatterControllerDevice.json +0 -146
  439. package/nodes/locales/fr/knxUltimateSceneController.html +0 -117
  440. package/nodes/locales/fr/knxUltimateSceneController.json +0 -32
  441. package/nodes/locales/fr/knxUltimateStaircase.html +0 -77
  442. package/nodes/locales/fr/knxUltimateStaircase.json +0 -62
  443. package/nodes/locales/fr/knxUltimateWatchDog.html +0 -228
  444. package/nodes/locales/fr/knxUltimateWatchDog.json +0 -27
  445. package/nodes/locales/fr/matter-config.html +0 -47
  446. package/nodes/locales/fr/matter-config.json +0 -47
  447. package/nodes/locales/fr/matterbridge-config.html +0 -45
  448. package/nodes/locales/fr/matterbridge-config.json +0 -25
  449. package/nodes/locales/it/hue-config.html +0 -33
  450. package/nodes/locales/it/hue-config.json +0 -21
  451. package/nodes/locales/it/knxUltimateAI.html +0 -13
  452. package/nodes/locales/it/knxUltimateAI.json +0 -234
  453. package/nodes/locales/it/knxUltimateAIHomeAssistant.html +0 -11
  454. package/nodes/locales/it/knxUltimateAlerter.html +0 -159
  455. package/nodes/locales/it/knxUltimateAlerter.json +0 -27
  456. package/nodes/locales/it/knxUltimateAutoResponder.html +0 -96
  457. package/nodes/locales/it/knxUltimateAutoResponder.json +0 -8
  458. package/nodes/locales/it/knxUltimateDateTime.html +0 -67
  459. package/nodes/locales/it/knxUltimateDateTime.json +0 -32
  460. package/nodes/locales/it/knxUltimateGarage.html +0 -79
  461. package/nodes/locales/it/knxUltimateGarage.json +0 -51
  462. package/nodes/locales/it/knxUltimateGlobalContext.html +0 -81
  463. package/nodes/locales/it/knxUltimateGlobalContext.json +0 -24
  464. package/nodes/locales/it/knxUltimateHATranslator.html +0 -24
  465. package/nodes/locales/it/knxUltimateHATranslator.json +0 -8
  466. package/nodes/locales/it/knxUltimateHueAreaMotion.html +0 -44
  467. package/nodes/locales/it/knxUltimateHueAreaMotion.json +0 -31
  468. package/nodes/locales/it/knxUltimateHueBattery.html +0 -37
  469. package/nodes/locales/it/knxUltimateHueBattery.json +0 -30
  470. package/nodes/locales/it/knxUltimateHueButton.html +0 -52
  471. package/nodes/locales/it/knxUltimateHueButton.json +0 -34
  472. package/nodes/locales/it/knxUltimateHueCameraMotion.html +0 -38
  473. package/nodes/locales/it/knxUltimateHueCameraMotion.json +0 -30
  474. package/nodes/locales/it/knxUltimateHueContactSensor.html +0 -35
  475. package/nodes/locales/it/knxUltimateHueContactSensor.json +0 -26
  476. package/nodes/locales/it/knxUltimateHueController.html +0 -690
  477. package/nodes/locales/it/knxUltimateHueController.json +0 -64
  478. package/nodes/locales/it/knxUltimateHueHumiditySensor 2.html +0 -11
  479. package/nodes/locales/it/knxUltimateHueHumiditySensor.html +0 -38
  480. package/nodes/locales/it/knxUltimateHueHumiditySensor.json +0 -30
  481. package/nodes/locales/it/knxUltimateHueLight.html +0 -124
  482. package/nodes/locales/it/knxUltimateHueLight.json +0 -94
  483. package/nodes/locales/it/knxUltimateHueLightSensor.html +0 -38
  484. package/nodes/locales/it/knxUltimateHueLightSensor.json +0 -19
  485. package/nodes/locales/it/knxUltimateHueMotion.html +0 -41
  486. package/nodes/locales/it/knxUltimateHueMotion.json +0 -27
  487. package/nodes/locales/it/knxUltimateHuePlug.html +0 -50
  488. package/nodes/locales/it/knxUltimateHuePlug.json +0 -33
  489. package/nodes/locales/it/knxUltimateHueScene.html +0 -45
  490. package/nodes/locales/it/knxUltimateHueScene.json +0 -41
  491. package/nodes/locales/it/knxUltimateHueTapDial.html +0 -40
  492. package/nodes/locales/it/knxUltimateHueTapDial.json +0 -28
  493. package/nodes/locales/it/knxUltimateHueTemperatureSensor.html +0 -38
  494. package/nodes/locales/it/knxUltimateHueTemperatureSensor.json +0 -30
  495. package/nodes/locales/it/knxUltimateHueZigbeeConnectivity.html +0 -39
  496. package/nodes/locales/it/knxUltimateHueZigbeeConnectivity.json +0 -30
  497. package/nodes/locales/it/knxUltimateHuedevice_software_update.html +0 -35
  498. package/nodes/locales/it/knxUltimateHuedevice_software_update.json +0 -30
  499. package/nodes/locales/it/knxUltimateLoadControl.html +0 -76
  500. package/nodes/locales/it/knxUltimateLoadControl.json +0 -28
  501. package/nodes/locales/it/knxUltimateLogger.html +0 -132
  502. package/nodes/locales/it/knxUltimateLogger.json +0 -31
  503. package/nodes/locales/it/knxUltimateMatterBridge.html +0 -65
  504. package/nodes/locales/it/knxUltimateMatterBridge.json +0 -123
  505. package/nodes/locales/it/knxUltimateMatterControllerDevice.html +0 -57
  506. package/nodes/locales/it/knxUltimateMatterControllerDevice.json +0 -146
  507. package/nodes/locales/it/knxUltimateSceneController.html +0 -101
  508. package/nodes/locales/it/knxUltimateSceneController.json +0 -32
  509. package/nodes/locales/it/knxUltimateStaircase.html +0 -77
  510. package/nodes/locales/it/knxUltimateStaircase.json +0 -62
  511. package/nodes/locales/it/knxUltimateWatchDog.html +0 -194
  512. package/nodes/locales/it/knxUltimateWatchDog.json +0 -27
  513. package/nodes/locales/it/matter-config.html +0 -47
  514. package/nodes/locales/it/matter-config.json +0 -48
  515. package/nodes/locales/it/matterbridge-config.html +0 -45
  516. package/nodes/locales/it/matterbridge-config.json +0 -25
  517. package/nodes/locales/zh-CN/hue-config.html +0 -33
  518. package/nodes/locales/zh-CN/hue-config.json +0 -21
  519. package/nodes/locales/zh-CN/knxUltimateAI.html +0 -13
  520. package/nodes/locales/zh-CN/knxUltimateAI.json +0 -231
  521. package/nodes/locales/zh-CN/knxUltimateAIHomeAssistant.html +0 -11
  522. package/nodes/locales/zh-CN/knxUltimateAlerter.html +0 -159
  523. package/nodes/locales/zh-CN/knxUltimateAlerter.json +0 -27
  524. package/nodes/locales/zh-CN/knxUltimateAutoResponder.html +0 -94
  525. package/nodes/locales/zh-CN/knxUltimateAutoResponder.json +0 -8
  526. package/nodes/locales/zh-CN/knxUltimateDateTime.html +0 -45
  527. package/nodes/locales/zh-CN/knxUltimateDateTime.json +0 -32
  528. package/nodes/locales/zh-CN/knxUltimateGarage.html +0 -79
  529. package/nodes/locales/zh-CN/knxUltimateGarage.json +0 -51
  530. package/nodes/locales/zh-CN/knxUltimateGlobalContext.html +0 -77
  531. package/nodes/locales/zh-CN/knxUltimateGlobalContext.json +0 -24
  532. package/nodes/locales/zh-CN/knxUltimateHATranslator.html +0 -25
  533. package/nodes/locales/zh-CN/knxUltimateHATranslator.json +0 -8
  534. package/nodes/locales/zh-CN/knxUltimateHueAreaMotion.html +0 -44
  535. package/nodes/locales/zh-CN/knxUltimateHueAreaMotion.json +0 -31
  536. package/nodes/locales/zh-CN/knxUltimateHueBattery.html +0 -37
  537. package/nodes/locales/zh-CN/knxUltimateHueBattery.json +0 -30
  538. package/nodes/locales/zh-CN/knxUltimateHueButton.html +0 -52
  539. package/nodes/locales/zh-CN/knxUltimateHueButton.json +0 -34
  540. package/nodes/locales/zh-CN/knxUltimateHueCameraMotion.html +0 -38
  541. package/nodes/locales/zh-CN/knxUltimateHueCameraMotion.json +0 -30
  542. package/nodes/locales/zh-CN/knxUltimateHueContactSensor.html +0 -35
  543. package/nodes/locales/zh-CN/knxUltimateHueContactSensor.json +0 -26
  544. package/nodes/locales/zh-CN/knxUltimateHueController.html +0 -693
  545. package/nodes/locales/zh-CN/knxUltimateHueController.json +0 -64
  546. package/nodes/locales/zh-CN/knxUltimateHueHumiditySensor.html +0 -38
  547. package/nodes/locales/zh-CN/knxUltimateHueHumiditySensor.json +0 -30
  548. package/nodes/locales/zh-CN/knxUltimateHueLight.html +0 -126
  549. package/nodes/locales/zh-CN/knxUltimateHueLight.json +0 -86
  550. package/nodes/locales/zh-CN/knxUltimateHueLightSensor.html +0 -38
  551. package/nodes/locales/zh-CN/knxUltimateHueLightSensor.json +0 -9
  552. package/nodes/locales/zh-CN/knxUltimateHueMotion.html +0 -41
  553. package/nodes/locales/zh-CN/knxUltimateHueMotion.json +0 -27
  554. package/nodes/locales/zh-CN/knxUltimateHuePlug.html +0 -50
  555. package/nodes/locales/zh-CN/knxUltimateHuePlug.json +0 -33
  556. package/nodes/locales/zh-CN/knxUltimateHueScene.html +0 -45
  557. package/nodes/locales/zh-CN/knxUltimateHueScene.json +0 -41
  558. package/nodes/locales/zh-CN/knxUltimateHueTapDial.html +0 -40
  559. package/nodes/locales/zh-CN/knxUltimateHueTapDial.json +0 -28
  560. package/nodes/locales/zh-CN/knxUltimateHueTemperatureSensor.html +0 -38
  561. package/nodes/locales/zh-CN/knxUltimateHueTemperatureSensor.json +0 -30
  562. package/nodes/locales/zh-CN/knxUltimateHueZigbeeConnectivity.html +0 -39
  563. package/nodes/locales/zh-CN/knxUltimateHueZigbeeConnectivity.json +0 -30
  564. package/nodes/locales/zh-CN/knxUltimateHuedevice_software_update.html +0 -36
  565. package/nodes/locales/zh-CN/knxUltimateHuedevice_software_update.json +0 -30
  566. package/nodes/locales/zh-CN/knxUltimateLoadControl.html +0 -76
  567. package/nodes/locales/zh-CN/knxUltimateLoadControl.json +0 -28
  568. package/nodes/locales/zh-CN/knxUltimateLogger.html +0 -126
  569. package/nodes/locales/zh-CN/knxUltimateLogger.json +0 -31
  570. package/nodes/locales/zh-CN/knxUltimateMatterBridge.html +0 -65
  571. package/nodes/locales/zh-CN/knxUltimateMatterBridge.json +0 -123
  572. package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.html +0 -57
  573. package/nodes/locales/zh-CN/knxUltimateMatterControllerDevice.json +0 -146
  574. package/nodes/locales/zh-CN/knxUltimateSceneController.html +0 -98
  575. package/nodes/locales/zh-CN/knxUltimateSceneController.json +0 -32
  576. package/nodes/locales/zh-CN/knxUltimateStaircase.html +0 -77
  577. package/nodes/locales/zh-CN/knxUltimateStaircase.json +0 -62
  578. package/nodes/locales/zh-CN/knxUltimateWatchDog.html +0 -178
  579. package/nodes/locales/zh-CN/knxUltimateWatchDog.json +0 -27
  580. package/nodes/locales/zh-CN/matter-config.html +0 -47
  581. package/nodes/locales/zh-CN/matter-config.json +0 -47
  582. package/nodes/locales/zh-CN/matterbridge-config.html +0 -45
  583. package/nodes/locales/zh-CN/matterbridge-config.json +0 -25
  584. package/nodes/matter-config.html +0 -578
  585. package/nodes/matter-config.js +0 -387
  586. package/nodes/matterbridge-config.html +0 -198
  587. package/nodes/matterbridge-config.js +0 -261
  588. package/nodes/plugins/knxUltimate-cerebrum-runtime-plugin.js +0 -79
  589. package/nodes/plugins/knxUltimate-migration-notice-plugin.html +0 -44
  590. package/nodes/plugins/knxUltimateAI-vue/assets/app.css +0 -1
  591. package/nodes/plugins/knxUltimateAI-vue/assets/app.js +0 -13
  592. package/nodes/plugins/knxUltimateAI-vue/assets/chunk-html2canvas.esm.js +0 -5
  593. package/nodes/plugins/knxUltimateAI-vue/assets/chunk-index.es.js +0 -5
  594. package/nodes/plugins/knxUltimateAI-vue/assets/chunk-jspdf.es.min.js +0 -79
  595. package/nodes/plugins/knxUltimateAI-vue/assets/chunk-purify.es.js +0 -3
  596. package/nodes/plugins/knxUltimateAI-vue/index.html +0 -13
  597. package/nodes/utils/HueEventStream.mjs +0 -176
  598. package/nodes/utils/colorManipulators/XYFromRGB_Supergiovane.js +0 -113
  599. package/nodes/utils/colorManipulators/hueColorConverter.js +0 -521
  600. package/nodes/utils/http.js +0 -291
  601. package/nodes/utils/hueControllerProfileAdapter.js +0 -104
  602. package/nodes/utils/hueControllerProfiles/runtime/area_motion.js +0 -221
  603. package/nodes/utils/hueControllerProfiles/runtime/button.js +0 -295
  604. package/nodes/utils/hueControllerProfiles/runtime/camera_motion.js +0 -221
  605. package/nodes/utils/hueControllerProfiles/runtime/contact.js +0 -191
  606. package/nodes/utils/hueControllerProfiles/runtime/device_power.js +0 -185
  607. package/nodes/utils/hueControllerProfiles/runtime/device_software_update.js +0 -185
  608. package/nodes/utils/hueControllerProfiles/runtime/humidity.js +0 -204
  609. package/nodes/utils/hueControllerProfiles/runtime/light.js +0 -1585
  610. package/nodes/utils/hueControllerProfiles/runtime/light_level.js +0 -180
  611. package/nodes/utils/hueControllerProfiles/runtime/motion.js +0 -185
  612. package/nodes/utils/hueControllerProfiles/runtime/plug.js +0 -344
  613. package/nodes/utils/hueControllerProfiles/runtime/relative_rotary.js +0 -271
  614. package/nodes/utils/hueControllerProfiles/runtime/scene.js +0 -352
  615. package/nodes/utils/hueControllerProfiles/runtime/temperature.js +0 -187
  616. package/nodes/utils/hueControllerProfiles/runtime/zigbee_connectivity.js +0 -185
  617. package/nodes/utils/hueControllerResourceCatalog.js +0 -71
  618. package/nodes/utils/hueEngine.mjs +0 -469
  619. package/nodes/utils/knxAiCamera.js +0 -302
  620. package/nodes/utils/knxAiCatalogRetrieval.js +0 -349
  621. package/nodes/utils/knxAiCerebrum.js +0 -406
  622. package/nodes/utils/knxAiChatContext.js +0 -496
  623. package/nodes/utils/knxAiEventHistory.js +0 -521
  624. package/nodes/utils/knxAiHomeMemory.js +0 -1021
  625. package/nodes/utils/knxAiScheduler.js +0 -445
  626. package/nodes/utils/knxAiSemanticContext.js +0 -662
  627. package/nodes/utils/knxAiTelegramVoice.js +0 -545
  628. package/nodes/utils/knxAiWebAccess.js +0 -631
  629. package/nodes/utils/lightEngines/canonicalLight.js +0 -75
  630. package/nodes/utils/lightEngines/hueLightEngine.js +0 -51
  631. package/nodes/utils/lightEngines/index.js +0 -25
  632. package/nodes/utils/lightEngines/knxLightCommand.js +0 -79
  633. package/nodes/utils/lightEngines/lightEngine.js +0 -46
  634. package/nodes/utils/lightEngines/matterHueShim.js +0 -59
  635. package/nodes/utils/lightEngines/matterLightEngine.js +0 -117
  636. package/nodes/utils/matterBridgeDeviceFactory.mjs +0 -780
  637. package/nodes/utils/matterBridgeEngine.mjs +0 -297
  638. package/nodes/utils/matterControllerCommandGate.js +0 -47
  639. package/nodes/utils/matterControllerProfiles/doorLock.js +0 -258
  640. package/nodes/utils/matterControllerProfiles/fan.js +0 -19
  641. package/nodes/utils/matterControllerProfiles/index.js +0 -34
  642. package/nodes/utils/matterControllerProfiles/mappedEndpoint.js +0 -217
  643. package/nodes/utils/matterControllerProfiles/switch.js +0 -13
  644. package/nodes/utils/matterControllerProfiles/thermostat.js +0 -19
  645. package/nodes/utils/matterControllerProfiles/universal.js +0 -462
  646. package/nodes/utils/matterControllerProfiles/windowCovering.js +0 -19
  647. package/nodes/utils/matterControllerSemanticInput.js +0 -212
  648. package/nodes/utils/matterEngine.mjs +0 -894
  649. package/nodes/utils/matterEnvironmentLock.mjs +0 -32
  650. package/nodes/utils/matterKnxConverter.js +0 -204
  651. package/nodes/utils/matterStorageBackup.js +0 -100
  652. package/resources/HA-icon.png +0 -0
  653. package/resources/dim.png +0 -0
  654. package/resources/rgb.png +0 -0
  655. package/resources/tunablewhite.png +0 -0
  656. package/resources/zxing-browser-0.2.0.min.js +0 -1
  657. 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>&nbsp;
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>