@smarthome.exchange/integrations 1.0.0 → 3.0.0

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 (529) hide show
  1. package/changelog.md +84 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/core/classes.configstore.d.ts +2 -0
  4. package/dist_ts/core/classes.configstore.js +84 -27
  5. package/dist_ts/core/classes.nativehomeadmission.d.ts +19 -0
  6. package/dist_ts/core/classes.nativehomeadmission.js +84 -0
  7. package/dist_ts/core/classes.nativeintegrationowner.d.ts +81 -0
  8. package/dist_ts/core/classes.nativeintegrationowner.js +273 -0
  9. package/dist_ts/core/classes.runtimemanager.d.ts +2 -0
  10. package/dist_ts/core/classes.runtimemanager.js +11 -3
  11. package/dist_ts/core/index.d.ts +2 -0
  12. package/dist_ts/core/index.js +3 -1
  13. package/dist_ts/core/types.d.ts +16 -0
  14. package/dist_ts/integrations/braviatv/braviatv.classes.client.d.ts +23 -72
  15. package/dist_ts/integrations/braviatv/braviatv.classes.client.js +265 -625
  16. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.d.ts +7 -7
  17. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.js +51 -68
  18. package/dist_ts/integrations/braviatv/braviatv.classes.integration.d.ts +8 -11
  19. package/dist_ts/integrations/braviatv/braviatv.classes.integration.js +186 -135
  20. package/dist_ts/integrations/braviatv/braviatv.discovery.js +12 -11
  21. package/dist_ts/integrations/braviatv/braviatv.mapper.d.ts +6 -14
  22. package/dist_ts/integrations/braviatv/braviatv.mapper.js +37 -131
  23. package/dist_ts/integrations/braviatv/braviatv.types.d.ts +55 -133
  24. package/dist_ts/integrations/braviatv/braviatv.validation.d.ts +7 -0
  25. package/dist_ts/integrations/braviatv/braviatv.validation.js +72 -0
  26. package/dist_ts/integrations/broadlink/broadlink.actions.d.ts +2 -0
  27. package/dist_ts/integrations/broadlink/broadlink.actions.js +36 -0
  28. package/dist_ts/integrations/broadlink/broadlink.classes.client.d.ts +21 -19
  29. package/dist_ts/integrations/broadlink/broadlink.classes.client.js +185 -124
  30. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.d.ts +5 -4
  31. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.js +64 -83
  32. package/dist_ts/integrations/broadlink/broadlink.classes.integration.d.ts +16 -19
  33. package/dist_ts/integrations/broadlink/broadlink.classes.integration.js +114 -59
  34. package/dist_ts/integrations/broadlink/broadlink.mapper.d.ts +3 -2
  35. package/dist_ts/integrations/broadlink/broadlink.mapper.js +2 -1
  36. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.d.ts +10 -0
  37. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.js +41 -0
  38. package/dist_ts/integrations/broadlink/broadlink.types.d.ts +43 -7
  39. package/dist_ts/integrations/broadlink/broadlink.validation.d.ts +7 -0
  40. package/dist_ts/integrations/broadlink/broadlink.validation.js +63 -0
  41. package/dist_ts/integrations/daikin/daikin.classes.client.d.ts +10 -52
  42. package/dist_ts/integrations/daikin/daikin.classes.client.js +55 -614
  43. package/dist_ts/integrations/daikin/daikin.classes.configflow.d.ts +8 -12
  44. package/dist_ts/integrations/daikin/daikin.classes.configflow.js +77 -138
  45. package/dist_ts/integrations/daikin/daikin.classes.integration.d.ts +7 -24
  46. package/dist_ts/integrations/daikin/daikin.classes.integration.js +175 -67
  47. package/dist_ts/integrations/daikin/daikin.discovery.d.ts +11 -24
  48. package/dist_ts/integrations/daikin/daikin.discovery.js +98 -305
  49. package/dist_ts/integrations/daikin/daikin.mapper.d.ts +6 -7
  50. package/dist_ts/integrations/daikin/daikin.mapper.js +95 -155
  51. package/dist_ts/integrations/daikin/daikin.types.d.ts +24 -44
  52. package/dist_ts/integrations/daikin/daikin.types.js +1 -1
  53. package/dist_ts/integrations/daikin/daikin.validation.d.ts +5 -0
  54. package/dist_ts/integrations/daikin/daikin.validation.js +53 -0
  55. package/dist_ts/integrations/deconz/deconz.classes.client.d.ts +37 -29
  56. package/dist_ts/integrations/deconz/deconz.classes.client.js +521 -294
  57. package/dist_ts/integrations/deconz/deconz.classes.configflow.d.ts +6 -1
  58. package/dist_ts/integrations/deconz/deconz.classes.configflow.js +63 -33
  59. package/dist_ts/integrations/deconz/deconz.classes.integration.d.ts +4 -3
  60. package/dist_ts/integrations/deconz/deconz.classes.integration.js +85 -40
  61. package/dist_ts/integrations/deconz/deconz.mapper.d.ts +1 -0
  62. package/dist_ts/integrations/deconz/deconz.mapper.js +24 -6
  63. package/dist_ts/integrations/deconz/deconz.types.d.ts +43 -6
  64. package/dist_ts/integrations/deconz/deconz.validation.d.ts +7 -1
  65. package/dist_ts/integrations/deconz/deconz.validation.js +215 -4
  66. package/dist_ts/integrations/denonavr/denonavr.classes.client.d.ts +31 -40
  67. package/dist_ts/integrations/denonavr/denonavr.classes.client.js +149 -404
  68. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.d.ts +7 -2
  69. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.js +44 -36
  70. package/dist_ts/integrations/denonavr/denonavr.classes.integration.d.ts +6 -11
  71. package/dist_ts/integrations/denonavr/denonavr.classes.integration.js +192 -113
  72. package/dist_ts/integrations/denonavr/denonavr.discovery.d.ts +10 -18
  73. package/dist_ts/integrations/denonavr/denonavr.discovery.js +71 -193
  74. package/dist_ts/integrations/denonavr/denonavr.mapper.d.ts +5 -13
  75. package/dist_ts/integrations/denonavr/denonavr.mapper.js +35 -159
  76. package/dist_ts/integrations/denonavr/denonavr.types.d.ts +55 -90
  77. package/dist_ts/integrations/denonavr/denonavr.validation.d.ts +10 -0
  78. package/dist_ts/integrations/denonavr/denonavr.validation.js +86 -0
  79. package/dist_ts/integrations/esphome/esphome.classes.client.d.ts +19 -7
  80. package/dist_ts/integrations/esphome/esphome.classes.client.js +183 -89
  81. package/dist_ts/integrations/esphome/esphome.classes.configflow.d.ts +5 -2
  82. package/dist_ts/integrations/esphome/esphome.classes.configflow.js +43 -33
  83. package/dist_ts/integrations/esphome/esphome.classes.integration.d.ts +8 -6
  84. package/dist_ts/integrations/esphome/esphome.classes.integration.js +71 -43
  85. package/dist_ts/integrations/esphome/esphome.discovery.js +4 -12
  86. package/dist_ts/integrations/esphome/esphome.mapper.d.ts +2 -2
  87. package/dist_ts/integrations/esphome/esphome.mapper.js +6 -4
  88. package/dist_ts/integrations/esphome/esphome.types.d.ts +31 -6
  89. package/dist_ts/integrations/esphome/esphome.types.js +1 -1
  90. package/dist_ts/integrations/esphome/esphome.validation.d.ts +7 -0
  91. package/dist_ts/integrations/esphome/esphome.validation.js +66 -0
  92. package/dist_ts/integrations/homeassistant/homeassistant.classes.client.d.ts +32 -4
  93. package/dist_ts/integrations/homeassistant/homeassistant.classes.client.js +345 -116
  94. package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.d.ts +8 -5
  95. package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.js +34 -8
  96. package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.d.ts +7 -4
  97. package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.js +44 -56
  98. package/dist_ts/integrations/homeassistant/homeassistant.types.d.ts +12 -1
  99. package/dist_ts/integrations/hue/hue.classes.client.d.ts +6 -1
  100. package/dist_ts/integrations/hue/hue.classes.client.js +120 -45
  101. package/dist_ts/integrations/hue/hue.classes.configflow.js +16 -7
  102. package/dist_ts/integrations/hue/hue.classes.integration.d.ts +2 -0
  103. package/dist_ts/integrations/hue/hue.classes.integration.js +103 -30
  104. package/dist_ts/integrations/hue/hue.validation.d.ts +1 -0
  105. package/dist_ts/integrations/hue/hue.validation.js +14 -4
  106. package/dist_ts/integrations/kodi/kodi.classes.client.d.ts +11 -45
  107. package/dist_ts/integrations/kodi/kodi.classes.client.js +84 -310
  108. package/dist_ts/integrations/kodi/kodi.classes.configflow.d.ts +9 -8
  109. package/dist_ts/integrations/kodi/kodi.classes.configflow.js +53 -48
  110. package/dist_ts/integrations/kodi/kodi.classes.integration.d.ts +11 -11
  111. package/dist_ts/integrations/kodi/kodi.classes.integration.js +114 -171
  112. package/dist_ts/integrations/kodi/kodi.discovery.js +53 -29
  113. package/dist_ts/integrations/kodi/kodi.mapper.d.ts +7 -2
  114. package/dist_ts/integrations/kodi/kodi.mapper.js +48 -10
  115. package/dist_ts/integrations/kodi/kodi.types.d.ts +32 -28
  116. package/dist_ts/integrations/kodi/kodi.validation.d.ts +9 -0
  117. package/dist_ts/integrations/kodi/kodi.validation.js +62 -0
  118. package/dist_ts/integrations/modbus/modbus.classes.client.d.ts +15 -61
  119. package/dist_ts/integrations/modbus/modbus.classes.client.js +117 -776
  120. package/dist_ts/integrations/modbus/modbus.classes.configflow.d.ts +9 -5
  121. package/dist_ts/integrations/modbus/modbus.classes.configflow.js +70 -38
  122. package/dist_ts/integrations/modbus/modbus.classes.integration.d.ts +6 -17
  123. package/dist_ts/integrations/modbus/modbus.classes.integration.js +133 -57
  124. package/dist_ts/integrations/modbus/modbus.discovery.d.ts +5 -8
  125. package/dist_ts/integrations/modbus/modbus.discovery.js +38 -93
  126. package/dist_ts/integrations/modbus/modbus.mapper.d.ts +8 -32
  127. package/dist_ts/integrations/modbus/modbus.mapper.js +71 -431
  128. package/dist_ts/integrations/modbus/modbus.types.d.ts +82 -332
  129. package/dist_ts/integrations/modbus/modbus.validation.d.ts +10 -0
  130. package/dist_ts/integrations/modbus/modbus.validation.js +128 -0
  131. package/dist_ts/integrations/mqtt/mqtt.classes.client.d.ts +15 -2
  132. package/dist_ts/integrations/mqtt/mqtt.classes.client.js +173 -23
  133. package/dist_ts/integrations/mqtt/mqtt.classes.configflow.d.ts +5 -1
  134. package/dist_ts/integrations/mqtt/mqtt.classes.configflow.js +53 -33
  135. package/dist_ts/integrations/mqtt/mqtt.classes.integration.d.ts +4 -1
  136. package/dist_ts/integrations/mqtt/mqtt.classes.integration.js +127 -56
  137. package/dist_ts/integrations/mqtt/mqtt.classes.session.d.ts +13 -0
  138. package/dist_ts/integrations/mqtt/mqtt.classes.session.js +130 -0
  139. package/dist_ts/integrations/mqtt/mqtt.mapper.d.ts +3 -0
  140. package/dist_ts/integrations/mqtt/mqtt.mapper.js +44 -1
  141. package/dist_ts/integrations/mqtt/mqtt.types.d.ts +46 -0
  142. package/dist_ts/integrations/mqtt/mqtt.validation.d.ts +7 -0
  143. package/dist_ts/integrations/mqtt/mqtt.validation.js +180 -0
  144. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.d.ts +12 -34
  145. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.js +143 -231
  146. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.d.ts +6 -1
  147. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.js +105 -18
  148. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.d.ts +8 -8
  149. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.js +141 -155
  150. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.d.ts +9 -0
  151. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.js +35 -0
  152. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.d.ts +6 -18
  153. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.js +45 -220
  154. package/dist_ts/integrations/nanoleaf/nanoleaf.types.d.ts +33 -147
  155. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.d.ts +6 -0
  156. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.js +82 -0
  157. package/dist_ts/integrations/onkyo/onkyo.classes.client.d.ts +15 -20
  158. package/dist_ts/integrations/onkyo/onkyo.classes.client.js +161 -404
  159. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.d.ts +9 -4
  160. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.js +51 -6
  161. package/dist_ts/integrations/onkyo/onkyo.classes.integration.d.ts +22 -6
  162. package/dist_ts/integrations/onkyo/onkyo.classes.integration.js +144 -11
  163. package/dist_ts/integrations/onkyo/onkyo.discovery.d.ts +6 -1
  164. package/dist_ts/integrations/onkyo/onkyo.discovery.js +40 -4
  165. package/dist_ts/integrations/onkyo/onkyo.mapper.d.ts +7 -8
  166. package/dist_ts/integrations/onkyo/onkyo.mapper.js +45 -12
  167. package/dist_ts/integrations/onkyo/onkyo.types.d.ts +58 -8
  168. package/dist_ts/integrations/onkyo/onkyo.types.js +13 -102
  169. package/dist_ts/integrations/onkyo/onkyo.validation.d.ts +16 -0
  170. package/dist_ts/integrations/onkyo/onkyo.validation.js +77 -0
  171. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.d.ts +25 -25
  172. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.js +116 -360
  173. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.d.ts +11 -3
  174. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.js +76 -6
  175. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.d.ts +26 -4
  176. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.js +142 -9
  177. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.d.ts +2 -1
  178. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.js +31 -4
  179. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.d.ts +9 -9
  180. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.js +31 -149
  181. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.d.ts +51 -11
  182. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.js +22 -87
  183. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.d.ts +6 -0
  184. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.js +56 -0
  185. package/dist_ts/integrations/pioneer/pioneer.classes.client.d.ts +31 -16
  186. package/dist_ts/integrations/pioneer/pioneer.classes.client.js +167 -409
  187. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.d.ts +10 -3
  188. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.js +66 -6
  189. package/dist_ts/integrations/pioneer/pioneer.classes.integration.d.ts +13 -5
  190. package/dist_ts/integrations/pioneer/pioneer.classes.integration.js +239 -11
  191. package/dist_ts/integrations/pioneer/pioneer.discovery.d.ts +14 -1
  192. package/dist_ts/integrations/pioneer/pioneer.discovery.js +51 -4
  193. package/dist_ts/integrations/pioneer/pioneer.mapper.d.ts +14 -8
  194. package/dist_ts/integrations/pioneer/pioneer.mapper.js +54 -12
  195. package/dist_ts/integrations/pioneer/pioneer.types.d.ts +79 -12
  196. package/dist_ts/integrations/pioneer/pioneer.types.js +12 -76
  197. package/dist_ts/integrations/pioneer/pioneer.validation.d.ts +10 -0
  198. package/dist_ts/integrations/pioneer/pioneer.validation.js +85 -0
  199. package/dist_ts/integrations/samsungtv/samsungtv.classes.client.d.ts +4 -2
  200. package/dist_ts/integrations/samsungtv/samsungtv.classes.client.js +41 -16
  201. package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.d.ts +5 -0
  202. package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.js +20 -7
  203. package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.d.ts +1 -0
  204. package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.js +53 -50
  205. package/dist_ts/integrations/samsungtv/samsungtv.types.d.ts +4 -1
  206. package/dist_ts/integrations/shelly/shelly.classes.client.d.ts +26 -30
  207. package/dist_ts/integrations/shelly/shelly.classes.client.js +504 -276
  208. package/dist_ts/integrations/shelly/shelly.classes.configflow.d.ts +8 -3
  209. package/dist_ts/integrations/shelly/shelly.classes.configflow.js +43 -38
  210. package/dist_ts/integrations/shelly/shelly.classes.integration.d.ts +6 -6
  211. package/dist_ts/integrations/shelly/shelly.classes.integration.js +103 -101
  212. package/dist_ts/integrations/shelly/shelly.classes.subscription.d.ts +4 -0
  213. package/dist_ts/integrations/shelly/shelly.classes.subscription.js +24 -2
  214. package/dist_ts/integrations/shelly/shelly.mapper.d.ts +1 -2
  215. package/dist_ts/integrations/shelly/shelly.mapper.js +21 -20
  216. package/dist_ts/integrations/shelly/shelly.rpc.js +4 -1
  217. package/dist_ts/integrations/shelly/shelly.types.d.ts +42 -2
  218. package/dist_ts/integrations/shelly/shelly.types.js +11 -2
  219. package/dist_ts/integrations/shelly/shelly.validation.d.ts +7 -0
  220. package/dist_ts/integrations/shelly/shelly.validation.js +79 -0
  221. package/dist_ts/integrations/sonos/sonos.classes.client.d.ts +79 -22
  222. package/dist_ts/integrations/sonos/sonos.classes.client.js +427 -139
  223. package/dist_ts/integrations/sonos/sonos.classes.configflow.d.ts +9 -2
  224. package/dist_ts/integrations/sonos/sonos.classes.configflow.js +26 -28
  225. package/dist_ts/integrations/sonos/sonos.classes.integration.d.ts +7 -6
  226. package/dist_ts/integrations/sonos/sonos.classes.integration.js +289 -224
  227. package/dist_ts/integrations/sonos/sonos.config.d.ts +6 -1
  228. package/dist_ts/integrations/sonos/sonos.config.js +23 -2
  229. package/dist_ts/integrations/sonos/sonos.mapper.d.ts +1 -1
  230. package/dist_ts/integrations/sonos/sonos.mapper.js +14 -9
  231. package/dist_ts/integrations/sonos/sonos.matchers.js +3 -3
  232. package/dist_ts/integrations/sonos/sonos.types.d.ts +26 -1
  233. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.d.ts +13 -36
  234. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.js +179 -502
  235. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.d.ts +6 -1
  236. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.js +50 -40
  237. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.d.ts +14 -15
  238. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.js +108 -128
  239. package/dist_ts/integrations/soundtouch/soundtouch.discovery.d.ts +2 -20
  240. package/dist_ts/integrations/soundtouch/soundtouch.discovery.js +23 -113
  241. package/dist_ts/integrations/soundtouch/soundtouch.mapper.d.ts +3 -12
  242. package/dist_ts/integrations/soundtouch/soundtouch.mapper.js +35 -189
  243. package/dist_ts/integrations/soundtouch/soundtouch.types.d.ts +57 -142
  244. package/dist_ts/integrations/soundtouch/soundtouch.types.js +18 -3
  245. package/dist_ts/integrations/soundtouch/soundtouch.validation.d.ts +22 -0
  246. package/dist_ts/integrations/soundtouch/soundtouch.validation.js +65 -0
  247. package/dist_ts/integrations/tasmota/tasmota.classes.integration.d.ts +5 -0
  248. package/dist_ts/integrations/tasmota/tasmota.classes.integration.js +23 -7
  249. package/dist_ts/integrations/tasmota/tasmota.classes.runtime.d.ts +19 -5
  250. package/dist_ts/integrations/tasmota/tasmota.classes.runtime.js +115 -41
  251. package/dist_ts/integrations/tasmota/tasmota.config.js +23 -1
  252. package/dist_ts/integrations/tasmota/tasmota.credentials.d.ts +11 -0
  253. package/dist_ts/integrations/tasmota/tasmota.credentials.js +97 -0
  254. package/dist_ts/integrations/tasmota/tasmota.discovery.d.ts +7 -1
  255. package/dist_ts/integrations/tasmota/tasmota.discovery.js +108 -30
  256. package/dist_ts/integrations/tasmota/tasmota.mapper.d.ts +2 -2
  257. package/dist_ts/integrations/tasmota/tasmota.mapper.js +7 -7
  258. package/dist_ts/integrations/tasmota/tasmota.types.d.ts +41 -2
  259. package/dist_ts/integrations/tuya/tuya.classes.integration.d.ts +4 -1
  260. package/dist_ts/integrations/tuya/tuya.classes.integration.js +79 -110
  261. package/dist_ts/integrations/tuya/tuya.classes.runtime.d.ts +5 -2
  262. package/dist_ts/integrations/tuya/tuya.classes.runtime.js +73 -26
  263. package/dist_ts/integrations/tuya/tuya.mapper.js +2 -2
  264. package/dist_ts/integrations/tuya/tuya.types.d.ts +3 -0
  265. package/dist_ts/integrations/tuya/tuya.validation.d.ts +2 -2
  266. package/dist_ts/integrations/tuya/tuya.validation.js +6 -11
  267. package/dist_ts/integrations/webostv/webostv.classes.client.d.ts +6 -5
  268. package/dist_ts/integrations/webostv/webostv.classes.client.js +147 -76
  269. package/dist_ts/integrations/webostv/webostv.classes.configflow.d.ts +7 -2
  270. package/dist_ts/integrations/webostv/webostv.classes.configflow.js +36 -20
  271. package/dist_ts/integrations/webostv/webostv.classes.integration.d.ts +4 -4
  272. package/dist_ts/integrations/webostv/webostv.classes.integration.js +46 -54
  273. package/dist_ts/integrations/webostv/webostv.mapper.js +5 -5
  274. package/dist_ts/integrations/webostv/webostv.types.d.ts +16 -3
  275. package/dist_ts/integrations/webostv/webostv.types.js +1 -1
  276. package/dist_ts/integrations/webostv/webostv.validation.d.ts +3 -1
  277. package/dist_ts/integrations/webostv/webostv.validation.js +23 -1
  278. package/dist_ts/integrations/wiz/index.d.ts +1 -0
  279. package/dist_ts/integrations/wiz/index.js +2 -1
  280. package/dist_ts/integrations/wiz/wiz.classes.client.d.ts +14 -28
  281. package/dist_ts/integrations/wiz/wiz.classes.client.js +93 -229
  282. package/dist_ts/integrations/wiz/wiz.classes.configflow.d.ts +6 -4
  283. package/dist_ts/integrations/wiz/wiz.classes.configflow.js +38 -67
  284. package/dist_ts/integrations/wiz/wiz.classes.integration.d.ts +10 -21
  285. package/dist_ts/integrations/wiz/wiz.classes.integration.js +204 -44
  286. package/dist_ts/integrations/wiz/wiz.discovery.d.ts +10 -31
  287. package/dist_ts/integrations/wiz/wiz.discovery.js +48 -249
  288. package/dist_ts/integrations/wiz/wiz.mapper.d.ts +7 -51
  289. package/dist_ts/integrations/wiz/wiz.mapper.js +82 -668
  290. package/dist_ts/integrations/wiz/wiz.types.d.ts +34 -208
  291. package/dist_ts/integrations/wiz/wiz.validation.d.ts +8 -0
  292. package/dist_ts/integrations/wiz/wiz.validation.js +72 -0
  293. package/dist_ts/integrations/yamaha/index.d.ts +1 -0
  294. package/dist_ts/integrations/yamaha/index.js +2 -1
  295. package/dist_ts/integrations/yamaha/yamaha.classes.client.d.ts +30 -4
  296. package/dist_ts/integrations/yamaha/yamaha.classes.client.js +162 -6
  297. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.d.ts +10 -3
  298. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.js +106 -6
  299. package/dist_ts/integrations/yamaha/yamaha.classes.integration.d.ts +22 -4
  300. package/dist_ts/integrations/yamaha/yamaha.classes.integration.js +243 -8
  301. package/dist_ts/integrations/yamaha/yamaha.discovery.d.ts +13 -1
  302. package/dist_ts/integrations/yamaha/yamaha.discovery.js +57 -4
  303. package/dist_ts/integrations/yamaha/yamaha.mapper.d.ts +16 -8
  304. package/dist_ts/integrations/yamaha/yamaha.mapper.js +58 -12
  305. package/dist_ts/integrations/yamaha/yamaha.types.d.ts +73 -6
  306. package/dist_ts/integrations/yamaha/yamaha.types.js +8 -94
  307. package/dist_ts/integrations/yamaha/yamaha.validation.d.ts +12 -0
  308. package/dist_ts/integrations/yamaha/yamaha.validation.js +89 -0
  309. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.d.ts +6 -1
  310. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.js +18 -8
  311. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.d.ts +4 -1
  312. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.js +54 -6
  313. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.d.ts +12 -6
  314. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.js +73 -59
  315. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.d.ts +3 -2
  316. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.js +17 -12
  317. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.types.d.ts +31 -2
  318. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.d.ts +9 -1
  319. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.js +57 -7
  320. package/dist_ts/integrations/zwave_js/zwave_js.classes.client.d.ts +10 -4
  321. package/dist_ts/integrations/zwave_js/zwave_js.classes.client.js +167 -31
  322. package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.d.ts +6 -1
  323. package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.js +57 -35
  324. package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.d.ts +3 -1
  325. package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.js +59 -37
  326. package/dist_ts/integrations/zwave_js/zwave_js.discovery.js +3 -3
  327. package/dist_ts/integrations/zwave_js/zwave_js.mapper.js +41 -24
  328. package/dist_ts/integrations/zwave_js/zwave_js.types.d.ts +25 -3
  329. package/dist_ts/integrations/zwave_js/zwave_js.validation.d.ts +6 -2
  330. package/dist_ts/integrations/zwave_js/zwave_js.validation.js +52 -17
  331. package/dist_ts/plugins.d.ts +2 -1
  332. package/dist_ts/plugins.js +3 -2
  333. package/package.json +9 -9
  334. package/readme.md +539 -8
  335. package/ts/00_commitinfo_data.ts +1 -1
  336. package/ts/core/classes.configstore.ts +84 -27
  337. package/ts/core/classes.nativehomeadmission.ts +96 -0
  338. package/ts/core/classes.nativeintegrationowner.ts +302 -0
  339. package/ts/core/classes.runtimemanager.ts +11 -2
  340. package/ts/core/index.ts +2 -0
  341. package/ts/core/types.ts +18 -0
  342. package/ts/integrations/braviatv/braviatv.classes.client.ts +245 -709
  343. package/ts/integrations/braviatv/braviatv.classes.configflow.ts +47 -76
  344. package/ts/integrations/braviatv/braviatv.classes.integration.ts +167 -147
  345. package/ts/integrations/braviatv/braviatv.discovery.ts +11 -10
  346. package/ts/integrations/braviatv/braviatv.mapper.ts +39 -142
  347. package/ts/integrations/braviatv/braviatv.types.ts +53 -173
  348. package/ts/integrations/braviatv/braviatv.validation.ts +68 -0
  349. package/ts/integrations/broadlink/broadlink.actions.ts +31 -0
  350. package/ts/integrations/broadlink/broadlink.classes.client.ts +170 -144
  351. package/ts/integrations/broadlink/broadlink.classes.configflow.ts +59 -89
  352. package/ts/integrations/broadlink/broadlink.classes.integration.ts +110 -64
  353. package/ts/integrations/broadlink/broadlink.mapper.ts +5 -4
  354. package/ts/integrations/broadlink/broadlink.selected.mapper.ts +46 -0
  355. package/ts/integrations/broadlink/broadlink.types.ts +48 -8
  356. package/ts/integrations/broadlink/broadlink.validation.ts +66 -0
  357. package/ts/integrations/daikin/daikin.classes.client.ts +52 -661
  358. package/ts/integrations/daikin/daikin.classes.configflow.ts +72 -152
  359. package/ts/integrations/daikin/daikin.classes.integration.ts +166 -71
  360. package/ts/integrations/daikin/daikin.discovery.ts +94 -346
  361. package/ts/integrations/daikin/daikin.mapper.ts +83 -166
  362. package/ts/integrations/daikin/daikin.types.ts +27 -48
  363. package/ts/integrations/daikin/daikin.validation.ts +51 -0
  364. package/ts/integrations/daikin/readme.md +83 -0
  365. package/ts/integrations/deconz/deconz.classes.client.ts +348 -252
  366. package/ts/integrations/deconz/deconz.classes.configflow.ts +57 -29
  367. package/ts/integrations/deconz/deconz.classes.integration.ts +69 -37
  368. package/ts/integrations/deconz/deconz.mapper.ts +22 -5
  369. package/ts/integrations/deconz/deconz.types.ts +49 -6
  370. package/ts/integrations/deconz/deconz.validation.ts +177 -4
  371. package/ts/integrations/deconz/readme.md +15 -1
  372. package/ts/integrations/denonavr/denonavr.classes.client.ts +132 -421
  373. package/ts/integrations/denonavr/denonavr.classes.configflow.ts +44 -37
  374. package/ts/integrations/denonavr/denonavr.classes.integration.ts +171 -117
  375. package/ts/integrations/denonavr/denonavr.discovery.ts +67 -220
  376. package/ts/integrations/denonavr/denonavr.mapper.ts +36 -182
  377. package/ts/integrations/denonavr/denonavr.types.ts +48 -111
  378. package/ts/integrations/denonavr/denonavr.validation.ts +87 -0
  379. package/ts/integrations/esphome/esphome.classes.client.ts +179 -94
  380. package/ts/integrations/esphome/esphome.classes.configflow.ts +40 -33
  381. package/ts/integrations/esphome/esphome.classes.integration.ts +63 -36
  382. package/ts/integrations/esphome/esphome.discovery.ts +3 -12
  383. package/ts/integrations/esphome/esphome.mapper.ts +9 -7
  384. package/ts/integrations/esphome/esphome.types.ts +35 -6
  385. package/ts/integrations/esphome/esphome.validation.ts +66 -0
  386. package/ts/integrations/esphome/readme.md +20 -6
  387. package/ts/integrations/homeassistant/homeassistant.classes.client.ts +353 -125
  388. package/ts/integrations/homeassistant/homeassistant.classes.integration.ts +35 -18
  389. package/ts/integrations/homeassistant/homeassistant.classes.runtime.ts +50 -63
  390. package/ts/integrations/homeassistant/homeassistant.types.ts +17 -1
  391. package/ts/integrations/homeassistant/readme.md +22 -6
  392. package/ts/integrations/hue/hue.classes.client.ts +110 -41
  393. package/ts/integrations/hue/hue.classes.configflow.ts +12 -6
  394. package/ts/integrations/hue/hue.classes.integration.ts +92 -26
  395. package/ts/integrations/hue/hue.validation.ts +13 -3
  396. package/ts/integrations/hue/readme.md +3 -3
  397. package/ts/integrations/kodi/kodi.classes.client.ts +72 -352
  398. package/ts/integrations/kodi/kodi.classes.configflow.ts +52 -55
  399. package/ts/integrations/kodi/kodi.classes.integration.ts +97 -178
  400. package/ts/integrations/kodi/kodi.discovery.ts +49 -28
  401. package/ts/integrations/kodi/kodi.mapper.ts +52 -10
  402. package/ts/integrations/kodi/kodi.types.ts +33 -58
  403. package/ts/integrations/kodi/kodi.validation.ts +60 -0
  404. package/ts/integrations/modbus/modbus.classes.client.ts +100 -842
  405. package/ts/integrations/modbus/modbus.classes.configflow.ts +70 -41
  406. package/ts/integrations/modbus/modbus.classes.integration.ts +115 -60
  407. package/ts/integrations/modbus/modbus.discovery.ts +38 -106
  408. package/ts/integrations/modbus/modbus.mapper.ts +64 -467
  409. package/ts/integrations/modbus/modbus.types.ts +64 -381
  410. package/ts/integrations/modbus/modbus.validation.ts +119 -0
  411. package/ts/integrations/mqtt/mqtt.classes.client.ts +136 -19
  412. package/ts/integrations/mqtt/mqtt.classes.configflow.ts +45 -32
  413. package/ts/integrations/mqtt/mqtt.classes.integration.ts +99 -38
  414. package/ts/integrations/mqtt/mqtt.classes.session.ts +118 -0
  415. package/ts/integrations/mqtt/mqtt.mapper.ts +43 -1
  416. package/ts/integrations/mqtt/mqtt.types.ts +52 -0
  417. package/ts/integrations/mqtt/mqtt.validation.ts +157 -0
  418. package/ts/integrations/mqtt/readme.md +12 -3
  419. package/ts/integrations/nanoleaf/nanoleaf.classes.client.ts +115 -249
  420. package/ts/integrations/nanoleaf/nanoleaf.classes.configflow.ts +90 -19
  421. package/ts/integrations/nanoleaf/nanoleaf.classes.integration.ts +130 -181
  422. package/ts/integrations/nanoleaf/nanoleaf.credentials.ts +39 -0
  423. package/ts/integrations/nanoleaf/nanoleaf.mapper.ts +47 -260
  424. package/ts/integrations/nanoleaf/nanoleaf.types.ts +29 -147
  425. package/ts/integrations/nanoleaf/nanoleaf.validation.ts +77 -0
  426. package/ts/integrations/onkyo/onkyo.classes.client.ts +148 -457
  427. package/ts/integrations/onkyo/onkyo.classes.configflow.ts +52 -6
  428. package/ts/integrations/onkyo/onkyo.classes.integration.ts +121 -12
  429. package/ts/integrations/onkyo/onkyo.discovery.ts +41 -3
  430. package/ts/integrations/onkyo/onkyo.mapper.ts +46 -19
  431. package/ts/integrations/onkyo/onkyo.types.ts +55 -110
  432. package/ts/integrations/onkyo/onkyo.validation.ts +85 -0
  433. package/ts/integrations/onkyo/readme.md +126 -0
  434. package/ts/integrations/panasonic_viera/panasonic_viera.classes.client.ts +101 -398
  435. package/ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.ts +69 -5
  436. package/ts/integrations/panasonic_viera/panasonic_viera.classes.integration.ts +141 -9
  437. package/ts/integrations/panasonic_viera/panasonic_viera.discovery.ts +32 -3
  438. package/ts/integrations/panasonic_viera/panasonic_viera.mapper.ts +34 -161
  439. package/ts/integrations/panasonic_viera/panasonic_viera.types.ts +52 -96
  440. package/ts/integrations/panasonic_viera/panasonic_viera.validation.ts +56 -0
  441. package/ts/integrations/pioneer/pioneer.classes.client.ts +132 -428
  442. package/ts/integrations/pioneer/pioneer.classes.configflow.ts +67 -5
  443. package/ts/integrations/pioneer/pioneer.classes.integration.ts +225 -11
  444. package/ts/integrations/pioneer/pioneer.discovery.ts +45 -3
  445. package/ts/integrations/pioneer/pioneer.mapper.ts +57 -13
  446. package/ts/integrations/pioneer/pioneer.types.ts +87 -85
  447. package/ts/integrations/pioneer/pioneer.validation.ts +84 -0
  448. package/ts/integrations/samsungtv/readme.md +11 -5
  449. package/ts/integrations/samsungtv/samsungtv.classes.client.ts +40 -15
  450. package/ts/integrations/samsungtv/samsungtv.classes.configflow.ts +21 -6
  451. package/ts/integrations/samsungtv/samsungtv.classes.integration.ts +53 -38
  452. package/ts/integrations/samsungtv/samsungtv.types.ts +4 -1
  453. package/ts/integrations/shelly/readme.md +22 -7
  454. package/ts/integrations/shelly/shelly.classes.client.ts +386 -269
  455. package/ts/integrations/shelly/shelly.classes.configflow.ts +43 -38
  456. package/ts/integrations/shelly/shelly.classes.integration.ts +92 -111
  457. package/ts/integrations/shelly/shelly.classes.subscription.ts +24 -1
  458. package/ts/integrations/shelly/shelly.mapper.ts +19 -20
  459. package/ts/integrations/shelly/shelly.rpc.ts +2 -0
  460. package/ts/integrations/shelly/shelly.types.ts +50 -2
  461. package/ts/integrations/shelly/shelly.validation.ts +76 -0
  462. package/ts/integrations/sonos/readme.md +117 -38
  463. package/ts/integrations/sonos/sonos.classes.client.ts +392 -123
  464. package/ts/integrations/sonos/sonos.classes.configflow.ts +25 -28
  465. package/ts/integrations/sonos/sonos.classes.integration.ts +211 -186
  466. package/ts/integrations/sonos/sonos.config.ts +24 -2
  467. package/ts/integrations/sonos/sonos.mapper.ts +13 -8
  468. package/ts/integrations/sonos/sonos.matchers.ts +2 -2
  469. package/ts/integrations/sonos/sonos.types.ts +30 -1
  470. package/ts/integrations/soundtouch/soundtouch.classes.client.ts +152 -571
  471. package/ts/integrations/soundtouch/soundtouch.classes.configflow.ts +47 -42
  472. package/ts/integrations/soundtouch/soundtouch.classes.integration.ts +95 -150
  473. package/ts/integrations/soundtouch/soundtouch.discovery.ts +21 -133
  474. package/ts/integrations/soundtouch/soundtouch.mapper.ts +36 -207
  475. package/ts/integrations/soundtouch/soundtouch.types.ts +50 -195
  476. package/ts/integrations/soundtouch/soundtouch.validation.ts +60 -0
  477. package/ts/integrations/tasmota/readme.md +16 -5
  478. package/ts/integrations/tasmota/tasmota.classes.integration.ts +24 -6
  479. package/ts/integrations/tasmota/tasmota.classes.runtime.ts +112 -43
  480. package/ts/integrations/tasmota/tasmota.config.ts +17 -0
  481. package/ts/integrations/tasmota/tasmota.credentials.ts +92 -0
  482. package/ts/integrations/tasmota/tasmota.discovery.ts +87 -24
  483. package/ts/integrations/tasmota/tasmota.mapper.ts +6 -6
  484. package/ts/integrations/tasmota/tasmota.types.ts +43 -2
  485. package/ts/integrations/tuya/readme.md +52 -10
  486. package/ts/integrations/tuya/tuya.classes.integration.ts +69 -98
  487. package/ts/integrations/tuya/tuya.classes.runtime.ts +70 -24
  488. package/ts/integrations/tuya/tuya.mapper.ts +1 -1
  489. package/ts/integrations/tuya/tuya.types.ts +4 -0
  490. package/ts/integrations/tuya/tuya.validation.ts +5 -8
  491. package/ts/integrations/webostv/readme.md +115 -22
  492. package/ts/integrations/webostv/webostv.classes.client.ts +123 -50
  493. package/ts/integrations/webostv/webostv.classes.configflow.ts +35 -15
  494. package/ts/integrations/webostv/webostv.classes.integration.ts +44 -37
  495. package/ts/integrations/webostv/webostv.mapper.ts +4 -4
  496. package/ts/integrations/webostv/webostv.types.ts +18 -3
  497. package/ts/integrations/webostv/webostv.validation.ts +22 -1
  498. package/ts/integrations/wiz/index.ts +1 -0
  499. package/ts/integrations/wiz/wiz.classes.client.ts +84 -254
  500. package/ts/integrations/wiz/wiz.classes.configflow.ts +39 -70
  501. package/ts/integrations/wiz/wiz.classes.integration.ts +189 -45
  502. package/ts/integrations/wiz/wiz.discovery.ts +48 -291
  503. package/ts/integrations/wiz/wiz.mapper.ts +81 -754
  504. package/ts/integrations/wiz/wiz.types.ts +24 -224
  505. package/ts/integrations/wiz/wiz.validation.ts +73 -0
  506. package/ts/integrations/yamaha/index.ts +1 -0
  507. package/ts/integrations/yamaha/yamaha.classes.client.ts +150 -6
  508. package/ts/integrations/yamaha/yamaha.classes.configflow.ts +100 -5
  509. package/ts/integrations/yamaha/yamaha.classes.integration.ts +236 -8
  510. package/ts/integrations/yamaha/yamaha.discovery.ts +52 -3
  511. package/ts/integrations/yamaha/yamaha.mapper.ts +65 -13
  512. package/ts/integrations/yamaha/yamaha.types.ts +77 -97
  513. package/ts/integrations/yamaha/yamaha.validation.ts +86 -0
  514. package/ts/integrations/zigbee2mqtt/readme.md +22 -27
  515. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.ts +16 -7
  516. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.ts +53 -6
  517. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.ts +62 -49
  518. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.ts +17 -11
  519. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.types.ts +35 -2
  520. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.ts +53 -7
  521. package/ts/integrations/zwave_js/readme.md +42 -9
  522. package/ts/integrations/zwave_js/zwave_js.classes.client.ts +155 -31
  523. package/ts/integrations/zwave_js/zwave_js.classes.configflow.ts +55 -31
  524. package/ts/integrations/zwave_js/zwave_js.classes.integration.ts +57 -35
  525. package/ts/integrations/zwave_js/zwave_js.discovery.ts +2 -2
  526. package/ts/integrations/zwave_js/zwave_js.mapper.ts +37 -23
  527. package/ts/integrations/zwave_js/zwave_js.types.ts +26 -3
  528. package/ts/integrations/zwave_js/zwave_js.validation.ts +52 -18
  529. package/ts/plugins.ts +2 -1
