@smarthome.exchange/integrations 1.0.0 → 2.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 (294) hide show
  1. package/changelog.md +49 -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 +79 -0
  8. package/dist_ts/core/classes.nativeintegrationowner.js +269 -0
  9. package/dist_ts/core/index.d.ts +2 -0
  10. package/dist_ts/core/index.js +3 -1
  11. package/dist_ts/core/types.d.ts +14 -0
  12. package/dist_ts/integrations/braviatv/braviatv.classes.client.d.ts +23 -72
  13. package/dist_ts/integrations/braviatv/braviatv.classes.client.js +265 -625
  14. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.d.ts +7 -7
  15. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.js +51 -68
  16. package/dist_ts/integrations/braviatv/braviatv.classes.integration.d.ts +8 -11
  17. package/dist_ts/integrations/braviatv/braviatv.classes.integration.js +186 -135
  18. package/dist_ts/integrations/braviatv/braviatv.discovery.js +12 -11
  19. package/dist_ts/integrations/braviatv/braviatv.mapper.d.ts +6 -14
  20. package/dist_ts/integrations/braviatv/braviatv.mapper.js +37 -131
  21. package/dist_ts/integrations/braviatv/braviatv.types.d.ts +55 -133
  22. package/dist_ts/integrations/braviatv/braviatv.validation.d.ts +7 -0
  23. package/dist_ts/integrations/braviatv/braviatv.validation.js +72 -0
  24. package/dist_ts/integrations/broadlink/broadlink.actions.d.ts +2 -0
  25. package/dist_ts/integrations/broadlink/broadlink.actions.js +36 -0
  26. package/dist_ts/integrations/broadlink/broadlink.classes.client.d.ts +21 -19
  27. package/dist_ts/integrations/broadlink/broadlink.classes.client.js +185 -124
  28. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.d.ts +5 -4
  29. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.js +64 -83
  30. package/dist_ts/integrations/broadlink/broadlink.classes.integration.d.ts +16 -19
  31. package/dist_ts/integrations/broadlink/broadlink.classes.integration.js +114 -59
  32. package/dist_ts/integrations/broadlink/broadlink.mapper.d.ts +3 -2
  33. package/dist_ts/integrations/broadlink/broadlink.mapper.js +2 -1
  34. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.d.ts +10 -0
  35. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.js +41 -0
  36. package/dist_ts/integrations/broadlink/broadlink.types.d.ts +43 -7
  37. package/dist_ts/integrations/broadlink/broadlink.validation.d.ts +7 -0
  38. package/dist_ts/integrations/broadlink/broadlink.validation.js +63 -0
  39. package/dist_ts/integrations/daikin/daikin.classes.client.d.ts +10 -52
  40. package/dist_ts/integrations/daikin/daikin.classes.client.js +55 -614
  41. package/dist_ts/integrations/daikin/daikin.classes.configflow.d.ts +8 -12
  42. package/dist_ts/integrations/daikin/daikin.classes.configflow.js +77 -138
  43. package/dist_ts/integrations/daikin/daikin.classes.integration.d.ts +7 -24
  44. package/dist_ts/integrations/daikin/daikin.classes.integration.js +175 -67
  45. package/dist_ts/integrations/daikin/daikin.discovery.d.ts +11 -24
  46. package/dist_ts/integrations/daikin/daikin.discovery.js +98 -305
  47. package/dist_ts/integrations/daikin/daikin.mapper.d.ts +6 -7
  48. package/dist_ts/integrations/daikin/daikin.mapper.js +95 -155
  49. package/dist_ts/integrations/daikin/daikin.types.d.ts +24 -44
  50. package/dist_ts/integrations/daikin/daikin.types.js +1 -1
  51. package/dist_ts/integrations/daikin/daikin.validation.d.ts +5 -0
  52. package/dist_ts/integrations/daikin/daikin.validation.js +53 -0
  53. package/dist_ts/integrations/denonavr/denonavr.classes.client.d.ts +31 -40
  54. package/dist_ts/integrations/denonavr/denonavr.classes.client.js +149 -404
  55. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.d.ts +7 -2
  56. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.js +44 -36
  57. package/dist_ts/integrations/denonavr/denonavr.classes.integration.d.ts +6 -11
  58. package/dist_ts/integrations/denonavr/denonavr.classes.integration.js +192 -113
  59. package/dist_ts/integrations/denonavr/denonavr.discovery.d.ts +10 -18
  60. package/dist_ts/integrations/denonavr/denonavr.discovery.js +71 -193
  61. package/dist_ts/integrations/denonavr/denonavr.mapper.d.ts +5 -13
  62. package/dist_ts/integrations/denonavr/denonavr.mapper.js +35 -159
  63. package/dist_ts/integrations/denonavr/denonavr.types.d.ts +55 -90
  64. package/dist_ts/integrations/denonavr/denonavr.validation.d.ts +10 -0
  65. package/dist_ts/integrations/denonavr/denonavr.validation.js +86 -0
  66. package/dist_ts/integrations/kodi/kodi.classes.client.d.ts +11 -45
  67. package/dist_ts/integrations/kodi/kodi.classes.client.js +84 -310
  68. package/dist_ts/integrations/kodi/kodi.classes.configflow.d.ts +9 -8
  69. package/dist_ts/integrations/kodi/kodi.classes.configflow.js +53 -48
  70. package/dist_ts/integrations/kodi/kodi.classes.integration.d.ts +11 -11
  71. package/dist_ts/integrations/kodi/kodi.classes.integration.js +114 -171
  72. package/dist_ts/integrations/kodi/kodi.discovery.js +53 -29
  73. package/dist_ts/integrations/kodi/kodi.mapper.d.ts +7 -2
  74. package/dist_ts/integrations/kodi/kodi.mapper.js +48 -10
  75. package/dist_ts/integrations/kodi/kodi.types.d.ts +32 -28
  76. package/dist_ts/integrations/kodi/kodi.validation.d.ts +9 -0
  77. package/dist_ts/integrations/kodi/kodi.validation.js +62 -0
  78. package/dist_ts/integrations/modbus/modbus.classes.client.d.ts +15 -61
  79. package/dist_ts/integrations/modbus/modbus.classes.client.js +117 -776
  80. package/dist_ts/integrations/modbus/modbus.classes.configflow.d.ts +9 -5
  81. package/dist_ts/integrations/modbus/modbus.classes.configflow.js +70 -38
  82. package/dist_ts/integrations/modbus/modbus.classes.integration.d.ts +6 -17
  83. package/dist_ts/integrations/modbus/modbus.classes.integration.js +133 -57
  84. package/dist_ts/integrations/modbus/modbus.discovery.d.ts +5 -8
  85. package/dist_ts/integrations/modbus/modbus.discovery.js +38 -93
  86. package/dist_ts/integrations/modbus/modbus.mapper.d.ts +8 -32
  87. package/dist_ts/integrations/modbus/modbus.mapper.js +71 -431
  88. package/dist_ts/integrations/modbus/modbus.types.d.ts +82 -332
  89. package/dist_ts/integrations/modbus/modbus.validation.d.ts +10 -0
  90. package/dist_ts/integrations/modbus/modbus.validation.js +128 -0
  91. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.d.ts +12 -34
  92. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.js +143 -231
  93. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.d.ts +6 -1
  94. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.js +105 -18
  95. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.d.ts +8 -8
  96. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.js +141 -155
  97. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.d.ts +9 -0
  98. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.js +35 -0
  99. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.d.ts +6 -18
  100. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.js +45 -220
  101. package/dist_ts/integrations/nanoleaf/nanoleaf.types.d.ts +33 -147
  102. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.d.ts +6 -0
  103. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.js +82 -0
  104. package/dist_ts/integrations/onkyo/onkyo.classes.client.d.ts +15 -20
  105. package/dist_ts/integrations/onkyo/onkyo.classes.client.js +161 -404
  106. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.d.ts +9 -4
  107. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.js +51 -6
  108. package/dist_ts/integrations/onkyo/onkyo.classes.integration.d.ts +22 -6
  109. package/dist_ts/integrations/onkyo/onkyo.classes.integration.js +144 -11
  110. package/dist_ts/integrations/onkyo/onkyo.discovery.d.ts +6 -1
  111. package/dist_ts/integrations/onkyo/onkyo.discovery.js +40 -4
  112. package/dist_ts/integrations/onkyo/onkyo.mapper.d.ts +7 -8
  113. package/dist_ts/integrations/onkyo/onkyo.mapper.js +45 -12
  114. package/dist_ts/integrations/onkyo/onkyo.types.d.ts +58 -8
  115. package/dist_ts/integrations/onkyo/onkyo.types.js +13 -102
  116. package/dist_ts/integrations/onkyo/onkyo.validation.d.ts +16 -0
  117. package/dist_ts/integrations/onkyo/onkyo.validation.js +77 -0
  118. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.d.ts +25 -25
  119. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.js +116 -360
  120. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.d.ts +11 -3
  121. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.js +76 -6
  122. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.d.ts +26 -4
  123. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.js +142 -9
  124. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.d.ts +2 -1
  125. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.js +31 -4
  126. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.d.ts +9 -9
  127. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.js +31 -149
  128. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.d.ts +51 -11
  129. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.js +22 -87
  130. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.d.ts +6 -0
  131. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.js +56 -0
  132. package/dist_ts/integrations/pioneer/pioneer.classes.client.d.ts +31 -16
  133. package/dist_ts/integrations/pioneer/pioneer.classes.client.js +167 -409
  134. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.d.ts +10 -3
  135. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.js +66 -6
  136. package/dist_ts/integrations/pioneer/pioneer.classes.integration.d.ts +13 -5
  137. package/dist_ts/integrations/pioneer/pioneer.classes.integration.js +239 -11
  138. package/dist_ts/integrations/pioneer/pioneer.discovery.d.ts +14 -1
  139. package/dist_ts/integrations/pioneer/pioneer.discovery.js +51 -4
  140. package/dist_ts/integrations/pioneer/pioneer.mapper.d.ts +14 -8
  141. package/dist_ts/integrations/pioneer/pioneer.mapper.js +54 -12
  142. package/dist_ts/integrations/pioneer/pioneer.types.d.ts +79 -12
  143. package/dist_ts/integrations/pioneer/pioneer.types.js +12 -76
  144. package/dist_ts/integrations/pioneer/pioneer.validation.d.ts +10 -0
  145. package/dist_ts/integrations/pioneer/pioneer.validation.js +85 -0
  146. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.d.ts +13 -36
  147. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.js +179 -502
  148. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.d.ts +6 -1
  149. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.js +50 -40
  150. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.d.ts +14 -15
  151. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.js +108 -128
  152. package/dist_ts/integrations/soundtouch/soundtouch.discovery.d.ts +2 -20
  153. package/dist_ts/integrations/soundtouch/soundtouch.discovery.js +23 -113
  154. package/dist_ts/integrations/soundtouch/soundtouch.mapper.d.ts +3 -12
  155. package/dist_ts/integrations/soundtouch/soundtouch.mapper.js +35 -189
  156. package/dist_ts/integrations/soundtouch/soundtouch.types.d.ts +57 -142
  157. package/dist_ts/integrations/soundtouch/soundtouch.types.js +18 -3
  158. package/dist_ts/integrations/soundtouch/soundtouch.validation.d.ts +22 -0
  159. package/dist_ts/integrations/soundtouch/soundtouch.validation.js +65 -0
  160. package/dist_ts/integrations/wiz/index.d.ts +1 -0
  161. package/dist_ts/integrations/wiz/index.js +2 -1
  162. package/dist_ts/integrations/wiz/wiz.classes.client.d.ts +14 -28
  163. package/dist_ts/integrations/wiz/wiz.classes.client.js +93 -229
  164. package/dist_ts/integrations/wiz/wiz.classes.configflow.d.ts +6 -4
  165. package/dist_ts/integrations/wiz/wiz.classes.configflow.js +38 -67
  166. package/dist_ts/integrations/wiz/wiz.classes.integration.d.ts +10 -21
  167. package/dist_ts/integrations/wiz/wiz.classes.integration.js +204 -44
  168. package/dist_ts/integrations/wiz/wiz.discovery.d.ts +10 -31
  169. package/dist_ts/integrations/wiz/wiz.discovery.js +48 -249
  170. package/dist_ts/integrations/wiz/wiz.mapper.d.ts +7 -51
  171. package/dist_ts/integrations/wiz/wiz.mapper.js +82 -668
  172. package/dist_ts/integrations/wiz/wiz.types.d.ts +34 -208
  173. package/dist_ts/integrations/wiz/wiz.validation.d.ts +8 -0
  174. package/dist_ts/integrations/wiz/wiz.validation.js +72 -0
  175. package/dist_ts/integrations/yamaha/index.d.ts +1 -0
  176. package/dist_ts/integrations/yamaha/index.js +2 -1
  177. package/dist_ts/integrations/yamaha/yamaha.classes.client.d.ts +30 -4
  178. package/dist_ts/integrations/yamaha/yamaha.classes.client.js +162 -6
  179. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.d.ts +10 -3
  180. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.js +106 -6
  181. package/dist_ts/integrations/yamaha/yamaha.classes.integration.d.ts +22 -4
  182. package/dist_ts/integrations/yamaha/yamaha.classes.integration.js +243 -8
  183. package/dist_ts/integrations/yamaha/yamaha.discovery.d.ts +13 -1
  184. package/dist_ts/integrations/yamaha/yamaha.discovery.js +57 -4
  185. package/dist_ts/integrations/yamaha/yamaha.mapper.d.ts +16 -8
  186. package/dist_ts/integrations/yamaha/yamaha.mapper.js +58 -12
  187. package/dist_ts/integrations/yamaha/yamaha.types.d.ts +73 -6
  188. package/dist_ts/integrations/yamaha/yamaha.types.js +8 -94
  189. package/dist_ts/integrations/yamaha/yamaha.validation.d.ts +12 -0
  190. package/dist_ts/integrations/yamaha/yamaha.validation.js +89 -0
  191. package/package.json +3 -3
  192. package/readme.md +514 -2
  193. package/ts/00_commitinfo_data.ts +1 -1
  194. package/ts/core/classes.configstore.ts +84 -27
  195. package/ts/core/classes.nativehomeadmission.ts +96 -0
  196. package/ts/core/classes.nativeintegrationowner.ts +297 -0
  197. package/ts/core/index.ts +2 -0
  198. package/ts/core/types.ts +16 -0
  199. package/ts/integrations/braviatv/braviatv.classes.client.ts +245 -709
  200. package/ts/integrations/braviatv/braviatv.classes.configflow.ts +47 -76
  201. package/ts/integrations/braviatv/braviatv.classes.integration.ts +167 -147
  202. package/ts/integrations/braviatv/braviatv.discovery.ts +11 -10
  203. package/ts/integrations/braviatv/braviatv.mapper.ts +39 -142
  204. package/ts/integrations/braviatv/braviatv.types.ts +53 -173
  205. package/ts/integrations/braviatv/braviatv.validation.ts +68 -0
  206. package/ts/integrations/broadlink/broadlink.actions.ts +31 -0
  207. package/ts/integrations/broadlink/broadlink.classes.client.ts +170 -144
  208. package/ts/integrations/broadlink/broadlink.classes.configflow.ts +59 -89
  209. package/ts/integrations/broadlink/broadlink.classes.integration.ts +110 -64
  210. package/ts/integrations/broadlink/broadlink.mapper.ts +5 -4
  211. package/ts/integrations/broadlink/broadlink.selected.mapper.ts +46 -0
  212. package/ts/integrations/broadlink/broadlink.types.ts +48 -8
  213. package/ts/integrations/broadlink/broadlink.validation.ts +66 -0
  214. package/ts/integrations/daikin/daikin.classes.client.ts +52 -661
  215. package/ts/integrations/daikin/daikin.classes.configflow.ts +72 -152
  216. package/ts/integrations/daikin/daikin.classes.integration.ts +166 -71
  217. package/ts/integrations/daikin/daikin.discovery.ts +94 -346
  218. package/ts/integrations/daikin/daikin.mapper.ts +83 -166
  219. package/ts/integrations/daikin/daikin.types.ts +27 -48
  220. package/ts/integrations/daikin/daikin.validation.ts +51 -0
  221. package/ts/integrations/daikin/readme.md +83 -0
  222. package/ts/integrations/denonavr/denonavr.classes.client.ts +132 -421
  223. package/ts/integrations/denonavr/denonavr.classes.configflow.ts +44 -37
  224. package/ts/integrations/denonavr/denonavr.classes.integration.ts +171 -117
  225. package/ts/integrations/denonavr/denonavr.discovery.ts +67 -220
  226. package/ts/integrations/denonavr/denonavr.mapper.ts +36 -182
  227. package/ts/integrations/denonavr/denonavr.types.ts +48 -111
  228. package/ts/integrations/denonavr/denonavr.validation.ts +87 -0
  229. package/ts/integrations/kodi/kodi.classes.client.ts +72 -352
  230. package/ts/integrations/kodi/kodi.classes.configflow.ts +52 -55
  231. package/ts/integrations/kodi/kodi.classes.integration.ts +97 -178
  232. package/ts/integrations/kodi/kodi.discovery.ts +49 -28
  233. package/ts/integrations/kodi/kodi.mapper.ts +52 -10
  234. package/ts/integrations/kodi/kodi.types.ts +33 -58
  235. package/ts/integrations/kodi/kodi.validation.ts +60 -0
  236. package/ts/integrations/modbus/modbus.classes.client.ts +100 -842
  237. package/ts/integrations/modbus/modbus.classes.configflow.ts +70 -41
  238. package/ts/integrations/modbus/modbus.classes.integration.ts +115 -60
  239. package/ts/integrations/modbus/modbus.discovery.ts +38 -106
  240. package/ts/integrations/modbus/modbus.mapper.ts +64 -467
  241. package/ts/integrations/modbus/modbus.types.ts +64 -381
  242. package/ts/integrations/modbus/modbus.validation.ts +119 -0
  243. package/ts/integrations/nanoleaf/nanoleaf.classes.client.ts +115 -249
  244. package/ts/integrations/nanoleaf/nanoleaf.classes.configflow.ts +90 -19
  245. package/ts/integrations/nanoleaf/nanoleaf.classes.integration.ts +130 -181
  246. package/ts/integrations/nanoleaf/nanoleaf.credentials.ts +39 -0
  247. package/ts/integrations/nanoleaf/nanoleaf.mapper.ts +47 -260
  248. package/ts/integrations/nanoleaf/nanoleaf.types.ts +29 -147
  249. package/ts/integrations/nanoleaf/nanoleaf.validation.ts +77 -0
  250. package/ts/integrations/onkyo/onkyo.classes.client.ts +148 -457
  251. package/ts/integrations/onkyo/onkyo.classes.configflow.ts +52 -6
  252. package/ts/integrations/onkyo/onkyo.classes.integration.ts +121 -12
  253. package/ts/integrations/onkyo/onkyo.discovery.ts +41 -3
  254. package/ts/integrations/onkyo/onkyo.mapper.ts +46 -19
  255. package/ts/integrations/onkyo/onkyo.types.ts +55 -110
  256. package/ts/integrations/onkyo/onkyo.validation.ts +85 -0
  257. package/ts/integrations/onkyo/readme.md +126 -0
  258. package/ts/integrations/panasonic_viera/panasonic_viera.classes.client.ts +101 -398
  259. package/ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.ts +69 -5
  260. package/ts/integrations/panasonic_viera/panasonic_viera.classes.integration.ts +141 -9
  261. package/ts/integrations/panasonic_viera/panasonic_viera.discovery.ts +32 -3
  262. package/ts/integrations/panasonic_viera/panasonic_viera.mapper.ts +34 -161
  263. package/ts/integrations/panasonic_viera/panasonic_viera.types.ts +52 -96
  264. package/ts/integrations/panasonic_viera/panasonic_viera.validation.ts +56 -0
  265. package/ts/integrations/pioneer/pioneer.classes.client.ts +132 -428
  266. package/ts/integrations/pioneer/pioneer.classes.configflow.ts +67 -5
  267. package/ts/integrations/pioneer/pioneer.classes.integration.ts +225 -11
  268. package/ts/integrations/pioneer/pioneer.discovery.ts +45 -3
  269. package/ts/integrations/pioneer/pioneer.mapper.ts +57 -13
  270. package/ts/integrations/pioneer/pioneer.types.ts +87 -85
  271. package/ts/integrations/pioneer/pioneer.validation.ts +84 -0
  272. package/ts/integrations/soundtouch/soundtouch.classes.client.ts +152 -571
  273. package/ts/integrations/soundtouch/soundtouch.classes.configflow.ts +47 -42
  274. package/ts/integrations/soundtouch/soundtouch.classes.integration.ts +95 -150
  275. package/ts/integrations/soundtouch/soundtouch.discovery.ts +21 -133
  276. package/ts/integrations/soundtouch/soundtouch.mapper.ts +36 -207
  277. package/ts/integrations/soundtouch/soundtouch.types.ts +50 -195
  278. package/ts/integrations/soundtouch/soundtouch.validation.ts +60 -0
  279. package/ts/integrations/wiz/index.ts +1 -0
  280. package/ts/integrations/wiz/wiz.classes.client.ts +84 -254
  281. package/ts/integrations/wiz/wiz.classes.configflow.ts +39 -70
  282. package/ts/integrations/wiz/wiz.classes.integration.ts +189 -45
  283. package/ts/integrations/wiz/wiz.discovery.ts +48 -291
  284. package/ts/integrations/wiz/wiz.mapper.ts +81 -754
  285. package/ts/integrations/wiz/wiz.types.ts +24 -224
  286. package/ts/integrations/wiz/wiz.validation.ts +73 -0
  287. package/ts/integrations/yamaha/index.ts +1 -0
  288. package/ts/integrations/yamaha/yamaha.classes.client.ts +150 -6
  289. package/ts/integrations/yamaha/yamaha.classes.configflow.ts +100 -5
  290. package/ts/integrations/yamaha/yamaha.classes.integration.ts +236 -8
  291. package/ts/integrations/yamaha/yamaha.discovery.ts +52 -3
  292. package/ts/integrations/yamaha/yamaha.mapper.ts +65 -13
  293. package/ts/integrations/yamaha/yamaha.types.ts +77 -97
  294. package/ts/integrations/yamaha/yamaha.validation.ts +86 -0
