@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,84 +1,55 @@
1
1
  import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
2
- import type { IBraviatvConfig } from './braviatv.types.js';
2
+ import { NativeIntegrationOwner, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
3
+ import type { IBraviatvConfig, IBraviatvIntegrationOptions } from './braviatv.types.js';
4
+ import { BraviatvClient } from './braviatv.classes.client.js';
5
+ import { braviatvRecord, normalizeBraviatvConfig, normalizeBraviatvOptions } from './braviatv.validation.js';
3
6
 
4
7
  export class BraviatvConfigFlow implements IConfigFlow<IBraviatvConfig> {
5
- public async start(candidateArg: IDiscoveryCandidate, contextArg: IConfigFlowContext): Promise<IConfigFlowStep<IBraviatvConfig>> {
6
- void contextArg;
7
- return {
8
- kind: 'form',
9
- title: 'Connect Sony Bravia TV',
10
- description: 'Configure the local Sony Bravia REST/IRCC endpoint. This native port supports PSK authentication for live control; PIN pairing/cookie auth is reported as unsupported.',
8
+ readonly #options?: Readonly<IBraviatvIntegrationOptions>;
9
+ readonly #scope: NativeIntegrationScope;
10
+ public constructor(options?: IBraviatvIntegrationOptions, scope?: NativeIntegrationScope) {
11
+ this.#options = options === undefined ? undefined : normalizeBraviatvOptions(options);
12
+ this.#scope = scope ?? new NativeIntegrationOwner('braviatv', { homeId: this.#options?.homeId, capacity: this.#options?.capacity }).createFlowScope();
13
+ }
14
+ public async start(input: IDiscoveryCandidate, context: IConfigFlowContext): Promise<IConfigFlowStep<IBraviatvConfig>> {
15
+ const candidate = braviatvRecord(input);
16
+ if (candidate.integrationDomain !== 'braviatv') return { kind: 'error', error: 'Candidate does not belong to BRAVIA.' };
17
+ if (!this.#options) return { kind: 'error', error: 'BRAVIA admission requires caller-owned PSK resolver options.' };
18
+ const options = this.#options;
19
+ const hints = { host: candidate.host };
20
+ const admitted = this.#scope.admit(context);
21
+ return { kind: 'form', title: 'Select BRAVIA Professional display',
22
+ description: 'Confirm private IPv4, model and active-network MAC for the host-selected home. Caller provides a private-level PSK reference. LAN HTTP is unencrypted and PSK access does not prove peer identity. Speaker volume uses integer raw levels.',
11
23
  fields: [
12
- { name: 'host', label: 'Host', type: 'text', required: true },
13
- { name: 'port', label: 'HTTP port', type: 'number' },
14
- { name: 'useSsl', label: 'Use HTTPS', type: 'boolean' },
15
- { name: 'psk', label: 'Pre-shared key (PSK)', type: 'password' },
16
- { name: 'pin', label: 'PIN (pairing not implemented)', type: 'password' },
17
- { name: 'name', label: 'Name', type: 'text' },
18
- { name: 'model', label: 'Model', type: 'text' },
24
+ { name: 'host', label: 'Selected display IPv4', type: 'text', required: true },
25
+ { name: 'expectedModel', label: 'Exact observed model', type: 'text', required: true },
26
+ { name: 'expectedMacAddress', label: 'Exact active-network MAC', type: 'text', required: true },
27
+ { name: 'expectedSerial', label: 'Exact serial (optional)', type: 'text' },
28
+ { name: 'credentialRef', label: 'Caller private-level PSK reference', type: 'text', required: true },
29
+ { name: 'allowUnencryptedLan', label: 'Allow unencrypted selected LAN HTTP', type: 'boolean', required: true },
30
+ { name: 'volumeLimitRaw', label: 'Owner speaker ceiling (integer raw level 0..100)', type: 'number', required: true },
31
+ { name: 'name', label: 'Display name', type: 'text' },
19
32
  ],
20
- submit: async (valuesArg) => {
21
- const host = this.stringValue(valuesArg.host) || candidateArg.host;
22
- if (!host) {
23
- return { kind: 'error', error: 'Sony Bravia TV host is required.' };
24
- }
25
-
26
- const psk = this.stringValue(valuesArg.psk) || this.stringMetadata(candidateArg, 'psk');
27
- const pin = this.stringValue(valuesArg.pin);
28
- if (pin && !psk) {
29
- return { kind: 'error', error: 'Sony Bravia TV PIN pairing/cookie authentication is not implemented in this native TypeScript port. Configure a PSK instead.' };
33
+ submit: async (inputValues) => {
34
+ try {
35
+ const values = braviatvRecord(inputValues, ['homeId', 'host', 'expectedModel', 'expectedMacAddress', 'expectedSerial',
36
+ 'credentialRef', 'allowUnencryptedLan', 'volumeLimitRaw', 'name', 'port', 'timeoutMs', 'maxPendingOperations', 'maxResponseBytes']);
37
+ if (values.homeId !== undefined && values.homeId !== admitted.homeId) throw new Error('BRAVIA submitted home conflicts with the host-selected home.');
38
+ // Discovery supplies only captured endpoint hints; exact model and MAC remain explicit selections.
39
+ const config = normalizeBraviatvConfig({ ...values, homeId: admitted.homeId, host: values.host ?? hints.host });
40
+ return await this.#scope.run(admitted, config.homeId, async (lease) => {
41
+ const client = new BraviatvClient(config, { ...lease.context, abortSignal: lease.signal }, options);
42
+ lease.own(() => client.retryCleanup());
43
+ await client.start(lease.signal);
44
+ lease.assertOpen();
45
+ return { kind: 'done', title: 'Selected display admitted', config };
46
+ });
47
+ } catch (error) {
48
+ if (error instanceof AggregateError) throw error;
49
+ return { kind: 'error', title: 'Display admission failed', error: 'Confirm exact home and display identity, private PSK reference, explicit LAN consent, supported APIs and owner speaker ceiling.' };
30
50
  }
31
-
32
- const useSsl = this.booleanValue(valuesArg.useSsl) ?? this.booleanMetadata(candidateArg, 'useSsl') ?? false;
33
- return {
34
- kind: 'done',
35
- title: 'Sony Bravia TV configured',
36
- config: {
37
- host,
38
- port: this.numberValue(valuesArg.port) || candidateArg.port || (useSsl ? 443 : 80),
39
- useSsl,
40
- psk,
41
- pin,
42
- usePsk: Boolean(psk),
43
- name: this.stringValue(valuesArg.name) || candidateArg.name,
44
- model: this.stringValue(valuesArg.model) || candidateArg.model,
45
- manufacturer: candidateArg.manufacturer || 'Sony',
46
- macAddress: candidateArg.macAddress,
47
- serialNumber: candidateArg.serialNumber,
48
- cid: candidateArg.id || this.stringMetadata(candidateArg, 'cid'),
49
- scalarWebApiBaseUrl: this.stringMetadata(candidateArg, 'scalarWebApiBaseUrl'),
50
- },
51
- };
52
- },
53
- };
54
- }
55
-
56
- private stringValue(valueArg: unknown): string | undefined {
57
- return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
58
- }
59
-
60
- private numberValue(valueArg: unknown): number | undefined {
61
- if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
62
- return valueArg;
63
- }
64
- if (typeof valueArg === 'string' && valueArg.trim()) {
65
- const value = Number(valueArg);
66
- return Number.isFinite(value) ? value : undefined;
67
- }
68
- return undefined;
69
- }
70
-
71
- private booleanValue(valueArg: unknown): boolean | undefined {
72
- return typeof valueArg === 'boolean' ? valueArg : undefined;
73
- }
74
-
75
- private stringMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): string | undefined {
76
- const value = candidateArg.metadata?.[keyArg];
77
- return typeof value === 'string' && value ? value : undefined;
78
- }
79
-
80
- private booleanMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): boolean | undefined {
81
- const value = candidateArg.metadata?.[keyArg];
82
- return typeof value === 'boolean' ? value : undefined;
51
+ } };
83
52
  }