@@ -1,38 +1,62 @@
1
1
  import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
2
+ import { NativeIntegrationOwner, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
2
3
  import { ZwaveJsClient } from './zwave_js.classes.client.js';
3
- import type { IZwaveJsConfig } from './zwave_js.types.js';
4
- import { validateZwaveJsConfig } from './zwave_js.validation.js';
4
+ import type { IZwaveJsConfig, IZwaveJsIntegrationOptions } from './zwave_js.types.js';
5
+ import { captureZwaveJsData, normalizeZwaveJsOptions, validateZwaveJsConfig } from './zwave_js.validation.js';
5
6
 
6
7
  export class ZwaveJsConfigFlow implements IConfigFlow<IZwaveJsConfig> {
8
+ readonly #options: Readonly<IZwaveJsIntegrationOptions>;
9
+ readonly #scope: NativeIntegrationScope;
10
+
11
+ constructor(optionsArg: IZwaveJsIntegrationOptions = {}, scopeArg?: NativeIntegrationScope) {
12
+ this.#options = normalizeZwaveJsOptions(optionsArg);
13
+ this.#scope = scopeArg ?? new NativeIntegrationOwner('zwave_js', {
14
+ homeId: this.#options.homeId, capacity: this.#options.capacity,
15
+ }).createFlowScope();
16
+ }
17
+
7
18
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IZwaveJsConfig>> {
8
- void candidateArg;
9
- void contextArg;
10
- return {
11
- kind: 'form', title: 'Connect Z-Wave JS',
12
- description: 'Enter the explicit server endpoint and network home ID shown by Z-Wave JS. Proxy credentials require verified TLS.',
13
- fields: [
14
- { name: 'url', label: 'Server WebSocket URL', type: 'text', required: true },
15
- { name: 'expectedHomeId', label: 'Network home ID (decimal)', type: 'number', required: true },
16
- { name: 'authorization', label: 'TLS proxy Authorization header', type: 'password' },
17
- { name: 'ca', label: 'Additional TLS CA certificate (PEM)', type: 'text' },
18
- ],
19
- submit: async (valuesArg) => {
20
- let client: ZwaveJsClient | undefined;
21
- try {
22
- const config = validateZwaveJsConfig({
23
- url: typeof valuesArg.url === 'string' ? valuesArg.url : '',
24
- expectedHomeId: typeof valuesArg.expectedHomeId === 'number' ? valuesArg.expectedHomeId : 0,
25
- authorization: typeof valuesArg.authorization === 'string' && valuesArg.authorization ? valuesArg.authorization : undefined,
26
- ca: typeof valuesArg.ca === 'string' && valuesArg.ca ? valuesArg.ca : undefined,
27
- });
28
- client = new ZwaveJsClient(config);
29
- await client.start();
30
- return { kind: 'done', title: 'Verified Z-Wave JS network', config };
31
- } catch {
32
- return { kind: 'error', title: 'Z-Wave JS verification failed',
33
- description: 'Check the endpoint, network home ID, supported schema and TLS proxy admission.' };
34
- } finally { await client?.destroy(); }
35
- },
36
- };
19
+ try {
20
+ const candidate = captureZwaveJsData(candidateArg);
21
+ if (candidate.integrationDomain !== undefined && candidate.integrationDomain !== 'zwave_js') throw new Error('Foreign Z-Wave JS candidate.');
22
+ const admitted = this.#scope.admit(contextArg);
23
+ return {
24
+ kind: 'form', title: 'Connect selected Z-Wave JS server',
25
+ description: 'Select the server and its numeric Z-Wave network ID for the host-selected home. Optional proxy credentials use an explicit reference source and verified TLS. Controls default to read-only.',
26
+ fields: [
27
+ { name: 'url', label: 'Server WebSocket URL', type: 'text', required: true },
28
+ { name: 'expectedHomeId', label: 'Z-Wave network home ID (decimal)', type: 'number', required: true },
29
+ { name: 'allowControls', label: 'Authorize supported absolute Binary/Multilevel Switch writes', type: 'boolean' },
30
+ { name: 'credentialRef', label: 'Optional proxy credential reference', type: 'text' },
31
+ { name: 'credentialSource', label: 'Explicit credential source', type: 'select', options: [
32
+ { label: 'External provider', value: 'provider' }, { label: 'Borrowed encrypted config store', value: 'config-store' },
33
+ ] },
34
+ { name: 'ca', label: 'Additional TLS CA certificate (PEM)', type: 'text' },
35
+ ],
36
+ submit: async (inputArg) => {
37
+ try {
38
+ const values = captureZwaveJsData(inputArg, ['homeId', 'url', 'expectedHomeId', 'allowControls', 'credentialRef', 'credentialSource', 'ca', 'requestTimeoutMs']);
39
+ if (values.homeId !== undefined && values.homeId !== admitted.homeId) throw new Error('Submitted home conflicts with selected host home.');
40
+ const config = validateZwaveJsConfig({ ...values, homeId: admitted.homeId });
41
+ return await this.#scope.run(admitted, config.homeId, async (lease) => {
42
+ const client = new ZwaveJsClient(config, { ...lease.context, abortSignal: lease.signal }, this.#options);
43
+ lease.own(() => client.retryCleanup());
44
+ await client.start();
45
+ lease.assertOpen();
46
+ return { kind: 'done', title: 'Verified selected Z-Wave JS network', config };
47
+ });
48
+ } catch (errorArg) {
49
+ if (errorArg instanceof AggregateError) throw errorArg;
50
+ return { kind: 'error', title: 'Z-Wave JS verification failed',
51
+ description: 'Check host home, selected endpoint, network ID, schema, TLS and explicit credential source.' };
52
+ }
53
+ },
54
+ };
55
+ } catch {
56
+ return { kind: 'error', title: 'Z-Wave JS admission failed', description: 'Supply the independent host-selected home and matching optional store.' };
57
+ }
37
58
  }