@@ -1,278 +1,108 @@
1
- import type {
2
- IWizClientCommand,
3
- IWizCommandResult,
4
- IWizConfig,
5
- IWizDeviceInfo,
6
- IWizEvent,
7
- IWizPilotPatch,
8
- IWizPilotState,
9
- IWizSnapshot,
10
- IWizSnapshotDevice,
11
- IWizUdpCommand,
12
- IWizUdpResponse,
13
- } from './wiz.types.js';
14
- import { wizDefaultPort } from './wiz.types.js';
15
- import { WizMapper } from './wiz.mapper.js';
16
-
17
- type TWizEventHandler = (eventArg: IWizEvent) => void;
1
+ import * as plugins from '../../plugins.js';
2
+ import { NativeHomeAdmission } from '../../core/classes.nativehomeadmission.js';
3
+ import type { IIntegrationSetupContext } from '../../core/types.js';
4
+ import type { IWizConfig, IWizSnapshot, IWizWriteResult, TWizControl } from './wiz.types.js';
5
+ import { normalizeWizConfig, wizControl } from './wiz.validation.js';
18
6
 
19
7
  export class WizClient {
20
- private readonly events: IWizEvent[] = [];
21
- private readonly eventHandlers = new Set<TWizEventHandler>();
22
-
23
- constructor(private readonly config: IWizConfig) {}
24
-
25
- public async getSnapshot(): Promise<IWizSnapshot> {
26
- const host = this.host();
27
- if (!host) {
28
- return WizMapper.toSnapshot(this.config, false, this.events);
29
- }
30
-
31
- try {
32
- const pilot = await this.getPilot();
33
- const deviceInfo = await this.liveDeviceInfo(pilot).catch(() => this.staticDeviceInfo(pilot));
34
- const device: IWizSnapshotDevice = {
35
- host,
36
- port: this.port(),
37
- mac: pilot.mac || deviceInfo.mac || this.config.mac,
38
- name: this.config.name || deviceInfo.name,
39
- deviceInfo,
40
- pilot,
41
- available: true,
42
- };
43
- return WizMapper.toSnapshot({ ...this.config, snapshot: undefined, devices: [device], manualEntries: undefined }, true, this.events);
44
- } catch (error) {
45
- const message = error instanceof Error ? error.message : String(error);
46
- this.emit({ type: 'error', data: { message }, timestamp: Date.now() });
47
- return WizMapper.toSnapshot(this.config, false, this.events);
48
- }
49
- }
50
-
51
- public onEvent(handlerArg: TWizEventHandler): () => void {
52
- this.eventHandlers.add(handlerArg);
53
- return () => this.eventHandlers.delete(handlerArg);
54
- }
55
-
56
- public async getPilot(): Promise<IWizPilotState> {
57
- const response = await this.sendUdp<IWizPilotState>({ method: 'getPilot', params: {} });
58
- const result = this.record(response.result) ? response.result as IWizPilotState : {};
59
- this.emit({ type: 'pilot', data: result, timestamp: Date.now() });
60
- return result;
61
- }
62
-
63
- public async setPilot(payloadArg: IWizPilotPatch): Promise<IWizUdpResponse<Record<string, unknown>>> {
64
- return this.sendUdp<Record<string, unknown>>({ method: 'setPilot', params: payloadArg as Record<string, unknown> });
65
- }
66
-
67
- public async getSystemConfig(): Promise<IWizUdpResponse<Record<string, unknown>>> {
68
- return this.sendUdp<Record<string, unknown>>({ method: 'getSystemConfig', params: {} });
69
- }
70
-
71
- public async sendCommand(commandArg: IWizClientCommand): Promise<IWizCommandResult> {
72
- let result: IWizCommandResult;
73
- if (this.config.commandExecutor) {
74
- result = this.commandResult(await this.config.commandExecutor(commandArg), commandArg);
75
- } else if (!this.host()) {
76
- result = {
77
- success: false,
78
- error: this.unsupportedLiveControlMessage(),
79
- data: { command: commandArg },
80
- };
81
- } else {
82
- try {
83
- const response = await this.setPilot(commandArg.payload);
84
- result = { success: true, data: response.result || response };
85
- } catch (error) {
86
- result = {
87
- success: false,
88
- error: error instanceof Error ? error.message : String(error),
89
- data: { command: commandArg },
90
- };
91
- }
92
- }
93
-
94
- this.emit({
95
- type: result.success ? 'command_mapped' : 'command_failed',
96
- command: commandArg,
97
- data: result,
98
- timestamp: Date.now(),
99
- deviceId: commandArg.deviceId,
100
- entityId: commandArg.entityId,
8
+ readonly #config: ReturnType<typeof normalizeWizConfig>;
9
+ readonly #protocol: plugins.ecobridgeDeviceManager.WizProtocol;
10
+ readonly #lifetime = new AbortController();
11
+ readonly #operations = new Set<Promise<unknown>>();
12
+ readonly #ownerSignal?: AbortSignal;
13
+ #healthy = false;
14
+ #closed = false;
15
+ #closing?: Promise<void>;
16
+ #retrying?: Promise<void>;
17
+
18
+ constructor(configArg: IWizConfig, contextArg: IIntegrationSetupContext) {
19
+ this.#config = normalizeWizConfig(configArg);
20
+ const context = new NativeHomeAdmission('wiz').admit(contextArg, this.#config.homeId);
21
+ const ownerSignalArg = context.abortSignal;
22
+ ownerSignalArg?.throwIfAborted();
23
+ this.#ownerSignal = ownerSignalArg;
24
+ this.#protocol = new plugins.ecobridgeDeviceManager.WizProtocol({
25
+ host: this.#config.host, port: this.#config.port, macAddress: this.#config.macAddress,
26
+ timeoutMs: this.#config.timeoutMs, maxPendingOperations: this.#config.maxPendingOperations, maxExchanges: this.#config.maxExchanges,
101
27
  });
102
- return result;
103
28
  }
104
29
 
105
- public async destroy(): Promise<void> {
106
- this.eventHandlers.clear();
107
- }
30
+ public get homeId(): string { return this.#config.homeId; }
31
+ public get pollIntervalMs(): number { return this.#config.pollIntervalMs; }
32
+ public isHealthy(): boolean { return this.#healthy && !this.#closed; }
108
33
 
109
- private async liveDeviceInfo(pilotArg: IWizPilotState): Promise<IWizDeviceInfo> {
110
- const systemConfig = await this.getSystemConfig();
111
- const result = this.record(systemConfig.result) ? systemConfig.result : {};
112
- return this.staticDeviceInfo(pilotArg, result);
113
- }
114
-
115
- private staticDeviceInfo(pilotArg?: IWizPilotState, systemArg: Record<string, unknown> = {}): IWizDeviceInfo {
116
- const moduleName = this.stringValue(systemArg.moduleName) || this.config.deviceInfo?.moduleName;
117
- const model = this.config.deviceInfo?.model || moduleName;
118
- const isSocket = this.config.deviceInfo?.isSocket ?? this.textContainsSocket(model, moduleName, systemArg.typeId);
119
- return {
120
- ...this.config.deviceInfo,
121
- host: this.host(),
122
- port: this.port(),
123
- mac: this.stringValue(systemArg.mac) || pilotArg?.mac || this.config.mac || this.config.deviceInfo?.mac,
124
- name: this.config.name || this.config.deviceInfo?.name,
125
- manufacturer: this.config.deviceInfo?.manufacturer || 'WiZ',
126
- model,
127
- moduleName,
128
- fwVersion: this.stringValue(systemArg.fwVersion) || this.config.deviceInfo?.fwVersion,
129
- typeId: this.stringValue(systemArg.typeId) || this.numberValue(systemArg.typeId) || this.config.deviceInfo?.typeId,
130
- isSocket,
131
- features: {
132
- light: !isSocket,
133
- switch: isSocket,
134
- brightness: !isSocket || typeof pilotArg?.dimming === 'number',
135
- color: ['r', 'g', 'b'].every((keyArg) => typeof pilotArg?.[keyArg] === 'number') || this.textContains(moduleName, 'rgb'),
136
- colorTemp: typeof pilotArg?.temp === 'number' || this.textContains(moduleName, 'tw'),
137
- effect: typeof pilotArg?.sceneId === 'number' || typeof pilotArg?.schdPsetId === 'number',
138
- fan: typeof pilotArg?.fanState === 'number',
139
- power: typeof pilotArg?.pc === 'number',
140
- occupancy: pilotArg?.src === 'pir',
141
- ...this.config.deviceInfo?.features,
142
- },
143
- };
34
+ public getSnapshot(signalArg?: AbortSignal): Promise<IWizSnapshot> {
35
+ return this.track(async () => {
36
+ const signal = this.signal(signalArg);
37
+ const info = await this.#protocol.getDeviceInfo({ signal });
38
+ signal.throwIfAborted();
39
+ this.#healthy = true;
40
+ return Object.freeze({ homeId: this.#config.homeId, host: this.#config.host, port: this.#config.port,
41
+ name: this.#config.name, info, observedAt: new Date().toISOString() });
42
+ });
144
43
  }
145
44
 
146
- private async sendUdp<TResult>(commandArg: IWizUdpCommand): Promise<IWizUdpResponse<TResult>> {
147
- const host = this.host();
148
- if (!host) {
149
- throw new Error(this.unsupportedLiveControlMessage());
150
- }
151
- const port = this.port();
152
- const timeoutMs = this.timeoutMs();
153
- const { createSocket } = await import('node:dgram');
154
- const payload = Buffer.from(JSON.stringify(commandArg));
155
-
156
- return new Promise<IWizUdpResponse<TResult>>((resolve, reject) => {
157
- const socket = createSocket('udp4');
158
- const timers: Array<ReturnType<typeof setTimeout>> = [];
159
- let settled = false;
160
-
161
- const cleanup = () => {
162
- for (const timer of timers) {
163
- clearTimeout(timer);
164
- }
165
- socket.removeAllListeners();
166
- try {
167
- socket.close();
168
- } catch {
169
- // The socket may already be closed after an early UDP error.
170
- }
171
- };
172
-
173
- const finish = (errorArg: Error | undefined, responseArg?: IWizUdpResponse<TResult>) => {
174
- if (settled) {
175
- return;
176
- }
177
- settled = true;
178
- cleanup();
179
- if (errorArg) {
180
- reject(errorArg);
181
- } else {
182
- resolve(responseArg || {});
183
- }
184
- };
185
-
186
- const send = () => {
187
- if (settled) {
188
- return;
189
- }
190
- socket.send(payload, port, host, (errorArg) => {
191
- if (errorArg) {
192
- finish(errorArg);
193
- }
194
- });
195
- };
196
-
197
- socket.on('error', (errorArg) => finish(errorArg));
198
- socket.on('message', (messageArg) => {
199
- let response: IWizUdpResponse<TResult>;
200
- try {
201
- response = JSON.parse(messageArg.toString('utf8')) as IWizUdpResponse<TResult>;
202
- } catch (error) {
203
- finish(error instanceof Error ? error : new Error(String(error)));
204
- return;
205
- }
206
- if (response.method && response.method !== commandArg.method) {
207
- return;
208
- }
209
- if (response.error) {
210
- finish(new Error(response.error.message || `WiZ UDP error ${response.error.code ?? 'unknown'}`));
211
- return;
45
+ public write(controlArg: TWizControl, signalArg?: AbortSignal): Promise<IWizWriteResult> {
46
+ return this.track(async () => {
47
+ let control: TWizControl;
48
+ let signal: AbortSignal;
49
+ try { control = wizControl(controlArg); signal = this.signal(signalArg); }
50
+ catch { return Object.freeze({ outcome: 'not-sent', physicalStateConfirmed: false }); }
51
+ try {
52
+ const result = control.feature === 'power' ? await this.#protocol.setPower(control.value, { signal }) :
53
+ control.feature === 'brightness' ? await this.#protocol.setBrightness(control.value, { signal }) :
54
+ await this.#protocol.setRgb(control.value, { signal });
55
+ this.#healthy = true;
56
+ return Object.freeze({ outcome: result.outcome, physicalStateConfirmed: false, observedState: result.observedState });
57
+ } catch (errorArg) {
58
+ this.#healthy = false;
59
+ if (errorArg instanceof plugins.ecobridgeDeviceManager.WizProtocolError) {
60
+ return Object.freeze({ outcome: errorArg.effectOutcome, physicalStateConfirmed: false, errorCode: errorArg.code });
212
61
  }
213
- this.emit({ type: 'udp_response', data: response, timestamp: Date.now() });
214
- finish(undefined, response);
215
- });
216
-
217
- send();
218
- timers.push(setTimeout(send, 750));
219
- timers.push(setTimeout(send, 2250));
220
- timers.push(setTimeout(() => finish(new Error(`Timed out waiting for WiZ ${commandArg.method} response from ${host}:${port}.`)), timeoutMs));
62
+ throw errorArg;
63
+ }
221
64
  });
222
65
  }
223
66
 
224
- private emit(eventArg: IWizEvent): void {
225
- this.events.push(eventArg);
226
- for (const handler of this.eventHandlers) {
227
- handler(eventArg);
67
+ public destroy(): Promise<void> {
68
+ if (!this.#closing) {
69
+ this.#closed = true;
70
+ this.#healthy = false;
71
+ this.#closing = Promise.resolve().then(() => this.cleanup());
72
+ this.#lifetime.abort(new Error('WiZ client is destroyed.'));
228
73
  }
74
+ return this.#closing;
229
75
  }
230
76
 
231
- private commandResult(resultArg: unknown, commandArg: IWizClientCommand): IWizCommandResult {
232
- if (this.isCommandResult(resultArg)) {
233
- return resultArg;
77
+ /** Explicitly retries retained cleanup; no protocol operation is replayed. */
78
+ public retryCleanup(): Promise<void> {
79
+ if (!this.#closed) return Promise.reject(new Error('WiZ cleanup retry requires terminal shutdown.'));
80
+ if (!this.#retrying) {
81
+ this.#retrying = Promise.resolve().then(() => this.cleanup()).finally(() => { this.#retrying = undefined; });
234
82
  }
235
- return { success: true, data: resultArg ?? { command: commandArg } };
236
- }
237
-
238
- private isCommandResult(valueArg: unknown): valueArg is IWizCommandResult {
239
- return typeof valueArg === 'object' && valueArg !== null && 'success' in valueArg;
240
- }
241
-
242
- private host(): string | undefined {
243
- return this.config.host || this.config.manualEntries?.find((entryArg) => entryArg.host)?.host;
244
- }
245
-
246
- private port(): number {
247
- const manualPort = this.config.manualEntries?.find((entryArg) => entryArg.host)?.port;
248
- return this.config.port || manualPort || wizDefaultPort;
249
- }
250
-
251
- private timeoutMs(): number {
252
- return typeof this.config.timeoutMs === 'number' && this.config.timeoutMs > 0 ? this.config.timeoutMs : 5000;
253
- }
254
-
255
- private unsupportedLiveControlMessage(): string {
256
- return 'WiZ live UDP control requires a configured host. Snapshot-only WiZ configs are read-only unless commandExecutor is provided.';
257
- }
258
-
259
- private textContainsSocket(...valuesArg: unknown[]): boolean {
260
- return valuesArg.some((valueArg) => this.textContains(valueArg, 'socket') || this.textContains(valueArg, 'plug'));
261
- }
262
-
263
- private textContains(valueArg: unknown, fragmentArg: string): boolean {
264
- return typeof valueArg === 'string' && valueArg.toLowerCase().includes(fragmentArg);
83
+ return this.#retrying;
265
84
  }
266
85
 
267
- private stringValue(valueArg: unknown): string | undefined {
268
- return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
86
+ private async cleanup(): Promise<void> {
87
+ const results = await Promise.allSettled([
88
+ Promise.resolve().then(() => this.#protocol.close()),
89
+ Promise.allSettled([...this.#operations]),
90
+ ]);
91
+ const errors = results.flatMap((resultArg) => resultArg.status === 'rejected' ? [resultArg.reason] : []);
92
+ if (errors.length) throw new AggregateError(errors, 'WiZ client cleanup failed after draining admitted operations.');
269
93
  }
270
94
 
271
- private numberValue(valueArg: unknown): number | undefined {
272
- return typeof valueArg === 'number' && Number.isFinite(valueArg) ? valueArg : undefined;
95
+ private signal(signalArg?: AbortSignal): AbortSignal {
96
+ if (this.#closed) throw new Error('WiZ client is destroyed.');
97
+ const signal = AbortSignal.any([this.#lifetime.signal, ...(this.#ownerSignal ? [this.#ownerSignal] : []), ...(signalArg ? [signalArg] : [])]);
98
+ signal.throwIfAborted();
99
+ return signal;
273
100
  }
274
101
 
275
- private record(valueArg: unknown): valueArg is Record<string, unknown> {
276
- return typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
102
+ private track<T>(workArg: () => Promise<T>): Promise<T> {
103
+ const operation = workArg().catch((errorArg: unknown) => { this.#healthy = false; throw errorArg; });
104
+ this.#operations.add(operation);
105
+ void operation.then(() => this.#operations.delete(operation), () => this.#operations.delete(operation));
106
+ return operation;
277
107
  }
278
108
  }
@@ -1,84 +1,53 @@
1
1
  import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
2
- import type { IWizConfig, IWizDeviceInfo, IWizPilotState, IWizSnapshot } from './wiz.types.js';
3
- import { wizDefaultPort } from './wiz.types.js';
2
+ import { NativeIntegrationOwner, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
3
+ import type { INativeAdmissionContext } from '../../core/classes.nativehomeadmission.js';
4
+ import { WizClient } from './wiz.classes.client.js';
5
+ import type { IWizConfig } from './wiz.types.js';
6
+ import { normalizeWizConfig, wizRecord } from './wiz.validation.js';
4
7
 
5
8
  export class WizConfigFlow implements IConfigFlow<IWizConfig> {
9
+ readonly #scope: NativeIntegrationScope;
10
+
11
+ constructor(ownerArg: NativeIntegrationOwner = new NativeIntegrationOwner('wiz')) {
12
+ this.#scope = ownerArg.createFlowScope();
13
+ }
14
+
6
15
  public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IWizConfig>> {
7
- void contextArg;
8
- const defaults = this.defaultsFromCandidate(candidateArg);
16
+ const candidate = wizRecord(candidateArg);
17
+ const context = this.#scope.admit(contextArg);
9
18
  return {
10
- kind: 'form',
11
- title: 'Connect WiZ',
12
- description: 'Configure the WiZ device host. Local control uses UDP JSON on port 38899 by default.',
19
+ kind: 'form', title: 'Select WiZ device',
20
+ description: 'Confirm the local IPv4 address and unicast device MAC for the host-selected home. UDP replies are unauthenticated LAN observations.',
13
21
  fields: [
14
- { name: 'host', label: 'Host or IP address', type: 'text', required: true },
15
- { name: 'port', label: 'UDP port (default 38899)', type: 'number' },
16
- { name: 'mac', label: 'MAC address', type: 'text' },
17
- { name: 'name', label: 'Device name', type: 'text' },
22
+ { name: 'host', label: 'Selected local IPv4 address', type: 'text', required: true },
23
+ { name: 'macAddress', label: 'Exact device MAC', type: 'text', required: true },
24
+ { name: 'port', label: 'UDP port', type: 'number' },
25
+ { name: 'name', label: 'Display name', type: 'text' },
18
26
  ],
19
- submit: async (valuesArg) => {
20
- const host = this.stringValue(valuesArg.host) || defaults.host;
21
- if (!host) {
22
- return { kind: 'error', title: 'Invalid WiZ config', error: 'WiZ setup requires a host or IP address.' };
23
- }
24
- const port = this.numberValue(valuesArg.port) || defaults.port || wizDefaultPort;
25
- const mac = this.stringValue(valuesArg.mac) || defaults.mac;
26
- const name = this.stringValue(valuesArg.name) || defaults.name;
27
- return {
28
- kind: 'done',
29
- title: 'WiZ configured',
30
- config: {
31
- host,
32
- port,
33
- mac,
34
- name,
35
- deviceInfo: {
36
- ...defaults.deviceInfo,
37
- host,
38
- port,
39
- mac: mac || defaults.deviceInfo?.mac,
40
- name: name || defaults.deviceInfo?.name,
41
- },
42
- pilot: defaults.pilot,
43
- snapshot: defaults.snapshot,
44
- },
45
- };
46
- },
27
+ submit: (valuesArg) => this.submit(valuesArg, candidate, context),
47
28
  };
48
29
  }
49
30
 
50
- private defaultsFromCandidate(candidateArg: IDiscoveryCandidate): { host?: string; port?: number; mac?: string; name?: string; deviceInfo?: IWizDeviceInfo; pilot?: IWizPilotState; snapshot?: IWizSnapshot } {
51
- const metadata = candidateArg.metadata || {};
52
- const deviceInfo = this.isRecord(metadata.deviceInfo) ? metadata.deviceInfo as unknown as IWizDeviceInfo : undefined;
53
- const pilot = this.isRecord(metadata.pilot) ? metadata.pilot as unknown as IWizPilotState : undefined;
54
- const snapshot = this.isRecord(metadata.snapshot) ? metadata.snapshot as unknown as IWizSnapshot : undefined;
55
- return {
56
- host: candidateArg.host,
57
- port: candidateArg.port || wizDefaultPort,
58
- mac: candidateArg.macAddress,
59
- name: candidateArg.name,
60
- deviceInfo,
61
- pilot,
62
- snapshot,
63
- };
64
- }
31
+ public destroy(): Promise<void> { return this.#scope.close(); }
32
+ public retryCleanup(): Promise<void> { return this.#scope.retryCleanup(); }
65
33
 
66
- private stringValue(valueArg: unknown): string | undefined {
67
- return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
68
- }
69
-
70
- private numberValue(valueArg: unknown): number | undefined {
71
- if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
72
- return valueArg;
73
- }
74
- if (typeof valueArg === 'string' && valueArg.trim()) {
75
- const parsed = Number(valueArg);
76
- return Number.isFinite(parsed) ? parsed : undefined;
34
+ private async submit(valuesArg: Record<string, unknown>, candidateArg: Record<string, unknown>, contextArg: INativeAdmissionContext): Promise<IConfigFlowStep<IWizConfig>> {
35
+ try {
36
+ const values = wizRecord(valuesArg, ['homeId', 'host', 'macAddress', 'port', 'name', 'timeoutMs', 'pollIntervalMs', 'maxPendingOperations', 'maxExchanges']);
37
+ if (values.homeId !== undefined && values.homeId !== contextArg.homeId) throw new TypeError('WiZ submitted home must match the host-selected home.');
38
+ const config = normalizeWizConfig({ ...values, homeId: contextArg.homeId, host: values.host ?? candidateArg.host,
39
+ macAddress: values.macAddress ?? candidateArg.macAddress, port: values.port ?? candidateArg.port });
40
+ return await this.#scope.run(contextArg, config.homeId, async (leaseArg) => {
41
+ const client = new WizClient(config, { ...leaseArg.context, abortSignal: leaseArg.signal });
42
+ let cleanupAttempts = 0;
43
+ leaseArg.own(() => cleanupAttempts++ === 0 ? client.destroy() : client.retryCleanup());
44
+ await client.getSnapshot(leaseArg.signal);
45
+ leaseArg.assertOpen();
46
+ if (leaseArg.context.configStore) await leaseArg.context.configStore.set(`device:${config.macAddress}`, config);
47
+ return { kind: 'done', title: leaseArg.context.configStore ? 'Selected WiZ device verified and stored' : 'Selected WiZ device verified', config };
48
+ });
49
+ } catch (errorArg) {
50
+ return { kind: 'error', title: 'WiZ admission failed', error: errorArg instanceof Error ? errorArg.message : 'WiZ device admission failed.' };
77
51
  }
78
- return undefined;
79
- }
80
-
81
- private isRecord(valueArg: unknown): valueArg is Record<string, unknown> {
82
- return typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
83
52
  }
84
53
  }