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,2851 +0,0 @@
1
- 'use strict'
2
-
3
- <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/11f26b4500.js"></script>
4
-
5
- <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/htmlUtils.js"></script>
6
- <script type="text/javascript" src="resources/node-red-contrib-knx-ultimate/configNodeEditorSelection.js"></script>
7
-
8
- <script type="text/javascript">
9
- (function () {
10
-
11
- RED.nodes.registerType("knxUltimateMatterControllerDevice", {
12
- category: "KNX Ultimate",
13
- color: "#8FB1FA",
14
- defaults: {
15
- //buttonState: {value: true},
16
- server: { type: "knxUltimate-config", required: false },
17
- serverMatter: { type: "matter-config", required: true },
18
- matterControllerMode: { value: "single" },
19
- universalService: { value: "batteryMonitor" },
20
- universalBatteryThreshold: { value: 20, validate: RED.validators.number() },
21
- universalLowBatteryGA: { value: "" },
22
- universalLowBatteryGAName: { value: "" },
23
- universalLowBatteryTextGA: { value: "" },
24
- universalLowBatteryTextGAName: { value: "" },
25
- universalBatteryOnlyLow: { value: true },
26
- universalEmitInitialState: { value: true },
27
- universalIncludeRawEvent: { value: true },
28
- matterNodeId: { value: "" },
29
- matterEndpointId: { value: 1 },
30
- matterDeviceName: { value: "" },
31
- matterDeviceCapabilities: { value: "" },
32
- matterMappings: { value: "[]" },
33
- name: { value: "" },
34
-
35
- nameLightSwitch: { value: "" },
36
- GALightSwitch: { value: "" },
37
- dptLightSwitch: { value: "" },
38
-
39
- nameLightState: { value: "" },
40
- GALightState: { value: "" },
41
- dptLightState: { value: "" },
42
-
43
- nameLightDIM: { value: "" },
44
- GALightDIM: { value: "" },
45
- dptLightDIM: { value: "" },
46
-
47
- // TAB Color ---------------------------
48
- nameLightColor: { value: "" },
49
- GALightColor: { value: "" },
50
- dptLightColor: { value: "" },
51
-
52
- nameLightColorState: { value: "" },
53
- GALightColorState: { value: "" },
54
- dptLightColorState: { value: "" },
55
-
56
- // HSV H hue Color change
57
- nameLightHSV_H_DIM: { value: "" },
58
- GALightHSV_H_DIM: { value: "" },
59
- dptLightHSV_H_DIM: { value: "" },
60
-
61
- nameLightHSV_H_State: { value: "" },
62
- GALightHSV_H_State: { value: "" },
63
- dptLightHSV_H_State: { value: "" },
64
-
65
- // HSV S saturation change
66
- nameLightHSV_S_DIM: { value: "" },
67
- GALightHSV_S_DIM: { value: "" },
68
- dptLightHSV_S_DIM: { value: "" },
69
-
70
- nameLightHSV_S_State: { value: "" },
71
- GALightHSV_S_State: { value: "" },
72
- dptLightHSV_S_State: { value: "" },
73
- // -------------------------------------
74
-
75
- nameLightKelvinDIM: { value: "" },
76
- GALightKelvinDIM: { value: "" },
77
- dptLightKelvinDIM: { value: "" },
78
-
79
- nameLightKelvinPercentage: { value: "" },
80
- GALightKelvinPercentage: { value: "" },
81
- dptLightKelvinPercentage: { value: "" },
82
-
83
- nameLightKelvinPercentageState: { value: "" },
84
- GALightKelvinPercentageState: { value: "" },
85
- dptLightKelvinPercentageState: { value: "" },
86
-
87
- nameLightKelvin: { value: "" },
88
- GALightKelvin: { value: "" },
89
- dptLightKelvin: { value: "" },
90
-
91
- nameLightKelvinState: { value: "" },
92
- GALightKelvinState: { value: "" },
93
- dptLightKelvinState: { value: "" },
94
-
95
- nameLightBrightness: { value: "" },
96
- GALightBrightness: { value: "" },
97
- dptLightBrightness: { value: "" },
98
-
99
- nameLightBrightnessState: { value: "" },
100
- GALightBrightnessState: { value: "" },
101
- dptLightBrightnessState: { value: "" },
102
-
103
- nameLightBlink: { value: "" },
104
- GALightBlink: { value: "" },
105
- dptLightBlink: { value: "" },
106
-
107
- nameLightColorCycle: { value: "" },
108
- GALightColorCycle: { value: "" },
109
- dptLightColorCycle: { value: "" },
110
-
111
- nameDaylightSensor: { value: "" },
112
- GADaylightSensor: { value: "" },
113
- dptDaylightSensor: { value: "" },
114
-
115
- specifySwitchOnBrightness: { value: "temperature" },
116
- colorAtSwitchOnDayTime: { value: '{"kelvin":3000, "brightness":100 }' },
117
-
118
- enableDayNightLighting: { value: "no" },
119
- colorAtSwitchOnNightTime: { value: '{ "kelvin":2700, "brightness":20 }' },
120
-
121
- invertDayNight: { value: false },
122
- invertDimTunableWhiteDirection: { value: false },
123
-
124
- updateKNXBrightnessStatusOnHUEOnOff: { value: "no" },
125
- dimSpeed: { value: 5000, required: false },
126
- HSVDimSpeed: { value: 5000, required: false },
127
- minDimLevelLight: { value: 10, required: false },
128
- maxDimLevelLight: { value: 100, required: false },
129
- readStatusAtStartup: { value: "yes" },
130
- enableNodePINS: { value: "no" },
131
-
132
- outputs: { value: 0 },
133
- inputs: { value: 0 },
134
-
135
- restoreDayMode: { value: "no" }, // Starting from v 4.1.31
136
- updateLocalStateFromKNXWrite: { value: true } // Starting from v 4.1.31
137
- },
138
- credentials: {
139
- doorLockPin: { type: "password" }
140
- },
141
- inputs: 0,
142
- outputs: 0,
143
- icon: "node-matter-controller-icon.svg",
144
- label: function () {
145
- return this.name || this.matterDeviceName || "Control Matter from KNX";
146
- },
147
- paletteLabel: "Control Matter from KNX",
148
- oneditprepare: function () {
149
- // Go to the help panel
150
- try {
151
- RED.sidebar.show("help");
152
- } catch (error) { }
153
-
154
-
155
- var node = this; // Starting from v 4.1.31
156
- if (node.id) {
157
- $.ajax({
158
- url: "KNXUltimateMatterControllerEnable",
159
- type: "POST",
160
- contentType: "application/json",
161
- data: JSON.stringify({ nodeId: node.id })
162
- });
163
- }
164
- $("#node-input-updateLocalStateFromKNXWrite").prop("checked", node.updateLocalStateFromKNXWrite === true || node.updateLocalStateFromKNXWrite === "true"); // Starting from v 4.1.31
165
- function ensureVerticalTabsStyle() {
166
- if ($('#knxUltimateMatterControllerDeviceVerticalTabs').length) return;
167
- const style = `
168
- <style id="knxUltimateMatterControllerDeviceVerticalTabs">
169
- .hue-vertical-tabs.ui-tabs.ui-widget.ui-widget-content.ui-corner-all {
170
- display: flex;
171
- border: none;
172
- padding: 0;
173
- }
174
- .hue-vertical-tabs > ul.ui-tabs-nav {
175
- flex: 0 0 180px;
176
- border-right: 1px solid #ccc;
177
- border-left: none;
178
- border-top: none;
179
- border-bottom: none;
180
- padding: 0.5em 0.3em;
181
- }
182
- .hue-vertical-tabs > ul.ui-tabs-nav li {
183
- float: none;
184
- width: 100%;
185
- margin: 0 0 2px 0;
186
- }
187
- .hue-vertical-tabs > ul.ui-tabs-nav li a {
188
- display: block;
189
- width: 100%;
190
- white-space: normal;
191
- position: relative;
192
- border-bottom: none !important;
193
- }
194
- .hue-vertical-tabs > ul.ui-tabs-nav li.ui-tabs-active {
195
- border-bottom: none !important;
196
- }
197
- .hue-vertical-tabs > ul.ui-tabs-nav li.ui-tabs-active a::after {
198
- content: "";
199
- position: absolute;
200
- left: 0;
201
- bottom: 0;
202
- width: 50%;
203
- height: 3px;
204
- background: currentColor;
205
- }
206
- .hue-vertical-tabs .ui-tabs-panel {
207
- flex: 1;
208
- padding: 0.8em 1em;
209
- box-sizing: border-box;
210
- border: none;
211
- background: transparent;
212
- }
213
- .hue-vertical-tabs .form-row > dt {
214
- flex: 1 1 auto;
215
- margin: 0;
216
- }
217
- .hue-vertical-tabs hr {
218
- width: 100%;
219
- border: 0;
220
- border-top: 1px solid #ccc;
221
- margin: 8px 0;
222
- }
223
- .matter-input-help-table {
224
- width: 100%;
225
- border-collapse: collapse;
226
- margin: 8px 0 18px;
227
- }
228
- .matter-input-help-table th,
229
- .matter-input-help-table td {
230
- border-bottom: 1px solid #ddd;
231
- padding: 7px 6px;
232
- text-align: left;
233
- vertical-align: top;
234
- }
235
- .matter-input-help-table code {
236
- white-space: pre-wrap;
237
- word-break: break-word;
238
- }
239
- .matter-input-help-copy {
240
- white-space: nowrap;
241
- }
242
- .matter-input-help-advanced {
243
- max-height: 310px;
244
- overflow: auto;
245
- border: 1px solid #ddd;
246
- padding: 0 8px;
247
- }
248
- </style>`;
249
- $('head').append(style);
250
- }
251
-
252
- function onEditPrepare() {
253
- ensureVerticalTabsStyle();
254
- const $knxServerInput = $("#node-input-server");
255
- const KNX_EMPTY_VALUES = new Set(['', 'none', '_add_', '__none__']);
256
- // Historical variable names are retained for saved-flow compatibility; they point to Matter widgets.
257
- const $hueServerInput = $("#node-input-serverMatter");
258
- const $matterControllerModeInput = $("#node-input-matterControllerMode");
259
- const $universalServiceInput = $("#node-input-universalService");
260
- const $hueDeviceInput = $("#node-input-matterNodeId");
261
- const $deviceNameInput = $("#node-input-matterDeviceName");
262
- const $matterEndpointInput = $("#node-input-matterEndpointId");
263
- const $matterCapabilitiesInput = $("#node-input-matterDeviceCapabilities");
264
- const $nodeNameInput = $("#node-input-name");
265
- const $refreshDevicesButton = $(".hue-refresh-devices");
266
- const $locateDeviceButton = $(".hue-locate-device");
267
- const $hueDevicesLoading = $(".hue-devices-loading");
268
- const $inputHelpPanel = $("#matter-flow-input-help");
269
- const UNIVERSAL_NODE_ID = '__UNIVERSAL__';
270
- const isUniversalMode = () => $matterControllerModeInput.val() === 'universal';
271
- $matterControllerModeInput.val(node.matterControllerMode || 'single');
272
- let cachedHueDevices = Array.isArray(node._cachedHueLightDevices) ? node._cachedHueLightDevices : [];
273
- node._cachedHueLightDevices = cachedHueDevices;
274
- const defaultHueDevicePlaceholder = $deviceNameInput.attr('placeholder') || '';
275
- if (($hueDeviceInput.val() || '').trim() === '' && node.matterNodeId) {
276
- $hueDeviceInput.val(node.matterNodeId);
277
- }
278
- if (($matterEndpointInput.val() || '').trim() === '' && node.matterEndpointId) {
279
- $matterEndpointInput.val(node.matterEndpointId);
280
- }
281
- if (($matterCapabilitiesInput.val() || '').trim() === '' && node.matterDeviceCapabilities) {
282
- $matterCapabilitiesInput.val(node.matterDeviceCapabilities);
283
- }
284
- if (($nodeNameInput.val() || '').trim() === '' && node.name) {
285
- $nodeNameInput.val(node.name);
286
- }
287
- if (($deviceNameInput.val() || '').trim() === '' && node.matterNodeId && node.name) {
288
- $deviceNameInput.val(node.name);
289
- }
290
- let selectedMatterDeviceName = ($deviceNameInput.val() || '').trim();
291
- let matterDevicePickerMouseDown = false;
292
- let showingNoHueDevicesPlaceholder = false;
293
- const HUE_EMPTY_SERVER_VALUES = new Set(['', 'none', '_add_', '__none__', '__null__', 'null', 'undefined']);
294
- const selectionApi = window.KNXUltimateConfigNodeEditorSelection;
295
- const normalizeConfigSelection = selectionApi && typeof selectionApi.normalizeSelection === 'function'
296
- ? selectionApi.normalizeSelection
297
- : (value, emptyValues) => {
298
- const normalized = value === undefined || value === null ? '' : String(value).trim();
299
- return emptyValues.has(normalized.toLowerCase()) ? '' : normalized;
300
- };
301
- const resolveSelectedOrStoredSelection = selectionApi && typeof selectionApi.resolveSelectedOrStoredSelection === 'function'
302
- ? selectionApi.resolveSelectedOrStoredSelection
303
- : (selectedValue, storedValue, emptyValues) => normalizeConfigSelection(selectedValue, emptyValues) || normalizeConfigSelection(storedValue, emptyValues);
304
- const shouldPreserveSelection = selectionApi && typeof selectionApi.shouldPreserveSelection === 'function'
305
- ? selectionApi.shouldPreserveSelection
306
- : (event, nextValue, currentValue, emptyValues) => (!event || !event.originalEvent) && normalizeConfigSelection(nextValue, emptyValues) === '' && normalizeConfigSelection(currentValue, emptyValues) !== '';
307
- let activeKnxServerId = resolveSelectedOrStoredSelection($knxServerInput.val(), node.server, KNX_EMPTY_VALUES);
308
- let activeMatterServerId = resolveSelectedOrStoredSelection($hueServerInput.val(), node.serverMatter, HUE_EMPTY_SERVER_VALUES);
309
- let locateSessionActive = false;
310
- let locateAutoResetTimer = null;
311
- let locatePendingRequest = null;
312
- node.__stopHueLocateSession = null;
313
- node.__cleanupNodeRemovalListener = null;
314
- if (!node.__locateSessionInfo) node.__locateSessionInfo = null;
315
- node.__hueLocateActive = false;
316
-
317
- const clearLocateAutoReset = () => {
318
- if (locateAutoResetTimer !== null) {
319
- clearTimeout(locateAutoResetTimer);
320
- locateAutoResetTimer = null;
321
- }
322
- };
323
-
324
- const scheduleLocateAutoReset = (durationMs) => {
325
- clearLocateAutoReset();
326
- const ms = Number(durationMs);
327
- if (!Number.isFinite(ms) || ms <= 0) return;
328
- locateAutoResetTimer = setTimeout(() => {
329
- updateLocateButtonState(false);
330
- }, ms);
331
- };
332
-
333
- const updateLocateButtonState = (isActive) => {
334
- locateSessionActive = !!isActive;
335
- node.__hueLocateActive = locateSessionActive;
336
- if (!locateSessionActive) {
337
- clearLocateAutoReset();
338
- node.__locateSessionInfo = null;
339
- }
340
- if (!$locateDeviceButton.length) return;
341
- const $icon = $locateDeviceButton.find('i').first();
342
- if ($icon.length) {
343
- $icon.removeClass('fa-stop fa-play').addClass(locateSessionActive ? 'fa fa-stop' : 'fa fa-play');
344
- }
345
- const title = locateSessionActive
346
- ? (node._('knxUltimateMatterControllerDevice.locate_stop_title') || 'Stop Matter locate')
347
- : (node._('knxUltimateMatterControllerDevice.locate_start_title') || 'Locate selected Matter device');
348
- $locateDeviceButton.attr('title', isUniversalMode()
349
- ? (node._('knxUltimateMatterControllerDevice.universal_mode_locate_disabled') || 'Locate is unavailable in Universal Mode.')
350
- : title);
351
- $locateDeviceButton.prop('disabled', isUniversalMode());
352
- };
353
-
354
- const removeNodeRemovalListener = () => {
355
- if (typeof node.__cleanupNodeRemovalListener === 'function') {
356
- try {
357
- RED.events.removeListener('nodes:remove', node.__cleanupNodeRemovalListener);
358
- } catch (error) { /* empty */ }
359
- node.__cleanupNodeRemovalListener = null;
360
- }
361
- };
362
-
363
- const collectRemovedIds = (input, bucket = new Set()) => {
364
- if (!input) return bucket;
365
- if (Array.isArray(input)) {
366
- input.forEach((entry) => collectRemovedIds(entry, bucket));
367
- return bucket;
368
- }
369
- if (typeof input === 'string') {
370
- bucket.add(input);
371
- return bucket;
372
- }
373
- if (typeof input === 'object') {
374
- if (input.id) bucket.add(input.id);
375
- if (input.nodes) collectRemovedIds(input.nodes, bucket);
376
- }
377
- return bucket;
378
- };
379
-
380
- const handleNodeRemoved = (payload) => {
381
- const ids = collectRemovedIds(payload);
382
- if (ids.has(node.id) && typeof node.__stopHueLocateSession === 'function') {
383
- node.__stopHueLocateSession();
384
- removeNodeRemovalListener();
385
- }
386
- };
387
- RED.events.on('nodes:remove', handleNodeRemoved);
388
- node.__cleanupNodeRemovalListener = handleNodeRemoved;
389
-
390
- const buildLocateContext = ({ allowStored = false } = {}) => {
391
- const hueServerId = resolveHueServerValue({ allowStored });
392
- const rawDevice = getHueDeviceValue({ allowStored });
393
- if (!hueServerId || !rawDevice) return null;
394
- const parts = String(rawDevice).split('#');
395
- const deviceId = (parts[0] || '').trim();
396
- if (deviceId === '') return null;
397
- const deviceType = (parts[1] || 'light').trim() || 'light';
398
- return { serverId: hueServerId, deviceId, deviceType };
399
- };
400
-
401
- const performLocateRequest = ({ silent = false, allowStoredContext = false, action } = {}) => {
402
- if (isUniversalMode()) {
403
- if (!silent) RED.notify(node._('knxUltimateMatterControllerDevice.universal_mode_locate_disabled') || 'Locate is unavailable in Universal Mode.', 'warning');
404
- return null;
405
- }
406
- const context = buildLocateContext({ allowStored: allowStoredContext });
407
- if (!context) {
408
- if (!silent) {
409
- const message = !resolveHueServerValue({ allowStored: true })
410
- ? (node._('knxUltimateMatterControllerDevice.locate_no_bridge') || 'Select a Matter controller first')
411
- : (node._('knxUltimateMatterControllerDevice.locate_no_device') || 'Select a Matter device first');
412
- RED.notify(message, 'warning');
413
- }
414
- updateLocateButtonState(false);
415
- return null;
416
- }
417
- if ($locateDeviceButton.length) {
418
- $locateDeviceButton.prop('disabled', true);
419
- }
420
- const effectiveAction = action || (locateSessionActive ? 'stop' : 'start');
421
- const request = $.ajax({
422
- type: 'POST',
423
- url: 'KNXUltimateLocateHueDevice',
424
- data: {
425
- serverId: context.serverId,
426
- deviceId: context.deviceId,
427
- deviceType: context.deviceType,
428
- action: effectiveAction
429
- }
430
- });
431
- locatePendingRequest = request;
432
- if (!allowStoredContext && effectiveAction === 'start') {
433
- node.__locateSessionInfo = {
434
- serverId: context.serverId,
435
- deviceId: context.deviceId,
436
- deviceType: context.deviceType
437
- };
438
- } else if (!node.__locateSessionInfo && effectiveAction !== 'stop') {
439
- node.__locateSessionInfo = {
440
- serverId: context.serverId,
441
- deviceId: context.deviceId,
442
- deviceType: context.deviceType
443
- };
444
- }
445
- request.done((response) => {
446
- const statusValue = (response && typeof response.status === 'string') ? response.status.toLowerCase() : 'started';
447
- let messageKey;
448
- if (effectiveAction === 'stop' || statusValue === 'stopped') {
449
- messageKey = 'knxUltimateMatterControllerDevice.locate_stopped';
450
- node.__locateSessionInfo = null;
451
- updateLocateButtonState(false);
452
- clearLocateAutoReset();
453
- } else if (effectiveAction === 'start' || statusValue === 'started') {
454
- messageKey = 'knxUltimateMatterControllerDevice.locate_started';
455
- node.__locateSessionInfo = {
456
- serverId: context.serverId,
457
- deviceId: context.deviceId,
458
- deviceType: context.deviceType
459
- };
460
- updateLocateButtonState(true);
461
- scheduleLocateAutoReset(response && typeof response.expiresInMs === 'number' ? response.expiresInMs : 600000);
462
- } else {
463
- messageKey = 'knxUltimateMatterControllerDevice.locate_success';
464
- node.__locateSessionInfo = null;
465
- updateLocateButtonState(false);
466
- clearLocateAutoReset();
467
- }
468
- if (!silent) {
469
- const message = node._(messageKey) || (statusValue === 'stopped' ? 'Locate stopped' : 'Locate command sent');
470
- RED.notify(message, 'success');
471
- }
472
- }).fail((xhr) => {
473
- let message;
474
- if (xhr && xhr.responseJSON && xhr.responseJSON.error) {
475
- message = xhr.responseJSON.error;
476
- }
477
- updateLocateButtonState(false);
478
- clearLocateAutoReset();
479
- if (!silent) {
480
- RED.notify(message || (node._('knxUltimateMatterControllerDevice.locate_error') || 'Unable to locate Matter device'), 'error');
481
- }
482
- }).always(() => {
483
- locatePendingRequest = null;
484
- if ($locateDeviceButton.length) {
485
- $locateDeviceButton.prop('disabled', isUniversalMode());
486
- }
487
- });
488
- return request;
489
- };
490
-
491
- const resolveKnxServerValue = () => {
492
- return activeKnxServerId;
493
- };
494
-
495
- const hasKnxServerSelected = () => {
496
- const val = resolveKnxServerValue();
497
- if (val === undefined || val === null) return false;
498
- return !KNX_EMPTY_VALUES.has(val);
499
- };
500
-
501
- const resolveHueServerValue = ({ allowStored = false } = {}) => {
502
- if (activeMatterServerId !== '') return activeMatterServerId;
503
- if (allowStored && node.__locateSessionInfo && node.__locateSessionInfo.serverId) {
504
- return node.__locateSessionInfo.serverId;
505
- }
506
- return '';
507
- };
508
-
509
- const getHueServerConfig = () => {
510
- const id = resolveHueServerValue();
511
- if (id === '') return null;
512
- try {
513
- return RED.nodes.node(id) || null;
514
- } catch (error) {
515
- return null;
516
- }
517
- };
518
-
519
- const resolveDeviceTypeSuffix = (deviceType) => {
520
- const normalized = (deviceType || '').toLowerCase();
521
- return normalized === 'grouped_light' ? '#grouped_light' : '#light';
522
- };
523
-
524
- const applyHueDevicesPlaceholder = (hasDevices) => {
525
- if (!$deviceNameInput.length) return;
526
- if (hasDevices) {
527
- if (showingNoHueDevicesPlaceholder) {
528
- showingNoHueDevicesPlaceholder = false;
529
- $deviceNameInput.attr('placeholder', defaultHueDevicePlaceholder);
530
- }
531
- return;
532
- }
533
- const message = node._('knxUltimateMatterControllerDevice.no_devices') || defaultHueDevicePlaceholder;
534
- showingNoHueDevicesPlaceholder = true;
535
- $deviceNameInput.attr('placeholder', message);
536
- if (($deviceNameInput.val() || '').trim() === '') {
537
- $deviceNameInput.val('');
538
- }
539
- };
540
-
541
- // Human-readable name of a bridged Matter light: the nodeLabel attribute
542
- // (Bridged Device Basic Information), then productLabel, then a pretty type.
543
- const matterEndpointLabel = (ep) => {
544
- var val = null;
545
- (ep.clusters || []).forEach((c) => {
546
- (c.attributes || []).forEach((a) => {
547
- if (val === null && a.name === 'nodeLabel' && a.value != null && String(a.value).trim() !== '') val = String(a.value).trim();
548
- });
549
- });
550
- if (val === null) {
551
- (ep.clusters || []).forEach((c) => {
552
- (c.attributes || []).forEach((a) => {
553
- if (val === null && a.name === 'productLabel' && a.value != null && String(a.value).trim() !== '') val = String(a.value).trim();
554
- });
555
- });
556
- }
557
- return val;
558
- };
559
- const matterTypePretty = { 'ma-extendedcolorlight': 'Colour light', 'ma-colortemperaturelight': 'Tunable white', 'ma-dimmablelight': 'Dimmable light', 'ma-onofflight': 'On/off light', 'ma-onoffpluginunit': 'Plug', 'ma-dimmablepluginunit': 'Dimmable plug', 'ma-doorlock': 'Door lock', 'ma-windowcovering': 'Cover', 'ma-thermostat': 'Thermostat', 'ma-fan': 'Fan', 'ma-temperaturesensor': 'Temperature sensor', 'ma-humiditysensor': 'Humidity sensor', 'ma-lightsensor': 'Light sensor', 'ma-occupancysensor': 'Occupancy sensor', 'ma-contactsensor': 'Contact sensor' };
560
- const matterPrettyType = (raw) => {
561
- const key = String(raw || '').toLowerCase();
562
- if (matterTypePretty[key]) return matterTypePretty[key];
563
- return String(raw || '').replace(/^ma-/i, '').replace(/light$/i, ' light') || 'Matter endpoint';
564
- };
565
- const normalizeMatterToken = (value) => String(value || '').toLowerCase().replace(/[^a-z0-9]/g, '');
566
- const getMatterCluster = (ep, clusterId) => (ep.clusters || []).find((c) => Number(c.id) === Number(clusterId));
567
- const hasMatterAttribute = (cluster, names) => {
568
- const wanted = new Set(names.map(normalizeMatterToken));
569
- return !!cluster && (cluster.attributes || []).some((a) => wanted.has(normalizeMatterToken(a.name)));
570
- };
571
- const hasMatterCommand = (cluster, names) => {
572
- const wanted = new Set(names.map(normalizeMatterToken));
573
- return !!cluster && (cluster.commands || []).some((cmd) => wanted.has(normalizeMatterToken(cmd.name)));
574
- };
575
- const matterCapabilitiesFromEndpoint = (ep) => {
576
- const inputStructure = {
577
- endpointId: Number(ep.endpointId),
578
- clusters: (ep.clusters || []).map((cluster) => ({
579
- id: Number(cluster.id),
580
- name: cluster.name || '',
581
- attributes: (cluster.attributes || []).map((attribute) => ({
582
- id: Number(attribute.id),
583
- name: attribute.name,
584
- writable: attribute.writable === true
585
- })),
586
- commands: (cluster.commands || []).map((command) => ({ name: command.name }))
587
- }))
588
- };
589
- const deviceTypes = (ep.deviceTypes || []).map(normalizeMatterToken);
590
- const primaryDeviceType = (ep.deviceTypes || []).find((value) => !/bridgednode|aggregator|controlbridge/i.test(String(value))) || ep.name;
591
- const deviceTypeDisplay = matterPrettyType(primaryDeviceType);
592
- const typeText = deviceTypes.join(' ');
593
- const onOffCluster = getMatterCluster(ep, 6);
594
- const levelCluster = getMatterCluster(ep, 8);
595
- const colorCluster = getMatterCluster(ep, 768);
596
- const doorLockCluster = getMatterCluster(ep, 257);
597
- if (doorLockCluster) {
598
- return {
599
- known: true,
600
- profile: 'doorLock',
601
- deviceTypeDisplay,
602
- onOff: true,
603
- level: false,
604
- colorTemperature: false,
605
- color: false,
606
- lockDoor: hasMatterCommand(doorLockCluster, ['lockDoor']),
607
- unlockDoor: hasMatterCommand(doorLockCluster, ['unlockDoor']),
608
- inputStructure,
609
- requirePinForRemoteOperation: (() => {
610
- const attribute = (doorLockCluster.attributes || []).find((item) => normalizeMatterToken(item.name) === 'requirepinforremoteoperation');
611
- return attribute ? attribute.value === true : false;
612
- })()
613
- };
614
- }
615
- const isMatterLight = deviceTypes.some((type) => /(?:onoff|dimmable|colortemperature|extendedcolor)light/.test(type));
616
- if (!isMatterLight) {
617
- const specializedProfile = getMatterCluster(ep, 258) ? 'windowCovering'
618
- : getMatterCluster(ep, 513) ? 'thermostat'
619
- : getMatterCluster(ep, 514) ? 'fan'
620
- : getMatterCluster(ep, 59) ? 'switch'
621
- : 'mapped';
622
- const mappedTargets = [];
623
- const addCommand = (clusterId, target, label, dpt) => {
624
- const cluster = getMatterCluster(ep, clusterId);
625
- if (hasMatterCommand(cluster, [target])) mappedTargets.push({ direction: 'command', endpointId: Number(ep.endpointId), clusterId, targetKind: 'command', target, label, dpt });
626
- };
627
- const addAttribute = (clusterId, target, label, dpt, writable) => {
628
- const cluster = getMatterCluster(ep, clusterId);
629
- if (hasMatterAttribute(cluster, [target])) mappedTargets.push({ direction: writable ? 'command' : 'status', endpointId: Number(ep.endpointId), clusterId, targetKind: 'attribute', target, label, dpt });
630
- };
631
- addCommand(6, 'on', 'onoff_command', '1.001');
632
- addAttribute(6, 'onOff', 'onoff_state', '1.001', false);
633
- addCommand(258, 'upOrOpen', 'cover_updown', '1.008');
634
- addCommand(258, 'stopMotion', 'cover_stop', '1.017');
635
- addCommand(258, 'goToLiftPercentage', 'cover_position_command', '5.001');
636
- addAttribute(258, 'currentPositionLiftPercent100ths', 'cover_position_state', '5.001', false);
637
- addAttribute(513, 'occupiedHeatingSetpoint', 'heating_command', '9.001', true);
638
- addAttribute(513, 'occupiedHeatingSetpoint', 'heating_state', '9.001', false);
639
- addAttribute(513, 'occupiedCoolingSetpoint', 'cooling_command', '9.001', true);
640
- addAttribute(513, 'occupiedCoolingSetpoint', 'cooling_state', '9.001', false);
641
- addAttribute(513, 'localTemperature', 'local_temperature', '9.001', false);
642
- addAttribute(514, 'percentSetting', 'fan_command', '5.001', true);
643
- addAttribute(514, 'percentCurrent', 'fan_state', '5.001', false);
644
- addAttribute(1026, 'measuredValue', 'temperature', '9.001', false);
645
- addAttribute(1029, 'measuredValue', 'humidity', '9.007', false);
646
- addAttribute(1024, 'measuredValue', 'illuminance', '9.004', false);
647
- addAttribute(1030, 'occupancy', 'occupancy', '1.011', false);
648
- addAttribute(69, 'stateValue', 'contact', '1.002', false);
649
- addAttribute(47, 'batPercentRemaining', 'battery', '5.001', false);
650
- addAttribute(144, 'activePower', 'active_power', '14.056', false);
651
- addAttribute(145, 'cumulativeEnergyImported', 'imported_energy', '13.013', false);
652
- return { known: true, profile: specializedProfile, deviceTypeDisplay, onOff: false, level: false, colorTemperature: false, color: false, mappedTargets, inputStructure };
653
- }
654
- const hasColorTemperatureType = /colortemperature|extendedcolor/.test(typeText);
655
- const hasColorType = /extendedcolor/.test(typeText);
656
- const isTunableWhiteOnly = hasColorTemperatureType && !hasColorType;
657
- const hasLevelType = /dimmable|colortemperature|extendedcolor/.test(typeText);
658
- const colorFeatureMapAttribute = (colorCluster?.attributes || []).find((attribute) => normalizeMatterToken(attribute.name) === 'featuremap');
659
- const colorFeatureMap = Number(colorFeatureMapAttribute?.value);
660
- const hasColorFeatureMap = Number.isFinite(colorFeatureMap);
661
- const hasColorTemperature = !!colorCluster && (
662
- hasColorFeatureMap
663
- ? (colorFeatureMap & 0x10) !== 0
664
- : (
665
- hasColorTemperatureType ||
666
- hasMatterAttribute(colorCluster, ['colorTemperatureMireds', 'colorTempPhysicalMinMireds', 'colorTempPhysicalMaxMireds']) ||
667
- hasMatterCommand(colorCluster, ['moveToColorTemperature'])
668
- )
669
- );
670
- const hasColor = !!colorCluster && (
671
- !isTunableWhiteOnly && (
672
- hasColorFeatureMap
673
- ? (colorFeatureMap & 0x09) !== 0
674
- : (
675
- hasColorType ||
676
- hasMatterCommand(colorCluster, ['moveToColor', 'moveToHue', 'moveToSaturation', 'moveToHueAndSaturation'])
677
- )
678
- )
679
- );
680
- return {
681
- known: true,
682
- deviceTypeDisplay,
683
- matterLightType: isTunableWhiteOnly ? 'colorTemperature' : (hasColorType ? 'extendedColor' : 'other'),
684
- colorDetectionVersion: 3,
685
- onOff: !!onOffCluster || /onoff|dimmable|colortemperature|extendedcolor/.test(typeText),
686
- level: !!levelCluster || hasLevelType,
687
- colorTemperature: hasColorTemperature,
688
- color: hasColor
689
- };
690
- };
691
- const normalizeMatterCapabilities = (capabilities) => {
692
- if (!capabilities || typeof capabilities !== 'object') return capabilities;
693
- const normalized = Object.assign({}, capabilities);
694
- const displayType = normalizeMatterToken(normalized.deviceTypeDisplay);
695
- const tunableWhiteOnly = normalized.matterLightType === 'colorTemperature' ||
696
- displayType === 'tunablewhite' ||
697
- displayType === 'colortemperaturelight';
698
- if (tunableWhiteOnly) {
699
- normalized.colorTemperature = true;
700
- normalized.color = false;
701
- normalized.colorDetectionVersion = 3;
702
- } else if (normalized.known === true && normalized.color === true &&
703
- normalized.colorDetectionVersion !== 2 && normalized.colorDetectionVersion !== 3) {
704
- normalized.color = false;
705
- }
706
- return normalized;
707
- };
708
- const parseMatterCapabilities = (raw) => {
709
- if (raw && typeof raw === 'object') {
710
- return normalizeMatterCapabilities(raw);
711
- }
712
- if (typeof raw !== 'string' || raw.trim() === '') return null;
713
- try {
714
- return normalizeMatterCapabilities(JSON.parse(raw));
715
- } catch (error) {
716
- return null;
717
- }
718
- };
719
- const serializeMatterCapabilities = (capabilities) => JSON.stringify(capabilities || {});
720
- const universalMatterCapabilities = () => ({
721
- known: true,
722
- profile: 'universal',
723
- deviceTypeDisplay: node._('knxUltimateMatterControllerDevice.universal_mode') || 'Universal Mode'
724
- });
725
- const getJSONPromise = (url) => new Promise((resolve, reject) => { $.getJSON(url, resolve).fail(reject); });
726
-
727
- // Filters Matter items shaped as { value, matterNodeId, matterEndpointId }.
728
- const filterHueDevices = (devices, term) => {
729
- const cleaned = (term || '').replace(/exactmatch/gi, '').trim();
730
- return $.map(devices, (item) => {
731
- if (!item || !item.matterNodeId) return null;
732
- if (cleaned !== '' && !htmlUtilsfullCSVSearch(item.value, cleaned)) return null;
733
- return item;
734
- });
735
- };
736
-
737
- // Expand every commissioned node into its functional endpoints. Lights keep
738
- // the legacy light UI; other endpoints select a capability-driven profile.
739
- const fetchHueDevices = (term, respond, { forceRefresh = false } = {}) => {
740
- const matterServer = getHueServerConfig();
741
- if (!matterServer) {
742
- applyHueDevicesPlaceholder(true);
743
- if (typeof respond === 'function') respond([]);
744
- return;
745
- }
746
- if (!forceRefresh && Array.isArray(cachedHueDevices) && cachedHueDevices.length > 0) {
747
- applyHueDevicesPlaceholder(true);
748
- if (typeof respond === 'function') respond(filterHueDevices(cachedHueDevices, term));
749
- return;
750
- }
751
- if ($hueDevicesLoading.length) {
752
- $hueDevicesLoading.show();
753
- }
754
- getJSONPromise(`KNXUltimateMatterGetNodes?serverId=${encodeURIComponent(matterServer.id)}&_=${Date.now()}`)
755
- .then((data) => {
756
- const devices = (data && Array.isArray(data.devices)) ? data.devices : [];
757
- return Promise.all(devices.map((d) =>
758
- getJSONPromise(`KNXUltimateMatterGetStructure?serverId=${encodeURIComponent(matterServer.id)}&nodeId=${encodeURIComponent(d.nodeId)}&_=${Date.now()}`)
759
- .then((s) => ({ device: d, endpoints: (s && Array.isArray(s.endpoints)) ? s.endpoints : [] }))
760
- .catch(() => ({ device: d, endpoints: [] }))
761
- ));
762
- })
763
- .then((results) => {
764
- const items = [];
765
- results.forEach((entry) => {
766
- const device = entry.device;
767
- // Multi-purpose controller: list every functional endpoint. Capability
768
- // detection below decides whether it uses the unchanged light path or
769
- // a dedicated/mapped non-light profile.
770
- const eps = entry.endpoints.filter((ep) => Number(ep.endpointId) !== 0);
771
- const many = eps.length > 1;
772
- eps.forEach((ep) => {
773
- const label = matterEndpointLabel(ep);
774
- const typeRaw = (Array.isArray(ep.deviceTypes) && ep.deviceTypes.length) ? ep.deviceTypes[0] : ep.name;
775
- var text;
776
- if (label) text = device.name + ' › ' + label;
777
- else if (many) text = device.name + ' › ' + matterPrettyType(typeRaw) + ' ' + ep.endpointId;
778
- else text = device.name + ' (' + matterPrettyType(typeRaw) + ')';
779
- items.push({
780
- value: text,
781
- matterNodeId: String(device.nodeId),
782
- matterEndpointId: String(ep.endpointId),
783
- matterCapabilities: matterCapabilitiesFromEndpoint(ep)
784
- });
785
- });
786
- });
787
- cachedHueDevices = items;
788
- node._cachedHueLightDevices = cachedHueDevices;
789
- const selectedNodeId = String($hueDeviceInput.val() || node.matterNodeId || '');
790
- const selectedEndpointId = String($matterEndpointInput.val() || node.matterEndpointId || '');
791
- const selectedItem = items.find((item) => String(item.matterNodeId) === selectedNodeId && String(item.matterEndpointId) === selectedEndpointId);
792
- if (selectedItem && selectedItem.matterCapabilities) {
793
- currentMatterCapabilities = selectedItem.matterCapabilities;
794
- $matterCapabilitiesInput.val(serializeMatterCapabilities(currentMatterCapabilities));
795
- node.matterDeviceCapabilities = $matterCapabilitiesInput.val();
796
- applyMatterCapabilities(currentMatterCapabilities);
797
- }
798
- applyHueDevicesPlaceholder(cachedHueDevices.length > 0);
799
- if (typeof respond === 'function') respond(filterHueDevices(items, term));
800
- })
801
- .catch(() => {
802
- cachedHueDevices = [];
803
- node._cachedHueLightDevices = cachedHueDevices;
804
- applyHueDevicesPlaceholder(false);
805
- if (typeof respond === 'function') respond([]);
806
- })
807
- .then(() => {
808
- if ($hueDevicesLoading.length) {
809
- $hueDevicesLoading.hide();
810
- }
811
- });
812
- };
813
-
814
- // TIMER BLINK ####################################################
815
- let blinkStatus = 2;
816
- let timerBlinkBackground;
817
- function blinkBackground(_elementIDwithHashAtTheBeginning) {
818
- if (timerBlinkBackground !== undefined) clearInterval(timerBlinkBackground);
819
- timerBlinkBackground = setInterval(() => {
820
- if (isEven(blinkStatus)) $(_elementIDwithHashAtTheBeginning).css("background-color", "lightgreen");
821
- if (!isEven(blinkStatus)) $(_elementIDwithHashAtTheBeginning).css("background-color", "");
822
- blinkStatus += 1;
823
- if (blinkStatus >= 14) {
824
- clearInterval(timerBlinkBackground);
825
- blinkStatus = 2;
826
- $(_elementIDwithHashAtTheBeginning).css("background-color", "");
827
- }
828
- }, 100);
829
- }
830
- function isEven(n) {
831
- return (n % 2 == 0);
832
- }
833
- // ################################################################
834
-
835
-
836
- const $tabs = $("#tabs");
837
- const $universalTabs = $("#matter-universal-tabs");
838
- const $pinSectionRow = $("#node-input-enableNodePINS").closest('.form-row');
839
- const $pinSelect = $("#node-input-enableNodePINS");
840
- let currentMatterCapabilities = parseMatterCapabilities($matterCapabilitiesInput.val() || node.matterDeviceCapabilities);
841
- if (currentMatterCapabilities) {
842
- $matterCapabilitiesInput.val(serializeMatterCapabilities(currentMatterCapabilities));
843
- node.matterDeviceCapabilities = $matterCapabilitiesInput.val();
844
- }
845
-
846
- const semanticInputDefinitions = [
847
- {
848
- fn: 'onoff',
849
- label: 'On / Off',
850
- read: [6, ['onOff']],
851
- writes: [
852
- { descriptor: [6, ['on']], value: true },
853
- { descriptor: [6, ['off']], value: false },
854
- { descriptor: [6, ['toggle']], value: 'toggle' }
855
- ]
856
- },
857
- { fn: 'level', label: 'Level', read: [8, ['currentLevel']], write: [8, ['moveToLevelWithOnOff', 'moveToLevel']], value: 50 },
858
- { fn: 'position', label: 'Cover position', read: [258, ['currentPositionLiftPercent100ths', 'currentPositionLiftPercentage']], write: [258, ['goToLiftPercentage']], value: 35 },
859
- { fn: 'tiltposition', label: 'Cover tilt', read: [258, ['currentPositionTiltPercent100ths', 'currentPositionTiltPercentage']], write: [258, ['goToTiltPercentage']], value: 35 },
860
- { fn: 'open', label: 'Open', write: [258, ['upOrOpen']], omitValue: true },
861
- { fn: 'close', label: 'Close', write: [258, ['downOrClose']], omitValue: true },
862
- { fn: 'stop', label: 'Stop', write: [258, ['stopMotion']], omitValue: true },
863
- { fn: 'setpoint', label: 'Heating setpoint', read: [513, ['occupiedHeatingSetpoint']], writeAttribute: [513, ['occupiedHeatingSetpoint']], value: 21.5 },
864
- { fn: 'coolingsetpoint', label: 'Cooling setpoint', read: [513, ['occupiedCoolingSetpoint']], writeAttribute: [513, ['occupiedCoolingSetpoint']], value: 24 },
865
- { fn: 'currenttemp', label: 'Current temperature', read: [513, ['localTemperature']] },
866
- { fn: 'fanspeed', label: 'Fan speed', read: [514, ['percentCurrent', 'percentSetting']], writeAttribute: [514, ['percentSetting']], value: 60 },
867
- { fn: 'temperature', label: 'Temperature', read: [1026, ['measuredValue']] },
868
- { fn: 'humidity', label: 'Humidity', read: [1029, ['measuredValue']] },
869
- { fn: 'illuminance', label: 'Illuminance', read: [1024, ['measuredValue']] },
870
- { fn: 'occupancy', label: 'Occupancy', read: [1030, ['occupancy']] },
871
- { fn: 'contact', label: 'Contact', read: [69, ['stateValue']] },
872
- { fn: 'battery', label: 'Battery', read: [47, ['batPercentRemaining']] },
873
- { fn: 'activepower', label: 'Active power', read: [144, ['activePower']] },
874
- { fn: 'importedenergy', label: 'Imported energy', read: [145, ['cumulativeEnergyImported']] },
875
- { fn: 'identify', label: 'Identify', write: [3, ['identify']], omitValue: true }
876
- ];
877
- const inputStructureFor = (caps) => caps && caps.inputStructure && Array.isArray(caps.inputStructure.clusters)
878
- ? caps.inputStructure
879
- : null;
880
- const structureMember = (structure, targetKind, descriptor, writableOnly = false) => {
881
- if (!structure || !descriptor) return null;
882
- const cluster = structure.clusters.find((item) => Number(item.id) === Number(descriptor[0]));
883
- if (!cluster) return null;
884
- const collection = targetKind === 'command' ? cluster.commands : cluster.attributes;
885
- if (!Array.isArray(collection)) return null;
886
- const wanted = descriptor[1].map(normalizeMatterToken);
887
- return collection.find((item) =>
888
- wanted.includes(normalizeMatterToken(item.name)) &&
889
- (!writableOnly || item.writable === true)
890
- ) || null;
891
- };
892
- const functionCode = (payload) => `msg.payload = ${JSON.stringify(payload, null, 2)};\nreturn msg;`;
893
- const advancedCode = (kind, clusterId, name) => {
894
- if (kind === 'read') return `msg.clusterId = ${Number(clusterId)};\nmsg.attribute = ${JSON.stringify(name)};\nreturn msg;`;
895
- if (kind === 'write') return `msg.clusterId = ${Number(clusterId)};\nmsg.attribute = ${JSON.stringify(name)};\nmsg.value = 0;\nreturn msg;`;
896
- return `msg.clusterId = ${Number(clusterId)};\nmsg.command = ${JSON.stringify(name)};\nmsg.args = {};\nreturn msg;`;
897
- };
898
- const appendInputHelpRow = ($body, operation, label, code) => {
899
- const $row = $('<tr></tr>');
900
- $('<td></td>').text(operation).appendTo($row);
901
- $('<td></td>').text(label).appendTo($row);
902
- $('<td><code></code></td>').find('code').text(code).end().appendTo($row);
903
- $('<td></td>').append(
904
- $('<button type="button" class="red-ui-button matter-input-help-copy"><i class="fa fa-copy"></i></button>')
905
- .attr('title', node._('knxUltimateMatterControllerDevice.input_help_copy') || 'Copy')
906
- .data('copy-text', code)
907
- ).appendTo($row);
908
- $body.append($row);
909
- };
910
- const renderInputHelp = () => {
911
- const caps = getEffectiveMatterCapabilities();
912
- const structure = inputStructureFor(caps);
913
- const endpointId = structure ? structure.endpointId : Number($matterEndpointInput.val() || node.matterEndpointId || 1);
914
- const isMatterLight = !caps.profile;
915
- $('#matter-input-help-endpoint').text(String(endpointId));
916
- const $simpleBody = $('#matter-input-help-simple-body').empty();
917
- if (isMatterLight) {
918
- const writeLabel = node._('knxUltimateMatterControllerDevice.input_help_write') || 'Write';
919
- if (caps.onOff !== false) {
920
- appendInputHelpRow($simpleBody, writeLabel, node._('knxUltimateMatterControllerDevice.input_functions.on') || 'On', 'msg.on = { on: true };\nreturn msg;');
921
- appendInputHelpRow($simpleBody, writeLabel, node._('knxUltimateMatterControllerDevice.input_functions.off') || 'Off', 'msg.on = { on: false };\nreturn msg;');
922
- }
923
- if (caps.level !== false) {
924
- appendInputHelpRow($simpleBody, writeLabel, node._('knxUltimateMatterControllerDevice.input_functions.brightness') || 'Brightness', 'msg.dimming = { brightness: 50 };\nreturn msg;');
925
- }
926
- if (caps.colorTemperature === true) {
927
- appendInputHelpRow($simpleBody, writeLabel, node._('knxUltimateMatterControllerDevice.input_functions.color_temperature') || 'Colour temperature', 'msg.color_temperature = { mirek: 370 };\nreturn msg;');
928
- }
929
- if (caps.color === true) {
930
- appendInputHelpRow($simpleBody, writeLabel, node._('knxUltimateMatterControllerDevice.input_functions.xy_color') || 'XY colour', 'msg.color = { xy: { x: 0.675, y: 0.322 } };\nreturn msg;');
931
- }
932
- } else if (caps.profile === 'doorLock') {
933
- if (caps.lockDoor !== false) appendInputHelpRow($simpleBody, node._('knxUltimateMatterControllerDevice.input_help_write') || 'Write', node._('knxUltimateMatterControllerDevice.input_functions.lock') || 'Lock', functionCode({ function: 'lock', value: true }));
934
- if (caps.unlockDoor !== false) appendInputHelpRow($simpleBody, node._('knxUltimateMatterControllerDevice.input_help_write') || 'Write', node._('knxUltimateMatterControllerDevice.input_functions.unlock') || 'Unlock', functionCode({ function: 'lock', value: false }));
935
- } else {
936
- semanticInputDefinitions.forEach((definition) => {
937
- const readTarget = structureMember(structure, 'attribute', definition.read);
938
- const writeVariants = definition.writes || [{
939
- descriptor: definition.write || definition.writeAttribute,
940
- targetKind: definition.write ? 'command' : 'attribute',
941
- value: definition.value,
942
- omitValue: definition.omitValue
943
- }];
944
- writeVariants.forEach((variant) => {
945
- const targetKind = variant.targetKind || 'command';
946
- const writeTarget = structureMember(structure, targetKind, variant.descriptor, targetKind === 'attribute');
947
- if (!writeTarget) return;
948
- const payload = { function: definition.fn };
949
- if (!variant.omitValue) payload.value = variant.value;
950
- appendInputHelpRow($simpleBody, node._('knxUltimateMatterControllerDevice.input_help_write') || 'Write', node._(`knxUltimateMatterControllerDevice.input_functions.${definition.fn}`) || definition.label, functionCode(payload));
951
- });
952
- if (readTarget) {
953
- appendInputHelpRow($simpleBody, node._('knxUltimateMatterControllerDevice.input_help_read') || 'Read', node._(`knxUltimateMatterControllerDevice.input_functions.${definition.fn}`) || definition.label, functionCode({ function: definition.fn }));
954
- }
955
- });
956
- }
957
- $('#matter-input-help-simple-empty').toggle($simpleBody.children().length === 0);
958
- $('#matter-input-help-simple-hint').attr(
959
- 'data-i18n',
960
- isMatterLight
961
- ? 'knxUltimateMatterControllerDevice.input_help_light_hint'
962
- : 'knxUltimateMatterControllerDevice.input_help_simple_hint'
963
- ).text(node._(
964
- isMatterLight
965
- ? 'knxUltimateMatterControllerDevice.input_help_light_hint'
966
- : 'knxUltimateMatterControllerDevice.input_help_simple_hint'
967
- ) || '');
968
-
969
- const $advancedBody = $('#matter-input-help-advanced-body').empty();
970
- if (structure && !isMatterLight) {
971
- structure.clusters.forEach((cluster) => {
972
- (cluster.attributes || []).forEach((attribute) => {
973
- const prefix = `${cluster.name || 'Cluster'} (${cluster.id}) · ${attribute.name} (${attribute.id})`;
974
- appendInputHelpRow($advancedBody, node._('knxUltimateMatterControllerDevice.input_help_read') || 'Read', prefix, advancedCode('read', cluster.id, attribute.name));
975
- if (attribute.writable === true) {
976
- appendInputHelpRow($advancedBody, node._('knxUltimateMatterControllerDevice.input_help_write') || 'Write', prefix, advancedCode('write', cluster.id, attribute.name));
977
- }
978
- });
979
- (cluster.commands || []).forEach((command) => {
980
- const prefix = `${cluster.name || 'Cluster'} (${cluster.id}) · ${command.name}`;
981
- appendInputHelpRow($advancedBody, node._('knxUltimateMatterControllerDevice.input_help_command') || 'Command', prefix, advancedCode('command', cluster.id, command.name));
982
- });
983
- });
984
- }
985
- $('#matter-input-help-advanced-empty').toggle($advancedBody.children().length === 0);
986
- $('#matter-input-help-advanced-details').toggle(!isMatterLight);
987
- };
988
- const copyInputHelpText = (text) => {
989
- const copied = () => RED.notify(node._('knxUltimateMatterControllerDevice.input_help_copied') || 'Message copied', 'success');
990
- if (navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {
991
- navigator.clipboard.writeText(text).then(copied).catch(() => {
992
- const $temporary = $('<textarea></textarea>').val(text).appendTo('body').select();
993
- try { document.execCommand('copy'); copied(); } finally { $temporary.remove(); }
994
- });
995
- return;
996
- }
997
- const $temporary = $('<textarea></textarea>').val(text).appendTo('body').select();
998
- try { document.execCommand('copy'); copied(); } finally { $temporary.remove(); }
999
- };
1000
- $inputHelpPanel.off('click.matterInputHelp').on('click.matterInputHelp', '.matter-input-help-copy', function () {
1001
- copyInputHelpText($(this).data('copy-text') || '');
1002
- });
1003
- $tabs.addClass('hue-vertical-tabs');
1004
- $tabs.tabs(); // Tabs gestione KNX
1005
- $tabs.find('ul').addClass('ui-tabs-nav');
1006
- $tabs.find('li').removeClass('ui-corner-top').addClass('ui-corner-left');
1007
- $universalTabs.addClass('hue-vertical-tabs');
1008
- $universalTabs.tabs();
1009
- $universalTabs.find('ul').addClass('ui-tabs-nav');
1010
- $universalTabs.find('li').removeClass('ui-corner-top').addClass('ui-corner-left');
1011
-
1012
- function getDPT(_dpt, _destinationWidget) {
1013
- // DPT Switch command
1014
- // ########################
1015
- const prefixes = Array.isArray(_dpt) ? _dpt : [_dpt];
1016
- $(_destinationWidget).empty();
1017
- if (!hasKnxServerSelected()) {
1018
- return;
1019
- }
1020
- const serverId = resolveKnxServerValue();
1021
- $.getJSON(`knxUltimateDpts?serverId=${serverId}&_=${Date.now()}`, (data) => {
1022
- data.forEach((dpt) => {
1023
- if (prefixes.some((prefix) => prefix === "" || dpt.value.startsWith(prefix))) {
1024
- // Adjustment for Matter color temperature
1025
- if (dpt.value.startsWith("7.600")) {
1026
- $(_destinationWidget).append($("<option></option>").attr("value", dpt.value).text(dpt.text + " - KNX Kelvin range 2000-6535k (Homeassistant color_temperature_mode: absolute)"));
1027
- } else if (dpt.value.startsWith("9.002")) {
1028
- $(_destinationWidget).append($("<option></option>").attr("value", dpt.value).text(dpt.text + " - Matter Kelvin range 2000-6535 K (Home Assistant color_temperature_mode: absolute_float)"));
1029
- } else if (dpt.value.startsWith("5.001")) {
1030
- $(_destinationWidget).append($("<option></option>").attr("value", dpt.value).text(dpt.text + " - Homeassistant color_temperature_mode: relative"));
1031
- } else {
1032
- $(_destinationWidget).append($("<option></option>").attr("value", dpt.value).text(dpt.text));
1033
- }
1034
- }
1035
- });
1036
- // Eval
1037
- const format = "node." + _destinationWidget.replace("#node-input-", "");
1038
- try {
1039
- if (format !== undefined) $(_destinationWidget).val(eval(format).toString());
1040
- } catch (error) { }
1041
- });
1042
- }
1043
-
1044
- function getGroupAddress(_sourceWidgetAutocomplete, _destinationWidgetName, _destinationWidgetDPT, _additionalSearchTerm) {
1045
- $(_sourceWidgetAutocomplete).autocomplete({
1046
- minLength: 0,
1047
- source: function (request, response) {
1048
- if (!hasKnxServerSelected()) {
1049
- response([]);
1050
- return;
1051
- }
1052
- const serverId = resolveKnxServerValue();
1053
- $.getJSON(`knxUltimatecsv?nodeID=${serverId}&_=${Date.now()}`, (data) => {
1054
- response(
1055
- $.map(data, function (value, key) {
1056
- var sSearch = value.ga + " (" + value.devicename + ") DPT" + value.dpt;
1057
- for (let index = 0; index < _additionalSearchTerm.length; index++) {
1058
- const sDPT = _additionalSearchTerm[index];
1059
- if (htmlUtilsfullCSVSearch(sSearch, request.term + " " + sDPT)) {
1060
- return {
1061
- label: value.ga + " # " + value.devicename + " # " + value.dpt, // Label for Display
1062
- value: value.ga, // Value
1063
- };
1064
- }
1065
- };
1066
- })
1067
- );
1068
- });
1069
- },
1070
- select: function (event, ui) {
1071
- // Sets Datapoint and device name automatically
1072
- var sDevName = ui.item.label.split("#")[1].trim();
1073
- try {
1074
- sDevName = sDevName.substr(sDevName.indexOf(")") + 1).trim();
1075
- } catch (error) { }
1076
- $(_destinationWidgetName).val(sDevName);
1077
- var optVal = $(_destinationWidgetDPT + " option:contains('" + ui.item.label.split("#")[2].trim() + "')").attr("value");
1078
- const $dptSelect = $(_destinationWidgetDPT);
1079
- if (optVal !== undefined && optVal !== null) {
1080
- $dptSelect.val(optVal).trigger('change');
1081
- } else {
1082
- // Ensure downstream widgets refresh even when the DPT is missing
1083
- $dptSelect.trigger('change');
1084
- }
1085
- },
1086
- }).focus(function () {
1087
- $(this).autocomplete('search', $(this).val() + 'exactmatch');
1088
- });
1089
- try {
1090
- if (hasKnxServerSelected()) {
1091
- const srv = RED.nodes.node(resolveKnxServerValue());
1092
- if (srv && srv.id) KNX_enableSecureFormatting($(_sourceWidgetAutocomplete), srv.id);
1093
- }
1094
- } catch (e) { }
1095
- }
1096
-
1097
- function getFixedDptGroupAddress(_sourceWidgetAutocomplete, _destinationWidgetName, _dptPrefix) {
1098
- const $source = $(_sourceWidgetAutocomplete);
1099
- if ($source.data('ui-autocomplete')) {
1100
- try { $source.autocomplete('destroy'); } catch (error) { /* empty */ }
1101
- }
1102
- $source.autocomplete({
1103
- minLength: 0,
1104
- source: function (request, response) {
1105
- if (!hasKnxServerSelected()) {
1106
- response([]);
1107
- return;
1108
- }
1109
- const serverId = resolveKnxServerValue();
1110
- $.getJSON(`knxUltimatecsv?nodeID=${serverId}&_=${Date.now()}`, (data) => {
1111
- response($.map(data, function (value) {
1112
- const searchable = `${value.ga} (${value.devicename}) DPT${value.dpt}`;
1113
- if (!htmlUtilsfullCSVSearch(searchable, `${request.term || ''} ${_dptPrefix}`)) return null;
1114
- return {
1115
- label: `${value.ga} # ${value.devicename} # ${value.dpt}`,
1116
- value: value.ga,
1117
- deviceName: value.devicename
1118
- };
1119
- }));
1120
- });
1121
- },
1122
- select: function (event, ui) {
1123
- $(_destinationWidgetName).val(ui.item.deviceName || '');
1124
- }
1125
- }).focus(function () {
1126
- $(this).autocomplete('search', `${$(this).val()}exactmatch`);
1127
- });
1128
- try {
1129
- if (hasKnxServerSelected()) {
1130
- const srv = RED.nodes.node(resolveKnxServerValue());
1131
- if (srv && srv.id) KNX_enableSecureFormatting($source, srv.id);
1132
- }
1133
- } catch (error) { /* empty */ }
1134
- }
1135
-
1136
- const refreshKnxBindings = () => {
1137
- getFixedDptGroupAddress("#node-input-universalLowBatteryGA", "#node-input-universalLowBatteryGAName", "1.");
1138
- getFixedDptGroupAddress("#node-input-universalLowBatteryTextGA", "#node-input-universalLowBatteryTextGAName", "16.");
1139
-
1140
- getDPT("1.", "#node-input-dptLightSwitch");
1141
- getGroupAddress("#node-input-GALightSwitch", "#node-input-nameLightSwitch", "#node-input-dptLightSwitch", ["1."]);
1142
-
1143
- getDPT("1.", "#node-input-dptLightState");
1144
- getGroupAddress("#node-input-GALightState", "#node-input-nameLightState", "#node-input-dptLightState", ["1."]);
1145
-
1146
- getDPT("3.007", "#node-input-dptLightDIM");
1147
- getGroupAddress("#node-input-GALightDIM", "#node-input-nameLightDIM", "#node-input-dptLightDIM", ["3.007"]);
1148
-
1149
- getDPT("5.001", "#node-input-dptLightBrightness");
1150
- getGroupAddress("#node-input-GALightBrightness", "#node-input-nameLightBrightness", "#node-input-dptLightBrightness", ["5.001"]);
1151
-
1152
- getDPT("5.001", "#node-input-dptLightBrightnessState");
1153
- getGroupAddress("#node-input-GALightBrightnessState", "#node-input-nameLightBrightnessState", "#node-input-dptLightBrightnessState", ["5.001"]);
1154
-
1155
- getDPT("232.600", "#node-input-dptLightColor");
1156
- getGroupAddress("#node-input-GALightColor", "#node-input-nameLightColor", "#node-input-dptLightColor", ["232.600"]);
1157
-
1158
- getDPT("232.600", "#node-input-dptLightColorState");
1159
- getGroupAddress("#node-input-GALightColorState", "#node-input-nameLightColorState", "#node-input-dptLightColorState", ["232.600"]);
1160
-
1161
- getDPT("3.007", "#node-input-dptLightKelvinDIM");
1162
- getGroupAddress("#node-input-GALightKelvinDIM", "#node-input-nameLightKelvinDIM", "#node-input-dptLightKelvinDIM", ["3.007"]);
1163
-
1164
- getDPT("5.001", "#node-input-dptLightKelvinPercentage");
1165
- getGroupAddress("#node-input-GALightKelvinPercentage", "#node-input-nameLightKelvinPercentage", "#node-input-dptLightKelvinPercentage", ["5.001"]);
1166
-
1167
- getDPT("5.001", "#node-input-dptLightKelvinPercentageState");
1168
- getGroupAddress("#node-input-GALightKelvinPercentageState", "#node-input-nameLightKelvinPercentageState", "#node-input-dptLightKelvinPercentageState", ["5.001"]);
1169
-
1170
- getDPT("1.", "#node-input-dptLightBlink");
1171
- getGroupAddress("#node-input-GALightBlink", "#node-input-nameLightBlink", "#node-input-dptLightBlink", ["1."]);
1172
-
1173
- getDPT("1.", "#node-input-dptLightColorCycle");
1174
- getGroupAddress("#node-input-GALightColorCycle", "#node-input-nameLightColorCycle", "#node-input-dptLightColorCycle", ["1."]);
1175
-
1176
- getDPT("1.", "#node-input-dptDaylightSensor");
1177
- getGroupAddress("#node-input-GADaylightSensor", "#node-input-nameDaylightSensor", "#node-input-dptDaylightSensor", ["1."]);
1178
-
1179
- getDPT("7.600", "#node-input-dptLightKelvin");
1180
- getDPT("9.002", "#node-input-dptLightKelvin");
1181
- getDPT("9.002", "#node-input-dptLightKelvinState");
1182
- getDPT("7.600", "#node-input-dptLightKelvinState");
1183
- getGroupAddress("#node-input-GALightKelvin", "#node-input-nameLightKelvin", "#node-input-dptLightKelvin", ["7.600", "9.002"]);
1184
- getGroupAddress("#node-input-GALightKelvinState", "#node-input-nameLightKelvinState", "#node-input-dptLightKelvinState", ["7.600", "9.002"]);
1185
-
1186
- // HSV ----------------------
1187
- // H
1188
- getDPT("3.007", "#node-input-dptLightHSV_H_DIM");
1189
- getGroupAddress("#node-input-GALightHSV_H_DIM", "#node-input-nameLightHSV_H_DIM", "#node-input-dptLightHSV_H_DIM", ["3.007"]);
1190
-
1191
- getDPT("5.001", "#node-input-dptLightHSV_H_State");
1192
- getGroupAddress("#node-input-GALightHSV_H_State", "#node-input-nameLightHSV_H_State", "#node-input-dptLightHSV_H_State", ["5.001"]);
1193
-
1194
- // S
1195
- getDPT("3.007", "#node-input-dptLightHSV_S_DIM");
1196
- getGroupAddress("#node-input-GALightHSV_S_DIM", "#node-input-nameLightHSV_S_DIM", "#node-input-dptLightHSV_S_DIM", ["3.007"]);
1197
-
1198
- getDPT("5.001", "#node-input-dptLightHSV_S_State");
1199
- getGroupAddress("#node-input-GALightHSV_S_State", "#node-input-nameLightHSV_S_State", "#node-input-dptLightHSV_S_State", ["5.001"]);
1200
-
1201
- // V
1202
- getDPT("3.007", "#node-input-dptLightHSV_V_DIM");
1203
- getGroupAddress("#node-input-GALightHSV_V_DIM", "#node-input-nameLightHSV_V_DIM", "#node-input-dptLightHSV_V_DIM", ["3.007"]);
1204
-
1205
- getDPT("5.001", "#node-input-dptLightHSV_V_State");
1206
- getGroupAddress("#node-input-GALightHSV_V_State", "#node-input-nameLightHSV_V_State", "#node-input-dptLightHSV_V_State", ["5.001"]);
1207
- // END HSV ----------------------
1208
- };
1209
-
1210
- refreshKnxBindings();
1211
-
1212
- const getHueDeviceValue = ({ allowStored = false } = {}) => {
1213
- if ($hueDeviceInput.length) {
1214
- const domValue = $hueDeviceInput.val();
1215
- if (domValue !== undefined && domValue !== null && domValue !== '') {
1216
- return domValue;
1217
- }
1218
- }
1219
- if (node.matterNodeId !== undefined && node.matterNodeId !== null && node.matterNodeId !== '') {
1220
- return node.matterNodeId;
1221
- }
1222
- return '';
1223
- };
1224
-
1225
- const getEffectiveMatterCapabilities = () => {
1226
- return currentMatterCapabilities || {
1227
- known: false,
1228
- onOff: true,
1229
- level: true,
1230
- colorTemperature: true,
1231
- color: true
1232
- };
1233
- };
1234
-
1235
- const setMatterTabVisible = (tabId, visible) => {
1236
- const $link = $tabs.find(`a[href="#${tabId}"]`);
1237
- $link.closest('li').toggle(!!visible);
1238
- $(`#${tabId}`).toggle(!!visible);
1239
- };
1240
-
1241
- const ensureVisibleMatterTabSelected = () => {
1242
- const $active = $tabs.find('ul.ui-tabs-nav li.ui-tabs-active');
1243
- const isTabAvailable = function () { return $(this).css('display') !== 'none'; };
1244
- if ($active.length && $active.filter(isTabAvailable).length) return;
1245
- const $firstVisible = $tabs.find('ul.ui-tabs-nav li').filter(isTabAvailable).first();
1246
- if (!$firstVisible.length) return;
1247
- const visibleIndex = $tabs.find('ul.ui-tabs-nav li').index($firstVisible);
1248
- if (visibleIndex >= 0) {
1249
- try { $tabs.tabs('option', 'active', visibleIndex); } catch (error) { /* empty */ }
1250
- }
1251
- };
1252
-
1253
- const restrictSelectOptions = ($select, allowedValues, fallbackValue) => {
1254
- $select.find('option').each(function () {
1255
- const allowed = allowedValues.indexOf($(this).val()) !== -1;
1256
- $(this).prop('disabled', !allowed).toggle(allowed);
1257
- });
1258
- if (allowedValues.indexOf($select.val()) === -1) {
1259
- $select.val(fallbackValue);
1260
- }
1261
- };
1262
-
1263
- const refreshBehaviourVisibility = () => {
1264
- const switchOnMode = $("#node-input-specifySwitchOnBrightness").val();
1265
- if (switchOnMode === "yes") {
1266
- $("#divColorsAtSwitchOn").show();
1267
- $("#divTemperatureAtSwitchOn").hide();
1268
- } else if (switchOnMode === "temperature") {
1269
- $("#divColorsAtSwitchOn").hide();
1270
- $("#divTemperatureAtSwitchOn").show();
1271
- } else {
1272
- $("#divColorsAtSwitchOn").hide();
1273
- $("#divTemperatureAtSwitchOn").hide();
1274
- }
1275
-
1276
- const dayNightMode = $("#node-input-enableDayNightLighting").val();
1277
- if (dayNightMode === "yes") {
1278
- $("#divEnableDayNightLighting").show();
1279
- $("#divCCSBoxAtNightLighting").css({ border: "1px solid dimgrey", "border-radius": "12px", padding: "5px" });
1280
- $("#divColorsAtSwitchOnNightTime").show();
1281
- $("#divTemperatureAtSwitchOnNightTime").hide();
1282
- } else if (dayNightMode === "temperature") {
1283
- $("#divEnableDayNightLighting").show();
1284
- $("#divCCSBoxAtNightLighting").css({ border: "1px solid dimgrey", "border-radius": "12px", padding: "5px" });
1285
- $("#divColorsAtSwitchOnNightTime").hide();
1286
- $("#divTemperatureAtSwitchOnNightTime").show();
1287
- } else {
1288
- $("#divEnableDayNightLighting").hide();
1289
- $("#divCCSBoxAtNightLighting").css({ border: "", "border-radius": "", padding: "" });
1290
- $("#divColorsAtSwitchOnNightTime").hide();
1291
- $("#divTemperatureAtSwitchOnNightTime").hide();
1292
- }
1293
- };
1294
-
1295
- const applyMatterCapabilities = (capabilities) => {
1296
- currentMatterCapabilities = normalizeMatterCapabilities(capabilities) || null;
1297
- const caps = getEffectiveMatterCapabilities();
1298
- const hasHueDevice = getHueDeviceValue() !== '';
1299
- const supportsSwitch = hasHueDevice && caps.onOff !== false;
1300
- const supportsDim = hasHueDevice && caps.level !== false;
1301
- const supportsTemperature = hasHueDevice && caps.colorTemperature === true;
1302
- const supportsColor = hasHueDevice && caps.color === true;
1303
- const hasRichBehaviour = supportsDim && (supportsTemperature || supportsColor);
1304
- const isDoorLock = caps.profile === 'doorLock';
1305
- const isMapped = ['mapped', 'windowCovering', 'thermostat', 'fan', 'switch'].includes(caps.profile);
1306
- const isUniversal = caps.profile === 'universal' || isUniversalMode();
1307
- const knxSelected = hasKnxServerSelected();
1308
- const deviceTypeDisplay = String(caps.deviceTypeDisplay || '').trim();
1309
-
1310
- setMatterTabVisible('tabs-1', !isUniversal && knxSelected && supportsSwitch);
1311
- setMatterTabVisible('tabs-2', !isUniversal && knxSelected && supportsDim);
1312
- setMatterTabVisible('tabs-3', !isUniversal && knxSelected && supportsTemperature);
1313
- setMatterTabVisible('tabs-4', !isUniversal && knxSelected && supportsColor);
1314
- setMatterTabVisible('tabs-mapped', !isUniversal && knxSelected && isMapped);
1315
- setMatterTabVisible('tabs-6', !isUniversal && knxSelected && hasHueDevice);
1316
- $('#matter-universal-description').toggle(isUniversal);
1317
- $pinSelect.val(isUniversal ? 'yes' : $pinSelect.val()).prop('disabled', isUniversal);
1318
- updateLocateButtonState(false);
1319
- $('#matter-door-lock-options').toggle(isDoorLock);
1320
- $('#matter-switch-command-label').text(isDoorLock
1321
- ? (node._('knxUltimateMatterControllerDevice.door_lock_command') || 'Lock / unlock')
1322
- : (node._('knxUltimateMatterControllerDevice.control') || 'Control'));
1323
- $('#matter-switch-status-label').text(isDoorLock
1324
- ? (node._('knxUltimateMatterControllerDevice.door_lock_status') || 'Lock state')
1325
- : (node._('knxUltimateMatterControllerDevice.status') || 'Status'));
1326
- $('#matter-door-lock-command-warning').toggle(isDoorLock && (caps.lockDoor === false || caps.unlockDoor === false));
1327
- $('#matter-door-lock-pin-required').toggle(isDoorLock && caps.requirePinForRemoteOperation === true);
1328
- $('#matter-mapped-profile').toggle(isMapped);
1329
- if (isMapped) renderMappedProfile(caps.mappedTargets || []);
1330
- const showInputHelp = !isUniversal && hasHueDevice && $pinSelect.val() === 'yes';
1331
- $inputHelpPanel.toggle(showInputHelp);
1332
- if (showInputHelp) renderInputHelp();
1333
- $('#matter-selected-device-type-value').text(deviceTypeDisplay);
1334
- $('#matter-selected-device-type').toggle(hasHueDevice && deviceTypeDisplay !== '');
1335
- try { $tabs.tabs('refresh'); } catch (error) { /* empty */ }
1336
- ensureVisibleMatterTabSelected();
1337
-
1338
- $("#divUpdateKNXBrightnessStatusOnHUEOnOff").toggle(supportsDim);
1339
- $("#divBehaviourBrightness").toggle(hasRichBehaviour);
1340
- const switchOnAllowed = ['no'];
1341
- const nightAllowed = ['no'];
1342
- if (supportsColor) {
1343
- switchOnAllowed.push('yes');
1344
- nightAllowed.push('yes');
1345
- }
1346
- if (supportsTemperature) {
1347
- switchOnAllowed.push('temperature');
1348
- nightAllowed.push('temperature');
1349
- }
1350
- restrictSelectOptions($("#node-input-specifySwitchOnBrightness"), switchOnAllowed, 'no');
1351
- restrictSelectOptions($("#node-input-enableDayNightLighting"), nightAllowed, 'no');
1352
- refreshBehaviourVisibility();
1353
- };
1354
-
1355
- const parseMatterMappings = () => {
1356
- try { return JSON.parse($('#node-input-matterMappings').val() || node.matterMappings || '[]'); } catch (error) { return []; }
1357
- };
1358
- const renderMappedProfile = (targets) => {
1359
- const saved = parseMatterMappings();
1360
- const $body = $('#matter-mapped-profile-body').empty();
1361
- targets.forEach((target) => {
1362
- const key = `${target.direction}:${target.endpointId}:${target.clusterId}:${target.targetKind}:${target.target}`;
1363
- const previous = saved.find((item) => `${item.direction}:${item.endpointId}:${item.clusterId}:${item.targetKind}:${item.target}` === key) || {};
1364
- const $row = $('<div class="form-row matter-mapped-row" style="display:flex;align-items:center;"></div>').data('mapping', target);
1365
- const translated = node._(`knxUltimateMatterControllerDevice.mapped.${target.label}`);
1366
- $('<label style="width:220px; margin-right:10px;"></label>').text(translated || target.target).appendTo($row);
1367
- $('<label style="width:25px; margin:0 5px 0 0;">GA</label>').appendTo($row);
1368
- const $ga = $('<input class="matter-mapped-ga" type="text" placeholder="Ex: 1/1/1" style="width:100px; margin-right:18px;">').val(previous.ga || '').appendTo($row);
1369
- $('<label style="width:35px; margin:0 5px 0 0;">DPT</label>').appendTo($row);
1370
- const $dpt = $('<input class="matter-mapped-dpt" type="text" placeholder="DPT" style="width:140px;">').val(previous.dpt || target.dpt || '').appendTo($row);
1371
- $ga.autocomplete({
1372
- minLength: 0,
1373
- source(request, response) {
1374
- if (!hasKnxServerSelected()) { response([]); return; }
1375
- $.getJSON(`knxUltimatecsv?nodeID=${resolveKnxServerValue()}&_=${Date.now()}`, (data) => {
1376
- response($.map(data, (value) => {
1377
- const searchable = `${value.ga} ${value.devicename} ${value.dpt}`;
1378
- if (!htmlUtilsfullCSVSearch(searchable, request.term || '')) return null;
1379
- return { label: `${value.ga} # ${value.devicename} # ${value.dpt}`, value: value.ga, dpt: value.dpt };
1380
- }));
1381
- }).fail(() => response([]));
1382
- },
1383
- select(event, ui) { if (ui.item.dpt) $dpt.val(ui.item.dpt); }
1384
- }).focus(function () { $(this).autocomplete('search', $(this).val()); });
1385
- $body.append($row);
1386
- });
1387
- };
1388
-
1389
- const updateTabsVisibility = () => {
1390
- const hueDeviceSelected = getHueDeviceValue() !== '';
1391
- applyMatterCapabilities(currentMatterCapabilities);
1392
- const hasVisibleTab = $tabs.find('ul.ui-tabs-nav li').filter(function () {
1393
- return $(this).css('display') !== 'none';
1394
- }).length > 0;
1395
- const shouldShowTabs = !isUniversalMode() && hueDeviceSelected && hasVisibleTab;
1396
-
1397
- if (shouldShowTabs) {
1398
- $tabs.show();
1399
- try { $tabs.tabs('refresh'); } catch (error) { /* empty */ }
1400
- } else {
1401
- $tabs.hide();
1402
- }
1403
-
1404
- if ($pinSectionRow.length) {
1405
- $pinSectionRow.show();
1406
- }
1407
- };
1408
-
1409
- const refreshUniversalServiceVisibility = () => {
1410
- const universal = $matterControllerModeInput.val() === 'universal';
1411
- $('#matter-universal-options').toggle(universal);
1412
- $universalTabs.toggle(universal && $universalServiceInput.val() === 'batteryMonitor');
1413
- if ($universalTabs.is(':visible')) {
1414
- try { $universalTabs.tabs('refresh'); } catch (error) { /* empty */ }
1415
- }
1416
- };
1417
-
1418
- const applyControllerMode = () => {
1419
- const universal = $matterControllerModeInput.val() === 'universal';
1420
- $('#matter-device-section-title, #matter-device-row').toggle(!universal);
1421
- if (universal) {
1422
- const universalName = node._('knxUltimateMatterControllerDevice.universal_mode') || 'Universal Mode';
1423
- currentMatterCapabilities = universalMatterCapabilities();
1424
- selectedMatterDeviceName = universalName;
1425
- $deviceNameInput.val(universalName);
1426
- $hueDeviceInput.val(UNIVERSAL_NODE_ID);
1427
- $matterEndpointInput.val('');
1428
- $matterCapabilitiesInput.val(serializeMatterCapabilities(currentMatterCapabilities));
1429
- $nodeNameInput.val(node._('knxUltimateMatterControllerDevice.universal_controller_name') || 'Matter Universal Controller');
1430
- $pinSelect.val('yes');
1431
- } else if (String($hueDeviceInput.val() || '') === UNIVERSAL_NODE_ID) {
1432
- currentMatterCapabilities = null;
1433
- selectedMatterDeviceName = '';
1434
- $deviceNameInput.val('');
1435
- $hueDeviceInput.val('');
1436
- $matterEndpointInput.val('');
1437
- $matterCapabilitiesInput.val('');
1438
- }
1439
- refreshUniversalServiceVisibility();
1440
- applyMatterCapabilities(currentMatterCapabilities);
1441
- updateTabsVisibility();
1442
- };
1443
-
1444
- updateTabsVisibility();
1445
- applyControllerMode();
1446
-
1447
- $matterControllerModeInput.on('change.knxUltimateMatterControllerDevice', applyControllerMode);
1448
- $universalServiceInput.on('change.knxUltimateMatterControllerDevice', refreshUniversalServiceVisibility);
1449
-
1450
- $knxServerInput.on('change.knxUltimateMatterControllerDevice', function (event) {
1451
- const selectedValue = $(this).val();
1452
- if (shouldPreserveSelection(event, selectedValue, activeKnxServerId, KNX_EMPTY_VALUES)) {
1453
- // Node-RED 5 can briefly emit an empty placeholder while rebuilding
1454
- // config-node selectors. Restore the effective saved value so an
1455
- // untouched save and the mapping tabs both keep the KNX gateway.
1456
- $knxServerInput.val(activeKnxServerId);
1457
- updateTabsVisibility();
1458
- return;
1459
- }
1460
- activeKnxServerId = normalizeConfigSelection(selectedValue, KNX_EMPTY_VALUES);
1461
- // Selecting none only changes visibility. Keep the mounted GA/DPT
1462
- // controls intact so choosing the gateway again cannot lose values.
1463
- if (activeKnxServerId !== '') refreshKnxBindings();
1464
- updateTabsVisibility();
1465
- });
1466
-
1467
- $hueDeviceInput.on('change.knxUltimateMatterControllerDevice input.knxUltimateMatterControllerDevice', updateTabsVisibility);
1468
- $pinSelect.on('change.knxUltimateMatterControllerDevice', updateTabsVisibility);
1469
-
1470
- if (($deviceNameInput.val() || '').trim() !== '') {
1471
- applyHueDevicesPlaceholder(true);
1472
- } else {
1473
- applyHueDevicesPlaceholder(cachedHueDevices.length > 0);
1474
- }
1475
-
1476
- if ($deviceNameInput.length) {
1477
- if ($deviceNameInput.data('ui-autocomplete')) {
1478
- try { $deviceNameInput.autocomplete('destroy'); } catch (error) { /* empty */ }
1479
- }
1480
- $deviceNameInput.autocomplete({
1481
- minLength: 0,
1482
- source(request, response) {
1483
- fetchHueDevices(request.term, response);
1484
- },
1485
- select(event, ui) {
1486
- if (!ui.item || !ui.item.matterNodeId) {
1487
- event.preventDefault();
1488
- return;
1489
- }
1490
- $deviceNameInput.val(ui.item.value || '');
1491
- selectedMatterDeviceName = ui.item.value || '';
1492
- node.matterDeviceName = selectedMatterDeviceName;
1493
- node.name = selectedMatterDeviceName || node.name;
1494
- $nodeNameInput.val(node.name);
1495
- $hueDeviceInput.val(ui.item.matterNodeId);
1496
- node.matterNodeId = ui.item.matterNodeId;
1497
- $matterEndpointInput.val(ui.item.matterEndpointId);
1498
- node.matterEndpointId = ui.item.matterEndpointId;
1499
- currentMatterCapabilities = ui.item.matterCapabilities || null;
1500
- $matterCapabilitiesInput.val(currentMatterCapabilities ? serializeMatterCapabilities(currentMatterCapabilities) : '');
1501
- node.matterDeviceCapabilities = $matterCapabilitiesInput.val();
1502
- applyMatterCapabilities(currentMatterCapabilities);
1503
- updateTabsVisibility();
1504
- setTimeout(() => {
1505
- try { $deviceNameInput.autocomplete('close'); } catch (error) { /* empty */ }
1506
- }, 0);
1507
- },
1508
- focus(event, ui) {
1509
- event.preventDefault();
1510
- }
1511
- }).on('mousedown.knxUltimateMatterControllerDevicePicker', () => {
1512
- matterDevicePickerMouseDown = true;
1513
- }).on('focus.knxUltimateMatterControllerDevicePicker', function () {
1514
- if (!matterDevicePickerMouseDown) $(this).autocomplete('search', '');
1515
- }).on('click.knxUltimateMatterControllerDevicePicker', function () {
1516
- matterDevicePickerMouseDown = false;
1517
- const input = this;
1518
- setTimeout(() => $(input).autocomplete('search', ''), 0);
1519
- }).on('blur.knxUltimateMatterControllerDevicePicker', () => {
1520
- matterDevicePickerMouseDown = false;
1521
- }).on('input.knxUltimateMatterControllerDevice', function () {
1522
- const typedValue = $(this).val().trim();
1523
- if (typedValue === '' || typedValue !== selectedMatterDeviceName) {
1524
- $hueDeviceInput.val('');
1525
- $matterEndpointInput.val('');
1526
- $matterCapabilitiesInput.val('');
1527
- node.matterNodeId = '';
1528
- node.matterEndpointId = '';
1529
- node.matterDeviceCapabilities = '';
1530
- currentMatterCapabilities = null;
1531
- updateTabsVisibility();
1532
- }
1533
- });
1534
- }
1535
-
1536
- if ($refreshDevicesButton.length) {
1537
- $refreshDevicesButton.off('.knxUltimateMatterControllerDevice').on('click.knxUltimateMatterControllerDevice', () => {
1538
- cachedHueDevices = [];
1539
- node._cachedHueLightDevices = cachedHueDevices;
1540
- fetchHueDevices('', () => {
1541
- if ($deviceNameInput.length) {
1542
- $deviceNameInput.autocomplete('search', '');
1543
- }
1544
- }, { forceRefresh: true });
1545
- });
1546
- }
1547
-
1548
- if ($locateDeviceButton.length) {
1549
- $locateDeviceButton.off('.knxUltimateMatterControllerDevice').on('click.knxUltimateMatterControllerDevice', () => {
1550
- const desiredAction = locateSessionActive ? 'stop' : 'start';
1551
- performLocateRequest({ silent: false, action: desiredAction });
1552
- });
1553
- updateLocateButtonState(false);
1554
- }
1555
-
1556
- if ($hueServerInput.length) {
1557
- $hueServerInput.off('.knxUltimateMatterControllerDeviceDevices').on('change.knxUltimateMatterControllerDeviceDevices', function (event) {
1558
- const selectedValue = $(this).val();
1559
- if (shouldPreserveSelection(event, selectedValue, activeMatterServerId, HUE_EMPTY_SERVER_VALUES)) {
1560
- $hueServerInput.val(activeMatterServerId);
1561
- return;
1562
- }
1563
- const nextMatterServerId = normalizeConfigSelection(selectedValue, HUE_EMPTY_SERVER_VALUES);
1564
- if (nextMatterServerId === activeMatterServerId) return;
1565
- activeMatterServerId = nextMatterServerId;
1566
- cachedHueDevices = [];
1567
- node._cachedHueLightDevices = cachedHueDevices;
1568
- showingNoHueDevicesPlaceholder = false;
1569
- applyHueDevicesPlaceholder(true);
1570
- node.__locateSessionInfo = null;
1571
- updateLocateButtonState(false);
1572
- if ($hueDevicesLoading.length) {
1573
- $hueDevicesLoading.hide();
1574
- }
1575
- });
1576
- }
1577
-
1578
- node.__stopHueLocateSession = () => {
1579
- clearLocateAutoReset();
1580
- removeNodeRemovalListener();
1581
- const pending = locatePendingRequest;
1582
- if (pending && typeof pending.always === 'function') {
1583
- pending.always(() => {
1584
- if (node.__locateSessionInfo || locateSessionActive) {
1585
- const followUp = performLocateRequest({ silent: true, allowStoredContext: true, action: 'stop' });
1586
- if (!followUp || typeof followUp.then !== 'function') {
1587
- updateLocateButtonState(false);
1588
- }
1589
- } else {
1590
- updateLocateButtonState(false);
1591
- }
1592
- });
1593
- return;
1594
- }
1595
- if (locateSessionActive || (node.__locateSessionInfo && node.__locateSessionInfo.deviceId)) {
1596
- const request = performLocateRequest({ silent: true, allowStoredContext: true, action: 'stop' });
1597
- if (!request || typeof request.then !== 'function') {
1598
- updateLocateButtonState(false);
1599
- }
1600
- } else {
1601
- updateLocateButtonState(false);
1602
- }
1603
- };
1604
-
1605
- // Matter lights: expose the full switch-on options statically. The runtime
1606
- // sends only what the device supports; unsupported commands are ignored.
1607
- const populateSwitchOnCombos = () => {
1608
- $("#node-input-specifySwitchOnBrightness").empty()
1609
- .append($("<option>").val("no").text(node._("knxUltimateMatterControllerDevice.none")))
1610
- .append($("<option>").val("yes").text(node._("knxUltimateMatterControllerDevice.select_color")))
1611
- .append($("<option>").val("temperature").text(node._("knxUltimateMatterControllerDevice.select_temperature_brightness")));
1612
- $("#node-input-enableDayNightLighting").empty()
1613
- .append($("<option>").val("no").text(node._("knxUltimateMatterControllerDevice.opt_no")))
1614
- .append($("<option>").val("yes").text(node._("knxUltimateMatterControllerDevice.select_color")))
1615
- .append($("<option>").val("temperature").text(node._("knxUltimateMatterControllerDevice.select_temperature_brightness")));
1616
- $("#node-input-specifySwitchOnBrightness").val(node.specifySwitchOnBrightness);
1617
- $("#node-input-enableDayNightLighting").val(node.enableDayNightLighting);
1618
- // Live "Get current" reads are not available on this Matter path.
1619
- $("#getColorAtSwitchOnDayTimeButton").hide();
1620
- $("#getColorAtSwitchOnNightTimeButton").hide();
1621
- applyMatterCapabilities(currentMatterCapabilities);
1622
- };
1623
- populateSwitchOnCombos();
1624
-
1625
- const initialHueDeviceRaw = getHueDeviceValue();
1626
- if (initialHueDeviceRaw === '') {
1627
- updateTabsVisibility();
1628
- return;
1629
- }
1630
- $hueDeviceInput.val(initialHueDeviceRaw);
1631
- updateTabsVisibility();
1632
- fetchHueDevices('', () => { }, { forceRefresh: true });
1633
- $("#node-input-specifySwitchOnBrightness").on("change", function () {
1634
- refreshBehaviourVisibility();
1635
- if ($("#node-input-specifySwitchOnBrightness").val() === "yes") blinkBackground("#colorPickerDay");
1636
- });
1637
-
1638
- $("#node-input-enableDayNightLighting").on("change", function () {
1639
- refreshBehaviourVisibility();
1640
- if ($("#node-input-enableDayNightLighting").val() === "yes") blinkBackground("#colorPickerNight");
1641
- });
1642
-
1643
- // Live "Get current" reads do not exist on this Matter path; the buttons are
1644
- // hidden by populateSwitchOnCombos above.
1645
-
1646
- // Fill options for minDimLevel and maxDimLevel and comboBrightnessAtSwitchOn (for color brightness at switch on, with temperature toghedher)
1647
- for (let index = 100; index >= 0; index -= 5) {
1648
- if (index === 0) {
1649
- $("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "% " + node._("knxUltimateMatterControllerDevice.switch_off")));
1650
- $("#comboBrightnessAtSwitchOn").append($("<option>").val(index).text(index.toString() + "% " + node._("knxUltimateMatterControllerDevice.switch_off")));
1651
- $("#comboBrightnessAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + "% " + node._("knxUltimateMatterControllerDevice.switch_off")));
1652
- } else {
1653
- $("#node-input-minDimLevelLight").append($("<option>").val(index).text(index.toString() + "%"));
1654
- $("#comboBrightnessAtSwitchOn").append($("<option>").val(index).text(index.toString() + "%"));
1655
- $("#comboBrightnessAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + "%"));
1656
- }
1657
- }
1658
- // Temperatures, from 2000 to 6535K (circa)
1659
- for (let index = 2000; index <= 6500; index += 100) {
1660
- if (index === 2200) {
1661
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_2200")));
1662
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_2200")));
1663
- } else if (index === 2700) {
1664
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_2700")));
1665
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_2700")));
1666
- } else if (index === 3000) {
1667
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_3000")));
1668
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_3000")));
1669
- } else if (index === 3500) {
1670
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_3500_day")));
1671
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_3500_night")));
1672
- } else if (index === 4100) {
1673
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_4100_day")));
1674
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_4100_night")));
1675
- } else if (index === 5000) {
1676
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_5000_day")));
1677
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_5000_night")));
1678
- } else if (index === 6500) {
1679
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_6500_day")));
1680
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix") + " " + node._("knxUltimateMatterControllerDevice.temp_desc_6500_night")));
1681
- } else {
1682
- $("#comboTemperatureAtSwitchOn").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix")));
1683
- $("#comboTemperatureAtSwitchOnNightTime").append($("<option>").val(index).text(index.toString() + node._("knxUltimateMatterControllerDevice.k_suffix")));
1684
- }
1685
- }
1686
-
1687
-
1688
- // Calculate kelvin/color
1689
- let json;
1690
- node.colorAtSwitchOnDayTime = node.colorAtSwitchOnDayTime.replace("geen", "green"); // Old bug in "geen" property
1691
- node.colorAtSwitchOnNightTime = node.colorAtSwitchOnNightTime.replace("geen", "green"); // Old bug in "geen" property
1692
- try {
1693
- json = JSON.parse(node.colorAtSwitchOnDayTime);
1694
- } catch (error) {
1695
- console.log("json = JSON.parse(node.colorAtSwitchOnDayTime) in HTML: " + error.message)
1696
- }
1697
- if (json !== undefined && json.kelvin !== undefined) {
1698
- // Kelvin
1699
- $("#comboTemperatureAtSwitchOn").val(json.kelvin);
1700
- $("#comboBrightnessAtSwitchOn").val(json.brightness);
1701
- if (node.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('temperature'); // Adjust in case of mismatch (from old geen bug)
1702
- } else if (json !== undefined && json.red !== undefined) {
1703
- // Must transform RGB into HTML HEX color
1704
- try {
1705
- $("#node-input-colorAtSwitchOnDayTime").val("#" + rgbHex(json.red, json.green, json.blue));
1706
- } catch (error) {
1707
- }
1708
- $("#colorPickerDay").val($("#node-input-colorAtSwitchOnDayTime").val());
1709
- if (node.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('yes'); // Adjust in case of mismatch (from old geen bug)
1710
- } else {
1711
- // It's already an HEX color
1712
- $("#colorPickerDay").val(node.colorAtSwitchOnDayTime);
1713
- if (node.specifySwitchOnBrightness !== 'no') $("#node-input-specifySwitchOnBrightness").val('yes'); // Adjust in case of mismatch (from old geen bug)
1714
- }
1715
- //Night
1716
- json = undefined;
1717
- try {
1718
- json = JSON.parse(node.colorAtSwitchOnNightTime);
1719
- } catch (error) { }
1720
- if (json !== undefined && json.kelvin !== undefined) {
1721
- // Kelvin
1722
- $("#comboTemperatureAtSwitchOnNightTime").val(json.kelvin);
1723
- $("#comboBrightnessAtSwitchOnNightTime").val(json.brightness);
1724
- if (node.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('temperature'); // Adjust in case of mismatch (from old geen bug)
1725
- } else if (json !== undefined && json.red !== undefined) {
1726
- // Must transform RGB into HTML HEX color
1727
- try {
1728
- $("#node-input-colorAtSwitchOnNightTime").val("#" + rgbHex(json.red, json.green, json.blue));
1729
- } catch (error) {
1730
- }
1731
- $("#colorPickerNight").val($("#node-input-colorAtSwitchOnNightTime").val());
1732
- if (node.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('yes'); // Adjust in case of mismatch (from old geen bug)
1733
- } else {
1734
- // It's already an HEX color
1735
- $("#colorPickerNight").val(node.colorAtSwitchOnNightTime);
1736
- if (node.enableDayNightLighting !== 'no') $("#node-input-enableDayNightLighting").val('yes'); // Adjust in case of mismatch (from old geen bug)
1737
- }
1738
- applyMatterCapabilities(currentMatterCapabilities);
1739
-
1740
-
1741
- $("#comboTemperatureAtSwitchOn, #comboBrightnessAtSwitchOn").on("change", function () {
1742
- $("#node-input-colorAtSwitchOnDayTime").val('{ "kelvin":' + $("#comboTemperatureAtSwitchOn").val() + ', "brightness":' + $("#comboBrightnessAtSwitchOn").val() + ' }');
1743
- });
1744
- $("#comboTemperatureAtSwitchOnNightTime, #comboBrightnessAtSwitchOnNightTime").on("change", function () {
1745
- $("#node-input-colorAtSwitchOnNightTime").val('{ "kelvin":' + $("#comboTemperatureAtSwitchOnNightTime").val() + ', "brightness":' + $("#comboBrightnessAtSwitchOnNightTime").val() + ' }');
1746
- });
1747
-
1748
- // Create and put the JSON to node-input-colorAtSwitchOnDayTime
1749
- $("#colorPickerDay").on("change", function () {
1750
- $("#node-input-colorAtSwitchOnDayTime").val(this.value);
1751
- });
1752
- $("#colorPickerNight").on("change", function () {
1753
- $("#node-input-colorAtSwitchOnNightTime").val(this.value);
1754
- });
1755
-
1756
-
1757
- $("#node-input-minDimLevelLight").val(node.minDimLevelLight);
1758
- for (let index = 100; index >= 10; index--) {
1759
- $("#node-input-maxDimLevelLight").append(
1760
- $("<option>")
1761
- .val(index)
1762
- .text(index.toString() + "%")
1763
- );
1764
- }
1765
- $("#node-input-maxDimLevelLight").val(node.maxDimLevelLight);
1766
-
1767
- }
1768
-
1769
- function Go() {
1770
- $("#waitWindow").hide();
1771
- $("#mainWindow").show();
1772
- // $.post("banana", { func: "getNameAndTime" }, function (data) {
1773
- // //alert(data.body); // John
1774
- // }, "json");
1775
- try {
1776
- RED.sidebar.show("help");
1777
- } catch (error) { }
1778
- onEditPrepare();
1779
- }
1780
-
1781
-
1782
- // The Matter controller needs no readiness poll here: the light list is fetched
1783
- // on demand by the autocomplete. Start the editor immediately.
1784
- Go();
1785
- // ################################################################
1786
-
1787
- },
1788
-
1789
- oneditsave: function () {
1790
- // Return to the info tab
1791
- try {
1792
- RED.sidebar.show("info");
1793
- } catch (error) { }
1794
-
1795
- //RED.sidebar.removeTab("tabNRColor");
1796
- const universalMode = $("#node-input-matterControllerMode").val() === 'universal';
1797
- this.matterControllerMode = universalMode ? 'universal' : 'single';
1798
- if (universalMode || $("#node-input-enableNodePINS").val() === "yes") {
1799
- this.outputs = 1;
1800
- this.inputs = 1;
1801
- this.enableNodePINS = 'yes';
1802
- } else {
1803
- this.outputs = 0;
1804
- this.inputs = 0;
1805
- }
1806
-
1807
- this.updateLocalStateFromKNXWrite = $("#node-input-updateLocalStateFromKNXWrite").is(":checked"); // Starting from v 4.1.31
1808
- this.matterDeviceName = ($("#node-input-matterDeviceName").val() || '').trim();
1809
- this.matterNodeId = ($("#node-input-matterNodeId").val() || '').trim();
1810
- this.matterEndpointId = universalMode ? '' : Number($("#node-input-matterEndpointId").val() || 1);
1811
- this.matterDeviceCapabilities = ($("#node-input-matterDeviceCapabilities").val() || '').trim();
1812
- const mappedMappings = [];
1813
- const $mappedRows = $('#matter-mapped-profile-body .matter-mapped-row');
1814
- $mappedRows.each(function () {
1815
- const base = $(this).data('mapping') || {};
1816
- const ga = ($(this).find('.matter-mapped-ga').val() || '').trim();
1817
- const dpt = ($(this).find('.matter-mapped-dpt').val() || '').trim();
1818
- if (ga && dpt) mappedMappings.push(Object.assign({}, base, { ga, dpt }));
1819
- });
1820
- // Preserve saved mappings when the endpoint is offline and its asynchronous
1821
- // structure could not be rebuilt during an untouched editor round trip.
1822
- this.matterMappings = $mappedRows.length > 0
1823
- ? JSON.stringify(mappedMappings)
1824
- : ($('#node-input-matterMappings').val() || this.matterMappings || '[]');
1825
- $('#node-input-matterMappings').val(this.matterMappings);
1826
- this.name = universalMode
1827
- ? ($("#node-input-name").val() || this._('knxUltimateMatterControllerDevice.universal_controller_name') || 'Matter Universal Controller')
1828
- : (this.matterDeviceName || this.name || '');
1829
- $("#node-input-name").val(this.name);
1830
- const parseSavedMatterCapabilities = (raw) => {
1831
- if (typeof raw !== 'string' || raw.trim() === '') return null;
1832
- try {
1833
- return JSON.parse(raw);
1834
- } catch (error) {
1835
- return null;
1836
- }
1837
- };
1838
- const clearUnsupportedFields = (fields) => {
1839
- fields.forEach((field) => {
1840
- this[field] = '';
1841
- $(`#node-input-${field}`).val('');
1842
- });
1843
- };
1844
- const savedCapabilities = parseSavedMatterCapabilities(this.matterDeviceCapabilities);
1845
- if (savedCapabilities && savedCapabilities.known === true) {
1846
- if (savedCapabilities.onOff === false) {
1847
- clearUnsupportedFields(['nameLightSwitch', 'GALightSwitch', 'dptLightSwitch', 'nameLightState', 'GALightState', 'dptLightState', 'nameLightBlink', 'GALightBlink', 'dptLightBlink']);
1848
- }
1849
- if (savedCapabilities.level === false) {
1850
- clearUnsupportedFields(['nameLightDIM', 'GALightDIM', 'dptLightDIM', 'nameLightBrightness', 'GALightBrightness', 'dptLightBrightness', 'nameLightBrightnessState', 'GALightBrightnessState', 'dptLightBrightnessState']);
1851
- this.updateKNXBrightnessStatusOnHUEOnOff = 'no';
1852
- $("#node-input-updateKNXBrightnessStatusOnHUEOnOff").val('no');
1853
- }
1854
- if (savedCapabilities.colorTemperature !== true) {
1855
- clearUnsupportedFields(['nameLightKelvinDIM', 'GALightKelvinDIM', 'dptLightKelvinDIM', 'nameLightKelvinPercentage', 'GALightKelvinPercentage', 'dptLightKelvinPercentage', 'nameLightKelvinPercentageState', 'GALightKelvinPercentageState', 'dptLightKelvinPercentageState', 'nameLightKelvin', 'GALightKelvin', 'dptLightKelvin', 'nameLightKelvinState', 'GALightKelvinState', 'dptLightKelvinState']);
1856
- this.invertDimTunableWhiteDirection = false;
1857
- $("#node-input-invertDimTunableWhiteDirection").prop('checked', false);
1858
- }
1859
- if (savedCapabilities.color !== true) {
1860
- clearUnsupportedFields(['nameLightColor', 'GALightColor', 'dptLightColor', 'nameLightColorState', 'GALightColorState', 'dptLightColorState', 'nameLightHSV_H_DIM', 'GALightHSV_H_DIM', 'dptLightHSV_H_DIM', 'nameLightHSV_H_State', 'GALightHSV_H_State', 'dptLightHSV_H_State', 'nameLightHSV_S_DIM', 'GALightHSV_S_DIM', 'dptLightHSV_S_DIM', 'nameLightHSV_S_State', 'GALightHSV_S_State', 'dptLightHSV_S_State', 'nameLightColorCycle', 'GALightColorCycle', 'dptLightColorCycle']);
1861
- }
1862
- if (savedCapabilities.level === false || (savedCapabilities.color !== true && savedCapabilities.colorTemperature !== true)) {
1863
- this.specifySwitchOnBrightness = 'no';
1864
- this.enableDayNightLighting = 'no';
1865
- $("#node-input-specifySwitchOnBrightness").val('no');
1866
- $("#node-input-enableDayNightLighting").val('no');
1867
- }
1868
- }
1869
- this._cachedHueLightDevices = [];
1870
- if (typeof this.__stopHueLocateSession === 'function') {
1871
- try { this.__stopHueLocateSession(); } catch (error) { /* empty */ }
1872
- this.__stopHueLocateSession = null;
1873
- }
1874
- if (typeof this.__cleanupNodeRemovalListener === 'function') {
1875
- try { RED.events.removeListener('nodes:remove', this.__cleanupNodeRemovalListener); } catch (error) { /* empty */ }
1876
- this.__cleanupNodeRemovalListener = null;
1877
- }
1878
- this.__locateSessionInfo = null;
1879
- },
1880
- oneditcancel: function () {
1881
- // Return to the info tab
1882
- try {
1883
- RED.sidebar.show("info");
1884
- } catch (error) { }
1885
- //RED.sidebar.removeTab("tabNRColor");
1886
- //RED.sidebar.show("help");
1887
-
1888
- this._cachedHueLightDevices = [];
1889
- if (typeof this.__stopHueLocateSession === 'function') {
1890
- try { this.__stopHueLocateSession(); } catch (error) { /* empty */ }
1891
- this.__stopHueLocateSession = null;
1892
- }
1893
- if (typeof this.__cleanupNodeRemovalListener === 'function') {
1894
- try { RED.events.removeListener('nodes:remove', this.__cleanupNodeRemovalListener); } catch (error) { /* empty */ }
1895
- this.__cleanupNodeRemovalListener = null;
1896
- }
1897
- this.__locateSessionInfo = null;
1898
- },
1899
- oneditdelete: function () {
1900
- if (typeof this.oneditclose === 'function') {
1901
- try { this.oneditclose(); } catch (error) { /* empty */ }
1902
- }
1903
- },
1904
- oneditclose: function () {
1905
- if (typeof this.__stopHueLocateSession === 'function') {
1906
- try { this.__stopHueLocateSession(); } catch (error) { /* empty */ }
1907
- }
1908
- if (typeof this.__cleanupNodeRemovalListener === 'function') {
1909
- try { RED.events.removeListener('nodes:remove', this.__cleanupNodeRemovalListener); } catch (error) { /* empty */ }
1910
- this.__cleanupNodeRemovalListener = null;
1911
- }
1912
- this.__stopHueLocateSession = null;
1913
- this.__hueLocateActive = false;
1914
- this.__locateSessionInfo = null;
1915
- },
1916
- oneditresize: function (size) {
1917
- //var height = size.height;
1918
- //$('.editor-tray-content').css({ "width": "2700px" });
1919
- }
1920
- });
1921
-
1922
- function rgbHex(red, green, blue, alpha) {
1923
- const toHex = (red, green, blue, alpha) => ((blue | green << 8 | red << 16) | 1 << 24).toString(16).slice(1) + alpha;
1924
- const parseCssRgbString = (input) => {
1925
- const parts = input.replace(/rgba?\(([^)]+)\)/, '$1').split(/[,\s/]+/).filter(Boolean);
1926
- if (parts.length < 3) {
1927
- return;
1928
- }
1929
-
1930
- const parseValue = (value, max) => {
1931
- value = value.trim();
1932
-
1933
- if (value.endsWith('%')) {
1934
- return Math.min(Number.parseFloat(value) * max / 100, max);
1935
- }
1936
-
1937
- return Math.min(Number.parseFloat(value), max);
1938
- };
1939
-
1940
- const red = parseValue(parts[0], 255);
1941
- const green = parseValue(parts[1], 255);
1942
- const blue = parseValue(parts[2], 255);
1943
- let alpha;
1944
-
1945
- if (parts.length === 4) {
1946
- alpha = parseValue(parts[3], 1);
1947
- }
1948
-
1949
- return [red, green, blue, alpha];
1950
- };
1951
-
1952
- let isPercent = (red + (alpha || '')).toString().includes('%');
1953
-
1954
- if (typeof red === 'string' && !green) { // Single string parameter.
1955
- const parsed = parseCssRgbString(red);
1956
- if (!parsed) {
1957
- throw new TypeError('Invalid or unsupported color format.');
1958
- }
1959
-
1960
- isPercent = false;
1961
- [red, green, blue, alpha] = parsed;
1962
- } else if (alpha !== undefined) {
1963
- alpha = Number.parseFloat(alpha);
1964
- }
1965
-
1966
- if (typeof red !== 'number'
1967
- || typeof green !== 'number'
1968
- || typeof blue !== 'number'
1969
- || red > 255
1970
- || green > 255
1971
- || blue > 255
1972
- ) {
1973
- throw new TypeError('Expected three numbers below 256');
1974
- }
1975
-
1976
- if (typeof alpha === 'number') {
1977
- if (!isPercent && alpha >= 0 && alpha <= 1) {
1978
- alpha = Math.round(255 * alpha);
1979
- } else if (isPercent && alpha >= 0 && alpha <= 100) {
1980
- alpha = Math.round(255 * alpha / 100);
1981
- } else {
1982
- throw new TypeError(`Expected alpha value (${alpha}) as a fraction or percentage`);
1983
- }
1984
-
1985
- alpha = (alpha | 1 << 8).toString(16).slice(1); // eslint-disable-line no-mixed-operators
1986
- } else {
1987
- alpha = '';
1988
- }
1989
-
1990
- return toHex(red, green, blue, alpha);
1991
- }
1992
- }())
1993
-
1994
- </script>
1995
-
1996
-
1997
-
1998
- <script type="text/html" data-template-name="knxUltimateMatterControllerDevice">
1999
- <div class="form-row knx-ultimate-v8-upgrade-row">
2000
- <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">
2001
- <i class="fa fa-arrow-circle-up" aria-hidden="true"></i>
2002
- <span data-i18n="node-red-contrib-knx-ultimate/knxUltimateUtility:knxUltimateUtility.v8_upgrade.button"></span>
2003
- </button>
2004
- </div>
2005
- <div class="form-row" style="margin-bottom:10px;">
2006
- <span style="color:#ff0000"><i class="fa fa-youtube"></i></span>&nbsp;<a target="_blank" href="https://www.youtube.com/playlist?list=PL9Yh1bjbLAYrU8PsVhW4xzEug2WtVFv3E"><b>KNX-Ultimate video tutorials (YouTube playlist)</b></a>
2007
- </div>
2008
- <div id="waitWindow">
2009
- <br/><br/>
2010
- <p align="center">
2011
- <i class="fa-solid fa-hourglass-start fa-spin-pulse fa-2x"></i><br/><br/>
2012
- <span data-i18n="hue-config.properties.wait_message"></span>
2013
- </p>
2014
- </div>
2015
- <div id="mainWindow" hidden>
2016
- <div class="form-row">
2017
- <b><span data-i18n="knxUltimateMatterControllerDevice.title"></span></b>&nbsp&nbsp<span style="color:red" &nbsp &nbsp<i class="fa fa-youtube"></i></span>&nbsp<a
2018
- target="_blank" href="https://youtu.be/jjEUI1J8bkA"><u><span data-i18n="common.youtube_sample"></span></u></a>
2019
- <br />
2020
- <br />
2021
- <label for="node-input-server">
2022
- <img
2023
- src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKnRFWHRDcmVhdGlvbiBUaW1lAEZyIDYgQXVnIDIwMTAgMjE6NTI6MTkgKzAxMDD84aS8AAAAB3RJTUUH3gYYCicNV+4WIQAAAAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAACUSURBVHjaY2CgFZg5c+Z/ZEyWAZ8+f/6/ZsWs/xoamqMGkGrA6Wla/1+fVARjEBuGsSoGmY4eZSCNL59d/g8DIDbIAHR14OgFGQByKjIGKX5+6/T///8gGMQGiV1+/B0Fg70GIkD+RMYgxf/O5/7//2MSmAZhkBi6OrgB6Bg5DGB4ajr3f2xqsYYLSDE2THJUDg0AAAqyDVd4tp4YAAAAAElFTkSuQmCC"></img>
2024
- <span data-i18n="common.knx_gw"></span>
2025
- </label>
2026
- <input type="text" id="node-input-server" />
2027
- </div>
2028
-
2029
- <div class="form-row">
2030
- <label for="node-input-serverMatter">
2031
- <i class="fa fa-circle-nodes"></i>
2032
- <span data-i18n="knxUltimateMatterControllerDevice.matter_controller"></span>
2033
- </label>
2034
- <input type="text" id="node-input-serverMatter" />
2035
- </div>
2036
-
2037
- <div class="form-row">
2038
- <label for="node-input-matterControllerMode">
2039
- <i class="fa fa-list"></i>
2040
- <span data-i18n="knxUltimateMatterControllerDevice.controller_mode"></span>
2041
- </label>
2042
- <select id="node-input-matterControllerMode">
2043
- <option value="single" data-i18n="knxUltimateMatterControllerDevice.single_mode"></option>
2044
- <option value="universal" data-i18n="knxUltimateMatterControllerDevice.universal_mode"></option>
2045
- </select>
2046
- </div>
2047
-
2048
- <div id="matter-universal-description" class="form-tips" style="display:none; margin:8px 0;"
2049
- data-i18n="knxUltimateMatterControllerDevice.universal_mode_description"></div>
2050
-
2051
- <div id="matter-universal-options" style="display:none;">
2052
- <div class="form-row">
2053
- <label for="node-input-universalService">
2054
- <i class="fa fa-bell"></i>
2055
- <span data-i18n="knxUltimateMatterControllerDevice.universal_service"></span>
2056
- </label>
2057
- <select id="node-input-universalService">
2058
- <option value="batteryMonitor" data-i18n="knxUltimateMatterControllerDevice.universal_service_battery_monitor"></option>
2059
- <option value="allEvents" data-i18n="knxUltimateMatterControllerDevice.universal_service_all_events"></option>
2060
- </select>
2061
- </div>
2062
- <div id="matter-universal-tabs" style="display:none; width:900px;">
2063
- <ul>
2064
- <li>
2065
- <a href="#matter-universal-battery-options">
2066
- <i class="fa fa-battery-quarter"></i>
2067
- <span data-i18n="knxUltimateMatterControllerDevice.universal_service_battery_monitor"></span>
2068
- </a>
2069
- </li>
2070
- </ul>
2071
- <div id="matter-universal-battery-options">
2072
- <div class="form-row">
2073
- <label for="node-input-universalBatteryThreshold">
2074
- <i class="fa fa-battery-quarter"></i>
2075
- <span data-i18n="knxUltimateMatterControllerDevice.universal_battery_threshold"></span>
2076
- </label>
2077
- <input type="number" id="node-input-universalBatteryThreshold" min="0" max="100" step="1" style="width:100px;" />
2078
- <span style="margin-left:5px;">%</span>
2079
- </div>
2080
- <div class="form-row" style="display:flex; align-items:center; flex-wrap:nowrap; gap:5px;">
2081
- <label for="node-input-universalLowBatteryGA" style="width:155px; flex:0 0 155px; margin:0;">
2082
- <i class="fa fa-bell"></i>
2083
- <span data-i18n="knxUltimateMatterControllerDevice.universal_low_battery_ga"></span>
2084
- </label>
2085
-
2086
- <label for="node-input-universalLowBatteryGA" style="width:25px; flex:0 0 25px; margin:0;"><span data-i18n="common.ga"></span></label>
2087
- <input type="text" id="node-input-universalLowBatteryGA" placeholder="Ex: 1/1/1"
2088
- style="width:70px; flex:0 0 70px; margin:0; text-align:left;" />
2089
-
2090
- <label for="node-input-universalLowBatteryDPT" style="width:38px; flex:0 0 38px; margin:0; text-align:right;"><span data-i18n="common.dpt"></span></label>
2091
- <input type="text" id="node-input-universalLowBatteryDPT" value="1.005" readonly
2092
- style="width:75px; flex:0 0 75px; margin:0;" />
2093
-
2094
- <label for="node-input-universalLowBatteryGAName" style="width:45px; flex:0 0 45px; margin:0; text-align:right;"><span data-i18n="common.name"></span></label>
2095
- <input type="text" id="node-input-universalLowBatteryGAName"
2096
- style="width:auto; min-width:90px; flex:1 1 auto; margin:0; text-align:left;" />
2097
- </div>
2098
- <div class="form-row" style="display:flex; align-items:center; flex-wrap:nowrap; gap:5px;">
2099
- <label for="node-input-universalLowBatteryTextGA" style="width:155px; flex:0 0 155px; margin:0;">
2100
- <i class="fa fa-font"></i>
2101
- <span data-i18n="knxUltimateMatterControllerDevice.universal_low_battery_text_ga"></span>
2102
- </label>
2103
-
2104
- <label for="node-input-universalLowBatteryTextGA" style="width:25px; flex:0 0 25px; margin:0;"><span data-i18n="common.ga"></span></label>
2105
- <input type="text" id="node-input-universalLowBatteryTextGA" placeholder="Ex: 1/1/1"
2106
- style="width:70px; flex:0 0 70px; margin:0; text-align:left;" />
2107
-
2108
- <label for="node-input-universalLowBatteryTextDPT" style="width:38px; flex:0 0 38px; margin:0; text-align:right;"><span data-i18n="common.dpt"></span></label>
2109
- <input type="text" id="node-input-universalLowBatteryTextDPT" value="16.001" readonly
2110
- style="width:75px; flex:0 0 75px; margin:0;" />
2111
-
2112
- <label for="node-input-universalLowBatteryTextGAName" style="width:45px; flex:0 0 45px; margin:0; text-align:right;"><span data-i18n="common.name"></span></label>
2113
- <input type="text" id="node-input-universalLowBatteryTextGAName"
2114
- style="width:auto; min-width:90px; flex:1 1 auto; margin:0; text-align:left;" />
2115
- </div>
2116
- <div class="form-row">
2117
- <label for="node-input-universalBatteryOnlyLow" style="width:260px;">
2118
- <i class="fa fa-filter"></i>
2119
- <span data-i18n="knxUltimateMatterControllerDevice.universal_battery_only_low"></span>
2120
- </label>
2121
- <input type="checkbox" id="node-input-universalBatteryOnlyLow" style="display:inline-block; width:auto;" />
2122
- </div>
2123
- <div class="form-row">
2124
- <label for="node-input-universalEmitInitialState" style="width:260px;">
2125
- <i class="fa fa-camera"></i>
2126
- <span data-i18n="knxUltimateMatterControllerDevice.universal_emit_initial"></span>
2127
- </label>
2128
- <input type="checkbox" id="node-input-universalEmitInitialState" style="display:inline-block; width:auto;" />
2129
- </div>
2130
- <div class="form-row">
2131
- <label for="node-input-universalIncludeRawEvent" style="width:260px;">
2132
- <i class="fa fa-code"></i>
2133
- <span data-i18n="knxUltimateMatterControllerDevice.universal_include_raw"></span>
2134
- </label>
2135
- <input type="checkbox" id="node-input-universalIncludeRawEvent" style="display:inline-block; width:auto;" />
2136
- </div>
2137
- </div>
2138
- </div>
2139
- </div>
2140
-
2141
- <br />
2142
- <p id="matter-device-section-title">
2143
- <b><span data-i18n="knxUltimateMatterControllerDevice.matter_section"></span></b>
2144
- </p>
2145
-
2146
- <div class="form-row" id="matter-device-row">
2147
- <label for="node-input-matterDeviceName">
2148
- <i class="fa fa-play-circle"></i> <span data-i18n="knxUltimateMatterControllerDevice.matter_device"></span>
2149
- </label>
2150
- <input type="text" id="node-input-matterDeviceName" placeholder="Search your Matter light name"
2151
- style="flex:1 1 240px; min-width:240px; max-width:240px;" />
2152
- <button type="button" class="red-ui-button hue-refresh-devices"
2153
- style="margin-left:6px; color:#1b7d33; border-color:#1b7d33;" title="Refresh Matter lights">
2154
- <i class="fa fa-sync"></i>
2155
- </button>
2156
- <span class="hue-devices-loading" style="margin-left:6px; display:none; color:#1b7d33;">
2157
- <i class="fa fa-circle-notch fa-spin"></i>
2158
- </span>
2159
- <span id="matter-selected-device-type" style="display:none; margin-left:10px; color:#666; white-space:nowrap;">
2160
- <i class="fa fa-microchip"></i>
2161
- <span data-i18n="knxUltimateMatterControllerDevice.device_type"></span>:
2162
- <span id="matter-selected-device-type-value" style="font-weight:600;"></span>
2163
- </span>
2164
- <input type="hidden" id="node-input-matterNodeId" />
2165
- <input type="hidden" id="node-input-matterEndpointId" />
2166
- <input type="hidden" id="node-input-matterDeviceCapabilities" />
2167
- <input type="hidden" id="node-input-matterMappings" />
2168
- <input type="hidden" id="node-input-name" />
2169
- </div>
2170
-
2171
- <br />
2172
-
2173
- <div id="tabs" style="display:none; width: 900px;">
2174
- <ul>
2175
- <li><a href="#tabs-1"><i class="fa-solid fa-toggle-on"></i> <span data-i18n="knxUltimateMatterControllerDevice.tabs.switch"></span></a></li>
2176
- <li><a href="#tabs-2"><i class="fa-solid fa-arrow-up-wide-short"></i> <span data-i18n="knxUltimateMatterControllerDevice.tabs.dim"></span></a></li>
2177
- <li><a href="#tabs-3"><i class="fa-solid fa-temperature-quarter"></i> <span data-i18n="knxUltimateMatterControllerDevice.tabs.tunable_white"></span></a></li>
2178
- <li><a href="#tabs-4"><i class="fa-solid fa-palette"></i> <span data-i18n="knxUltimateMatterControllerDevice.tabs.rgb_hsv"></span></a></li>
2179
- <li><a href="#tabs-mapped"><i class="fa-solid fa-list-check"></i> <span data-i18n="knxUltimateMatterControllerDevice.tabs.mappings"></span></a></li>
2180
- <li><a href="#tabs-6"><i class="fa-solid fa-code-merge"></i> <span data-i18n="knxUltimateMatterControllerDevice.tabs.behaviour"></span></a></li>
2181
- </ul>
2182
- <div id="tabs-mapped">
2183
- <div id="matter-mapped-profile" style="display:none;">
2184
- <div id="matter-mapped-profile-body"></div>
2185
- </div>
2186
- </div>
2187
- <div id="tabs-1">
2188
- <p>
2189
- <div class="form-row">
2190
- <label for="node-input-nameLightSwitch" style="width:110px;"><i class="fa fa-play-circle-o"></i> <span id="matter-switch-command-label" data-i18n="knxUltimateMatterControllerDevice.control"></span></label>
2191
-
2192
- <label for="node-input-GALightSwitch" style="width:20px;"><span data-i18n="common.ga"></span></label>
2193
- <input type="text" id="node-input-GALightSwitch" placeholder="Ex: 1/1/1"
2194
- style="width:70px;margin-left: 5px; text-align: left;">
2195
-
2196
- <label for="node-input-dptLightSwitch" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2197
- <select id="node-input-dptLightSwitch" style="width:140px;"></select>
2198
-
2199
- <label for="node-input-nameLightSwitch" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
2200
- <input type="text" id="node-input-nameLightSwitch" style="width:190px;margin-left: 5px; text-align: left;">
2201
- </div>
2202
- <div class="form-row">
2203
- <label for="node-input-nameLightState" style="width:110px;"><i class="fa fa-question-circle"></i> <span id="matter-switch-status-label" data-i18n="knxUltimateMatterControllerDevice.status"></span></label>
2204
-
2205
- <label for="node-input-GALightState" style="width:20px;"><span data-i18n="common.ga"></span></label>
2206
- <input type="text" id="node-input-GALightState" placeholder="Ex: 1/1/1"
2207
- style="width:70px;margin-left: 5px; text-align: left;">
2208
-
2209
- <label for="node-input-dptLightState" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2210
- <select id="node-input-dptLightState" style="width:140px;"></select>
2211
-
2212
- <label for="node-input-nameLightState" style="width:50px; margin-left: 0px; text-align: right;"><span
2213
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2214
- <input type="text" id="node-input-nameLightState" style="width:190px;margin-left: 5px; text-align: left;">
2215
- </div>
2216
- <div id="matter-door-lock-options" style="display:none;">
2217
- <div class="form-row">
2218
- <label for="node-input-doorLockPin" style="width:260px;"><i class="fa fa-key"></i> <span data-i18n="knxUltimateMatterControllerDevice.door_lock_pin"></span></label>
2219
- <input type="password" id="node-input-doorLockPin" style="width:210px;" autocomplete="new-password">
2220
- </div>
2221
- <div id="matter-door-lock-pin-required" class="form-tips" style="display:none;" data-i18n="knxUltimateMatterControllerDevice.door_lock_pin_required"></div>
2222
- <div id="matter-door-lock-command-warning" class="form-tips" style="display:none; color:#a94442;" data-i18n="knxUltimateMatterControllerDevice.door_lock_commands_missing"></div>
2223
- </div>
2224
- </p>
2225
- </div>
2226
- <div id="tabs-2">
2227
- <p>
2228
- <img src="resources/node-red-contrib-knx-ultimate/dim.png" style="width: 900px;">
2229
- <div class="form-row">
2230
- <label for="node-input-nameLightDIM" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control dim</label>
2231
-
2232
- <label for="node-input-GALightDIM" style="width:20px;"><span data-i18n="common.ga"></span></label>
2233
- <input type="text" id="node-input-GALightDIM" placeholder="Ex: 1/1/1"
2234
- style="width:70px;margin-left: 5px; text-align: left;">
2235
-
2236
- <label for="node-input-dptLightDIM" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2237
- <select id="node-input-dptLightDIM" style="width:140px;"></select>
2238
-
2239
- <label for="node-input-nameLightDIM" style="width:50px; margin-left: 0px; text-align: right;"><span
2240
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2241
- <input type="text" id="node-input-nameLightDIM" style="width:190px;margin-left: 5px; text-align: left;">
2242
- </div>
2243
- <div class="form-row">
2244
- <label for="node-input-nameLightBrightness" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control
2245
- %</label>
2246
-
2247
- <label for="node-input-GALightBrightness" style="width:20px;"><span data-i18n="common.ga"></span></label>
2248
- <input type="text" id="node-input-GALightBrightness" placeholder="Ex: 1/1/1"
2249
- style="width:70px;margin-left: 5px; text-align: left;">
2250
-
2251
- <label for="node-input-dptLightBrightness" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2252
- <select id="node-input-dptLightBrightness" style="width:140px;"></select>
2253
-
2254
- <label for="node-input-nameLightBrightness" style="width:50px; margin-left: 0px; text-align: right;"><span
2255
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2256
- <input type="text" id="node-input-nameLightBrightness" style="width:190px;margin-left: 5px; text-align: left;">
2257
- </div>
2258
-
2259
- <div class="form-row">
2260
- <label for="node-input-nameLightBrightnessState" style="width:110px;"><i class="fa fa-question-circle"></i> Status %</label>
2261
-
2262
- <label for="node-input-GALightBrightnessState" style="width:20px;"><span
2263
- data-i18n="knxUltimateMatterControllerDevice.node-input-GALightState"></span></label>
2264
- <input type="text" id="node-input-GALightBrightnessState" placeholder="Ex: 1/1/1"
2265
- style="width:70px;margin-left: 5px; text-align: left;">
2266
-
2267
- <label for="node-input-dptLightBrightnessState"
2268
- style="width:40px; margin-left: 0px; text-align: right;">DPT</label>
2269
- <select id="node-input-dptLightBrightnessState" style="width:140px;"></select>
2270
-
2271
- <label for="node-input-nameLightBrightnessState" style="width:50px; margin-left: 0px; text-align: right;"><span
2272
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2273
- <input type="text" id="node-input-nameLightBrightnessState"
2274
- style="width:190px;margin-left: 5px; text-align: left;">
2275
- </div>
2276
- <div class="form-row">
2277
- <label for="node-input-dimSpeed" style="width:260px">
2278
- <i class="fa fa-bolt"></i> Dim Speed (ms)
2279
- </label>
2280
- <input type="text" id="node-input-dimSpeed" placeholder='Default is 5000' style="width:210px">
2281
- </div>
2282
- <div class="form-row">
2283
- <label for="node-input-minDimLevelLight" style="width:260px;">
2284
- <i class="fa fa-clone"></i> Min Dim Brightness
2285
- </label>
2286
- <select id="node-input-minDimLevelLight">
2287
- <option value="useHueLightLevel" data-i18n="knxUltimateMatterControllerDevice.use_min_brightness"></option>
2288
- </select>
2289
- </div>
2290
- <div class="form-row">
2291
- <label for="node-input-maxDimLevelLight" style="width:260px;">
2292
- <i class="fa fa-clone"></i> Max Dim Brightness
2293
- </label>
2294
- <select id="node-input-maxDimLevelLight"></select>
2295
- </div>
2296
- </p>
2297
- </div>
2298
- <div id="tabs-3">
2299
- <p>
2300
- <img src="resources/node-red-contrib-knx-ultimate/tunablewhite.png" style="width: 900px;">
2301
- <div class="form-row">
2302
- <label for="node-input-nameLightKelvinDIM" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control dim</label>
2303
-
2304
- <label for="node-input-GALightKelvinDIM" style="width:20px;"><span data-i18n="common.ga"></span></label>
2305
- <input type="text" id="node-input-GALightKelvinDIM" placeholder="Ex: 1/1/1"
2306
- style="width:70px;margin-left: 5px; text-align: left;">
2307
-
2308
- <label for="node-input-dptLightKelvinDIM" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2309
- <select id="node-input-dptLightKelvinDIM" style="width:140px;"></select>
2310
-
2311
- <label for="node-input-nameLightKelvinDIM" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
2312
- <input type="text" id="node-input-nameLightKelvinDIM" style="width:190px;margin-left: 5px; text-align: left;">
2313
- </div>
2314
- <div class="form-row">
2315
- <label for="node-input-nameLightKelvinPercentage" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control
2316
- %</label>
2317
-
2318
- <label for="node-input-GALightKelvinPercentage" style="width:20px;"><span data-i18n="common.ga"></span></label>
2319
- <input type="text" id="node-input-GALightKelvinPercentage" placeholder="Ex: 1/1/1"
2320
- style="width:70px;margin-left: 5px; text-align: left;">
2321
-
2322
- <label for="node-input-dptLightKelvinPercentage" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2323
- <select id="node-input-dptLightKelvinPercentage" style="width:140px;"></select>
2324
-
2325
- <label for="node-input-nameLightKelvinPercentage"
2326
- style="width:50px; margin-left: 0px; text-align: right;">Name</label>
2327
- <input type="text" id="node-input-nameLightKelvinPercentage" style="width:190px;margin-left: 5px; text-align: left;">
2328
- </div>
2329
- <div class="form-row">
2330
- <label for="node-input-nameLightKelvinPercentageState" style="width:110px;"><i class="fa fa-question-circle"></i> Status
2331
- %</label>
2332
-
2333
- <label for="node-input-GALightKelvinPercentageState" style="width:20px;"><span data-i18n="common.ga"></span></label>
2334
- <input type="text" id="node-input-GALightKelvinPercentageState" placeholder="Ex: 1/1/1"
2335
- style="width:70px;margin-left: 5px; text-align: left;">
2336
-
2337
- <label for="node-input-dptLightKelvinPercentageState" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2338
- <select id="node-input-dptLightKelvinPercentageState" style="width:140px;"></select>
2339
-
2340
- <label for="node-input-nameLightKelvinPercentageState" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
2341
- <input type="text" id="node-input-nameLightKelvinPercentageState" style="width:190px;margin-left: 5px; text-align: left;">
2342
- </div>
2343
- <div class="form-row">
2344
- <label for="node-input-nameLightKelvin" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control
2345
- Kelvin</label>
2346
-
2347
- <label for="node-input-GALightKelvin" style="width:20px;"><span data-i18n="common.ga"></span></label>
2348
- <input type="text" id="node-input-GALightKelvin" placeholder="Ex: 1/1/1"
2349
- style="width:70px;margin-left: 5px; text-align: left;">
2350
-
2351
- <label for="node-input-dptLightKelvin" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2352
- <select id="node-input-dptLightKelvin" style="width:140px;"></select>
2353
-
2354
- <label for="node-input-nameLightKelvin" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
2355
- <input type="text" id="node-input-nameLightKelvin" style="width:190px;margin-left: 5px; text-align: left;">
2356
- </div>
2357
- <div class="form-row">
2358
- <label for="node-input-nameLightKelvinState" style="width:110px;"><i class="fa fa-question-circle"></i> Status
2359
- Kelvin</label>
2360
- <label for="node-input-GALightKelvinState" style="width:20px;"><span data-i18n="common.ga"></span></label>
2361
- <input type="text" id="node-input-GALightKelvinState" placeholder="Ex: 1/1/1"
2362
- style="width:70px;margin-left: 5px; text-align: left;">
2363
-
2364
- <label for="node-input-dptLightKelvinState" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2365
- <select id="node-input-dptLightKelvinState" style="width:140px;"></select>
2366
-
2367
- <label for="node-input-nameLightKelvinState" style="width:50px; margin-left: 0px; text-align: right;"><span data-i18n="common.name"></span></label>
2368
- <input type="text" id="node-input-nameLightKelvinState" style="width:190px;margin-left: 5px; text-align: left;">
2369
- </div>
2370
- <div class="form-row">
2371
- <label style="width:170px" for="node-input-invertDimTunableWhiteDirection">
2372
- <i class="fa fa-shuffle"></i> Invert dim direction
2373
- </label>
2374
- <input type="checkbox" id="node-input-invertDimTunableWhiteDirection"
2375
- style="display:inline-block; width:auto; vertical-align:top;" />
2376
- </div>
2377
- </p>
2378
- </div>
2379
- <div id="tabs-4">
2380
- <p>
2381
- <img src="resources/node-red-contrib-knx-ultimate/rgb.png" style="width: 900px;">
2382
- <p><b> RGB section</b></p>
2383
- <div class="form-row">
2384
- <label for="node-input-nameLightColor" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control rgb</label>
2385
-
2386
- <label for="node-input-GALightColor" style="width:20px;"><span
2387
- data-i18n="knxUltimateMatterControllerDevice.node-input-GALightState"></span></label>
2388
- <input type="text" id="node-input-GALightColor" placeholder="Ex: 1/1/1"
2389
- style="width:70px;margin-left: 5px; text-align: left;">
2390
-
2391
- <label for="node-input-dptLightColor" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2392
- <select id="node-input-dptLightColor" style="width:140px;"></select>
2393
-
2394
- <label for="node-input-nameLightColor" style="width:50px; margin-left: 0px; text-align: right;"><span
2395
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2396
- <input type="text" id="node-input-nameLightColor" style="width:190px;margin-left: 5px; text-align: left;">
2397
- </div>
2398
- <div class="form-row">
2399
- <label for="node-input-nameLightColorState" style="width:110px;"><i class="fa fa-question-circle"></i> Status rgb</label>
2400
-
2401
- <label for="node-input-GALightColorState" style="width:20px;"><span
2402
- data-i18n="knxUltimateMatterControllerDevice.node-input-GALightState"></span></label>
2403
- <input type="text" id="node-input-GALightColorState" placeholder="Ex: 1/1/1"
2404
- style="width:70px;margin-left: 5px; text-align: left;">
2405
-
2406
- <label for="node-input-dptLightColorState" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2407
- <select id="node-input-dptLightColorState" style="width:140px;"></select>
2408
-
2409
- <label for="node-input-nameLightColorState" style="width:50px; margin-left: 0px; text-align: right;"><span
2410
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2411
- <input type="text" id="node-input-nameLightColorState" style="width:190px;margin-left: 5px; text-align: left;">
2412
- </div>
2413
-
2414
- <p><b> HSV section</b></p>
2415
- <!-- // HSV Color change
2416
- // nameLightHSV_H_DIM: { value: "" },
2417
- // GALightHSV_H_DIM: { value: "" },
2418
- // dptLightHSV_H_DIM: { value: "" }, -->
2419
- <div class="form-row">
2420
- <label for="node-input-nameLightHSV_H_DIM" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control H dim</label>
2421
-
2422
- <label for="node-input-GALightHSV_H_DIM" style="width:20px;"><span
2423
- data-i18n="knxUltimateMatterControllerDevice.node-input-GALightState"></span></label>
2424
- <input type="text" id="node-input-GALightHSV_H_DIM" placeholder="Ex: 1/1/1"
2425
- style="width:70px;margin-left: 5px; text-align: left;">
2426
-
2427
- <label for="node-input-dptLightHSV_H_DIM" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2428
- <select id="node-input-dptLightHSV_H_DIM" style="width:140px;"></select>
2429
-
2430
- <label for="node-input-nameLightHSV_H_DIM" style="width:50px; margin-left: 0px; text-align: right;"><span
2431
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2432
- <input type="text" id="node-input-nameLightHSV_H_DIM" style="width:190px;margin-left: 5px; text-align: left;">
2433
- </div>
2434
- <div class="form-row">
2435
- <label for="node-input-nameLightHSV_H_State" style="width:110px;"><i class="fa fa-question-circle"></i> Status H %</label>
2436
-
2437
- <label for="node-input-GALightHSV_H_State" style="width:20px;"><span
2438
- data-i18n="knxUltimateMatterControllerDevice.node-input-GALightState"></span></label>
2439
- <input type="text" id="node-input-GALightHSV_H_State" placeholder="Ex: 1/1/1"
2440
- style="width:70px;margin-left: 5px; text-align: left;">
2441
-
2442
- <label for="node-input-dptLightHSV_H_State" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2443
- <select id="node-input-dptLightHSV_H_State" style="width:140px;"></select>
2444
-
2445
- <label for="node-input-nameLightHSV_H_State" style="width:50px; margin-left: 0px; text-align: right;"><span
2446
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2447
- <input type="text" id="node-input-nameLightHSV_H_State" style="width:190px;margin-left: 5px; text-align: left;">
2448
- </div>
2449
-
2450
- <!-- // HSV Saturation change
2451
- nameLightHSV_S_DIM: { value: "" },
2452
- GALightHSV_S_DIM: { value: "" },
2453
- dptLightHSV_S_DIM: { value: "" },
2454
- nameLightHSV_S_State: { value: "" },
2455
- GALightHSV_S_State: { value: "" },
2456
- dptLightHSV_S_State: { value: "" }, -->
2457
- <div class="form-row">
2458
- <label for="node-input-nameLightHSV_S_DIM" style="width:110px;"><i class="fa fa-play-circle-o"></i> Control S dim</label>
2459
-
2460
- <label for="node-input-GALightHSV_S_DIM" style="width:20px;"><span
2461
- data-i18n="knxUltimateMatterControllerDevice.node-input-GALightState"></span></label>
2462
- <input type="text" id="node-input-GALightHSV_S_DIM" placeholder="Ex: 1/1/1"
2463
- style="width:70px;margin-left: 5px; text-align: left;">
2464
-
2465
- <label for="node-input-dptLightHSV_S_DIM" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2466
- <select id="node-input-dptLightHSV_S_DIM" style="width:140px;"></select>
2467
-
2468
- <label for="node-input-nameLightHSV_S_DIM" style="width:50px; margin-left: 0px; text-align: right;"><span
2469
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2470
- <input type="text" id="node-input-nameLightHSV_S_DIM" style="width:190px;margin-left: 5px; text-align: left;">
2471
- </div>
2472
- <div class="form-row">
2473
- <label for="node-input-nameLightHSV_S_State" style="width:110px;"><i class="fa fa-question-circle"></i> Status S %</label>
2474
-
2475
- <label for="node-input-GALightHSV_S_State" style="width:20px;"><span
2476
- data-i18n="knxUltimateMatterControllerDevice.node-input-GALightState"></span></label>
2477
- <input type="text" id="node-input-GALightHSV_S_State" placeholder="Ex: 1/1/1"
2478
- style="width:70px;margin-left: 5px; text-align: left;">
2479
-
2480
- <label for="node-input-dptLightHSV_S_State" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2481
- <select id="node-input-dptLightHSV_S_State" style="width:140px;"></select>
2482
-
2483
- <label for="node-input-nameLightHSV_S_State" style="width:50px; margin-left: 0px; text-align: right;"><span
2484
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2485
- <input type="text" id="node-input-nameLightHSV_S_State" style="width:190px;margin-left: 5px; text-align: left;">
2486
- </div>
2487
-
2488
- <!-- // HSV V Brightness change
2489
- nameLightHSV_V_DIM: { value: "" },
2490
- GALightHSV_V_DIM: { value: "" },
2491
- dptLightHSV_V_DIM: { value: "" },
2492
- nameLightHSV_V_State: { value: "" },
2493
- GALightHSV_V_State: { value: "" },
2494
- dptLightHSV_V_State: { value: "" }, -->
2495
- <div class="form-row">
2496
- <label for="node-input-HSVDimSpeed" style="width:260px">
2497
- <i class="fa fa-bolt"></i> Dim Speed (ms)
2498
- </label>
2499
- <input type="text" id="node-input-HSVDimSpeed" placeholder='Default is 5000' style="width:210px">
2500
- </div>
2501
-
2502
- </p>
2503
- </div>
2504
- <div id="tabs-6">
2505
- <p>
2506
- <div class="form-row">
2507
- <label style="width:260px;" for="node-input-readStatusAtStartup"><i class="fa fa-question-circle"></i> <span data-i18n="knxUltimateMatterControllerDevice.read_status_startup"></span></label>
2508
- <select id="node-input-readStatusAtStartup">
2509
- <option value="no" data-i18n="knxUltimateMatterControllerDevice.opt_no"></option>
2510
- <option value="yes" data-i18n="knxUltimateMatterControllerDevice.opt_yes_emit"></option>
2511
- </select>
2512
- </div>
2513
- <div class="form-row" id="divUpdateKNXBrightnessStatusOnHUEOnOff">
2514
- <label style="width:260px;" for="node-input-updateKNXBrightnessStatusOnHUEOnOff">
2515
- <i class="fa fa-tag"></i> <span data-i18n="knxUltimateMatterControllerDevice.knx_brightness_status"></span>
2516
- </label>
2517
- <select id="node-input-updateKNXBrightnessStatusOnHUEOnOff">
2518
- <option value="onhueoff" data-i18n="knxUltimateMatterControllerDevice.knx_brightness_onhueoff"></option>
2519
- <option value="no" data-i18n="knxUltimateMatterControllerDevice.knx_brightness_no"></option>
2520
- </select>
2521
- </div>
2522
- <div class="form-row">
2523
- <label style="width:260px;" for="node-input-updateLocalStateFromKNXWrite">
2524
- <i class="fa fa-database"></i> <span data-i18n="knxUltimateMatterControllerDevice.update_local_state_from_knx_write"></span>
2525
- </label>
2526
- <input type="checkbox" id="node-input-updateLocalStateFromKNXWrite" style="display:inline-block; width:auto; vertical-align:top;" />
2527
- </div>
2528
- <div id ="divBehaviourBrightness">
2529
- <div class="form-row">
2530
- <label for="node-input-specifySwitchOnBrightness" style="width:260px;">
2531
- <i class="fa fa-tag"></i> <span data-i18n="knxUltimateMatterControllerDevice.switch_on_behaviour"></span>
2532
- </label>
2533
- <select id="node-input-specifySwitchOnBrightness">
2534
- <option value="no" data-i18n="knxUltimateMatterControllerDevice.none"></option>
2535
- <option value="temperature" data-i18n="knxUltimateMatterControllerDevice.select_temperature_brightness"></option>
2536
- <option value="yes" data-i18n="knxUltimateMatterControllerDevice.select_color"></option>
2537
- </select>
2538
- </div>
2539
-
2540
- <div class="form-row" id="divColorsAtSwitchOn">
2541
- <label for="node-input-colorAtSwitchOnDayTime" style="width:260px">
2542
- </label>
2543
- <input type="hidden" id="node-input-colorAtSwitchOnDayTime">
2544
- <input type="color" id="colorPickerDay" style="width:260px">
2545
- <button id="getColorAtSwitchOnDayTimeButton" type="button" class="red-ui-button"><span data-i18n="knxUltimateMatterControllerDevice.get_current"></span></button>
2546
- </div>
2547
- <div class="form-row" id="divTemperatureAtSwitchOn" hidden>
2548
- <label for="node-input-colorAtSwitchOnDayTime" style="width:260px">
2549
- </label>
2550
- <select style="width:12%;" id="comboTemperatureAtSwitchOn"></select>
2551
- <select style="width:25%;" id="comboBrightnessAtSwitchOn"></select>
2552
- </div>
2553
-
2554
- <div id="divCCSBoxAtNightLighting">
2555
- <div class="form-row">
2556
- <label for="node-input-enableDayNightLighting" style="width:260px;">
2557
- <i class="fa fa-clone"></i> <span data-i18n="knxUltimateMatterControllerDevice.night_lighting"></span>
2558
- </label>
2559
- <select id="node-input-enableDayNightLighting">
2560
- <option value="no" data-i18n="knxUltimateMatterControllerDevice.no_night_lighting"></option>
2561
- <!-- <option value="temperature">Select temperature and brightness</option>
2562
- <option value="yes">Select color</option> -->
2563
- </select>
2564
- </div>
2565
-
2566
- <div id="divEnableDayNightLighting">
2567
-
2568
- <div class="form-row" id="divColorsAtSwitchOnNightTime">
2569
- <label for="node-input-colorAtSwitchOnNightTime" style="width:260px"></label>
2570
- <input type="hidden" id="node-input-colorAtSwitchOnNightTime">
2571
- <input type="color" id="colorPickerNight" style="width:260px">
2572
- <button id="getColorAtSwitchOnNightTimeButton" type="button" class="red-ui-button"><span data-i18n="knxUltimateMatterControllerDevice.get_current"></span></button>
2573
- </div>
2574
- <div class="form-row" id="divTemperatureAtSwitchOnNightTime" hidden>
2575
- <label for="node-input-colorAtSwitchOnNightTime" style="width:260px"></label>
2576
- <select style="width:25%;" id="comboTemperatureAtSwitchOnNightTime"></select>
2577
- <select style="width:25%;" id="comboBrightnessAtSwitchOnNightTime"></select>
2578
- </div>
2579
-
2580
- <div class="form-row">
2581
- <label for="node-input-nameDaylightSensor" style="width:110px;"><i class="fa fa-clock-o"></i>
2582
- <span data-i18n="knxUltimateMatterControllerDevice.day_night"></span></label>
2583
- <label for="node-input-GADaylightSensor" style="width:20px;"><span data-i18n="common.ga"></span></label>
2584
- <input type="text" id="node-input-GADaylightSensor" placeholder="Ex: 1/1/1"
2585
- style="width:70px;margin-left: 5px; text-align: left;">
2586
-
2587
- <label for="node-input-dptDaylightSensor" style="width:40px; margin-left: 0px; text-align: right;"><span data-i18n="common.dpt"></span></label>
2588
- <select id="node-input-dptDaylightSensor" style="width:140px;"></select>
2589
-
2590
- <label for="node-input-nameDaylightSensor" style="width:50px; margin-left: 0px; text-align: right;"><span
2591
- data-i18n="knxUltimateMatterControllerDevice.node-input-name"></span></label>
2592
- <input type="text" id="node-input-nameDaylightSensor" style="width:190px;margin-left: 5px; text-align: left;">
2593
- </div>
2594
- <div class="form-row">
2595
- <label style="width:170px" for="node-input-invertDayNight">
2596
- <i class="fa fa-shuffle"></i> <span data-i18n="knxUltimateMatterControllerDevice.invert_day_night"></span>
2597
- </label>
2598
- <input type="checkbox" id="node-input-invertDayNight"
2599
- style="display:inline-block; width:auto; vertical-align:top;" />
2600
- </div>
2601
- <div class="form-row">
2602
- <label for="node-input-restoreDayMode" style="width:260px;">
2603
- <i class="fa fa-circle"></i> <span data-i18n="knxUltimateMatterControllerDevice.override_night_mode"></span>
2604
- </label>
2605
- <select id="node-input-restoreDayMode">
2606
- <option value="no" data-i18n="knxUltimateMatterControllerDevice.override_no"></option>
2607
- <option value="setDayByFastSwitchLightSingle" data-i18n="knxUltimateMatterControllerDevice.override_set_day_fast_this"></option>
2608
- <option value="setDayByFastSwitchLightALL" data-i18n="knxUltimateMatterControllerDevice.override_set_day_fast_all"></option>
2609
- </select>
2610
- </div>
2611
- </div>
2612
- </div>
2613
- <br/>
2614
- </div>
2615
- </p>
2616
- </div>
2617
- </div>
2618
-
2619
- <div class="form-row" style="margin-top:12px;">
2620
- <label for="node-input-enableNodePINS" style="width:260px;">
2621
- <i class="fa fa-circle"></i> <span data-i18n="knxUltimateMatterControllerDevice.node_pins"></span>
2622
- </label>
2623
- <select id="node-input-enableNodePINS">
2624
- <option value="no" data-i18n="knxUltimateMatterControllerDevice.node_pins_hide"></option>
2625
- <option value="yes" data-i18n="knxUltimateMatterControllerDevice.node_pins_show"></option>
2626
- </select>
2627
- </div>
2628
- <div id="matter-flow-input-help" style="display:none; width:900px; margin-top:12px;">
2629
- <h4><i class="fa-solid fa-code"></i> <span data-i18n="knxUltimateMatterControllerDevice.input_help_label"></span></h4>
2630
- <p>
2631
- <strong data-i18n="knxUltimateMatterControllerDevice.input_help_endpoint"></strong>:
2632
- <code id="matter-input-help-endpoint"></code>.
2633
- <span data-i18n="knxUltimateMatterControllerDevice.input_help_endpoint_hint"></span>
2634
- </p>
2635
- <h4 data-i18n="knxUltimateMatterControllerDevice.input_help_simple_title"></h4>
2636
- <p id="matter-input-help-simple-hint" data-i18n="knxUltimateMatterControllerDevice.input_help_simple_hint"></p>
2637
- <table class="matter-input-help-table">
2638
- <thead>
2639
- <tr>
2640
- <th data-i18n="knxUltimateMatterControllerDevice.input_help_operation"></th>
2641
- <th data-i18n="knxUltimateMatterControllerDevice.input_help_function"></th>
2642
- <th data-i18n="knxUltimateMatterControllerDevice.input_help_message"></th>
2643
- <th></th>
2644
- </tr>
2645
- </thead>
2646
- <tbody id="matter-input-help-simple-body"></tbody>
2647
- </table>
2648
- <p id="matter-input-help-simple-empty" style="display:none;" data-i18n="knxUltimateMatterControllerDevice.input_help_no_simple"></p>
2649
- <details id="matter-input-help-advanced-details">
2650
- <summary><strong data-i18n="knxUltimateMatterControllerDevice.input_help_advanced_title"></strong></summary>
2651
- <p data-i18n="knxUltimateMatterControllerDevice.input_help_advanced_hint"></p>
2652
- <div class="matter-input-help-advanced">
2653
- <table class="matter-input-help-table">
2654
- <thead>
2655
- <tr>
2656
- <th data-i18n="knxUltimateMatterControllerDevice.input_help_operation"></th>
2657
- <th data-i18n="knxUltimateMatterControllerDevice.input_help_target"></th>
2658
- <th data-i18n="knxUltimateMatterControllerDevice.input_help_message"></th>
2659
- <th></th>
2660
- </tr>
2661
- </thead>
2662
- <tbody id="matter-input-help-advanced-body"></tbody>
2663
- </table>
2664
- <p id="matter-input-help-advanced-empty" style="display:none;" data-i18n="knxUltimateMatterControllerDevice.input_help_no_structure"></p>
2665
- </div>
2666
- </details>
2667
- </div>
2668
- </div>
2669
-
2670
- <br/>
2671
- <br/>
2672
- <br/>
2673
- <br/>
2674
- <br/>
2675
-
2676
- </script>
2677
-
2678
-
2679
- <script type="text/markdown" data-help-name="knxUltimateMatterControllerDevice">
2680
- ### Upgrade to KNX Ultimate 8
2681
-
2682
- Version 7 shows a compact **Upgrade to v8** button at the top of this editor. It downloads a flow backup, installs the required companion 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.
2683
-
2684
- [Full upgrade guide](https://supergiovane.github.io/node-red-contrib-knx-ultimate/wiki/Upgrade-to-v8)
2685
-
2686
- <br/>
2687
-
2688
- <p>This node controls commissioned Matter endpoints and maps their commands and states to KNX.</p>
2689
-
2690
- **General**
2691
-
2692
- The editor detects the selected endpoint capabilities and exposes only the corresponding
2693
- Matter functions. Bridged Matter devices are expanded into their individual endpoints in
2694
- the device picker. Door Lock, Window Covering, Thermostat, Fan and Switch endpoints use
2695
- dedicated profiles. Switch press, long-press and multi-press events are emitted on the
2696
- optional flow output; simpler endpoints continue through the generic mapped fallback.
2697
-
2698
- Clicking or focusing the Matter device field always opens the complete commissioned
2699
- endpoint list, even when a device is already selected. Typing continues to filter it.
2700
-
2701
- **Flow input**
2702
-
2703
- Enable **Node Input/Output PINs** to reveal the **Flow input** section directly below
2704
- the selector. Lights show copyable examples for supported top-level properties such as
2705
- `msg.on`, `msg.dimming`, `msg.color_temperature` and `msg.color`. For non-light
2706
- endpoints the section shows the selected endpoint, all advertised readable/writable
2707
- attributes and all accepted commands.
2708
-
2709
- Use `msg.payload = {function:"position", value:35}` for a simple write. Omit `value`
2710
- to read a supported state, for example `{function:"temperature"}`. Values use human
2711
- units and read output includes raw Matter details in `msg.matter`. The available
2712
- functions are filtered by the endpoint and can include `onoff`, `level`, `position`,
2713
- `tiltposition`, `open`, `close`, `stop`, `setpoint`, `coolingsetpoint`, `currenttemp`,
2714
- `fanspeed`, sensor readings and `identify`. Door Lock accepts
2715
- `{function:"lock", value:true|false}`.
2716
-
2717
- The advanced top-level fields remain supported: `msg.clusterId` with
2718
- `msg.command`/`msg.args`, or `msg.attribute` with optional `msg.value`. Node ID and
2719
- Endpoint ID are already selected by this node; `msg.endpointId` is only an override.
2720
-
2721
- **Device isolation**
2722
-
2723
- Commands use a separate ordered queue for every commissioned device. An offline,
2724
- timing-out or removed device cannot delay other Matter devices sharing the same KNX
2725
- group address. A Controller node that still points to a removed device rejects the
2726
- command immediately and shows **Device no longer commissioned** in red.
2727
-
2728
- An unavailable-device error is latched. Further KNX and flow commands are ignored and
2729
- cannot repaint the red status. The node resumes automatically when its Matter device
2730
- reports `connected`; opening the node editor also clears the latch for a manual retry.
2731
-
2732
- **Universal Mode**
2733
-
2734
- Select **Universal Mode** in the **Mode** selector to listen to every attribute report,
2735
- cluster event and device initialization from this controller. It always exposes one input
2736
- and one output, does not require a KNX gateway, and does not use endpoint KNX mappings.
2737
- Output values are in `msg.payload`; routing metadata is in `msg.matter`, including
2738
- `source`, `nodeId`, `endpointId`, `clusterId` and the attribute/event name.
2739
- The **Universal Battery Monitor** scans every node and endpoint for Power Source,
2740
- emits an initial snapshot, and maintains complete battery state. It can emit only
2741
- batteries below the configured threshold or every battery update. `msg.payload`
2742
- contains normalized percent, charge level, replacement state, replaceability and
2743
- voltage; raw Matter metadata remains in `msg.matter`. Send
2744
- `{payload:{action:"getAllBatteries"}}` to retrieve the cached inventory.
2745
-
2746
- Use `msg.nodeId`, `msg.endpointId`, `msg.clusterId` and either `msg.command` plus
2747
- `msg.args`, or `msg.attribute`. Add `msg.value` for an attribute write; omit it for a
2748
- read. The same selectors may be placed under `msg.matter`. For example, read battery
2749
- with `{nodeId:"100", endpointId:1, clusterId:47, attribute:"batPercentRemaining"}` or
2750
- switch on with `{nodeId:"100", endpointId:1, clusterId:6, command:"on", args:{}}`.
2751
- Battery is emitted in Matter's raw half-percent units and can be divided by two in a
2752
- Function node.
2753
-
2754
- |Property|Description|
2755
- |--|--|
2756
- | KNX GW | Select the KNX gateway to be used |
2757
- | Matter controller | Select the Matter controller configuration to be used |
2758
- | Matter device | Matter light or plug to use (autocomplete while typing).|
2759
-
2760
- <br/>
2761
-
2762
- **OPTIONS**
2763
-
2764
- Here you can link KNX Group Addresses to the available Matter commands and states.<br/>
2765
- Start typing in the GA field (name or Group Address); suggestions appear while you type.
2766
-
2767
- **Switch**
2768
-
2769
- |Property|Description|
2770
- |--|--|
2771
- | Control | This GA turns the Matter light on or off via a boolean KNX value true/false. |
2772
- | Status | Link this to the light's switch status group address|
2773
-
2774
- <br/>
2775
-
2776
- **Dim**
2777
-
2778
- |Property|Description|
2779
- |--|--|
2780
- | Control dim | Relative DIM of the Matter light. You can set the dimming speed in the **Behaviour** tab. |
2781
- | Control % | Changes the absolute Matter light brightness (0-100%). |
2782
- | Status % | Link this to the light's brightness status KNX group address |
2783
- | Dim Speed (ms) | Dimming speed in milliseconds. Applies to both the light brightness and the tunable-white datapoints. Calculated over the 0%→100% range. |
2784
- | 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 %. |
2785
- | 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 %. |
2786
-
2787
- <br/>
2788
-
2789
- **Tunable White**
2790
-
2791
- |Property|Description|
2792
- |--|--|
2793
- | Control dim | Change white temperature using DPT 3.007 dimming. Speed is set in the **Behaviour** tab.|
2794
- | Control % | Change white temperature using DPT 5.001. 0 = full warm, 100 = full cold.|
2795
- | Status %| Temperature status GA. DPT 5.001 absolute value: 0 = full warm, 100 = full cold.|
2796
- | Control kelvin | **DPT 7.600:** set the Matter color temperature in Kelvin in the supported endpoint range.<br/>**DPT 9.002:** set the temperature as a KNX floating-point value. Conversions may introduce small deviations. |
2797
- | Status kelvin | **DPT 7.600:** read the Matter color temperature in Kelvin.<br/>**DPT 9.002:** read the temperature as a KNX floating-point value. |
2798
- | Invert dim direction | Inverts the DIM direction. |
2799
- <br/>
2800
-
2801
- **RGB/HSV**
2802
-
2803
- |Property|Description|
2804
- |--|--|
2805
- | **RGB section** ||
2806
- | 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. |
2807
- | Status rgb | The light's color status group address. Accepted datapoint is RGB triplet (r,g,b)|
2808
- | **HSV section** ||
2809
- | Color H dim | Cycle through HSV hue using DPT 3.007 dimming. Speed is set in the **Behaviour** tab.|
2810
- | Status H %| Status of the HSV chromatic circle.|
2811
- | Control S dim | Changes the light's color saturation, using DPT 3.007 dimming. You can set the dimming speed in the **_Behaviour_** tab.|
2812
- | Status S %| The light color saturation status group address.|
2813
- | Dim Speed (ms) | The dimming speed, in Milliseconds, from bottom to top scale. |
2814
-
2815
- For controlling the HSV "V” (brightness), use the standard controls under the **Dim** tab.
2816
-
2817
- <br/>
2818
-
2819
- **Effects**
2820
-
2821
- _Basic Matter effects_
2822
-
2823
- |Property|Description|
2824
- |--|--|
2825
- | Blink | _true_ blinks the light, _false_ stops blinking. Useful for signalling and available on compatible Matter lights. |
2826
- | Color Cycle | _true_ starts the cycle, _false_ stops it. Randomly changes the Matter light color at regular intervals when color control is supported. |
2827
-
2828
- <br/>
2829
-
2830
- **Behaviour**
2831
-
2832
- | Property | Description |
2833
- | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2834
- | Read status at startup | Read the Matter endpoint status at Node-RED startup or full deploy and send it to the KNX bus. |
2835
- | KNX Brightness Status | Updates the KNX brightness status whenever the Matter light switches ON/OFF. It can send 0% while OFF and restore the previous value when ON, or leave the brightness status unchanged. |
2836
- | Update local cached Matter state from KNX bus writes | When enabled, KNX writes immediately update the local Matter-state cache without waiting for the endpoint report. Disable it if the cache should follow only real Matter reports. |
2837
- | Node Input/Output PINs | Reveals the **Flow input** section below the selector. Lights use the supported top-level state properties shown there (`msg.on`, `msg.dimming`, `msg.color_temperature`, `msg.color`). Mapped endpoints use `msg.payload = {function,value}` or the advanced Matter selectors. Door Lock accepts both `msg.payload = true/false` and `{function:"lock",value:true/false}`. |
2838
- | 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. |
2839
- | 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.|
2840
- | Day/Night | Select the group address used to set the day/night behaviour. The group address value is _true_ if daytime, _false_ if nighttime. |
2841
- | Invert day/night value | Invert the values of _Day/Night_ group address. Default value is **unchecked** . |
2842
- | Read status at startup | Read the status at startup and emit the event to the KNX bus at startup/reconnection. (Default "no")|
2843
- | 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. |
2844
- | Node Input/Output PINs | Hide or show the flow input/output PINs. The input accepts supported Matter commands and the output emits validated Matter endpoint events. The selection is persisted with the node. |
2845
-
2846
- ### Note
2847
-
2848
- 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.
2849
-
2850
- <br/>
2851
- </script>