53
+ public destroy(): Promise<void> { return this.#scope.close(); }
54
+ public retryCleanup(): Promise<void> { return this.#scope.retryCleanup(); }
84
55
  }
@@ -1,177 +1,197 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import { BaseIntegration } from '../../core/classes.baseintegration.js';
3
- import type { IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
3
+ import { NativeIntegrationOwner, type INativeSetupLease } from '../../core/classes.nativeintegrationowner.js';
4
+ import type { IDeviceFeatureWriteRequest, IIntegrationEntity, IIntegrationEvent, IIntegrationRuntime,
5
+ IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
4
6
  import { BraviatvClient } from './braviatv.classes.client.js';
5
7
  import { BraviatvConfigFlow } from './braviatv.classes.configflow.js';
6
8
  import { createBraviatvDiscoveryDescriptor } from './braviatv.discovery.js';
7
9
  import { BraviatvMapper } from './braviatv.mapper.js';
8
- import type { IBraviatvConfig } from './braviatv.types.js';
10
+ import { braviatvRecord, normalizeBraviatvConfig, normalizeBraviatvOptions, validateBraviatvControl } from './braviatv.validation.js';
11
+ import type { IBraviatvConfig, IBraviatvEffectResult, IBraviatvIntegrationOptions,
12
+ IBraviatvSetupContext, IBraviatvSnapshot, TBraviatvControl } from './braviatv.types.js';
9
13
 
10
14
  export class BraviatvIntegration extends BaseIntegration<IBraviatvConfig> {
11
15
  public readonly domain = 'braviatv';
12
- public readonly displayName = 'Sony Bravia TV';
16
+ public readonly displayName = 'Selected Sony BRAVIA Professional display';
13
17
  public readonly status = 'control-runtime' as const;
14
18
  public readonly discoveryDescriptor = createBraviatvDiscoveryDescriptor();
15
- public readonly configFlow = new BraviatvConfigFlow();
16
- public readonly metadata = {
17
- source: 'home-assistant/core',
18
- upstreamPath: 'homeassistant/components/braviatv',
19
- upstreamDomain: 'braviatv',
20
- integrationType: 'device',
21
- iotClass: 'local_polling',
22
- requirements: ['pybravia==0.4.1'],
23
- dependencies: ['ssdp'],
24
- afterDependencies: [],
25
- codeowners: ['@bieniu', '@Drafteed'],
26
- configFlow: true,
27
- documentation: 'https://www.home-assistant.io/integrations/braviatv',
28
- };
19
+ public readonly configFlow: BraviatvConfigFlow;
20
+ public readonly metadata = { source: 'native-typescript', integrationType: 'device', iotClass: 'local_poll',
21
+ documentation: 'https://pro-bravia.sony.net/remote-display-control/rest-api/reference/' };
22
+ readonly #options?: Readonly<IBraviatvIntegrationOptions>;
23
+ readonly #owner: NativeIntegrationOwner;
29
24
 
30
- public async setup(configArg: IBraviatvConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
31
- void contextArg;
32
- return new BraviatvRuntime(new BraviatvClient(configArg));
25
+ /** Unconfigured registry descriptors are inert; setup requires explicit caller home and credentials. */
26
+ public constructor(options?: IBraviatvIntegrationOptions) {
27
+ super();
28
+ this.#options = options === undefined ? undefined : normalizeBraviatvOptions(options);
29
+ this.#owner = new NativeIntegrationOwner('braviatv', { homeId: this.#options?.homeId, capacity: this.#options?.capacity });
30
+ this.configFlow = new BraviatvConfigFlow(this.#options, this.#owner.createFlowScope());
33
31
  }
34
32
 
35
- public async destroy(): Promise<void> {}
36
- }
33
+ public setup(config: IBraviatvConfig, context: IBraviatvSetupContext): Promise<IIntegrationRuntime> {
34
+ if (!this.#options) return Promise.reject(new Error('BRAVIA setup requires caller-owned PSK resolver options.'));
35
+ const options = this.#options;
36
+ try {
37
+ const selected = normalizeBraviatvConfig(config);
38
+ return this.#owner.runSetup(context, selected.homeId, async (lease) => {
39
+ const client = new BraviatvClient(selected, { ...lease.context, abortSignal: lease.signal }, options);
40
+ let runtime: BraviatvRuntime | undefined;
41
+ lease.own(async () => {
42
+ const ownedRuntime = runtime;
43
+ const results = await Promise.allSettled([
44
+ Promise.resolve().then(() => client.retryCleanup()),
45
+ ...(ownedRuntime ? [Promise.resolve().then(() => ownedRuntime.closeSubscriptions())] : []),
46
+ ]);
47
+ const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
48
+ if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'BRAVIA owned cleanup failed.');
49
+ });
50
+ const initial = await client.start(lease.signal);
51
+ lease.assertOpen();
52
+ runtime = new BraviatvRuntime(client, initial, lease);
53
+ lease.promoteToRuntime();
54
+ return runtime;
55
+ });
56
+ } catch (error) { return Promise.reject(error); }
57
+ }
37
58
 
59
+ public destroy(): Promise<void> {
60
+ return this.#owner.close();
61
+ }
62
+ public retryCleanup(): Promise<void> { return this.#owner.retryCleanup(); }
63
+ }
38
64
  export class HomeAssistantBraviatvIntegration extends BraviatvIntegration {}
39
65
 
40
- class BraviatvRuntime implements IIntegrationRuntime {
41
- public domain = 'braviatv';
66
+ interface IBraviatvSubscription {
67
+ handler: (event: IIntegrationEvent) => void;
68
+ active: boolean;
69
+ failed: boolean;
70
+ detach(): void;
71
+ stop(): Promise<void>;
72
+ }
42
73
 
43
- constructor(private readonly client: BraviatvClient) {}
74
+ class BraviatvRuntime implements IIntegrationRuntime {
75
+ public readonly domain = 'braviatv';
76
+ readonly #subscriptions = new Set<IBraviatvSubscription>();
77
+ readonly #parentAbort: () => void;
78
+ #closePromise?: Promise<void>;
79
+ #closed = false;
44
80
 
45
- public async devices(): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> {
46
- return BraviatvMapper.toDevices(await this.client.getSnapshot());
81
+ public constructor(private readonly client: BraviatvClient, private snapshot: IBraviatvSnapshot,
82
+ private readonly lease: INativeSetupLease) {
83
+ this.#parentAbort = () => { void this.destroy().catch(() => {}); };
84
+ lease.signal.addEventListener('abort', this.#parentAbort, { once: true });
85
+ if (lease.signal.aborted) this.#parentAbort();
86
+ }
87
+ public isHealthy(): boolean { return !this.#closed && this.client.isHealthy(); }
88
+ public async devices(signal?: AbortSignal): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> {
89
+ this.assertOpen();
90
+ const snapshot = await this.client.getSnapshot(signal);
91
+ this.publish(snapshot);
92
+ return BraviatvMapper.toDevices(snapshot);
47
93
  }
48
-
49
94
  public async entities(): Promise<IIntegrationEntity[]> {
50
- return BraviatvMapper.toEntities(await this.client.getSnapshot());
95
+ this.assertOpen();
96
+ const snapshot = await this.client.getSnapshot();
97
+ this.publish(snapshot);
98
+ return BraviatvMapper.toEntities(snapshot);
51
99
  }
52
-
53
- public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
54
- try {
55
- if (requestArg.domain === 'remote') {
56
- return await this.callRemoteService(requestArg);
57
- }
58
- if (requestArg.domain === 'braviatv') {
59
- return await this.callBraviatvService(requestArg);
60
- }
61
- if (requestArg.domain !== 'media_player') {
62
- return { success: false, error: `Unsupported Sony Bravia TV service domain: ${requestArg.domain}` };
63
- }
64
- return await this.callMediaPlayerService(requestArg);
65
- } catch (errorArg) {
66
- return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
67
- }
100
+ public async writeFeature(input: IDeviceFeatureWriteRequest, signal?: AbortSignal): Promise<IServiceCallResult> {
101
+ this.assertOpen();
102
+ const request = braviatvRecord(input, ['device', 'feature', 'value']);
103
+ const device = braviatvRecord(request.device);
104
+ const feature = braviatvRecord(request.feature);
105
+ const deviceId = BraviatvMapper.deviceId(this.snapshot.homeId, this.snapshot.identity.macAddress);
106
+ if (device.id !== deviceId || device.integrationDomain !== this.domain) throw new Error('BRAVIA feature target is outside the selected home and display.');
107
+ const control = validateBraviatvControl({ feature: feature.id, value: request.value });
108
+ if (feature.capability !== (control.feature === 'speaker_volume_raw' ? 'sensor' : 'switch')) throw new Error('BRAVIA feature capability does not match the selected control.');
109
+ return this.control(control, signal);
68
110
  }
69
-
70
- public async destroy(): Promise<void> {
71
- await this.client.destroy();
111
+ public async callService(input: IServiceCallRequest): Promise<IServiceCallResult> {
112
+ this.assertOpen();
113
+ const request = braviatvRecord(input, ['domain', 'service', 'target', 'data']);
114
+ if (request.domain !== 'braviatv') throw new Error('BRAVIA selected-display services use braviatv.');
115
+ let control: TBraviatvControl;
116
+ if (request.service === 'set_power') {
117
+ const data = braviatvRecord(request.data, ['power']);
118
+ control = validateBraviatvControl({ feature: 'power', value: data.power });
119
+ } else if (request.service === 'set_device_mute') {
120
+ const data = braviatvRecord(request.data, ['muted']);
121
+ control = validateBraviatvControl({ feature: 'device_mute', value: data.muted });
122
+ } else if (request.service === 'set_speaker_volume_raw') {
123
+ const data = braviatvRecord(request.data, ['volume_raw']);
124
+ control = validateBraviatvControl({ feature: 'speaker_volume_raw', value: data.volume_raw });
125
+ } else throw new Error('BRAVIA supports separate absolute power, device mute and integer speaker volume services only.');
126
+ const target = braviatvRecord(request.target, ['deviceId', 'entityId']);
127
+ const deviceId = BraviatvMapper.deviceId(this.snapshot.homeId, this.snapshot.identity.macAddress);
128
+ const entityId = BraviatvMapper.entityId(this.snapshot.homeId, this.snapshot.identity.macAddress, control.feature);
129
+ if ((!target.deviceId && !target.entityId) || target.deviceId !== undefined && target.deviceId !== deviceId || target.entityId !== undefined && target.entityId !== entityId) {
130
+ throw new Error('BRAVIA service target is outside the selected home, display and control.');
131
+ }
132
+ return this.control(control);
72
133
  }
73
-
74
- private async callRemoteService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
75
- if (requestArg.service !== 'send_command') {
76
- return { success: false, error: `Unsupported Sony Bravia TV remote service: ${requestArg.service}` };
77
- }
78
- const command = requestArg.data?.command;
79
- const commands = typeof command === 'string' ? [command] : Array.isArray(command) ? command.filter((itemArg): itemArg is string => typeof itemArg === 'string' && Boolean(itemArg)) : [];
80
- if (!commands.length) {
81
- return { success: false, error: 'Sony Bravia TV remote.send_command requires data.command.' };
82
- }
83
- const repeatsValue = requestArg.data?.num_repeats ?? requestArg.data?.numRepeats ?? 1;
84
- const repeats = typeof repeatsValue === 'number' && Number.isFinite(repeatsValue) ? repeatsValue : 1;
85
- await this.client.sendCommands(commands, repeats);
86
- return { success: true };
134
+ /** Completed observations only; subscriptions never start a polling loop. */
135
+ public async subscribe(handler: (event: IIntegrationEvent) => void, signal?: AbortSignal): Promise<() => Promise<void>> {
136
+ this.assertOpen();
137
+ if (typeof handler !== 'function' || signal !== undefined && !(signal instanceof AbortSignal)) throw new TypeError('BRAVIA subscription requires a callback and optional AbortSignal.');
138
+ if (signal?.aborted) throw new Error('BRAVIA subscription was cancelled.');
139
+ if (this.#subscriptions.size >= 32) throw new Error('BRAVIA subscription capacity reached.');
140
+ const aborted = () => { subscription.detach(); this.#subscriptions.delete(subscription); };
141
+ const subscription: IBraviatvSubscription = { handler, active: true, failed: false,
142
+ detach: () => { subscription.active = false; signal?.removeEventListener('abort', aborted); },
143
+ stop: async () => { subscription.detach(); this.#subscriptions.delete(subscription);
144
+ if (subscription.failed) throw new Error('BRAVIA subscriber failed.'); } };
145
+ signal?.addEventListener('abort', aborted, { once: true });
146
+ this.#subscriptions.add(subscription);
147
+ if (signal?.aborted) aborted();
148
+ return subscription.stop;
87
149
  }
88
-
89
- private async callBraviatvService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
90
- if (requestArg.service === 'reboot') {
91
- await this.client.reboot();
92
- return { success: true };
93
- }
94
- if (requestArg.service === 'terminate_apps') {
95
- await this.client.terminateApps();
96
- return { success: true };
97
- }
98
- return { success: false, error: `Unsupported Sony Bravia TV service: ${requestArg.service}` };
150
+ public destroy(): Promise<void> {
151
+ if (!this.#closePromise) {
152
+ this.#closePromise = Promise.resolve().then(() => this.lease.close());
153
+ this.#closed = true;
154
+ this.lease.signal.removeEventListener('abort', this.#parentAbort);
155
+ for (const subscription of this.#subscriptions) subscription.detach();
156
+ }
157
+ return this.#closePromise;
99
158
  }
100
-
101
- private async callMediaPlayerService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
102
- if (requestArg.service === 'turn_on') {
103
- await this.client.turnOn();
104
- return { success: true };
105
- }
106
- if (requestArg.service === 'turn_off') {
107
- await this.client.turnOff();
108
- return { success: true };
109
- }
110
- if (requestArg.service === 'play' || requestArg.service === 'media_play') {
111
- await this.client.mediaPlay();
112
- return { success: true };
113
- }
114
- if (requestArg.service === 'pause' || requestArg.service === 'media_pause') {
115
- await this.client.mediaPause();
116
- return { success: true };
117
- }
118
- if (requestArg.service === 'play_pause' || requestArg.service === 'media_play_pause') {
119
- await this.client.sendCommand('Play');
120
- return { success: true };
121
- }
122
- if (requestArg.service === 'stop' || requestArg.service === 'media_stop') {
123
- await this.client.mediaStop();
124
- return { success: true };
125
- }
126
- if (requestArg.service === 'next_track' || requestArg.service === 'media_next_track') {
127
- await this.client.nextTrack();
128
- return { success: true };
129
- }
130
- if (requestArg.service === 'previous_track' || requestArg.service === 'media_previous_track') {
131
- await this.client.previousTrack();
132
- return { success: true };
133
- }
134
- if (requestArg.service === 'volume_set') {
135
- const level = requestArg.data?.volume_level;
136
- if (typeof level !== 'number') {
137
- return { success: false, error: 'Sony Bravia TV volume_set requires data.volume_level.' };
138
- }
139
- await this.client.setVolumeLevel(level);
140
- return { success: true };
141
- }
142
- if (requestArg.service === 'volume_up') {
143
- await this.client.volumeUp();
144
- return { success: true };
145
- }
146
- if (requestArg.service === 'volume_down') {
147
- await this.client.volumeDown();
148
- return { success: true };
149
- }
150
- if (requestArg.service === 'volume_mute' || requestArg.service === 'mute') {
151
- const muted = requestArg.data?.is_volume_muted ?? requestArg.data?.muted;
152
- if (typeof muted !== 'boolean') {
153
- return { success: false, error: 'Sony Bravia TV volume_mute requires data.is_volume_muted.' };
154
- }
155
- await this.client.muteVolume(muted);
156
- return { success: true };
157
- }
158
- if (requestArg.service === 'select_source') {
159
- const source = requestArg.data?.source;
160
- if (typeof source !== 'string' || !source) {
161
- return { success: false, error: 'Sony Bravia TV select_source requires data.source.' };
162
- }
163
- await this.client.selectSource(source);
164
- return { success: true };
159
+ public async closeSubscriptions(): Promise<void> {
160
+ this.#closed = true;
161
+ this.lease.signal.removeEventListener('abort', this.#parentAbort);
162
+ const results = await Promise.allSettled([...this.#subscriptions].map((entry) => entry.stop()));
163
+ const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
164
+ if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'BRAVIA subscriber cleanup failed.');
165
+ }
166
+ private async control(control: TBraviatvControl, signal?: AbortSignal): Promise<IServiceCallResult> {
167
+ try {
168
+ const result = await this.client.setControl(control, signal);
169
+ this.publish(result.snapshot);
170
+ return this.result(result);
171
+ } catch (error) {
172
+ const failure = error instanceof plugins.ecobridgeDeviceManager.SonyBraviaProtocolError ? error : undefined;
173
+ return { success: false, error: failure?.message ?? 'BRAVIA selected-display control was not admitted.',
174
+ data: { effectOutcome: failure?.effectOutcome ?? 'not-sent', commandAcknowledged: failure?.commandAcknowledged ?? false, causalityConfirmed: false,
175
+ ...(failure ? { code: failure.code } : {}) } };
165
176
  }
166
- if (requestArg.service === 'play_media') {
167
- const mediaId = requestArg.data?.media_content_id;
168
- const mediaType = requestArg.data?.media_content_type;
169
- if (typeof mediaId !== 'string' || typeof mediaType !== 'string') {
170
- return { success: false, error: 'Sony Bravia TV play_media requires data.media_content_type and data.media_content_id.' };
171
- }
172
- await this.client.playMedia(mediaType, mediaId);
173
- return { success: true };
177
+ }
178
+ private result(result: IBraviatvEffectResult): IServiceCallResult {
179
+ return { success: result.observation === 'matching-reported-state',
180
+ ...(result.observation === 'different-reported-state' ? { error: 'BRAVIA acknowledged the command, but the independent reported state differs.' } : {}),
181
+ data: { commandAcknowledged: result.commandAcknowledged, causalityConfirmed: result.causalityConfirmed,
182
+ observation: result.observation, control: result.control, requested: result.requested,
183
+ devices: BraviatvMapper.toDevices(result.snapshot), entities: BraviatvMapper.toEntities(result.snapshot) } };
184
+ }
185
+ private publish(snapshot: IBraviatvSnapshot): void {
186
+ if (this.#closed) return;
187
+ this.snapshot = snapshot;
188
+ for (const subscription of [...this.#subscriptions]) {
189
+ if (this.#closed) break;
190
+ if (!subscription.active) continue;
191
+ try { subscription.handler({ type: 'state_changed', integrationDomain: this.domain,
192
+ deviceId: BraviatvMapper.deviceId(snapshot.homeId, snapshot.identity.macAddress), data: structuredClone(snapshot), timestamp: Date.now() }); }
193
+ catch { subscription.failed = true; subscription.detach(); }
174
194
  }
175
- return { success: false, error: `Unsupported Sony Bravia TV media_player service: ${requestArg.service}` };
176
195
  }
196
+ private assertOpen(): void { if (this.#closed) throw new Error('BRAVIA runtime is closed.'); }
177
197
  }
@@ -30,8 +30,8 @@ export class BraviatvSsdpMatcher implements IDiscoveryMatcher<IBraviatvSsdpRecor
30
30
  const id = stripUuid(usn || stringValue(recordArg, 'udn', 'UDN')) || stringValue(recordArg, 'cid', 'macAddr');
31
31
  return {
32
32
  matched: true,
33
- confidence: id ? 'certain' : 'high',
34
- reason: 'SSDP record matches Sony Bravia ScalarWebAPI metadata.',
33
+ confidence: 'medium',
34
+ reason: 'Unverified SSDP metadata supplies Sony BRAVIA setup hints only.',
35
35
  normalizedDeviceId: id,
36
36
  candidate: {
37
37
  source: 'ssdp',
@@ -72,8 +72,8 @@ export class BraviatvMdnsMatcher implements IDiscoveryMatcher<IBraviatvMdnsRecor
72
72
  const id = valueForKey(properties, 'cid') || valueForKey(properties, 'id') || valueForKey(properties, 'deviceid') || name;
73
73
  return {
74
74
  matched: true,
75
- confidence: id ? 'certain' : recordArg.host ? 'high' : 'medium',
76
- reason: 'mDNS record matches Sony Bravia metadata.',
75
+ confidence: 'medium',
76
+ reason: 'Unverified mDNS metadata supplies Sony BRAVIA setup hints only.',
77
77
  normalizedDeviceId: id,
78
78
  candidate: {
79
79
  source: 'mdns',
@@ -88,7 +88,6 @@ export class BraviatvMdnsMatcher implements IDiscoveryMatcher<IBraviatvMdnsRecor
88
88
  metadata: {
89
89
  mdnsType: recordArg.type,
90
90
  mdnsName: recordArg.name,
91
- txt: properties,
92
91
  },
93
92
  },
94
93
  };
@@ -116,17 +115,14 @@ export class BraviatvManualMatcher implements IDiscoveryMatcher<IBraviatvManualE
116
115
  integrationDomain: 'braviatv',
117
116
  id,
118
117
  host: inputArg.host,
119
- port: inputArg.port || (inputArg.useSsl ? 443 : 80),
118
+ port: inputArg.port || 80,
120
119
  name: inputArg.name,
121
120
  manufacturer: inputArg.manufacturer || 'Sony',
122
121
  model: inputArg.model,
123
122
  serialNumber: inputArg.serialNumber,
124
123
  macAddress: inputArg.macAddress,
125
124
  metadata: {
126
- ...(inputArg.metadata || {}),
127
125
  cid: inputArg.cid,
128
- psk: inputArg.psk,
129
- useSsl: inputArg.useSsl,
130
126
  },
131
127
  },
132
128
  };
@@ -146,7 +142,12 @@ export class BraviatvCandidateValidator implements IDiscoveryValidator {
146
142
  matched,
147
143
  confidence: matched && candidateArg.host ? 'high' : matched ? 'medium' : 'low',
148
144
  reason: matched ? 'Candidate has Sony Bravia metadata.' : 'Candidate is not Sony Bravia TV.',
149
- candidate: matched ? candidateArg : undefined,
145
+ candidate: matched ? {
146
+ source: candidateArg.source, integrationDomain: 'braviatv', id: candidateArg.id,
147
+ host: candidateArg.host, port: candidateArg.port, name: candidateArg.name,
148
+ manufacturer: candidateArg.manufacturer, model: candidateArg.model,
149
+ macAddress: candidateArg.macAddress, serialNumber: candidateArg.serialNumber,
150
+ } : undefined,
150
151
  normalizedDeviceId: candidateArg.id || candidateArg.macAddress || candidateArg.serialNumber || candidateArg.host,
151
152
  };
152
153
  }