59
+
60
+ public destroy(): Promise<void> { return this.#scope.close(); }
61
+ public retryCleanup(): Promise<void> { return this.#scope.retryCleanup(); }
38
62
  }
@@ -1,69 +1,83 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import { BaseIntegration } from '../../core/classes.baseintegration.js';
3
+ import { NativeIntegrationOwner, type INativeSetupLease } from '../../core/classes.nativeintegrationowner.js';
3
4
  import type { IDeviceFeatureWriteRequest, IIntegrationEntity, IIntegrationEvent, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
4
5
  import { ZwaveJsClient } from './zwave_js.classes.client.js';
5
6
  import { ZwaveJsConfigFlow } from './zwave_js.classes.configflow.js';
6
7
  import { createZwaveJsDiscoveryDescriptor } from './zwave_js.discovery.js';
7
8
  import { ZwaveJsMapper } from './zwave_js.mapper.js';
8
- import type { IZwaveJsConfig, IZwaveJsServerCommand, IZwaveJsWriteResult } from './zwave_js.types.js';
9
+ import type { IZwaveJsConfig, IZwaveJsIntegrationOptions, IZwaveJsServerCommand, IZwaveJsWriteResult } from './zwave_js.types.js';
10
+ import { normalizeZwaveJsOptions, validateZwaveJsConfig } from './zwave_js.validation.js';
9
11
 
10
12
  export class ZwaveJsIntegration extends BaseIntegration<IZwaveJsConfig> {
11
13
  public readonly domain = 'zwave_js';
12
14
  public readonly displayName = 'Z-Wave';
13
15
  public readonly status = 'control-runtime' as const;
14
16
  public readonly discoveryDescriptor = createZwaveJsDiscoveryDescriptor();
15
- public readonly configFlow = new ZwaveJsConfigFlow();
17
+ public readonly configFlow: ZwaveJsConfigFlow;
16
18
  public readonly metadata = {
17
19
  source: 'zwave-js/zwave-js-server', upstreamPath: 'src/lib', upstreamDomain: 'zwave_js',
18
20
  integrationType: 'hub', iotClass: 'local_push', qualityScale: 'unknown',
19
21
  };
20
- #clients = new Set<ZwaveJsClient>();
21
- #destroyed = false;
22
+ readonly #owner: NativeIntegrationOwner;
23
+ readonly #options: Readonly<IZwaveJsIntegrationOptions>;
22
24
 
23
- public async setup(configArg: IZwaveJsConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
24
- if (this.#destroyed) throw new Error('Z-Wave JS integration is destroyed.');
25
- const client = new ZwaveJsClient(configArg, contextArg.abortSignal);
26
- this.#clients.add(client);
27
- try {
28
- await client.start();
29
- if (this.#destroyed) throw new Error('Z-Wave JS integration is destroyed.');
30
- return new ZwaveJsRuntime(client, () => { this.#clients.delete(client); });
31
- } catch (errorArg) {
32
- await client.destroy();
33
- this.#clients.delete(client);
34
- throw errorArg;
35
- }
25
+ constructor(optionsArg: IZwaveJsIntegrationOptions = {}) {
26
+ super();
27
+ this.#options = normalizeZwaveJsOptions(optionsArg);
28
+ this.#owner = new NativeIntegrationOwner('zwave_js', { homeId: this.#options.homeId, capacity: this.#options.capacity });
29
+ this.configFlow = new ZwaveJsConfigFlow(this.#options, this.#owner.createFlowScope());
36
30
  }
37
31
 
38
- public async destroy(): Promise<void> {
39
- this.#destroyed = true;
40
- await Promise.all([...this.#clients].map((clientArg) => clientArg.destroy()));
41
- this.#clients.clear();
32
+ public setup(configArg: IZwaveJsConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
33
+ try {
34
+ const config = validateZwaveJsConfig(configArg);
35
+ return this.#owner.runSetup(contextArg, config.homeId, async (lease) => {
36
+ const client = new ZwaveJsClient(config, { ...lease.context, abortSignal: lease.signal }, this.#options);
37
+ let runtime: ZwaveJsRuntime | undefined;
38
+ lease.own(async () => {
39
+ const results = await Promise.allSettled([Promise.resolve().then(() => client.retryCleanup()),
40
+ ...(runtime ? [Promise.resolve().then(() => runtime!.closeSubscriptions())] : [])]);
41
+ const failures = results.filter((result): result is PromiseRejectedResult => result.status === 'rejected');
42
+ if (failures.length) throw new AggregateError(failures.map((result) => result.reason as unknown), 'Z-Wave JS owned cleanup failed.');
43
+ });
44
+ await client.start();
45
+ lease.assertOpen();
46
+ runtime = new ZwaveJsRuntime(client, lease);
47
+ lease.promoteToRuntime();
48
+ return runtime;
49
+ });
50
+ } catch (errorArg) { return Promise.reject(errorArg); }
42
51
  }
52
+
53
+ public destroy(): Promise<void> { return this.#owner.close(); }
54
+ public retryCleanup(): Promise<void> { return this.#owner.retryCleanup(); }
43
55
  }
44
56
 
45
57
  export class HomeAssistantZwaveJsIntegration extends ZwaveJsIntegration {}
46
58
 
47
59
  class ZwaveJsRuntime implements IIntegrationRuntime {
48
60
  public readonly domain = 'zwave_js';
49
- #subscriptions = new Set<() => void>();
61
+ #subscriptions = new Set<() => Promise<void>>();
50
62
  #destroyPromise?: Promise<void>;
51
63
 
52
- constructor(private readonly client: ZwaveJsClient, private readonly released: () => void) {}
64
+ constructor(private readonly client: ZwaveJsClient, private readonly lease: INativeSetupLease) {}
53
65
 
54
66
  public isHealthy(): boolean { return this.client.isHealthy(); }
55
67
 
56
68
  public async devices(abortSignalArg?: AbortSignal): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> {
69
+ this.lease.assertOpen();
57
70
  return ZwaveJsMapper.toDevices(await this.client.getSnapshot(abortSignalArg));
58
71
  }
59
72
 
60
- public async entities(): Promise<IIntegrationEntity[]> { return ZwaveJsMapper.toEntities(await this.client.getSnapshot()); }
73
+ public async entities(): Promise<IIntegrationEntity[]> { this.lease.assertOpen(); return ZwaveJsMapper.toEntities(await this.client.getSnapshot()); }
61
74
 
62
75
  public async subscribe(handlerArg: (eventArg: IIntegrationEvent) => void, abortSignalArg?: AbortSignal): Promise<() => Promise<void>> {
76
+ this.lease.assertOpen();
63
77
  if (abortSignalArg?.aborted) throw new Error('Z-Wave JS subscription was aborted.');
64
78
  const snapshot = await this.client.getSnapshot(abortSignalArg);
65
79
  const unsubscribe = this.client.onEvent((eventArg) => {
66
- handlerArg({
80
+ return handlerArg({
67
81
  type: eventArg.source === 'connection' || ['alive', 'dead', 'sleep', 'wake up'].includes(eventArg.event) ?
68
82
  'availability_changed' : 'state_changed',
69
83
  integrationDomain: this.domain,
@@ -71,36 +85,44 @@ class ZwaveJsRuntime implements IIntegrationRuntime {
71
85
  data: eventArg, timestamp: Date.now(),
72
86
  });
73
87
  });
74
- const release = () => {
75
- unsubscribe();
76
- abortSignalArg?.removeEventListener('abort', release);
88
+ const abort = () => { void release().catch(() => undefined); };
89
+ const release = async () => {
90
+ abortSignalArg?.removeEventListener('abort', abort);
91
+ await unsubscribe();
77
92
  this.#subscriptions.delete(release);
78
93
  };
79
94
  this.#subscriptions.add(release);
80
- abortSignalArg?.addEventListener('abort', release, { once: true });
81
- if (abortSignalArg?.aborted) release();
82
- return async () => { release(); };
95
+ abortSignalArg?.addEventListener('abort', abort, { once: true });
96
+ if (abortSignalArg?.aborted) await release();
97
+ this.lease.assertOpen();
98
+ return release;
83
99
  }
84
100
 
85
101
  public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
102
+ this.lease.assertOpen();
86
103
  const command = ZwaveJsMapper.commandForService(await this.client.getSnapshot(), requestArg);
87
104
  if (!command) return { success: false, error: 'Unsupported, missing or ambiguous Z-Wave JS control target.' };
88
105
  return this.execute(command);
89
106
  }
90
107
 
91
108
  public async writeFeature(requestArg: IDeviceFeatureWriteRequest, abortSignalArg?: AbortSignal): Promise<IServiceCallResult> {
109
+ this.lease.assertOpen();
92
110
  const command = ZwaveJsMapper.commandForFeature(await this.client.getSnapshot(abortSignalArg), requestArg);
93
111
  return this.execute(command, abortSignalArg);
94
112
  }
95
113
 
96
114
  public destroy(): Promise<void> {
97
- if (!this.#destroyPromise) {
98
- for (const release of this.#subscriptions) release();
99
- this.#destroyPromise = this.client.destroy().finally(() => this.released());
100
- }
115
+ if (!this.#destroyPromise) this.#destroyPromise = this.lease.close();
101
116
  return this.#destroyPromise;
102
117
  }
103
118
 
119
+ public async closeSubscriptions(): Promise<void> {
120
+ const results = await Promise.allSettled([...this.#subscriptions].map((release) => Promise.resolve().then(release)));
121
+ this.#subscriptions.clear(); // Callback work/failures remain owned by the client ledger.
122
+ const failures = results.filter((result): result is PromiseRejectedResult => result.status === 'rejected');
123
+ if (failures.length) throw new AggregateError(failures.map((result) => result.reason as unknown), 'Z-Wave JS subscription cleanup failed.');
124
+ }
125
+
104
126
  private async execute(commandArg: IZwaveJsServerCommand, abortSignalArg?: AbortSignal): Promise<IServiceCallResult> {
105
127
  const data: IZwaveJsWriteResult = await this.client.sendCommand(commandArg, abortSignalArg);
106
128
  return { success: data.outcome === 'confirmed', data,
@@ -1,7 +1,7 @@
1
1
  import { DiscoveryDescriptor } from '../../core/classes.discoverydescriptor.js';
2
2
  import type { IDiscoveryCandidate, IDiscoveryMatch, IDiscoveryMatcher, IDiscoveryValidator } from '../../core/types.js';
3
3
  import type { IZwaveJsManualEntry, IZwaveJsMdnsRecord, IZwaveJsUsbRecord } from './zwave_js.types.js';
4
- import { validateZwaveJsConfig, zwaveJsRecord } from './zwave_js.validation.js';
4
+ import { validateZwaveJsEndpoint, zwaveJsRecord } from './zwave_js.validation.js';
5
5
 
6
6
  const knownUsbIds = new Set(['0658:0200', '10c4:8a2a', '303a:4001', '10c4:ea60']);
7
7
 
@@ -133,7 +133,7 @@ export const createZwaveJsDiscoveryDescriptor = (): DiscoveryDescriptor => {
133
133
  };
134
134
 
135
135
  const safeUrl = (urlArg: string): string | undefined => {
136
- try { return validateZwaveJsConfig({ url: urlArg, expectedHomeId: 1 }).url.replace(/\/$/, ''); }
136
+ try { return validateZwaveJsEndpoint(urlArg).replace(/\/$/, ''); }
137
137
  catch { return undefined; }
138
138
  };
139
139
 
@@ -1,7 +1,7 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import type { IDeviceFeatureWriteRequest, IIntegrationEntity, IServiceCallRequest, TEntityPlatform } from '../../core/types.js';
3
3
  import type { IZwaveJsNode, IZwaveJsServerCommand, IZwaveJsSnapshot, IZwaveJsValue, IZwaveJsValueId, TZwaveJsControlValue } from './zwave_js.types.js';
4
- import { parseZwaveJsValueId, zwaveJsRecord, zwaveJsValueKey } from './zwave_js.validation.js';
4
+ import { captureZwaveJsData, parseZwaveJsValueId, zwaveJsRecord, zwaveJsValueKey } from './zwave_js.validation.js';
5
5
 
6
6
  interface IControlTarget { node: IZwaveJsNode; value: IZwaveJsValue }
7
7
 
@@ -9,14 +9,16 @@ export class ZwaveJsMapper {
9
9
  /** Pure mapping helper; runtime setup always obtains its state from the server. */
10
10
  public static toSnapshot(snapshotArg: Partial<IZwaveJsSnapshot>, connectedArg = false,
11
11
  eventsArg: IZwaveJsSnapshot['events'] = []): IZwaveJsSnapshot {
12
- return structuredClone({ ...snapshotArg, nodes: snapshotArg.nodes ?? [], events: eventsArg, connected: connectedArg });
12
+ if (typeof snapshotArg.homeId !== 'string' || !snapshotArg.homeId) throw new Error('Z-Wave JS snapshot requires its admitted SHX home.');
13
+ return structuredClone({ ...snapshotArg, homeId: snapshotArg.homeId, allowControls: snapshotArg.allowControls === true,
14
+ nodes: snapshotArg.nodes ?? [], events: eventsArg, connected: connectedArg });
13
15
  }
14
16
 
15
17
  public static toDevices(snapshotArg: IZwaveJsSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
16
18
  const updatedAt = new Date().toISOString();
17
19
  const devices: plugins.shxInterfaces.data.IDeviceDefinition[] = [{
18
- id: this.controllerDeviceId(snapshotArg), integrationDomain: 'zwave_js', name: 'Z-Wave controller',
19
- protocol: 'zwave', manufacturer: 'Z-Wave JS', model: 'Controller', online: snapshotArg.connected,
20
+ id: this.controllerDeviceId(snapshotArg), integrationDomain: 'zwave_js', name: 'Z-Wave JS server connection',
21
+ protocol: 'zwave', online: snapshotArg.connected,
20
22
  features: [
21
23
  { id: 'connection', capability: 'sensor', name: 'Connection', readable: true, writable: false },
22
24
  { id: 'node_count', capability: 'sensor', name: 'Node count', readable: true, writable: false },
@@ -25,7 +27,8 @@ export class ZwaveJsMapper {
25
27
  { featureId: 'connection', value: snapshotArg.connected ? 'connected' : 'disconnected', updatedAt },
26
28
  { featureId: 'node_count', value: snapshotArg.nodes.length, updatedAt },
27
29
  ],
28
- metadata: { homeId: this.homeId(snapshotArg), serverVersion: snapshotArg.version?.serverVersion, driverVersion: snapshotArg.version?.driverVersion },
30
+ metadata: { homeId: snapshotArg.homeId, zwaveHomeId: this.homeId(snapshotArg), ownNodeId: snapshotArg.controller?.ownNodeId,
31
+ serverVersion: snapshotArg.version?.serverVersion, driverVersion: snapshotArg.version?.driverVersion, adapterObservation: true },
29
32
  }];
30
33
  for (const node of snapshotArg.nodes) {
31
34
  const values = this.nodeValues(node).filter((valueArg) => valueArg.metadata?.secret !== true);
@@ -40,7 +43,7 @@ export class ZwaveJsMapper {
40
43
  id: this.featureId(valueArg), capability: this.platformForValue(valueArg) === 'light' ? 'light' :
41
44
  this.platformForValue(valueArg) === 'switch' ? 'switch' : 'sensor',
42
45
  name: this.valueLabel(valueArg), readable: valueArg.metadata?.readable === true,
43
- writable: this.valueWritable(valueArg), unit: valueArg.metadata?.unit,
46
+ writable: snapshotArg.allowControls && this.nodeAvailable(snapshotArg, node) && this.valueWritable(valueArg), unit: valueArg.metadata?.unit,
44
47
  })),
45
48
  ],
46
49
  state: [
@@ -49,7 +52,7 @@ export class ZwaveJsMapper {
49
52
  featureId: this.featureId(valueArg), value: this.stateValue(valueArg.value), updatedAt,
50
53
  })),
51
54
  ],
52
- metadata: { homeId: this.homeId(snapshotArg), nodeId: node.nodeId, manufacturerId: node.manufacturerId,
55
+ metadata: { homeId: snapshotArg.homeId, zwaveHomeId: this.homeId(snapshotArg), nodeId: node.nodeId, manufacturerId: node.manufacturerId,
53
56
  productId: node.productId, productType: node.productType, firmwareVersion: node.firmwareVersion },
54
57
  });
55
58
  }
@@ -66,14 +69,24 @@ export class ZwaveJsMapper {
66
69
  id: `${platform}.${identity}`, uniqueId: identity, integrationDomain: 'zwave_js',
67
70
  deviceId: this.nodeDeviceId(snapshotArg, nodeArg.nodeId), platform, name: this.valueLabel(valueArg),
68
71
  state: valueArg.metadata?.readable === true ? this.entityState(valueArg, platform) : 'unknown',
69
- attributes: { homeId: this.homeId(snapshotArg), nodeId: nodeArg.nodeId, valueId: this.valueId(valueArg),
70
- featureId: this.featureId(valueArg), unit: valueArg.metadata?.unit, writable: this.valueWritable(valueArg) },
72
+ attributes: { homeId: snapshotArg.homeId, zwaveHomeId: this.homeId(snapshotArg), nodeId: nodeArg.nodeId, valueId: this.valueId(valueArg),
73
+ featureId: this.featureId(valueArg), unit: valueArg.metadata?.unit,
74
+ writable: snapshotArg.allowControls && this.nodeAvailable(snapshotArg, nodeArg) && this.valueWritable(valueArg) },
71
75
  available: this.nodeAvailable(snapshotArg, nodeArg),
72
76
  };
73
77
  }));
74
78
  }
75
79
 
76
80
  public static commandForService(snapshotArg: IZwaveJsSnapshot, requestArg: IServiceCallRequest): IZwaveJsServerCommand | undefined {
81
+ const data = captureZwaveJsData(requestArg, ['domain', 'service', 'target', 'data']);
82
+ const targetData = captureZwaveJsData(data.target, ['entityId', 'deviceId']);
83
+ const serviceData = data.data === undefined ? undefined : captureZwaveJsData(data.data, ['featureId', 'value']);
84
+ if (typeof data.domain !== 'string' || typeof data.service !== 'string' ||
85
+ targetData.deviceId !== undefined && typeof targetData.deviceId !== 'string' ||
86
+ targetData.entityId !== undefined && typeof targetData.entityId !== 'string' ||
87
+ serviceData?.featureId !== undefined && typeof serviceData.featureId !== 'string' ||
88
+ data.service !== 'set_value' && serviceData?.value !== undefined) return undefined;
89
+ requestArg = { domain: data.domain, service: data.service, target: targetData, data: serviceData } as IServiceCallRequest;
77
90
  if (!['switch', 'light', 'zwave_js'].includes(requestArg.domain) ||
78
91
  !['turn_on', 'turn_off', 'set_value'].includes(requestArg.service)) return undefined;
79
92
  const target = this.findTargetValue(snapshotArg, requestArg);
@@ -86,25 +99,26 @@ export class ZwaveJsMapper {
86
99
  }
87
100
 
88
101
  public static commandForFeature(snapshotArg: IZwaveJsSnapshot, requestArg: IDeviceFeatureWriteRequest): IZwaveJsServerCommand {
89
- const node = snapshotArg.nodes.find((nodeArg) => this.nodeDeviceId(snapshotArg, nodeArg.nodeId) === requestArg.device.id);
90
- const value = node && this.nodeValues(node).find((valueArg) => this.featureId(valueArg) === requestArg.feature.id);
102
+ const request = captureZwaveJsData(requestArg, ['device', 'feature', 'value']);
103
+ const device = captureZwaveJsData(request.device);
104
+ const feature = captureZwaveJsData(request.feature);
105
+ if (device.integrationDomain !== 'zwave_js') throw new Error('Z-Wave JS device target belongs to another integration.');
106
+ const node = snapshotArg.nodes.find((nodeArg) => this.nodeDeviceId(snapshotArg, nodeArg.nodeId) === device.id);
107
+ const value = node && this.nodeValues(node).find((valueArg) => this.featureId(valueArg) === feature.id);
91
108
  if (!node || !value) throw new Error('Z-Wave JS feature target is not in the verified network.');
92
- return this.createCommand(snapshotArg, { node, value }, requestArg.value);
109
+ return this.createCommand(snapshotArg, { node, value }, request.value);
93
110
  }
94
111
 
95
112
  public static validateCommand(snapshotArg: IZwaveJsSnapshot, commandArg: IZwaveJsServerCommand): IZwaveJsServerCommand {
96
- if (!zwaveJsRecord(commandArg) || commandArg.command !== 'node.set_value' ||
97
- Object.keys(commandArg).some((keyArg) => !['command', 'nodeId', 'valueId', 'value'].includes(keyArg))) {
113
+ const command = captureZwaveJsData(commandArg, ['command', 'nodeId', 'valueId', 'value']);
114
+ if (command.command !== 'node.set_value') {
98
115
  throw new Error('Unsupported Z-Wave JS command.');
99
116
  }
100
- const id = parseZwaveJsValueId(commandArg.valueId);
101
- if (Object.keys(commandArg.valueId).some((keyArg) => !['commandClass', 'endpoint', 'property', 'propertyKey'].includes(keyArg))) {
102
- throw new Error('Invalid Z-Wave JS control identity fields.');
103
- }
104
- const node = snapshotArg.nodes.find((nodeArg) => nodeArg.nodeId === commandArg.nodeId);
117
+ const id = parseZwaveJsValueId(captureZwaveJsData(command.valueId, ['commandClass', 'endpoint', 'property', 'propertyKey']));
118
+ const node = snapshotArg.nodes.find((nodeArg) => nodeArg.nodeId === command.nodeId);
105
119
  const value = node && this.nodeValues(node).find((valueArg) => zwaveJsValueKey(valueArg) === zwaveJsValueKey(id));
106
120
  if (!node || !value) throw new Error('Z-Wave JS command target is not in the verified network.');
107
- return this.createCommand(snapshotArg, { node, value }, commandArg.value);
121
+ return this.createCommand(snapshotArg, { node, value }, command.value);
108
122
  }
109
123
 
110
124
  public static valueId(valueArg: IZwaveJsValue): IZwaveJsValueId {
@@ -120,11 +134,11 @@ export class ZwaveJsMapper {
120
134
  }
121
135
 
122
136
  public static nodeDeviceId(snapshotArg: IZwaveJsSnapshot, nodeIdArg: number): string {
123
- return `zwave_js.${this.homeId(snapshotArg).toString(16)}.node.${nodeIdArg}`;
137
+ return `zwave_js.${encodeURIComponent(snapshotArg.homeId)}.${this.homeId(snapshotArg).toString(16)}.node.${nodeIdArg}`;
124
138
  }
125
139
 
126
140
  private static createCommand(snapshotArg: IZwaveJsSnapshot, targetArg: IControlTarget, valueArg: unknown): IZwaveJsServerCommand {
127
- if (!this.nodeAvailable(snapshotArg, targetArg.node) || !this.valueWritable(targetArg.value)) {
141
+ if (!snapshotArg.allowControls || !this.nodeAvailable(snapshotArg, targetArg.node) || !this.valueWritable(targetArg.value)) {
128
142
  throw new Error('Z-Wave JS target is unavailable or is not a supported writable value.');
129
143
  }
130
144
  const metadata = targetArg.value.metadata!;
@@ -188,7 +202,7 @@ export class ZwaveJsMapper {
188
202
  return homeId;
189
203
  }
190
204
 
191
- private static controllerDeviceId(snapshotArg: IZwaveJsSnapshot): string { return `zwave_js.${this.homeId(snapshotArg).toString(16)}.controller`; }
205
+ private static controllerDeviceId(snapshotArg: IZwaveJsSnapshot): string { return `zwave_js.${encodeURIComponent(snapshotArg.homeId)}.${this.homeId(snapshotArg).toString(16)}.server`; }
192
206
  private static nodeName(nodeArg: IZwaveJsNode): string { return nodeArg.name || nodeArg.productLabel || `Z-Wave node ${nodeArg.nodeId}`; }
193
207
  private static valueLabel(valueArg: IZwaveJsValue): string { return valueArg.metadata?.label || valueArg.propertyName || String(valueArg.property); }
194
208
  }
@@ -1,13 +1,33 @@
1
1
  export interface IZwaveJsConfig {
2
+ /** Consistency with the independent home selected by the embedding host. */
3
+ homeId: string;
2
4
  url: string;
3
5
  expectedHomeId: number;
4
- /** Authorization enforced by the operator's TLS reverse proxy, not by Z-Wave JS. */
5
- authorization?: string;
6
+ /** Controls are disabled unless the owning host explicitly enables them. */
7
+ allowControls?: boolean;
8
+ credentialRef?: string;
9
+ /** Explicit alternatives; neither source falls back to the other. */
10
+ credentialSource?: 'provider' | 'config-store';
6
11
  /** Additional TLS trust anchor. Certificate and hostname verification stay enabled. */
7
12
  ca?: string;
8
13
  requestTimeoutMs?: number;
9
14
  }
10
15
 
16
+ export interface IZwaveJsCredentialRequest {
17
+ readonly homeId: string;
18
+ readonly credentialRef: string;
19
+ readonly signal: AbortSignal;
20
+ /** Monotonic performance.now() deadline in milliseconds. */
21
+ readonly deadline: number;
22
+ }
23
+ export type TZwaveJsAuthorizationResolver = (requestArg: IZwaveJsCredentialRequest) => Promise<string>;
24
+ export interface IZwaveJsIntegrationOptions {
25
+ readonly homeId?: string;
26
+ readonly capacity?: number;
27
+ /** Caller-owned; never persisted or closed by the integration. */
28
+ readonly resolveAuthorization?: TZwaveJsAuthorizationResolver;
29
+ }
30
+
11
31
  export interface IZwaveJsVersion {
12
32
  type: 'version';
13
33
  driverVersion: string;
@@ -89,6 +109,8 @@ export interface IZwaveJsValue {
89
109
  }
90
110
 
91
111
  export interface IZwaveJsSnapshot {
112
+ homeId: string;
113
+ allowControls: boolean;
92
114
  version?: IZwaveJsVersion;
93
115
  controller?: IZwaveJsController;
94
116
  nodes: IZwaveJsNode[];
@@ -107,9 +129,10 @@ export interface IZwaveJsServerCommand {
107
129
  }
108
130
 
109
131
  export interface IZwaveJsWriteResult {
110
- /** Only supervised status 255 proves completion. Status 1/254 remain indeterminate. */
132
+ /** Supervised status is a device report, not independent proof of physical causality. */
111
133
  outcome: 'confirmed' | 'working' | 'unsupervised' | 'rejected';
112
134
  status: number;
135
+ causalityConfirmed: false;
113
136
  }
114
137
 
115
138
  export interface IZwaveJsServerEvent {
@@ -1,4 +1,4 @@
1
- import type { IZwaveJsConfig, IZwaveJsNode, IZwaveJsState, IZwaveJsValue, IZwaveJsValueId, IZwaveJsValueMetadata, IZwaveJsVersion } from './zwave_js.types.js';
1
+ import type { IZwaveJsConfig, IZwaveJsIntegrationOptions, IZwaveJsNode, IZwaveJsState, IZwaveJsValue, IZwaveJsValueId, IZwaveJsValueMetadata, IZwaveJsVersion } from './zwave_js.types.js';
2
2
 
3
3
  export const zwaveJsSchemaVersion = 32;
4
4
 
@@ -8,34 +8,68 @@ export const zwaveJsRecord = (valueArg: unknown): valueArg is Record<string, unk
8
8
  export const zwaveJsInteger = (valueArg: unknown, minArg: number, maxArg: number): valueArg is number =>
9
9
  typeof valueArg === 'number' && Number.isSafeInteger(valueArg) && valueArg >= minArg && valueArg <= maxArg;
10
10
 
11
- export const validateZwaveJsConfig = (configArg: IZwaveJsConfig): IZwaveJsConfig => {
12
- if (!zwaveJsRecord(configArg) || Object.keys(configArg).some((keyArg) =>
13
- !['url', 'expectedHomeId', 'authorization', 'ca', 'requestTimeoutMs'].includes(keyArg))) {
14
- throw new Error('Invalid Z-Wave JS configuration fields.');
15
- }
16
- if (typeof configArg.url !== 'string' || configArg.url.length > 2048) {
11
+ /** Capture foreign data without executing getters or accepting hidden/symbol fields. */
12
+ export const captureZwaveJsData = (valueArg: unknown, fieldsArg?: readonly string[]): Record<string, unknown> => {
13
+ if (!zwaveJsRecord(valueArg) || ![Object.prototype, null].includes(Object.getPrototypeOf(valueArg))) {
14
+ throw new TypeError('Z-Wave JS input must be a plain data object.');
15
+ }
16
+ const captured: Record<string, unknown> = {};
17
+ for (const key of Reflect.ownKeys(valueArg)) {
18
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
19
+ if (typeof key !== 'string' || fieldsArg && !fieldsArg.includes(key) || !descriptor ||
20
+ !descriptor.enumerable || !('value' in descriptor)) throw new TypeError('Unsupported Z-Wave JS data field or accessor.');
21
+ Object.defineProperty(captured, key, { value: descriptor.value as unknown, enumerable: true, writable: true });
22
+ }
23
+ return captured;
24
+ };
25
+
26
+ export const validateZwaveJsEndpoint = (urlArg: unknown): string => {
27
+ if (typeof urlArg !== 'string' || urlArg.length > 2048) {
17
28
  throw new Error('Z-Wave JS requires an explicit WebSocket URL.');
18
29
  }
19
30
  let url: URL;
20
- try { url = new URL(configArg.url); } catch { throw new Error('Invalid Z-Wave JS WebSocket URL.'); }
31
+ try { url = new URL(urlArg); } catch { throw new Error('Invalid Z-Wave JS WebSocket URL.'); }
21
32
  if (!['ws:', 'wss:'].includes(url.protocol) || !url.hostname || url.username || url.password || url.search || url.hash) {
22
33
  throw new Error('Z-Wave JS URL must use ws/wss without credentials, query or fragment.');
23
34
  }
24
- if (!zwaveJsInteger(configArg.expectedHomeId, 1, 0xffffffff)) {
35
+ return url.href;
36
+ };
37
+
38
+ export const normalizeZwaveJsOptions = (optionsArg: IZwaveJsIntegrationOptions = {}): Readonly<IZwaveJsIntegrationOptions> => {
39
+ const options = captureZwaveJsData(optionsArg, ['homeId', 'capacity', 'resolveAuthorization']);
40
+ if (options.resolveAuthorization !== undefined && typeof options.resolveAuthorization !== 'function') {
41
+ throw new TypeError('Z-Wave JS authorization resolver must be a caller-owned function.');
42
+ }
43
+ return Object.freeze(options) as Readonly<IZwaveJsIntegrationOptions>;
44
+ };
45
+
46
+ export const validateZwaveJsConfig = (inputArg: IZwaveJsConfig | Record<string, unknown>): IZwaveJsConfig => {
47
+ const config = captureZwaveJsData(inputArg, ['homeId', 'url', 'expectedHomeId', 'allowControls', 'credentialRef', 'credentialSource', 'ca', 'requestTimeoutMs']);
48
+ if (typeof config.homeId !== 'string' || !config.homeId || config.homeId.length > 256 ||
49
+ config.homeId.trim() !== config.homeId || /[\p{Cc}\p{Cs}]/u.test(config.homeId)) throw new Error('Z-Wave JS configuration requires host home consistency.');
50
+ const url = validateZwaveJsEndpoint(config.url);
51
+ if (!zwaveJsInteger(config.expectedHomeId, 1, 0xffffffff)) {
25
52
  throw new Error('Z-Wave JS requires the expected network home ID.');
26
53
  }
27
- if (configArg.authorization !== undefined && (url.protocol !== 'wss:' ||
28
- typeof configArg.authorization !== 'string' || !configArg.authorization.trim() ||
29
- configArg.authorization.length > 4096 || /[\x00-\x1f\x7f]/.test(configArg.authorization))) {
30
- throw new Error('Z-Wave JS proxy authorization requires verified TLS and a valid header.');
54
+ if (config.allowControls !== undefined && typeof config.allowControls !== 'boolean') throw new Error('Invalid Z-Wave JS control authorization.');
55
+ if (config.credentialRef !== undefined && (typeof config.credentialRef !== 'string' || !config.credentialRef ||
56
+ config.credentialRef.length > 1024 || config.credentialRef.trim() !== config.credentialRef || /[\p{Cc}\p{Cs}]/u.test(config.credentialRef))) {
57
+ throw new Error('Invalid Z-Wave JS credential reference.');
58
+ }
59
+ if (config.credentialSource !== undefined && config.credentialSource !== 'provider' && config.credentialSource !== 'config-store' ||
60
+ (config.credentialRef === undefined) !== (config.credentialSource === undefined) || config.credentialRef !== undefined && !url.startsWith('wss:')) {
61
+ throw new Error('Z-Wave JS credentials require an explicit source, reference and verified TLS.');
31
62
  }
32
- if (configArg.ca !== undefined && (url.protocol !== 'wss:' || typeof configArg.ca !== 'string' ||
33
- configArg.ca.length > 65536 || !configArg.ca.includes('-----BEGIN CERTIFICATE-----'))) {
63
+ if (config.ca !== undefined && (!url.startsWith('wss:') || typeof config.ca !== 'string' ||
64
+ config.ca.length > 65536 || !config.ca.includes('-----BEGIN CERTIFICATE-----'))) {
34
65
  throw new Error('Z-Wave JS CA must be a PEM certificate for a wss endpoint.');
35
66
  }
36
- const requestTimeoutMs = configArg.requestTimeoutMs ?? 10000;
67
+ const requestTimeoutMs = config.requestTimeoutMs ?? 10000;
37
68
  if (!zwaveJsInteger(requestTimeoutMs, 50, 60000)) throw new Error('Invalid Z-Wave JS request deadline.');
38
- return { ...configArg, url: url.href, requestTimeoutMs };
69
+ return Object.freeze({ homeId: config.homeId, url, expectedHomeId: config.expectedHomeId,
70
+ allowControls: config.allowControls === true, requestTimeoutMs,
71
+ credentialRef: config.credentialRef as string | undefined,
72
+ credentialSource: config.credentialSource as IZwaveJsConfig['credentialSource'], ca: config.ca as string | undefined });
39
73
  };
40
74
 
41
75
  export const parseZwaveJsVersion = (valueArg: unknown, expectedHomeIdArg: number): IZwaveJsVersion => {
@@ -81,7 +115,7 @@ export const parseZwaveJsMetadata = (valueArg: unknown): IZwaveJsValueMetadata =
81
115
  }
82
116
  const metadata: IZwaveJsValueMetadata = {
83
117
  type: valueArg.type, readable: valueArg.readable, writeable: valueArg.writeable,
84
- secret: valueArg.secret === true, stateful: valueArg.stateful !== false,
118
+ secret: valueArg.secret as boolean | undefined, stateful: valueArg.stateful as boolean | undefined,
85
119
  };
86
120
  for (const key of ['label', 'unit'] as const) {
87
121
  if (typeof valueArg[key] === 'string' && valueArg[key].length <= 1024) metadata[key] = valueArg[key];
package/ts/plugins.ts CHANGED
@@ -4,9 +4,10 @@ import * as path from 'node:path';
4
4
  import * as crypto from 'node:crypto';
5
5
  import * as net from 'node:net';
6
6
  import * as tls from 'node:tls';
7
+ import * as http from 'node:http';
7
8
  import * as https from 'node:https';
8
9
  import * as os from 'node:os';
9
- export { crypto, fs, https, net, path, tls, os };
10
+ export { crypto, fs, http, https, net, path, tls, os };
10
11
 
11
12
  // Project scope
12
13
  import * as shxInterfaces from '@smarthome.exchange/interfaces';