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,894 +0,0 @@
1
- /* eslint-disable max-len */
2
- import { EventEmitter } from 'events'
3
- import dns from 'dns/promises'
4
- import { setTimeout as pleaseWait } from 'timers/promises'
5
-
6
- // Last 4 hex chars of an id-ish string (serial, uniqueId, mDNS name...), uppercased.
7
- // Used to disambiguate identical device names (Shelly encode the MAC in the serial).
8
- const shortHexSuffix = (value) => {
9
- if (value === undefined || value === null) return ''
10
- const hex = String(value).replace(/[^0-9a-fA-F]/g, '')
11
- if (hex.length >= 4) return hex.slice(-4).toUpperCase()
12
- const alnum = String(value).replace(/[^0-9a-zA-Z]/g, '')
13
- return alnum.length >= 4 ? alnum.slice(-4).toUpperCase() : alnum.toUpperCase()
14
- }
15
-
16
- const normalizeHostForCompare = (value) => {
17
- if (value === undefined || value === null) return ''
18
- return String(value).trim().toLowerCase().replace(/^\[/, '').replace(/\]$/, '').split('%')[0]
19
- }
20
-
21
- // Wrapper around the matter.js CommissioningController.
22
- // It mirrors the contract of hueEngine.mjs: an EventEmitter with a command queue,
23
- // emitting 'connected', 'disconnected', 'event' (attribute changes), 'matterEvent' (cluster events),
24
- // 'nodeState' and 'structureChanged'.
25
- class classMatter extends EventEmitter {
26
- constructor (_storagePath, _instanceId, _fabricLabel, _sysLogger, {
27
- startQueue = true,
28
- commandTimeoutMs = 15000,
29
- queuePollMs = 150,
30
- queueMaxConcurrent = 32
31
- } = {}) {
32
- super()
33
- this.matterConnectionStatus = 'disconnected'
34
- this.storagePath = _storagePath
35
- this.instanceId = _instanceId
36
- this.fabricLabel = _fabricLabel || 'KNX-Ultimate'
37
- this.sysLogger = _sysLogger
38
- this.controller = null
39
- this.pairedNodes = new Map() // nodeId (string) -> PairedNode
40
- this.commandQueue = []
41
- // Commands remain strictly ordered per Matter node, but different nodes use
42
- // independent lanes. An unreachable device must never head-of-line block every
43
- // other endpoint sharing this controller/fabric.
44
- this.commandQueueInFlight = new Map()
45
- this.queueMaxLength = 2000
46
- this.queueMaxConcurrent = Math.max(1, Number(queueMaxConcurrent) || 32)
47
- this.commandTimeoutMs = Math.max(10, Number(commandTimeoutMs) || 15000)
48
- this.queuePollMs = Math.max(10, Number(queuePollMs) || 150)
49
- this.exitAllQueues = false
50
- this._api = null // Lazy loaded matter.js exports
51
- this._logThrottle = new Map()
52
- if (startQueue) {
53
- // The queue is intentionally fire-and-forget, but its Promise must always be
54
- // observed so an unexpected loop failure cannot become an unhandled rejection.
55
- this.handleQueue().catch((error) => this._log('error', `classMatter: queue loop: ${error.message}`))
56
- }
57
- }
58
-
59
- _log = (level, message) => {
60
- try {
61
- const logger = this.sysLogger
62
- if (logger && typeof logger[level] === 'function') return logger[level](message)
63
- if (logger && typeof logger.log === 'function') return logger.log(message)
64
- } catch (error) { /* empty */ }
65
- if (level === 'error') console.error(message)
66
- else if (level === 'warn') console.warn(message)
67
- else console.log(message)
68
- }
69
-
70
- _logThrottled = (level, throttleKey, message, intervalMs = 30000) => {
71
- const now = Date.now()
72
- const entry = this._logThrottle.get(throttleKey) || { last: 0, suppressed: 0 }
73
- if (this._logThrottle.size > 1000) this._logThrottle.clear()
74
- if (entry.last === 0 || (now - entry.last) >= intervalMs) {
75
- const suffix = entry.suppressed > 0 ? ` (suppressed ${entry.suppressed} similar)` : ''
76
- entry.last = now
77
- entry.suppressed = 0
78
- this._logThrottle.set(throttleKey, entry)
79
- this._log(level, `${message}${suffix}`)
80
- return
81
- }
82
- entry.suppressed += 1
83
- this._logThrottle.set(throttleKey, entry)
84
- }
85
-
86
- _loadApi = async () => {
87
- if (this._api !== null) return this._api
88
- const { Environment, StorageService, Logger, LogLevel } = await import('@matter/main')
89
- const { Seconds } = await import('@matter/general')
90
- const { CommissioningController } = await import('@project-chip/matter.js')
91
- const { ControllerCommissioningFlow } = await import('@matter/protocol')
92
- const { NodeStates } = await import('@project-chip/matter.js/device')
93
- const { ManualPairingCodeCodec, QrPairingCodeCodec, NodeId } = await import('@matter/main/types')
94
- const { BasicInformation, GeneralCommissioning } = await import('@matter/main/clusters')
95
- this._api = {
96
- Environment, StorageService, Logger, LogLevel, Seconds, CommissioningController, ControllerCommissioningFlow, NodeStates, ManualPairingCodeCodec, QrPairingCodeCodec, NodeId, BasicInformation, GeneralCommissioning
97
- }
98
- return this._api
99
- }
100
-
101
- _reportCommissioningProgress = (_callback, progress) => {
102
- if (typeof _callback !== 'function') return
103
- try {
104
- _callback(progress)
105
- } catch (error) {
106
- this._log('warn', `classMatter: commissioning progress callback: ${error.message}`)
107
- }
108
- }
109
-
110
- _createProgressCommissioningFlow = (_callback) => {
111
- const BaseFlow = this._api.ControllerCommissioningFlow
112
- const report = (progress) => this._reportCommissioningProgress(_callback, progress)
113
- const descriptions = {
114
- GetInitialData: { percent: 22, message: 'Reading commissioning information from the device…' },
115
- 'GeneralCommissioning.ArmFailsafe': { percent: 30, message: 'Arming the device fail-safe timer…' },
116
- 'GeneralCommissioning.ConfigureRegulatoryInformation': { percent: 36, message: 'Applying regulatory configuration…' },
117
- 'TimeSynchronization.SynchronizeTime': { percent: 42, message: 'Synchronizing the device clock…' },
118
- 'OperationalCredentials.DeviceAttestation': { percent: 50, message: 'Verifying device identity and attestation…' },
119
- 'OperationalCredentials.Certificates': { percent: 62, message: 'Installing operational credentials…' },
120
- AccessControl: { percent: 72, message: 'Configuring Matter access control…' },
121
- 'NetworkCommissioning.Validate': { percent: 76, message: 'Checking the device network configuration…' },
122
- 'NetworkCommissioning.Wifi': { percent: 78, message: 'Connecting the device to the Wi-Fi network…' },
123
- 'NetworkCommissioning.Thread': { percent: 78, message: 'Connecting the device to the Thread network…' },
124
- Reconnect: { percent: 84, message: 'Reconnecting through the operational CASE session…' },
125
- 'GeneralCommissioning.Complete': { percent: 92, message: 'Completing commissioning on the device…' },
126
- 'OperationalCredentials.UpdateFabricLabel': { percent: 96, message: 'Applying the Matter fabric label…' },
127
- 'AdditionalLogic.AddDefaultOtaProvider': { percent: 97, message: 'Configuring the default OTA provider…' }
128
- }
129
-
130
- return class ProgressCommissioningFlow extends BaseFlow {
131
- constructor (...args) {
132
- super(...args)
133
- this.commissioningSteps.forEach((step) => {
134
- const stepLogic = step.stepLogic
135
- step.stepLogic = async () => {
136
- const description = descriptions[step.name] || {
137
- percent: 20,
138
- message: `Running Matter commissioning step ${step.stepNumber}.${step.subStepNumber}: ${step.name}…`
139
- }
140
- const device = this.collectedCommissioningData?.productName
141
- ? {
142
- productName: this.collectedCommissioningData.productName,
143
- vendorId: this.collectedCommissioningData.vendorId,
144
- productId: this.collectedCommissioningData.productId
145
- }
146
- : undefined
147
- report({
148
- phase: 'commissioning',
149
- step: `${step.stepNumber}.${step.subStepNumber}`,
150
- stepName: step.name,
151
- percent: description.percent,
152
- message: description.message,
153
- device
154
- })
155
- const result = await stepLogic()
156
- // GetInitialData is the first point where the commissionee may have exposed
157
- // its product identity. Publish it immediately instead of waiting for the
158
- // following step to make the editor show it.
159
- if (step.name === 'GetInitialData' && this.collectedCommissioningData?.productName) {
160
- report({
161
- phase: 'commissioning',
162
- step: `${step.stepNumber}.${step.subStepNumber}`,
163
- stepName: step.name,
164
- percent: 28,
165
- message: 'Device identified. Preparing secure commissioning…',
166
- device: {
167
- productName: this.collectedCommissioningData.productName,
168
- vendorId: this.collectedCommissioningData.vendorId,
169
- productId: this.collectedCommissioningData.productId
170
- }
171
- })
172
- }
173
- return result
174
- }
175
- })
176
- }
177
- }
178
- }
179
-
180
- _resolveTargetHosts = async (_targetHost) => {
181
- const host = normalizeHostForCompare(_targetHost)
182
- if (host === '') return []
183
- const ret = new Set([host])
184
- try {
185
- const entries = await dns.lookup(host, { all: true })
186
- entries.forEach((entry) => {
187
- const address = normalizeHostForCompare(entry.address)
188
- if (address !== '') ret.add(address)
189
- })
190
- } catch (error) { /* Host may already be an IP or only resolvable by Matter/mDNS. */ }
191
- return Array.from(ret)
192
- }
193
-
194
- _deviceHasTargetHost = (device, targetHosts) => {
195
- if (!Array.isArray(targetHosts) || targetHosts.length === 0) return false
196
- try {
197
- return (device.addresses || []).some((address) => targetHosts.includes(normalizeHostForCompare(address.ip)))
198
- } catch (error) {
199
- return false
200
- }
201
- }
202
-
203
- _discoverCommissionableDeviceAtHost = async (identifierData, discoveryCapabilities, targetHost) => {
204
- const targetHosts = await this._resolveTargetHosts(targetHost)
205
- if (targetHosts.length === 0) return undefined
206
- const devices = await this.controller.discoverCommissionableDevices(
207
- identifierData,
208
- discoveryCapabilities,
209
- undefined,
210
- this._api.Seconds(20)
211
- )
212
- return devices.find((device) => this._deviceHasTargetHost(device, targetHosts))
213
- }
214
-
215
- _buildKnownAddressDiscoveryAttempts = (identifierData, discoveryCapabilities, targetHost) => {
216
- const host = normalizeHostForCompare(targetHost)
217
- if (host === '') return []
218
- // Matter devices normally listen for commissioning on UDP/5540. Shelly's HTTP RPC
219
- // gives us the device IP, not its mDNS service port, so try the standard PASE port
220
- // before falling back to mDNS-filtered discovery.
221
- return [{
222
- identifierData,
223
- discoveryCapabilities,
224
- knownAddress: {
225
- ip: host,
226
- port: 5540,
227
- type: 'udp'
228
- }
229
- }, {
230
- identifierData,
231
- discoveryCapabilities,
232
- knownAddress: {
233
- ip: host,
234
- port: 5540
235
- }
236
- }]
237
- }
238
-
239
- _allocateCommissionNodeId = () => {
240
- const commissioned = new Set()
241
- try {
242
- this.controller.getCommissionedNodes().forEach((nodeId) => commissioned.add(nodeId.toString()))
243
- } catch (error) { /* empty */ }
244
- try {
245
- if (this.controller.nodeId !== undefined) commissioned.add(this.controller.nodeId.toString())
246
- } catch (error) { /* empty */ }
247
- for (let index = 0; index < 100; index++) {
248
- const nodeId = this._api.NodeId.randomOperationalNodeId(this.controller.crypto)
249
- if (!commissioned.has(nodeId.toString())) return nodeId
250
- }
251
- throw new Error('Unable to allocate a free Matter Node ID for commissioning')
252
- }
253
-
254
- nodeStateToString = (state) => {
255
- try {
256
- const { NodeStates } = this._api
257
- switch (state) {
258
- case NodeStates.Connected: return 'connected'
259
- case NodeStates.Disconnected: return 'disconnected'
260
- case NodeStates.Reconnecting: return 'reconnecting'
261
- case NodeStates.WaitingForDeviceDiscovery: return 'waitingfordiscovery'
262
- default: return `unknown (${state})`
263
- }
264
- } catch (error) {
265
- return `unknown (${state})`
266
- }
267
- }
268
-
269
- Connect = async () => {
270
- const api = await this._loadApi()
271
- try {
272
- // Quiet down the very verbose default matter.js console logging.
273
- api.Logger.level = api.LogLevel.ERROR
274
- } catch (error) { /* empty */ }
275
- const { withEnvironmentLock } = await import('./matterEnvironmentLock.mjs')
276
- // Serialize with the Matter Bridge engine: both write Environment.default.vars
277
- // ('storage.path') before creating their matter.js node, and that Environment is a
278
- // process-wide singleton. See matterEnvironmentLock.mjs for why this matters.
279
- await withEnvironmentLock(async () => {
280
- const environment = api.Environment.default
281
- environment.vars.set('storage.path', this.storagePath)
282
- this.controller = new api.CommissioningController({
283
- environment: { environment, id: this.instanceId },
284
- autoConnect: false,
285
- adminFabricLabel: this.fabricLabel
286
- })
287
- await this.controller.start()
288
- })
289
- this.matterConnectionStatus = 'connected'
290
- this.emit('connected')
291
- // Connect all already commissioned nodes and hook their events.
292
- const nodeIds = this.controller.getCommissionedNodes()
293
- for (let index = 0; index < nodeIds.length; index++) {
294
- try {
295
- await this._attachNode(nodeIds[index])
296
- } catch (error) {
297
- this._log('error', `classMatter: Connect: cannot attach node ${nodeIds[index]}: ${error.message}`)
298
- }
299
- }
300
- }
301
-
302
- _attachNode = async (_nodeId) => {
303
- const key = _nodeId.toString()
304
- const node = await this.controller.getNode(_nodeId)
305
- this.pairedNodes.set(key, node)
306
- if (node.__knxUltimateHooked !== true) {
307
- node.__knxUltimateHooked = true
308
- node.events.attributeChanged.on((data) => {
309
- try {
310
- this.emit('event', {
311
- nodeId: key,
312
- endpointId: Number(data.path.endpointId),
313
- clusterId: Number(data.path.clusterId),
314
- attributeId: Number(data.path.attributeId),
315
- attributeName: data.path.attributeName,
316
- value: data.value
317
- })
318
- } catch (error) {
319
- this._logThrottled('error', 'matter:attrchanged', `classMatter: attributeChanged handler: ${error.message}`)
320
- }
321
- })
322
- node.events.eventTriggered.on((data) => {
323
- try {
324
- this.emit('matterEvent', {
325
- nodeId: key,
326
- endpointId: Number(data.path.endpointId),
327
- clusterId: Number(data.path.clusterId),
328
- eventId: Number(data.path.eventId),
329
- eventName: data.path.eventName,
330
- events: data.events
331
- })
332
- } catch (error) {
333
- this._logThrottled('error', 'matter:eventtriggered', `classMatter: eventTriggered handler: ${error.message}`)
334
- }
335
- })
336
- node.events.stateChanged.on((state) => {
337
- try {
338
- this.emit('nodeState', key, this.nodeStateToString(state))
339
- } catch (error) { /* empty */ }
340
- })
341
- node.events.structureChanged.on(() => {
342
- try {
343
- this.emit('structureChanged', key)
344
- } catch (error) { /* empty */ }
345
- })
346
- node.events.initializedFromRemote?.on(() => {
347
- try {
348
- this.emit('nodeInitialized', key)
349
- } catch (error) { /* empty */ }
350
- })
351
- }
352
- try {
353
- node.connect() // Establishes connection and auto-subscribes to all attributes/events
354
- } catch (error) {
355
- this._log('warn', `classMatter: _attachNode connect ${key}: ${error.message}`)
356
- }
357
- return node
358
- }
359
-
360
- // Commission (pair) a new device using an 11-digit manual pairing code or a QR code string (MT:...)
361
- commission = async (_pairingCode, _options = {}) => {
362
- if (this.controller === null) throw new Error('Matter controller not started')
363
- const api = await this._loadApi()
364
- const code = (_pairingCode || '').toString().trim()
365
- if (code === '') throw new Error('Empty pairing code')
366
- let passcode
367
- let identifierData
368
- const discoveryCapabilities = { onIpNetwork: true }
369
- const onProgress = _options?.onProgress
370
- this._reportCommissioningProgress(onProgress, {
371
- phase: 'preparing',
372
- percent: 5,
373
- message: 'Validating the Matter pairing code…'
374
- })
375
- if (code.toUpperCase().startsWith('MT:')) {
376
- const qr = api.QrPairingCodeCodec.decode(code)[0]
377
- passcode = qr.passcode
378
- identifierData = { longDiscriminator: qr.discriminator }
379
- } else {
380
- const manual = api.ManualPairingCodeCodec.decode(code.replace(/[^0-9]/g, ''))
381
- passcode = manual.passcode
382
- identifierData = { shortDiscriminator: manual.shortDiscriminator }
383
- }
384
- let nodeId
385
- try {
386
- const commissioningNodeId = this._allocateCommissionNodeId()
387
- this._log('info', `classMatter: commission: using Node ID ${commissioningNodeId.toString()} for new device`)
388
- let discovery = {
389
- identifierData,
390
- discoveryCapabilities
391
- }
392
- const targetHost = (_options?.targetHost || '').toString().trim()
393
- if (targetHost !== '') {
394
- this._reportCommissioningProgress(onProgress, {
395
- phase: 'discovery',
396
- percent: 10,
397
- message: `Looking for the Matter device at ${targetHost}…`
398
- })
399
- const commissionableDevice = await this._discoverCommissionableDeviceAtHost(identifierData, discoveryCapabilities, targetHost)
400
- discovery = commissionableDevice !== undefined
401
- ? {
402
- commissionableDevice,
403
- discoveryCapabilities
404
- }
405
- : undefined
406
- }
407
- const discoveryAttempts = discovery !== undefined
408
- ? [discovery]
409
- : this._buildKnownAddressDiscoveryAttempts(identifierData, discoveryCapabilities, targetHost)
410
- let lastError
411
- for (const discoveryAttempt of discoveryAttempts) {
412
- try {
413
- this._reportCommissioningProgress(onProgress, {
414
- phase: 'pase',
415
- percent: 15,
416
- message: 'Discovering the device and establishing a secure PASE session…'
417
- })
418
- nodeId = await this.controller.commissionNode({
419
- commissioning: {
420
- nodeId: commissioningNodeId,
421
- regulatoryLocation: api.GeneralCommissioning.RegulatoryLocationType.IndoorOutdoor
422
- },
423
- discovery: discoveryAttempt,
424
- passcode
425
- }, {
426
- connectNodeAfterCommissioning: false,
427
- commissioningFlowImpl: this._createProgressCommissioningFlow(onProgress)
428
- })
429
- lastError = undefined
430
- break
431
- } catch (error) {
432
- lastError = error
433
- }
434
- }
435
- if (nodeId === undefined) {
436
- if (targetHost !== '' && discoveryAttempts.length > 0) {
437
- throw new Error(`No commissionable Matter device matching this pairing code could be commissioned at ${targetHost}. Direct PASE on UDP/5540 and mDNS discovery both failed.${lastError ? ` Last error: ${lastError.message || lastError}` : ''}`)
438
- }
439
- throw lastError || new Error('Matter commissioning failed')
440
- }
441
- } catch (error) {
442
- // The 11-digit MANUAL code carries only the 4-bit short discriminator, so several
443
- // identical devices (e.g. same-model Shelly) look alike to discovery: it can reach
444
- // the WRONG one — typically the first, already-commissioned device — and fail with a
445
- // "node ID already commissioned" conflict. Point the user to the QR code.
446
- const msg = String((error && error.message) || error)
447
- const isManual = !code.toUpperCase().startsWith('MT:')
448
- if (/already commissioned|can not be reused/i.test(msg)) {
449
- throw new Error(`${msg} — the commissioner reached a device that is ALREADY paired to this controller.${isManual ? ' The MANUAL code can reach the wrong identical device (short discriminator): use the QR code (MT:...) to target the exact one.' : ''} If you really mean this device, factory-reset it (or unpair that node) and try again. Pair one device at a time.`)
450
- }
451
- if (isManual) {
452
- throw new Error(`${msg} — tip: the MANUAL code can't tell identical devices apart (short discriminator). Use the QR code (MT:...) for a precise match, pair one device at a time, and factory-reset the device if it is already commissioned elsewhere.`)
453
- }
454
- throw error
455
- }
456
- try {
457
- this._reportCommissioningProgress(onProgress, {
458
- phase: 'attaching',
459
- percent: 98,
460
- message: 'Loading the commissioned device structure…'
461
- })
462
- await this._attachNode(nodeId)
463
- } catch (error) {
464
- // Pairing succeeded: never report it as failed just because the first connection
465
- // attempt errored. The node will be attached again at the next controller start.
466
- this._log('warn', `classMatter: commission: node ${nodeId} paired but not yet attached: ${error.message}`)
467
- }
468
- this._reportCommissioningProgress(onProgress, {
469
- phase: 'complete',
470
- percent: 100,
471
- message: 'Matter commissioning completed successfully.'
472
- })
473
- return nodeId.toString()
474
- }
475
-
476
- // Decommission (unpair) a device. Falls back to forced removal if the device is unreachable.
477
- removeNode = async (_nodeIdString) => {
478
- if (this.controller === null) throw new Error('Matter controller not started')
479
- const api = await this._loadApi()
480
- const nodeId = api.NodeId(BigInt(_nodeIdString))
481
- const node = this.pairedNodes.get(_nodeIdString)
482
- try {
483
- if (node !== undefined) {
484
- await node.decommission()
485
- } else {
486
- await this.controller.removeNode(nodeId, true)
487
- }
488
- } catch (error) {
489
- this._log('warn', `classMatter: removeNode: decommission failed (${error.message}), forcing removal`)
490
- await this.controller.removeNode(nodeId, false)
491
- }
492
- this.pairedNodes.delete(_nodeIdString)
493
- this.commandQueue = this.commandQueue.filter((el) => el.nodeId !== _nodeIdString)
494
- }
495
-
496
- // Returns [{ nodeId, name, vendorName, productName, connectionState }]
497
- getCommissionedNodesDetails = () => {
498
- if (this.controller === null) return []
499
- const retArray = []
500
- let details = []
501
- try {
502
- details = this.controller.getCommissionedNodesDetails()
503
- } catch (error) {
504
- this._log('warn', `classMatter: getCommissionedNodesDetails: ${error.message}`)
505
- }
506
- details.forEach((detail) => {
507
- try {
508
- const key = detail.nodeId.toString()
509
- const node = this.pairedNodes.get(key)
510
- let basicInfo = detail.basicInformationData || detail.deviceData?.basicInformation || {}
511
- try {
512
- if (node !== undefined && node.basicInformation !== undefined) basicInfo = node.basicInformation
513
- } catch (error) { /* empty */ }
514
- let connectionState = 'disconnected'
515
- try {
516
- if (node !== undefined) connectionState = this.nodeStateToString(node.connectionState)
517
- } catch (error) { /* empty */ }
518
- // Name: prefer the user-assigned label; otherwise fall back to the model and
519
- // append a short unique suffix so identical devices (e.g. several Shelly of the
520
- // same model) are distinguishable. Shelly expose their MAC in the serial number,
521
- // so its last 4 hex chars are effectively the "last 4 of the MAC" other apps show.
522
- const userLabel = basicInfo.nodeLabel || basicInfo.productLabel
523
- const baseName = userLabel || basicInfo.productName || detail.advertisedName || `Node ${key}`
524
- let displayName = baseName
525
- if (!userLabel) {
526
- const idSource = basicInfo.serialNumber || basicInfo.uniqueId || detail.advertisedName || key
527
- const suffix = shortHexSuffix(idSource)
528
- if (suffix && !baseName.toUpperCase().includes(suffix)) displayName = `${baseName} (${suffix})`
529
- }
530
- retArray.push({
531
- nodeId: key,
532
- name: displayName,
533
- vendorName: basicInfo.vendorName || '',
534
- productName: basicInfo.productName || '',
535
- serialNumber: basicInfo.serialNumber || '',
536
- connectionState
537
- })
538
- } catch (error) {
539
- this._log('warn', `classMatter: getCommissionedNodesDetails item: ${error.message}`)
540
- }
541
- })
542
- return retArray
543
- }
544
-
545
- _walkEndpoints = (endpoint, _callback) => {
546
- _callback(endpoint)
547
- try {
548
- const parts = endpoint.parts
549
- if (parts !== undefined) {
550
- parts.forEach((child) => {
551
- this._walkEndpoints(child, _callback)
552
- })
553
- }
554
- } catch (error) { /* empty */ }
555
- }
556
-
557
- _getAllEndpoints = (node) => {
558
- const endpoints = []
559
- try {
560
- node.getDevices().forEach((device) => {
561
- this._walkEndpoints(device, (ep) => {
562
- if (ep.number !== undefined && !endpoints.some((e) => e.number === ep.number)) endpoints.push(ep)
563
- })
564
- })
565
- } catch (error) {
566
- this._log('warn', `classMatter: _getAllEndpoints: ${error.message}`)
567
- }
568
- return endpoints
569
- }
570
-
571
- _findEndpoint = (node, _endpointId) => {
572
- // getDevices() can expose only functional/bridged endpoints while the root endpoint
573
- // lives behind getRootEndpoint(). Resolve endpoint 0 explicitly for node clusters
574
- // such as BasicInformation and GeneralCommissioning.
575
- if (Number(_endpointId) === 0 && typeof node?.getRootEndpoint === 'function') {
576
- try {
577
- const root = node.getRootEndpoint()
578
- if (root !== undefined) return root
579
- } catch (error) { /* The legacy endpoint structure may still be initializing. */ }
580
- }
581
- return this._getAllEndpoints(node).find((ep) => Number(ep.number) === Number(_endpointId))
582
- }
583
-
584
- _findClusterClient = (node, _endpointId, _clusterId) => {
585
- try {
586
- const endpoint = this._findEndpoint(node, _endpointId)
587
- if (endpoint === undefined) return undefined
588
- return endpoint.getAllClusterClients().find((cc) => Number(cc.id) === Number(_clusterId))
589
- } catch (error) {
590
- this._logThrottled('warn', 'matter:findcluster', `classMatter: _findClusterClient: ${error.message}`)
591
- return undefined
592
- }
593
- }
594
-
595
- _findAttribute = (clusterClient, attributeNameOrId) => {
596
- if (clusterClient === undefined || attributeNameOrId === undefined || attributeNameOrId === null) return undefined
597
- if (typeof attributeNameOrId === 'string' && clusterClient.attributes[attributeNameOrId] !== undefined) {
598
- return clusterClient.attributes[attributeNameOrId]
599
- }
600
- return Object.values(clusterClient.attributes).find((attribute) => Number(attribute?.id) === Number(attributeNameOrId))
601
- }
602
-
603
- // Returns the full structure of a commissioned node: endpoints, clusters, attributes (with cached values) and commands.
604
- // Used by the editor UI to let the user pick the mapping targets.
605
- getNodeStructure = (_nodeIdString) => {
606
- const node = this.pairedNodes.get(_nodeIdString)
607
- if (node === undefined) throw new Error(`Matter node ${_nodeIdString} unknown or not yet connected`)
608
- const retEndpoints = []
609
- this._getAllEndpoints(node).forEach((endpoint) => {
610
- let deviceTypes = []
611
- try {
612
- deviceTypes = endpoint.getDeviceTypes().map((dt) => dt.name)
613
- } catch (error) { /* empty */ }
614
- const clusters = []
615
- let clusterClients = []
616
- try {
617
- clusterClients = endpoint.getAllClusterClients()
618
- } catch (error) {
619
- this._logThrottled('warn', 'matter:structure:clients', `classMatter: getNodeStructure getAllClusterClients: ${error.message}`)
620
- }
621
- clusterClients.forEach((cc) => {
622
- try {
623
- const attributes = []
624
- Object.keys(cc.attributes).forEach((attrName) => {
625
- try {
626
- if (/^\d+$/.test(attrName)) return // Skip numeric aliases
627
- if (typeof cc.isAttributeSupportedByName === 'function' && !cc.isAttributeSupportedByName(attrName)) return
628
- // Skip the global meta attributes (FeatureMap, AttributeList, ClusterRevision...):
629
- // they are useless for KNX mappings and only confuse the user.
630
- const exposeFeatureMap = [47, 768].includes(Number(cc.id)) && attrName === 'featureMap'
631
- if (Number(cc.attributes[attrName].id) >= 65528 && !exposeFeatureMap) return
632
- let value
633
- try {
634
- value = cc.attributes[attrName].getLocal()
635
- } catch (error) { value = undefined }
636
- attributes.push({
637
- name: attrName,
638
- id: Number(cc.attributes[attrName].id),
639
- value: this._jsonSafe(value),
640
- writable: cc.attributes[attrName]?.attribute?.schema?.writable === true
641
- })
642
- } catch (error) { /* empty */ }
643
- })
644
- const commands = []
645
- Object.keys(cc.commands).forEach((cmdName) => {
646
- try {
647
- if (/^\d+$/.test(cmdName)) return
648
- if (typeof cc.isCommandSupportedByName === 'function' && !cc.isCommandSupportedByName(cmdName)) return
649
- commands.push({ name: cmdName })
650
- } catch (error) { /* empty */ }
651
- })
652
- clusters.push({
653
- id: Number(cc.id),
654
- name: cc.name,
655
- attributes,
656
- commands
657
- })
658
- } catch (error) {
659
- this._logThrottled('warn', 'matter:structure', `classMatter: getNodeStructure cluster error: ${error.message}`)
660
- }
661
- })
662
- try {
663
- retEndpoints.push({
664
- endpointId: Number(endpoint.number),
665
- name: endpoint.name,
666
- deviceTypes,
667
- clusters
668
- })
669
- } catch (error) {
670
- this._logThrottled('warn', 'matter:structure:endpoint', `classMatter: getNodeStructure endpoint error: ${error.message}`)
671
- }
672
- })
673
- return { nodeId: _nodeIdString, endpoints: retEndpoints }
674
- }
675
-
676
- _jsonSafe = (value) => {
677
- try {
678
- return JSON.parse(JSON.stringify(value, (k, v) => (typeof v === 'bigint' ? v.toString() : v)))
679
- } catch (error) {
680
- return undefined
681
- }
682
- }
683
-
684
- // Read an attribute value. By default returns the locally cached (subscribed) value.
685
- readAttribute = async (_nodeIdString, _endpointId, _clusterId, _attributeName, _requestFromRemote = false) => {
686
- const node = this.pairedNodes.get(_nodeIdString)
687
- if (node === undefined) throw new Error(`Matter node ${_nodeIdString} unknown or not yet connected`)
688
- const clusterClient = this._findClusterClient(node, _endpointId, _clusterId)
689
- if (clusterClient === undefined) throw new Error(`Cluster ${_clusterId} not found on endpoint ${_endpointId}`)
690
- const attribute = this._findAttribute(clusterClient, _attributeName)
691
- if (attribute === undefined) throw new Error(`Attribute ${_attributeName} not found in cluster ${clusterClient.name}`)
692
- return attribute.get(_requestFromRemote)
693
- }
694
-
695
- // Synchronous read of the locally cached attribute value (undefined if not yet received).
696
- getCachedAttribute = (_nodeIdString, _endpointId, _clusterId, _attributeName) => {
697
- try {
698
- const node = this.pairedNodes.get(_nodeIdString)
699
- if (node === undefined) return undefined
700
- const clusterClient = this._findClusterClient(node, _endpointId, _clusterId)
701
- if (clusterClient === undefined) return undefined
702
- const attribute = this._findAttribute(clusterClient, _attributeName)
703
- if (attribute === undefined) return undefined
704
- return attribute.getLocal()
705
- } catch (error) {
706
- return undefined
707
- }
708
- }
709
-
710
- renameNode = async (_nodeIdString, _label) => {
711
- const label = (_label || '').toString().trim()
712
- if (label === '') throw new Error('Empty Matter device name')
713
- if (label.length > 64) throw new Error('Matter device name is too long')
714
- const node = this.pairedNodes.get(_nodeIdString)
715
- if (node === undefined) throw new Error(`Matter node ${_nodeIdString} unknown or not yet connected`)
716
- // commission() attaches the PairedNode before its first wildcard read/subscription
717
- // has necessarily built the legacy endpoint structure. A user-supplied name is
718
- // applied immediately after commissioning, so wait briefly for BasicInformation
719
- // instead of reporting a misleading permanent-cluster warning.
720
- const deadline = Date.now() + 10000
721
- let clusterClient
722
- do {
723
- try {
724
- if (typeof node.getRootClusterClient === 'function') clusterClient = node.getRootClusterClient(this._api.BasicInformation)
725
- } catch (error) { /* Endpoint structure is still initializing. */ }
726
- if (clusterClient === undefined) clusterClient = this._findClusterClient(node, 0, 40) // BasicInformation on the root endpoint
727
- if (clusterClient !== undefined) break
728
- await pleaseWait(100)
729
- } while (Date.now() < deadline)
730
- if (clusterClient === undefined) throw new Error(`BasicInformation cluster was not available on node ${_nodeIdString} after initialization`)
731
- const attribute = clusterClient.attributes.nodeLabel
732
- if (attribute === undefined) throw new Error(`nodeLabel attribute not found on node ${_nodeIdString}`)
733
- await attribute.set(label)
734
- return label
735
- }
736
-
737
- _enqueueCommand = (command) => {
738
- if (!command) return false
739
- if (!Array.isArray(this.commandQueue)) this.commandQueue = []
740
- this.commandQueue.unshift(command)
741
- if (this.commandQueue.length > this.queueMaxLength) {
742
- this.commandQueue.splice(this.queueMaxLength)
743
- this._logThrottled('warn', 'matter:queue:overflow', `Matter command queue overflow: capped at ${this.queueMaxLength}`, 60000)
744
- }
745
- return true
746
- }
747
-
748
- _isNodeCommissioned = (nodeId) => {
749
- const key = String(nodeId)
750
- try {
751
- if (this.controller && typeof this.controller.getCommissionedNodes === 'function') {
752
- return this.controller.getCommissionedNodes().some((commissionedNodeId) => commissionedNodeId.toString() === key)
753
- }
754
- } catch (error) { /* Fall back to the attached-node map while the controller changes state. */ }
755
- return this.pairedNodes.has(key)
756
- }
757
-
758
- // Add a command or attribute write to the queue.
759
- // _item: { nodeId, endpointId, clusterId, kind: 'command'|'attributeWrite', name, args }
760
- writeMatterQueueAdd = async (_item) => {
761
- const nodeId = _item?.nodeId === undefined || _item?.nodeId === null ? '' : String(_item.nodeId)
762
- const item = { ..._item, nodeId }
763
- if (nodeId === '' || !this._isNodeCommissioned(nodeId)) {
764
- const error = new Error(`Matter node ${nodeId || '(empty)'} is no longer commissioned`)
765
- error.code = 'MATTER_NODE_NOT_COMMISSIONED'
766
- // Defer the notification so a legacy fire-and-forget caller cannot overwrite
767
- // the red orphan-device status with its immediate optimistic "command sent" state.
768
- queueMicrotask(() => this.emit('commandError', { item, error: error.message, code: error.code }))
769
- throw error
770
- }
771
- return this._enqueueCommand(item)
772
- }
773
-
774
- deleteMatterQueue = async (_nodeIdString) => {
775
- const nodeId = String(_nodeIdString)
776
- this.commandQueue = this.commandQueue.filter((el) => String(el.nodeId) !== nodeId)
777
- }
778
-
779
- _withCommandTimeout = async (operation) => {
780
- let timer
781
- try {
782
- return await Promise.race([
783
- Promise.resolve().then(operation),
784
- new Promise((resolve, reject) => {
785
- timer = setTimeout(() => {
786
- const error = new Error(`Matter command timed out after ${this.commandTimeoutMs} ms`)
787
- error.code = 'MATTER_COMMAND_TIMEOUT'
788
- reject(error)
789
- }, this.commandTimeoutMs)
790
- timer.unref?.()
791
- })
792
- ])
793
- } finally {
794
- if (timer !== undefined) clearTimeout(timer)
795
- }
796
- }
797
-
798
- processQueueItem = async (_item = undefined) => {
799
- let item = _item ?? null
800
- try {
801
- if (this.matterConnectionStatus !== 'connected') return
802
- if (item === null) item = this.commandQueue.pop()
803
- if (!item) return
804
- const node = this.pairedNodes.get(item.nodeId)
805
- if (node === undefined || !this._isNodeCommissioned(item.nodeId)) {
806
- const error = new Error(`Matter node ${item.nodeId} is no longer commissioned`)
807
- error.code = 'MATTER_NODE_NOT_COMMISSIONED'
808
- throw error
809
- }
810
- const clusterClient = this._findClusterClient(node, item.endpointId, item.clusterId)
811
- if (clusterClient === undefined) throw new Error(`Cluster ${item.clusterId} not found on endpoint ${item.endpointId} of node ${item.nodeId}`)
812
- if (item.kind === 'attributeWrite') {
813
- const attribute = clusterClient.attributes[item.name]
814
- if (attribute === undefined) throw new Error(`Attribute ${item.name} not found in cluster ${clusterClient.name}`)
815
- await this._withCommandTimeout(() => attribute.set(item.args))
816
- } else {
817
- const command = clusterClient.commands[item.name]
818
- if (typeof command !== 'function') throw new Error(`Command ${item.name} not found in cluster ${clusterClient.name}`)
819
- await this._withCommandTimeout(() => command(item.args))
820
- }
821
- } catch (error) {
822
- const target = item ? `${item.nodeId}/${item.endpointId}/${item.clusterId}/${item.name}` : 'unknown'
823
- if (!error.code && item) {
824
- let connectionState = 'unknown'
825
- try {
826
- const targetNode = this.pairedNodes.get(item.nodeId)
827
- if (targetNode?.connectionState !== undefined) connectionState = this.nodeStateToString(targetNode.connectionState)
828
- } catch (stateError) { /* empty */ }
829
- if (connectionState !== 'unknown' && connectionState !== 'connected') {
830
- error.code = 'MATTER_NODE_UNAVAILABLE'
831
- } else if (/disconnected|reconnecting|unreachable|no session|peer communication|network.*(?:failed|error)|timed? ?out/i.test(error.message || '')) {
832
- error.code = 'MATTER_NODE_UNAVAILABLE'
833
- }
834
- }
835
- this._logThrottled('error', `matter:queue:error:${target}`, `classMatter: processQueueItem (${target}): ${error.message}`, 30000)
836
- this.emit('commandError', { item, error: error.message, code: error.code })
837
- }
838
- }
839
-
840
- _takeNextQueueItem = () => {
841
- if (!Array.isArray(this.commandQueue) || this.commandQueue.length === 0) return undefined
842
- // New items are unshifted, therefore the oldest FIFO item is at the end.
843
- // Walk backwards until a device lane that is not already busy is found.
844
- for (let index = this.commandQueue.length - 1; index >= 0; index--) {
845
- const item = this.commandQueue[index]
846
- const nodeId = String(item?.nodeId ?? '')
847
- if (this.commandQueueInFlight.has(nodeId)) continue
848
- return this.commandQueue.splice(index, 1)[0]
849
- }
850
- return undefined
851
- }
852
-
853
- _dispatchQueueItems = () => {
854
- if (this.matterConnectionStatus !== 'connected') return
855
- while (this.commandQueueInFlight.size < this.queueMaxConcurrent) {
856
- const item = this._takeNextQueueItem()
857
- if (!item) return
858
- const nodeId = String(item.nodeId)
859
- const laneToken = {}
860
- this.commandQueueInFlight.set(nodeId, laneToken)
861
- Promise.resolve(this.processQueueItem(item))
862
- .catch((error) => this._logThrottled('error', `matter:queue:lane:${nodeId}`, `classMatter: queue lane ${nodeId}: ${error.message}`, 30000))
863
- .finally(() => {
864
- if (this.commandQueueInFlight.get(nodeId) === laneToken) this.commandQueueInFlight.delete(nodeId)
865
- })
866
- }
867
- }
868
-
869
- handleQueue = async () => {
870
- do {
871
- if (this.matterConnectionStatus === 'connected' && this.commandQueue && this.commandQueue.length > 0) {
872
- this._dispatchQueueItems()
873
- }
874
- await pleaseWait(this.queuePollMs)
875
- } while (!this.exitAllQueues)
876
- }
877
-
878
- close = async () => {
879
- this.exitAllQueues = true
880
- this.commandQueue = []
881
- this.commandQueueInFlight.clear()
882
- this._logThrottle.clear()
883
- this.matterConnectionStatus = 'disconnected'
884
- try {
885
- if (this.controller !== null) await this.controller.close()
886
- } catch (error) {
887
- this._log('warn', `classMatter: close: ${error.message}`)
888
- }
889
- this.controller = null
890
- this.pairedNodes.clear()
891
- }
892
- }
893
-
894
- export { classMatter }