@smarthome.exchange/integrations 1.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (529) hide show
  1. package/changelog.md +84 -0
  2. package/dist_ts/00_commitinfo_data.js +1 -1
  3. package/dist_ts/core/classes.configstore.d.ts +2 -0
  4. package/dist_ts/core/classes.configstore.js +84 -27
  5. package/dist_ts/core/classes.nativehomeadmission.d.ts +19 -0
  6. package/dist_ts/core/classes.nativehomeadmission.js +84 -0
  7. package/dist_ts/core/classes.nativeintegrationowner.d.ts +81 -0
  8. package/dist_ts/core/classes.nativeintegrationowner.js +273 -0
  9. package/dist_ts/core/classes.runtimemanager.d.ts +2 -0
  10. package/dist_ts/core/classes.runtimemanager.js +11 -3
  11. package/dist_ts/core/index.d.ts +2 -0
  12. package/dist_ts/core/index.js +3 -1
  13. package/dist_ts/core/types.d.ts +16 -0
  14. package/dist_ts/integrations/braviatv/braviatv.classes.client.d.ts +23 -72
  15. package/dist_ts/integrations/braviatv/braviatv.classes.client.js +265 -625
  16. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.d.ts +7 -7
  17. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.js +51 -68
  18. package/dist_ts/integrations/braviatv/braviatv.classes.integration.d.ts +8 -11
  19. package/dist_ts/integrations/braviatv/braviatv.classes.integration.js +186 -135
  20. package/dist_ts/integrations/braviatv/braviatv.discovery.js +12 -11
  21. package/dist_ts/integrations/braviatv/braviatv.mapper.d.ts +6 -14
  22. package/dist_ts/integrations/braviatv/braviatv.mapper.js +37 -131
  23. package/dist_ts/integrations/braviatv/braviatv.types.d.ts +55 -133
  24. package/dist_ts/integrations/braviatv/braviatv.validation.d.ts +7 -0
  25. package/dist_ts/integrations/braviatv/braviatv.validation.js +72 -0
  26. package/dist_ts/integrations/broadlink/broadlink.actions.d.ts +2 -0
  27. package/dist_ts/integrations/broadlink/broadlink.actions.js +36 -0
  28. package/dist_ts/integrations/broadlink/broadlink.classes.client.d.ts +21 -19
  29. package/dist_ts/integrations/broadlink/broadlink.classes.client.js +185 -124
  30. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.d.ts +5 -4
  31. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.js +64 -83
  32. package/dist_ts/integrations/broadlink/broadlink.classes.integration.d.ts +16 -19
  33. package/dist_ts/integrations/broadlink/broadlink.classes.integration.js +114 -59
  34. package/dist_ts/integrations/broadlink/broadlink.mapper.d.ts +3 -2
  35. package/dist_ts/integrations/broadlink/broadlink.mapper.js +2 -1
  36. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.d.ts +10 -0
  37. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.js +41 -0
  38. package/dist_ts/integrations/broadlink/broadlink.types.d.ts +43 -7
  39. package/dist_ts/integrations/broadlink/broadlink.validation.d.ts +7 -0
  40. package/dist_ts/integrations/broadlink/broadlink.validation.js +63 -0
  41. package/dist_ts/integrations/daikin/daikin.classes.client.d.ts +10 -52
  42. package/dist_ts/integrations/daikin/daikin.classes.client.js +55 -614
  43. package/dist_ts/integrations/daikin/daikin.classes.configflow.d.ts +8 -12
  44. package/dist_ts/integrations/daikin/daikin.classes.configflow.js +77 -138
  45. package/dist_ts/integrations/daikin/daikin.classes.integration.d.ts +7 -24
  46. package/dist_ts/integrations/daikin/daikin.classes.integration.js +175 -67
  47. package/dist_ts/integrations/daikin/daikin.discovery.d.ts +11 -24
  48. package/dist_ts/integrations/daikin/daikin.discovery.js +98 -305
  49. package/dist_ts/integrations/daikin/daikin.mapper.d.ts +6 -7
  50. package/dist_ts/integrations/daikin/daikin.mapper.js +95 -155
  51. package/dist_ts/integrations/daikin/daikin.types.d.ts +24 -44
  52. package/dist_ts/integrations/daikin/daikin.types.js +1 -1
  53. package/dist_ts/integrations/daikin/daikin.validation.d.ts +5 -0
  54. package/dist_ts/integrations/daikin/daikin.validation.js +53 -0
  55. package/dist_ts/integrations/deconz/deconz.classes.client.d.ts +37 -29
  56. package/dist_ts/integrations/deconz/deconz.classes.client.js +521 -294
  57. package/dist_ts/integrations/deconz/deconz.classes.configflow.d.ts +6 -1
  58. package/dist_ts/integrations/deconz/deconz.classes.configflow.js +63 -33
  59. package/dist_ts/integrations/deconz/deconz.classes.integration.d.ts +4 -3
  60. package/dist_ts/integrations/deconz/deconz.classes.integration.js +85 -40
  61. package/dist_ts/integrations/deconz/deconz.mapper.d.ts +1 -0
  62. package/dist_ts/integrations/deconz/deconz.mapper.js +24 -6
  63. package/dist_ts/integrations/deconz/deconz.types.d.ts +43 -6
  64. package/dist_ts/integrations/deconz/deconz.validation.d.ts +7 -1
  65. package/dist_ts/integrations/deconz/deconz.validation.js +215 -4
  66. package/dist_ts/integrations/denonavr/denonavr.classes.client.d.ts +31 -40
  67. package/dist_ts/integrations/denonavr/denonavr.classes.client.js +149 -404
  68. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.d.ts +7 -2
  69. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.js +44 -36
  70. package/dist_ts/integrations/denonavr/denonavr.classes.integration.d.ts +6 -11
  71. package/dist_ts/integrations/denonavr/denonavr.classes.integration.js +192 -113
  72. package/dist_ts/integrations/denonavr/denonavr.discovery.d.ts +10 -18
  73. package/dist_ts/integrations/denonavr/denonavr.discovery.js +71 -193
  74. package/dist_ts/integrations/denonavr/denonavr.mapper.d.ts +5 -13
  75. package/dist_ts/integrations/denonavr/denonavr.mapper.js +35 -159
  76. package/dist_ts/integrations/denonavr/denonavr.types.d.ts +55 -90
  77. package/dist_ts/integrations/denonavr/denonavr.validation.d.ts +10 -0
  78. package/dist_ts/integrations/denonavr/denonavr.validation.js +86 -0
  79. package/dist_ts/integrations/esphome/esphome.classes.client.d.ts +19 -7
  80. package/dist_ts/integrations/esphome/esphome.classes.client.js +183 -89
  81. package/dist_ts/integrations/esphome/esphome.classes.configflow.d.ts +5 -2
  82. package/dist_ts/integrations/esphome/esphome.classes.configflow.js +43 -33
  83. package/dist_ts/integrations/esphome/esphome.classes.integration.d.ts +8 -6
  84. package/dist_ts/integrations/esphome/esphome.classes.integration.js +71 -43
  85. package/dist_ts/integrations/esphome/esphome.discovery.js +4 -12
  86. package/dist_ts/integrations/esphome/esphome.mapper.d.ts +2 -2
  87. package/dist_ts/integrations/esphome/esphome.mapper.js +6 -4
  88. package/dist_ts/integrations/esphome/esphome.types.d.ts +31 -6
  89. package/dist_ts/integrations/esphome/esphome.types.js +1 -1
  90. package/dist_ts/integrations/esphome/esphome.validation.d.ts +7 -0
  91. package/dist_ts/integrations/esphome/esphome.validation.js +66 -0
  92. package/dist_ts/integrations/homeassistant/homeassistant.classes.client.d.ts +32 -4
  93. package/dist_ts/integrations/homeassistant/homeassistant.classes.client.js +345 -116
  94. package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.d.ts +8 -5
  95. package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.js +34 -8
  96. package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.d.ts +7 -4
  97. package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.js +44 -56
  98. package/dist_ts/integrations/homeassistant/homeassistant.types.d.ts +12 -1
  99. package/dist_ts/integrations/hue/hue.classes.client.d.ts +6 -1
  100. package/dist_ts/integrations/hue/hue.classes.client.js +120 -45
  101. package/dist_ts/integrations/hue/hue.classes.configflow.js +16 -7
  102. package/dist_ts/integrations/hue/hue.classes.integration.d.ts +2 -0
  103. package/dist_ts/integrations/hue/hue.classes.integration.js +103 -30
  104. package/dist_ts/integrations/hue/hue.validation.d.ts +1 -0
  105. package/dist_ts/integrations/hue/hue.validation.js +14 -4
  106. package/dist_ts/integrations/kodi/kodi.classes.client.d.ts +11 -45
  107. package/dist_ts/integrations/kodi/kodi.classes.client.js +84 -310
  108. package/dist_ts/integrations/kodi/kodi.classes.configflow.d.ts +9 -8
  109. package/dist_ts/integrations/kodi/kodi.classes.configflow.js +53 -48
  110. package/dist_ts/integrations/kodi/kodi.classes.integration.d.ts +11 -11
  111. package/dist_ts/integrations/kodi/kodi.classes.integration.js +114 -171
  112. package/dist_ts/integrations/kodi/kodi.discovery.js +53 -29
  113. package/dist_ts/integrations/kodi/kodi.mapper.d.ts +7 -2
  114. package/dist_ts/integrations/kodi/kodi.mapper.js +48 -10
  115. package/dist_ts/integrations/kodi/kodi.types.d.ts +32 -28
  116. package/dist_ts/integrations/kodi/kodi.validation.d.ts +9 -0
  117. package/dist_ts/integrations/kodi/kodi.validation.js +62 -0
  118. package/dist_ts/integrations/modbus/modbus.classes.client.d.ts +15 -61
  119. package/dist_ts/integrations/modbus/modbus.classes.client.js +117 -776
  120. package/dist_ts/integrations/modbus/modbus.classes.configflow.d.ts +9 -5
  121. package/dist_ts/integrations/modbus/modbus.classes.configflow.js +70 -38
  122. package/dist_ts/integrations/modbus/modbus.classes.integration.d.ts +6 -17
  123. package/dist_ts/integrations/modbus/modbus.classes.integration.js +133 -57
  124. package/dist_ts/integrations/modbus/modbus.discovery.d.ts +5 -8
  125. package/dist_ts/integrations/modbus/modbus.discovery.js +38 -93
  126. package/dist_ts/integrations/modbus/modbus.mapper.d.ts +8 -32
  127. package/dist_ts/integrations/modbus/modbus.mapper.js +71 -431
  128. package/dist_ts/integrations/modbus/modbus.types.d.ts +82 -332
  129. package/dist_ts/integrations/modbus/modbus.validation.d.ts +10 -0
  130. package/dist_ts/integrations/modbus/modbus.validation.js +128 -0
  131. package/dist_ts/integrations/mqtt/mqtt.classes.client.d.ts +15 -2
  132. package/dist_ts/integrations/mqtt/mqtt.classes.client.js +173 -23
  133. package/dist_ts/integrations/mqtt/mqtt.classes.configflow.d.ts +5 -1
  134. package/dist_ts/integrations/mqtt/mqtt.classes.configflow.js +53 -33
  135. package/dist_ts/integrations/mqtt/mqtt.classes.integration.d.ts +4 -1
  136. package/dist_ts/integrations/mqtt/mqtt.classes.integration.js +127 -56
  137. package/dist_ts/integrations/mqtt/mqtt.classes.session.d.ts +13 -0
  138. package/dist_ts/integrations/mqtt/mqtt.classes.session.js +130 -0
  139. package/dist_ts/integrations/mqtt/mqtt.mapper.d.ts +3 -0
  140. package/dist_ts/integrations/mqtt/mqtt.mapper.js +44 -1
  141. package/dist_ts/integrations/mqtt/mqtt.types.d.ts +46 -0
  142. package/dist_ts/integrations/mqtt/mqtt.validation.d.ts +7 -0
  143. package/dist_ts/integrations/mqtt/mqtt.validation.js +180 -0
  144. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.d.ts +12 -34
  145. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.js +143 -231
  146. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.d.ts +6 -1
  147. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.js +105 -18
  148. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.d.ts +8 -8
  149. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.js +141 -155
  150. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.d.ts +9 -0
  151. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.js +35 -0
  152. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.d.ts +6 -18
  153. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.js +45 -220
  154. package/dist_ts/integrations/nanoleaf/nanoleaf.types.d.ts +33 -147
  155. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.d.ts +6 -0
  156. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.js +82 -0
  157. package/dist_ts/integrations/onkyo/onkyo.classes.client.d.ts +15 -20
  158. package/dist_ts/integrations/onkyo/onkyo.classes.client.js +161 -404
  159. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.d.ts +9 -4
  160. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.js +51 -6
  161. package/dist_ts/integrations/onkyo/onkyo.classes.integration.d.ts +22 -6
  162. package/dist_ts/integrations/onkyo/onkyo.classes.integration.js +144 -11
  163. package/dist_ts/integrations/onkyo/onkyo.discovery.d.ts +6 -1
  164. package/dist_ts/integrations/onkyo/onkyo.discovery.js +40 -4
  165. package/dist_ts/integrations/onkyo/onkyo.mapper.d.ts +7 -8
  166. package/dist_ts/integrations/onkyo/onkyo.mapper.js +45 -12
  167. package/dist_ts/integrations/onkyo/onkyo.types.d.ts +58 -8
  168. package/dist_ts/integrations/onkyo/onkyo.types.js +13 -102
  169. package/dist_ts/integrations/onkyo/onkyo.validation.d.ts +16 -0
  170. package/dist_ts/integrations/onkyo/onkyo.validation.js +77 -0
  171. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.d.ts +25 -25
  172. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.js +116 -360
  173. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.d.ts +11 -3
  174. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.js +76 -6
  175. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.d.ts +26 -4
  176. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.js +142 -9
  177. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.d.ts +2 -1
  178. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.js +31 -4
  179. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.d.ts +9 -9
  180. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.js +31 -149
  181. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.d.ts +51 -11
  182. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.js +22 -87
  183. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.d.ts +6 -0
  184. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.js +56 -0
  185. package/dist_ts/integrations/pioneer/pioneer.classes.client.d.ts +31 -16
  186. package/dist_ts/integrations/pioneer/pioneer.classes.client.js +167 -409
  187. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.d.ts +10 -3
  188. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.js +66 -6
  189. package/dist_ts/integrations/pioneer/pioneer.classes.integration.d.ts +13 -5
  190. package/dist_ts/integrations/pioneer/pioneer.classes.integration.js +239 -11
  191. package/dist_ts/integrations/pioneer/pioneer.discovery.d.ts +14 -1
  192. package/dist_ts/integrations/pioneer/pioneer.discovery.js +51 -4
  193. package/dist_ts/integrations/pioneer/pioneer.mapper.d.ts +14 -8
  194. package/dist_ts/integrations/pioneer/pioneer.mapper.js +54 -12
  195. package/dist_ts/integrations/pioneer/pioneer.types.d.ts +79 -12
  196. package/dist_ts/integrations/pioneer/pioneer.types.js +12 -76
  197. package/dist_ts/integrations/pioneer/pioneer.validation.d.ts +10 -0
  198. package/dist_ts/integrations/pioneer/pioneer.validation.js +85 -0
  199. package/dist_ts/integrations/samsungtv/samsungtv.classes.client.d.ts +4 -2
  200. package/dist_ts/integrations/samsungtv/samsungtv.classes.client.js +41 -16
  201. package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.d.ts +5 -0
  202. package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.js +20 -7
  203. package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.d.ts +1 -0
  204. package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.js +53 -50
  205. package/dist_ts/integrations/samsungtv/samsungtv.types.d.ts +4 -1
  206. package/dist_ts/integrations/shelly/shelly.classes.client.d.ts +26 -30
  207. package/dist_ts/integrations/shelly/shelly.classes.client.js +504 -276
  208. package/dist_ts/integrations/shelly/shelly.classes.configflow.d.ts +8 -3
  209. package/dist_ts/integrations/shelly/shelly.classes.configflow.js +43 -38
  210. package/dist_ts/integrations/shelly/shelly.classes.integration.d.ts +6 -6
  211. package/dist_ts/integrations/shelly/shelly.classes.integration.js +103 -101
  212. package/dist_ts/integrations/shelly/shelly.classes.subscription.d.ts +4 -0
  213. package/dist_ts/integrations/shelly/shelly.classes.subscription.js +24 -2
  214. package/dist_ts/integrations/shelly/shelly.mapper.d.ts +1 -2
  215. package/dist_ts/integrations/shelly/shelly.mapper.js +21 -20
  216. package/dist_ts/integrations/shelly/shelly.rpc.js +4 -1
  217. package/dist_ts/integrations/shelly/shelly.types.d.ts +42 -2
  218. package/dist_ts/integrations/shelly/shelly.types.js +11 -2
  219. package/dist_ts/integrations/shelly/shelly.validation.d.ts +7 -0
  220. package/dist_ts/integrations/shelly/shelly.validation.js +79 -0
  221. package/dist_ts/integrations/sonos/sonos.classes.client.d.ts +79 -22
  222. package/dist_ts/integrations/sonos/sonos.classes.client.js +427 -139
  223. package/dist_ts/integrations/sonos/sonos.classes.configflow.d.ts +9 -2
  224. package/dist_ts/integrations/sonos/sonos.classes.configflow.js +26 -28
  225. package/dist_ts/integrations/sonos/sonos.classes.integration.d.ts +7 -6
  226. package/dist_ts/integrations/sonos/sonos.classes.integration.js +289 -224
  227. package/dist_ts/integrations/sonos/sonos.config.d.ts +6 -1
  228. package/dist_ts/integrations/sonos/sonos.config.js +23 -2
  229. package/dist_ts/integrations/sonos/sonos.mapper.d.ts +1 -1
  230. package/dist_ts/integrations/sonos/sonos.mapper.js +14 -9
  231. package/dist_ts/integrations/sonos/sonos.matchers.js +3 -3
  232. package/dist_ts/integrations/sonos/sonos.types.d.ts +26 -1
  233. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.d.ts +13 -36
  234. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.js +179 -502
  235. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.d.ts +6 -1
  236. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.js +50 -40
  237. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.d.ts +14 -15
  238. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.js +108 -128
  239. package/dist_ts/integrations/soundtouch/soundtouch.discovery.d.ts +2 -20
  240. package/dist_ts/integrations/soundtouch/soundtouch.discovery.js +23 -113
  241. package/dist_ts/integrations/soundtouch/soundtouch.mapper.d.ts +3 -12
  242. package/dist_ts/integrations/soundtouch/soundtouch.mapper.js +35 -189
  243. package/dist_ts/integrations/soundtouch/soundtouch.types.d.ts +57 -142
  244. package/dist_ts/integrations/soundtouch/soundtouch.types.js +18 -3
  245. package/dist_ts/integrations/soundtouch/soundtouch.validation.d.ts +22 -0
  246. package/dist_ts/integrations/soundtouch/soundtouch.validation.js +65 -0
  247. package/dist_ts/integrations/tasmota/tasmota.classes.integration.d.ts +5 -0
  248. package/dist_ts/integrations/tasmota/tasmota.classes.integration.js +23 -7
  249. package/dist_ts/integrations/tasmota/tasmota.classes.runtime.d.ts +19 -5
  250. package/dist_ts/integrations/tasmota/tasmota.classes.runtime.js +115 -41
  251. package/dist_ts/integrations/tasmota/tasmota.config.js +23 -1
  252. package/dist_ts/integrations/tasmota/tasmota.credentials.d.ts +11 -0
  253. package/dist_ts/integrations/tasmota/tasmota.credentials.js +97 -0
  254. package/dist_ts/integrations/tasmota/tasmota.discovery.d.ts +7 -1
  255. package/dist_ts/integrations/tasmota/tasmota.discovery.js +108 -30
  256. package/dist_ts/integrations/tasmota/tasmota.mapper.d.ts +2 -2
  257. package/dist_ts/integrations/tasmota/tasmota.mapper.js +7 -7
  258. package/dist_ts/integrations/tasmota/tasmota.types.d.ts +41 -2
  259. package/dist_ts/integrations/tuya/tuya.classes.integration.d.ts +4 -1
  260. package/dist_ts/integrations/tuya/tuya.classes.integration.js +79 -110
  261. package/dist_ts/integrations/tuya/tuya.classes.runtime.d.ts +5 -2
  262. package/dist_ts/integrations/tuya/tuya.classes.runtime.js +73 -26
  263. package/dist_ts/integrations/tuya/tuya.mapper.js +2 -2
  264. package/dist_ts/integrations/tuya/tuya.types.d.ts +3 -0
  265. package/dist_ts/integrations/tuya/tuya.validation.d.ts +2 -2
  266. package/dist_ts/integrations/tuya/tuya.validation.js +6 -11
  267. package/dist_ts/integrations/webostv/webostv.classes.client.d.ts +6 -5
  268. package/dist_ts/integrations/webostv/webostv.classes.client.js +147 -76
  269. package/dist_ts/integrations/webostv/webostv.classes.configflow.d.ts +7 -2
  270. package/dist_ts/integrations/webostv/webostv.classes.configflow.js +36 -20
  271. package/dist_ts/integrations/webostv/webostv.classes.integration.d.ts +4 -4
  272. package/dist_ts/integrations/webostv/webostv.classes.integration.js +46 -54
  273. package/dist_ts/integrations/webostv/webostv.mapper.js +5 -5
  274. package/dist_ts/integrations/webostv/webostv.types.d.ts +16 -3
  275. package/dist_ts/integrations/webostv/webostv.types.js +1 -1
  276. package/dist_ts/integrations/webostv/webostv.validation.d.ts +3 -1
  277. package/dist_ts/integrations/webostv/webostv.validation.js +23 -1
  278. package/dist_ts/integrations/wiz/index.d.ts +1 -0
  279. package/dist_ts/integrations/wiz/index.js +2 -1
  280. package/dist_ts/integrations/wiz/wiz.classes.client.d.ts +14 -28
  281. package/dist_ts/integrations/wiz/wiz.classes.client.js +93 -229
  282. package/dist_ts/integrations/wiz/wiz.classes.configflow.d.ts +6 -4
  283. package/dist_ts/integrations/wiz/wiz.classes.configflow.js +38 -67
  284. package/dist_ts/integrations/wiz/wiz.classes.integration.d.ts +10 -21
  285. package/dist_ts/integrations/wiz/wiz.classes.integration.js +204 -44
  286. package/dist_ts/integrations/wiz/wiz.discovery.d.ts +10 -31
  287. package/dist_ts/integrations/wiz/wiz.discovery.js +48 -249
  288. package/dist_ts/integrations/wiz/wiz.mapper.d.ts +7 -51
  289. package/dist_ts/integrations/wiz/wiz.mapper.js +82 -668
  290. package/dist_ts/integrations/wiz/wiz.types.d.ts +34 -208
  291. package/dist_ts/integrations/wiz/wiz.validation.d.ts +8 -0
  292. package/dist_ts/integrations/wiz/wiz.validation.js +72 -0
  293. package/dist_ts/integrations/yamaha/index.d.ts +1 -0
  294. package/dist_ts/integrations/yamaha/index.js +2 -1
  295. package/dist_ts/integrations/yamaha/yamaha.classes.client.d.ts +30 -4
  296. package/dist_ts/integrations/yamaha/yamaha.classes.client.js +162 -6
  297. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.d.ts +10 -3
  298. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.js +106 -6
  299. package/dist_ts/integrations/yamaha/yamaha.classes.integration.d.ts +22 -4
  300. package/dist_ts/integrations/yamaha/yamaha.classes.integration.js +243 -8
  301. package/dist_ts/integrations/yamaha/yamaha.discovery.d.ts +13 -1
  302. package/dist_ts/integrations/yamaha/yamaha.discovery.js +57 -4
  303. package/dist_ts/integrations/yamaha/yamaha.mapper.d.ts +16 -8
  304. package/dist_ts/integrations/yamaha/yamaha.mapper.js +58 -12
  305. package/dist_ts/integrations/yamaha/yamaha.types.d.ts +73 -6
  306. package/dist_ts/integrations/yamaha/yamaha.types.js +8 -94
  307. package/dist_ts/integrations/yamaha/yamaha.validation.d.ts +12 -0
  308. package/dist_ts/integrations/yamaha/yamaha.validation.js +89 -0
  309. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.d.ts +6 -1
  310. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.js +18 -8
  311. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.d.ts +4 -1
  312. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.js +54 -6
  313. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.d.ts +12 -6
  314. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.js +73 -59
  315. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.d.ts +3 -2
  316. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.js +17 -12
  317. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.types.d.ts +31 -2
  318. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.d.ts +9 -1
  319. package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.js +57 -7
  320. package/dist_ts/integrations/zwave_js/zwave_js.classes.client.d.ts +10 -4
  321. package/dist_ts/integrations/zwave_js/zwave_js.classes.client.js +167 -31
  322. package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.d.ts +6 -1
  323. package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.js +57 -35
  324. package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.d.ts +3 -1
  325. package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.js +59 -37
  326. package/dist_ts/integrations/zwave_js/zwave_js.discovery.js +3 -3
  327. package/dist_ts/integrations/zwave_js/zwave_js.mapper.js +41 -24
  328. package/dist_ts/integrations/zwave_js/zwave_js.types.d.ts +25 -3
  329. package/dist_ts/integrations/zwave_js/zwave_js.validation.d.ts +6 -2
  330. package/dist_ts/integrations/zwave_js/zwave_js.validation.js +52 -17
  331. package/dist_ts/plugins.d.ts +2 -1
  332. package/dist_ts/plugins.js +3 -2
  333. package/package.json +9 -9
  334. package/readme.md +539 -8
  335. package/ts/00_commitinfo_data.ts +1 -1
  336. package/ts/core/classes.configstore.ts +84 -27
  337. package/ts/core/classes.nativehomeadmission.ts +96 -0
  338. package/ts/core/classes.nativeintegrationowner.ts +302 -0
  339. package/ts/core/classes.runtimemanager.ts +11 -2
  340. package/ts/core/index.ts +2 -0
  341. package/ts/core/types.ts +18 -0
  342. package/ts/integrations/braviatv/braviatv.classes.client.ts +245 -709
  343. package/ts/integrations/braviatv/braviatv.classes.configflow.ts +47 -76
  344. package/ts/integrations/braviatv/braviatv.classes.integration.ts +167 -147
  345. package/ts/integrations/braviatv/braviatv.discovery.ts +11 -10
  346. package/ts/integrations/braviatv/braviatv.mapper.ts +39 -142
  347. package/ts/integrations/braviatv/braviatv.types.ts +53 -173
  348. package/ts/integrations/braviatv/braviatv.validation.ts +68 -0
  349. package/ts/integrations/broadlink/broadlink.actions.ts +31 -0
  350. package/ts/integrations/broadlink/broadlink.classes.client.ts +170 -144
  351. package/ts/integrations/broadlink/broadlink.classes.configflow.ts +59 -89
  352. package/ts/integrations/broadlink/broadlink.classes.integration.ts +110 -64
  353. package/ts/integrations/broadlink/broadlink.mapper.ts +5 -4
  354. package/ts/integrations/broadlink/broadlink.selected.mapper.ts +46 -0
  355. package/ts/integrations/broadlink/broadlink.types.ts +48 -8
  356. package/ts/integrations/broadlink/broadlink.validation.ts +66 -0
  357. package/ts/integrations/daikin/daikin.classes.client.ts +52 -661
  358. package/ts/integrations/daikin/daikin.classes.configflow.ts +72 -152
  359. package/ts/integrations/daikin/daikin.classes.integration.ts +166 -71
  360. package/ts/integrations/daikin/daikin.discovery.ts +94 -346
  361. package/ts/integrations/daikin/daikin.mapper.ts +83 -166
  362. package/ts/integrations/daikin/daikin.types.ts +27 -48
  363. package/ts/integrations/daikin/daikin.validation.ts +51 -0
  364. package/ts/integrations/daikin/readme.md +83 -0
  365. package/ts/integrations/deconz/deconz.classes.client.ts +348 -252
  366. package/ts/integrations/deconz/deconz.classes.configflow.ts +57 -29
  367. package/ts/integrations/deconz/deconz.classes.integration.ts +69 -37
  368. package/ts/integrations/deconz/deconz.mapper.ts +22 -5
  369. package/ts/integrations/deconz/deconz.types.ts +49 -6
  370. package/ts/integrations/deconz/deconz.validation.ts +177 -4
  371. package/ts/integrations/deconz/readme.md +15 -1
  372. package/ts/integrations/denonavr/denonavr.classes.client.ts +132 -421
  373. package/ts/integrations/denonavr/denonavr.classes.configflow.ts +44 -37
  374. package/ts/integrations/denonavr/denonavr.classes.integration.ts +171 -117
  375. package/ts/integrations/denonavr/denonavr.discovery.ts +67 -220
  376. package/ts/integrations/denonavr/denonavr.mapper.ts +36 -182
  377. package/ts/integrations/denonavr/denonavr.types.ts +48 -111
  378. package/ts/integrations/denonavr/denonavr.validation.ts +87 -0
  379. package/ts/integrations/esphome/esphome.classes.client.ts +179 -94
  380. package/ts/integrations/esphome/esphome.classes.configflow.ts +40 -33
  381. package/ts/integrations/esphome/esphome.classes.integration.ts +63 -36
  382. package/ts/integrations/esphome/esphome.discovery.ts +3 -12
  383. package/ts/integrations/esphome/esphome.mapper.ts +9 -7
  384. package/ts/integrations/esphome/esphome.types.ts +35 -6
  385. package/ts/integrations/esphome/esphome.validation.ts +66 -0
  386. package/ts/integrations/esphome/readme.md +20 -6
  387. package/ts/integrations/homeassistant/homeassistant.classes.client.ts +353 -125
  388. package/ts/integrations/homeassistant/homeassistant.classes.integration.ts +35 -18
  389. package/ts/integrations/homeassistant/homeassistant.classes.runtime.ts +50 -63
  390. package/ts/integrations/homeassistant/homeassistant.types.ts +17 -1
  391. package/ts/integrations/homeassistant/readme.md +22 -6
  392. package/ts/integrations/hue/hue.classes.client.ts +110 -41
  393. package/ts/integrations/hue/hue.classes.configflow.ts +12 -6
  394. package/ts/integrations/hue/hue.classes.integration.ts +92 -26
  395. package/ts/integrations/hue/hue.validation.ts +13 -3
  396. package/ts/integrations/hue/readme.md +3 -3
  397. package/ts/integrations/kodi/kodi.classes.client.ts +72 -352
  398. package/ts/integrations/kodi/kodi.classes.configflow.ts +52 -55
  399. package/ts/integrations/kodi/kodi.classes.integration.ts +97 -178
  400. package/ts/integrations/kodi/kodi.discovery.ts +49 -28
  401. package/ts/integrations/kodi/kodi.mapper.ts +52 -10
  402. package/ts/integrations/kodi/kodi.types.ts +33 -58
  403. package/ts/integrations/kodi/kodi.validation.ts +60 -0
  404. package/ts/integrations/modbus/modbus.classes.client.ts +100 -842
  405. package/ts/integrations/modbus/modbus.classes.configflow.ts +70 -41
  406. package/ts/integrations/modbus/modbus.classes.integration.ts +115 -60
  407. package/ts/integrations/modbus/modbus.discovery.ts +38 -106
  408. package/ts/integrations/modbus/modbus.mapper.ts +64 -467
  409. package/ts/integrations/modbus/modbus.types.ts +64 -381
  410. package/ts/integrations/modbus/modbus.validation.ts +119 -0
  411. package/ts/integrations/mqtt/mqtt.classes.client.ts +136 -19
  412. package/ts/integrations/mqtt/mqtt.classes.configflow.ts +45 -32
  413. package/ts/integrations/mqtt/mqtt.classes.integration.ts +99 -38
  414. package/ts/integrations/mqtt/mqtt.classes.session.ts +118 -0
  415. package/ts/integrations/mqtt/mqtt.mapper.ts +43 -1
  416. package/ts/integrations/mqtt/mqtt.types.ts +52 -0
  417. package/ts/integrations/mqtt/mqtt.validation.ts +157 -0
  418. package/ts/integrations/mqtt/readme.md +12 -3
  419. package/ts/integrations/nanoleaf/nanoleaf.classes.client.ts +115 -249
  420. package/ts/integrations/nanoleaf/nanoleaf.classes.configflow.ts +90 -19
  421. package/ts/integrations/nanoleaf/nanoleaf.classes.integration.ts +130 -181
  422. package/ts/integrations/nanoleaf/nanoleaf.credentials.ts +39 -0
  423. package/ts/integrations/nanoleaf/nanoleaf.mapper.ts +47 -260
  424. package/ts/integrations/nanoleaf/nanoleaf.types.ts +29 -147
  425. package/ts/integrations/nanoleaf/nanoleaf.validation.ts +77 -0
  426. package/ts/integrations/onkyo/onkyo.classes.client.ts +148 -457
  427. package/ts/integrations/onkyo/onkyo.classes.configflow.ts +52 -6
  428. package/ts/integrations/onkyo/onkyo.classes.integration.ts +121 -12
  429. package/ts/integrations/onkyo/onkyo.discovery.ts +41 -3
  430. package/ts/integrations/onkyo/onkyo.mapper.ts +46 -19
  431. package/ts/integrations/onkyo/onkyo.types.ts +55 -110
  432. package/ts/integrations/onkyo/onkyo.validation.ts +85 -0
  433. package/ts/integrations/onkyo/readme.md +126 -0
  434. package/ts/integrations/panasonic_viera/panasonic_viera.classes.client.ts +101 -398
  435. package/ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.ts +69 -5
  436. package/ts/integrations/panasonic_viera/panasonic_viera.classes.integration.ts +141 -9
  437. package/ts/integrations/panasonic_viera/panasonic_viera.discovery.ts +32 -3
  438. package/ts/integrations/panasonic_viera/panasonic_viera.mapper.ts +34 -161
  439. package/ts/integrations/panasonic_viera/panasonic_viera.types.ts +52 -96
  440. package/ts/integrations/panasonic_viera/panasonic_viera.validation.ts +56 -0
  441. package/ts/integrations/pioneer/pioneer.classes.client.ts +132 -428
  442. package/ts/integrations/pioneer/pioneer.classes.configflow.ts +67 -5
  443. package/ts/integrations/pioneer/pioneer.classes.integration.ts +225 -11
  444. package/ts/integrations/pioneer/pioneer.discovery.ts +45 -3
  445. package/ts/integrations/pioneer/pioneer.mapper.ts +57 -13
  446. package/ts/integrations/pioneer/pioneer.types.ts +87 -85
  447. package/ts/integrations/pioneer/pioneer.validation.ts +84 -0
  448. package/ts/integrations/samsungtv/readme.md +11 -5
  449. package/ts/integrations/samsungtv/samsungtv.classes.client.ts +40 -15
  450. package/ts/integrations/samsungtv/samsungtv.classes.configflow.ts +21 -6
  451. package/ts/integrations/samsungtv/samsungtv.classes.integration.ts +53 -38
  452. package/ts/integrations/samsungtv/samsungtv.types.ts +4 -1
  453. package/ts/integrations/shelly/readme.md +22 -7
  454. package/ts/integrations/shelly/shelly.classes.client.ts +386 -269
  455. package/ts/integrations/shelly/shelly.classes.configflow.ts +43 -38
  456. package/ts/integrations/shelly/shelly.classes.integration.ts +92 -111
  457. package/ts/integrations/shelly/shelly.classes.subscription.ts +24 -1
  458. package/ts/integrations/shelly/shelly.mapper.ts +19 -20
  459. package/ts/integrations/shelly/shelly.rpc.ts +2 -0
  460. package/ts/integrations/shelly/shelly.types.ts +50 -2
  461. package/ts/integrations/shelly/shelly.validation.ts +76 -0
  462. package/ts/integrations/sonos/readme.md +117 -38
  463. package/ts/integrations/sonos/sonos.classes.client.ts +392 -123
  464. package/ts/integrations/sonos/sonos.classes.configflow.ts +25 -28
  465. package/ts/integrations/sonos/sonos.classes.integration.ts +211 -186
  466. package/ts/integrations/sonos/sonos.config.ts +24 -2
  467. package/ts/integrations/sonos/sonos.mapper.ts +13 -8
  468. package/ts/integrations/sonos/sonos.matchers.ts +2 -2
  469. package/ts/integrations/sonos/sonos.types.ts +30 -1
  470. package/ts/integrations/soundtouch/soundtouch.classes.client.ts +152 -571
  471. package/ts/integrations/soundtouch/soundtouch.classes.configflow.ts +47 -42
  472. package/ts/integrations/soundtouch/soundtouch.classes.integration.ts +95 -150
  473. package/ts/integrations/soundtouch/soundtouch.discovery.ts +21 -133
  474. package/ts/integrations/soundtouch/soundtouch.mapper.ts +36 -207
  475. package/ts/integrations/soundtouch/soundtouch.types.ts +50 -195
  476. package/ts/integrations/soundtouch/soundtouch.validation.ts +60 -0
  477. package/ts/integrations/tasmota/readme.md +16 -5
  478. package/ts/integrations/tasmota/tasmota.classes.integration.ts +24 -6
  479. package/ts/integrations/tasmota/tasmota.classes.runtime.ts +112 -43
  480. package/ts/integrations/tasmota/tasmota.config.ts +17 -0
  481. package/ts/integrations/tasmota/tasmota.credentials.ts +92 -0
  482. package/ts/integrations/tasmota/tasmota.discovery.ts +87 -24
  483. package/ts/integrations/tasmota/tasmota.mapper.ts +6 -6
  484. package/ts/integrations/tasmota/tasmota.types.ts +43 -2
  485. package/ts/integrations/tuya/readme.md +52 -10
  486. package/ts/integrations/tuya/tuya.classes.integration.ts +69 -98
  487. package/ts/integrations/tuya/tuya.classes.runtime.ts +70 -24
  488. package/ts/integrations/tuya/tuya.mapper.ts +1 -1
  489. package/ts/integrations/tuya/tuya.types.ts +4 -0
  490. package/ts/integrations/tuya/tuya.validation.ts +5 -8
  491. package/ts/integrations/webostv/readme.md +115 -22
  492. package/ts/integrations/webostv/webostv.classes.client.ts +123 -50
  493. package/ts/integrations/webostv/webostv.classes.configflow.ts +35 -15
  494. package/ts/integrations/webostv/webostv.classes.integration.ts +44 -37
  495. package/ts/integrations/webostv/webostv.mapper.ts +4 -4
  496. package/ts/integrations/webostv/webostv.types.ts +18 -3
  497. package/ts/integrations/webostv/webostv.validation.ts +22 -1
  498. package/ts/integrations/wiz/index.ts +1 -0
  499. package/ts/integrations/wiz/wiz.classes.client.ts +84 -254
  500. package/ts/integrations/wiz/wiz.classes.configflow.ts +39 -70
  501. package/ts/integrations/wiz/wiz.classes.integration.ts +189 -45
  502. package/ts/integrations/wiz/wiz.discovery.ts +48 -291
  503. package/ts/integrations/wiz/wiz.mapper.ts +81 -754
  504. package/ts/integrations/wiz/wiz.types.ts +24 -224
  505. package/ts/integrations/wiz/wiz.validation.ts +73 -0
  506. package/ts/integrations/yamaha/index.ts +1 -0
  507. package/ts/integrations/yamaha/yamaha.classes.client.ts +150 -6
  508. package/ts/integrations/yamaha/yamaha.classes.configflow.ts +100 -5
  509. package/ts/integrations/yamaha/yamaha.classes.integration.ts +236 -8
  510. package/ts/integrations/yamaha/yamaha.discovery.ts +52 -3
  511. package/ts/integrations/yamaha/yamaha.mapper.ts +65 -13
  512. package/ts/integrations/yamaha/yamaha.types.ts +77 -97
  513. package/ts/integrations/yamaha/yamaha.validation.ts +86 -0
  514. package/ts/integrations/zigbee2mqtt/readme.md +22 -27
  515. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.ts +16 -7
  516. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.ts +53 -6
  517. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.ts +62 -49
  518. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.ts +17 -11
  519. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.types.ts +35 -2
  520. package/ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.ts +53 -7
  521. package/ts/integrations/zwave_js/readme.md +42 -9
  522. package/ts/integrations/zwave_js/zwave_js.classes.client.ts +155 -31
  523. package/ts/integrations/zwave_js/zwave_js.classes.configflow.ts +55 -31
  524. package/ts/integrations/zwave_js/zwave_js.classes.integration.ts +57 -35
  525. package/ts/integrations/zwave_js/zwave_js.discovery.ts +2 -2
  526. package/ts/integrations/zwave_js/zwave_js.mapper.ts +37 -23
  527. package/ts/integrations/zwave_js/zwave_js.types.ts +26 -3
  528. package/ts/integrations/zwave_js/zwave_js.validation.ts +52 -18
  529. package/ts/plugins.ts +2 -1
@@ -1,739 +1,275 @@
1
- import type {
2
- IBraviatvApp,
3
- IBraviatvChannel,
4
- IBraviatvConfig,
5
- IBraviatvPlayingInfo,
6
- IBraviatvSnapshot,
7
- IBraviatvSource,
8
- IBraviatvState,
9
- IBraviatvSystemInfo,
10
- IBraviatvVolumeInfo,
11
- TBraviatvRestService,
12
- TBraviatvSourceType,
13
- } from './braviatv.types.js';
14
-
15
- interface IBraviatvRestResponse {
16
- result?: unknown[];
17
- error?: [number, string] | unknown[];
18
- id?: number;
19
- }
20
-
21
- const defaultTimeoutMs = 10000;
22
- const defaultAudioTarget = 'speaker';
23
- const defaultRestVersion = '1.0';
24
- const powerOnCode = 'AAAAAQAAAAEAAAAuAw==';
25
-
26
- const fallbackCommands: Record<string, string> = {
27
- Power: 'AAAAAQAAAAEAAAAVAw==',
28
- PowerOn: powerOnCode,
29
- Input: 'AAAAAQAAAAEAAAAlAw==',
30
- SyncMenu: 'AAAAAgAAABoAAABYAw==',
31
- Hdmi1: 'AAAAAgAAABoAAABaAw==',
32
- Hdmi2: 'AAAAAgAAABoAAABbAw==',
33
- Hdmi3: 'AAAAAgAAABoAAABcAw==',
34
- Hdmi4: 'AAAAAgAAABoAAABdAw==',
35
- Num1: 'AAAAAQAAAAEAAAAAAw==',
36
- Num2: 'AAAAAQAAAAEAAAABAw==',
37
- Num3: 'AAAAAQAAAAEAAAACAw==',
38
- Num4: 'AAAAAQAAAAEAAAADAw==',
39
- Num5: 'AAAAAQAAAAEAAAAEAw==',
40
- Num6: 'AAAAAQAAAAEAAAAFAw==',
41
- Num7: 'AAAAAQAAAAEAAAAGAw==',
42
- Num8: 'AAAAAQAAAAEAAAAHAw==',
43
- Num9: 'AAAAAQAAAAEAAAAIAw==',
44
- Num0: 'AAAAAQAAAAEAAAAJAw==',
45
- Dot: 'AAAAAgAAAJcAAAAdAw==',
46
- CC: 'AAAAAgAAAJcAAAAoAw==',
47
- Red: 'AAAAAgAAAJcAAAAlAw==',
48
- Green: 'AAAAAgAAAJcAAAAmAw==',
49
- Yellow: 'AAAAAgAAAJcAAAAnAw==',
50
- Blue: 'AAAAAgAAAJcAAAAkAw==',
51
- Up: 'AAAAAQAAAAEAAAB0Aw==',
52
- Down: 'AAAAAQAAAAEAAAB1Aw==',
53
- Right: 'AAAAAQAAAAEAAAAzAw==',
54
- Left: 'AAAAAQAAAAEAAAA0Aw==',
55
- Confirm: 'AAAAAQAAAAEAAABlAw==',
56
- Help: 'AAAAAgAAAMQAAABNAw==',
57
- Display: 'AAAAAQAAAAEAAAA6Aw==',
58
- Options: 'AAAAAgAAAJcAAAA2Aw==',
59
- Back: 'AAAAAgAAAJcAAAAjAw==',
60
- Home: 'AAAAAQAAAAEAAABgAw==',
61
- VolumeUp: 'AAAAAQAAAAEAAAASAw==',
62
- VolumeDown: 'AAAAAQAAAAEAAAATAw==',
63
- Mute: 'AAAAAQAAAAEAAAAUAw==',
64
- Audio: 'AAAAAQAAAAEAAAAXAw==',
65
- ChannelUp: 'AAAAAQAAAAEAAAAQAw==',
66
- ChannelDown: 'AAAAAQAAAAEAAAARAw==',
67
- Play: 'AAAAAgAAAJcAAAAaAw==',
68
- Pause: 'AAAAAgAAAJcAAAAZAw==',
69
- Stop: 'AAAAAgAAAJcAAAAYAw==',
70
- FlashPlus: 'AAAAAgAAAJcAAAB4Aw==',
71
- FlashMinus: 'AAAAAgAAAJcAAAB5Aw==',
72
- Prev: 'AAAAAgAAAJcAAAA8Aw==',
73
- Next: 'AAAAAgAAAJcAAAA9Aw==',
74
- };
75
-
76
- export class BraviatvAuthError extends Error {
77
- constructor(messageArg: string) {
78
- super(messageArg);
79
- this.name = 'BraviatvAuthError';
80
- }
81
- }
82
-
83
- export class BraviatvLiveControlError extends Error {
84
- constructor(messageArg: string) {
85
- super(messageArg);
86
- this.name = 'BraviatvLiveControlError';
87
- }
1
+ import * as plugins from '../../plugins.js';
2
+ import { NativeHomeAdmission, type INativeAdmissionContext } from '../../core/classes.nativehomeadmission.js';
3
+ import type { IBraviatvConfig, IBraviatvEffectResult, IBraviatvIntegrationOptions, IBraviatvSetupContext,
4
+ IBraviatvSnapshot, TBraviatvControl } from './braviatv.types.js';
5
+ import { normalizeBraviatvConfig, normalizeBraviatvOptions,
6
+ validateBraviatvControl } from './braviatv.validation.js';
7
+
8
+ interface IBraviatvOwnedProtocol {
9
+ readonly protocol: plugins.ecobridgeDeviceManager.SonyBraviaProtocol;
10
+ active: boolean;
11
+ failed: boolean;
12
+ cleanup?: Promise<void>;
88
13
  }
89
14
 
15
+ /** Home admission and caller work only; SonyBraviaProtocol owns every wire operation. */
90
16
  export class BraviatvClient {
91
- private commandCache?: Record<string, string>;
92
- private irccEndpoint: string;
93
-
94
- constructor(private readonly config: IBraviatvConfig) {
95
- this.irccEndpoint = config.irccEndpoint || 'ircc';
96
- this.commandCache = config.commands ? { ...fallbackCommands, ...config.commands } : undefined;
97
- }
98
-
99
- public async getSnapshot(): Promise<IBraviatvSnapshot> {
100
- if (this.config.snapshot) {
101
- return this.normalizeSnapshot(this.cloneSnapshot(this.config.snapshot));
102
- }
103
-
104
- if (this.hasLivePskConfig()) {
105
- try {
106
- return await this.getLiveSnapshot();
107
- } catch (errorArg) {
108
- if (errorArg instanceof BraviatvAuthError) {
109
- throw errorArg;
17
+ public readonly config: ReturnType<typeof normalizeBraviatvConfig>;
18
+ readonly #options: Readonly<IBraviatvIntegrationOptions>;
19
+ readonly #context: INativeAdmissionContext;
20
+ readonly #admission: NativeHomeAdmission;
21
+ readonly #lifetime = new AbortController();
22
+ readonly #protocols = new Map<plugins.ecobridgeDeviceManager.SonyBraviaProtocol, IBraviatvOwnedProtocol>();
23
+ readonly #operations = new Set<Promise<unknown>>();
24
+ readonly #credentialOperations = new Map<Promise<string>, Promise<unknown>>();
25
+ readonly #credentialFailures = new Map<plugins.ecobridgeDeviceManager.SonyBraviaProtocolError, Promise<unknown>>();
26
+ readonly #parentAbort: () => void;
27
+ #tail: Promise<void> = Promise.resolve();
28
+ #startPromise?: Promise<IBraviatvSnapshot>;
29
+ #snapshot?: IBraviatvSnapshot;
30
+ #started = false;
31
+ #healthy = false;
32
+ #closePromise?: Promise<void>;
33
+ #cleanupPromise?: Promise<void>;
34
+ #retryPromise?: Promise<void>;
35
+ #cleanupFailed = false;
36
+
37
+ public constructor(config: IBraviatvConfig, context: IBraviatvSetupContext, options: IBraviatvIntegrationOptions) {
38
+ this.config = normalizeBraviatvConfig(config);
39
+ this.#options = normalizeBraviatvOptions(options);
40
+ this.#admission = new NativeHomeAdmission('braviatv', { homeId: this.#options.homeId });
41
+ this.#context = this.#admission.admit(context, this.config.homeId);
42
+ this.#parentAbort = () => { void this.destroy().catch(() => {}); };
43
+ this.#context.abortSignal?.addEventListener('abort', this.#parentAbort, { once: true });
44
+ if (this.#context.abortSignal?.aborted) this.#parentAbort();
45
+ }
46
+
47
+ public isHealthy(): boolean { return !this.#lifetime.signal.aborted && this.#started && this.#healthy; }
48
+
49
+ public start(signal?: AbortSignal): Promise<IBraviatvSnapshot> {
50
+ if (!this.#startPromise) {
51
+ this.#startPromise = this.run((protocol, operation) => protocol.readState(operation), signal, false)
52
+ .then((state) => { const snapshot = this.observe(state); this.#started = true; return snapshot; })
53
+ .catch((error: unknown) => {
54
+ this.#healthy = false;
55
+ this.#lifetime.abort(this.failure('closed'));
56
+ throw error;
57
+ });
58
+ }
59
+ return this.#startPromise;
60
+ }
61
+
62
+ public getObservedSnapshot(): IBraviatvSnapshot {
63
+ this.assertOpen();
64
+ if (!this.#snapshot) throw new Error('BRAVIA has no admitted observation.');
65
+ return this.#snapshot;
66
+ }
67
+
68
+ public getSnapshot(signal?: AbortSignal): Promise<IBraviatvSnapshot> {
69
+ return this.run((protocol, operation) => protocol.readState(operation), signal).then((state) => this.observe(state));
70
+ }
71
+
72
+ public setControl(value: TBraviatvControl, signal?: AbortSignal): Promise<IBraviatvEffectResult> {
73
+ const control = validateBraviatvControl(value);
74
+ if (control.feature === 'speaker_volume_raw' && control.value > this.config.volumeLimitRaw) throw new TypeError('BRAVIA speaker volume exceeds the owner ceiling.');
75
+ return this.run((protocol, operation) => control.feature === 'power' ? protocol.setPower(control.value, operation)
76
+ : control.feature === 'device_mute' ? protocol.setMute(control.value, operation)
77
+ : protocol.setVolumeRaw(control.value, operation), signal).then((result) => {
78
+ try {
79
+ return Object.freeze({ control: result.control, requested: result.requested,
80
+ commandAcknowledged: result.commandAcknowledged, causalityConfirmed: result.causalityConfirmed,
81
+ observation: result.observation, snapshot: this.observe(result.observed) });
82
+ } catch {
83
+ throw new plugins.ecobridgeDeviceManager.SonyBraviaProtocolError('identity-mismatch', 'BRAVIA reported state could not be admitted after acknowledgment.', 'indeterminate', true);
110
84
  }
111
- return this.normalizeSnapshot(this.snapshotFromManualConfig(this.errorMessage(errorArg)));
112
- }
113
- }
114
-
115
- return this.normalizeSnapshot(this.snapshotFromManualConfig());
85
+ });
116
86
  }
117
87
 
118
- public async turnOn(): Promise<void> {
119
- this.assertLivePskSupported('turn_on');
120
- try {
121
- await this.sendRestQuick('system', 'setPowerStatus', { status: true });
122
- } catch {
123
- await this.sendIrcc(powerOnCode);
88
+ public destroy(): Promise<void> {
89
+ if (!this.#closePromise) {
90
+ this.#healthy = false;
91
+ this.#closePromise = Promise.resolve().then(() => this.drainCleanup(false));
92
+ this.#cleanupPromise = this.#closePromise;
93
+ this.#context.abortSignal?.removeEventListener('abort', this.#parentAbort);
94
+ this.#lifetime.abort(this.failure('closed'));
95
+ }
96
+ return this.#closePromise;
97
+ }
98
+
99
+ /** Explicit cleanup retry acknowledges settled credential failures; it cannot resolve a PSK, construct a facade or replay an effect. */
100
+ public retryCleanup(): Promise<void> {
101
+ if (!this.#closePromise) return this.destroy();
102
+ if (!this.#cleanupFailed) return this.#cleanupPromise ?? this.#closePromise;
103
+ if (!this.#retryPromise) {
104
+ this.#retryPromise = Promise.resolve().then(() => this.drainCleanup(true));
105
+ this.#cleanupPromise = this.#retryPromise;
106
+ const settled = (): void => { this.#retryPromise = undefined; };
107
+ void this.#retryPromise.then(settled, settled);
108
+ }
109
+ return this.#retryPromise;
110
+ }
111
+
112
+ private async drainCleanup(retry: boolean): Promise<void> {
113
+ const protocolCleanup = [...this.#protocols.values()].map((owned) => this.closeProtocol(owned, retry));
114
+ const results = await Promise.allSettled([...protocolCleanup, ...this.#credentialOperations.keys(), ...this.#operations, this.#startPromise]);
115
+ const finalResults = await Promise.allSettled([...this.#protocols.values()].map((owned) => this.closeProtocol(owned)));
116
+ this.#snapshot = undefined;
117
+ const failures = [...results.slice(0, protocolCleanup.length), ...finalResults].filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
118
+ const reasons = [...new Set(failures.map((entry) => entry.reason)), ...(!retry ? this.#credentialFailures.keys() : [])];
119
+ if (retry) this.#credentialFailures.clear();
120
+ this.#cleanupFailed = reasons.length > 0;
121
+ if (reasons.length) throw new AggregateError(reasons, 'BRAVIA owned operation cleanup failed.');
122
+ }
123
+
124
+ private closeProtocol(owned: IBraviatvOwnedProtocol, retry = false): Promise<void> {
125
+ if (retry && owned.failed) { owned.cleanup = undefined; owned.failed = false; }
126
+ if (!owned.cleanup) {
127
+ owned.cleanup = Promise.resolve().then(() => owned.protocol.close()).then(() => {
128
+ this.#protocols.delete(owned.protocol);
129
+ }, () => {
130
+ owned.failed = true;
131
+ throw new plugins.ecobridgeDeviceManager.SonyBraviaProtocolError('transport', 'BRAVIA owned protocol cleanup failed.');
132
+ });
124
133
  }
125
- this.updateLocalState({ powerStatus: 'active', power: 'on', available: true });
126
- }
127
-
128
- public async turnOff(): Promise<void> {
129
- await this.sendRestQuick('system', 'setPowerStatus', { status: false });
130
- this.updateLocalState({ powerStatus: 'standby', power: 'off', playback: 'off' });
134
+ return owned.cleanup;
131
135
  }
132
136
 
133
- public async setVolumeLevel(volumeLevelArg: number): Promise<void> {
134
- const volume = Math.max(0, Math.min(100, Math.round(volumeLevelArg * 100)));
135
- await this.sendRestQuick('audio', 'setAudioVolume', { target: defaultAudioTarget, volume: String(volume) });
136
- this.updateLocalState({ volumeLevel: volume / 100, volumePercent: volume });
137
+ private observe(state: plugins.ecobridgeDeviceManager.ISonyBraviaState): IBraviatvSnapshot {
138
+ this.assertOpen();
139
+ // Relevant readback replaces the prior observation; unrelated old state is never restamped fresh.
140
+ this.#snapshot = Object.freeze({ ...state, homeId: this.config.homeId, host: this.config.host,
141
+ port: this.config.port, name: this.config.name ?? `Sony BRAVIA ${state.identity.model}` });
142
+ this.#healthy = true;
143
+ return this.#snapshot;
137
144
  }
138
145
 
139
- public async volumeUp(): Promise<void> {
140
- await this.stepVolume(1);
146
+ private failure(code: 'cancelled' | 'closed' | 'timeout' | 'capacity'): plugins.ecobridgeDeviceManager.SonyBraviaProtocolError {
147
+ return new plugins.ecobridgeDeviceManager.SonyBraviaProtocolError(code, code === 'closed' ? 'BRAVIA client is closed.'
148
+ : code === 'timeout' ? 'BRAVIA operation deadline expired.' : code === 'capacity' ? 'BRAVIA operation capacity reached.' : 'BRAVIA operation was cancelled.');
141
149
  }
142
150
 
143
- public async volumeDown(): Promise<void> {
144
- await this.stepVolume(-1);
151
+ private assertOpen(): void {
152
+ if (this.#lifetime.signal.aborted) throw this.failure('closed');
153
+ this.#admission.admit(this.#context, this.config.homeId);
145
154
  }
146
155
 
147
- public async muteVolume(mutedArg: boolean): Promise<void> {
148
- await this.sendRestQuick('audio', 'setAudioMute', { status: mutedArg });
149
- this.updateLocalState({ muted: mutedArg });
150
- }
151
-
152
- public async mediaPlay(): Promise<void> {
153
- await this.sendCommand('Play');
154
- this.updateLocalState({ playback: 'playing' });
155
- }
156
-
157
- public async mediaPause(): Promise<void> {
158
- await this.sendCommand('Pause');
159
- this.updateLocalState({ playback: 'paused' });
160
- }
161
-
162
- public async mediaStop(): Promise<void> {
163
- await this.sendCommand('Stop');
164
- this.updateLocalState({ playback: 'idle' });
165
- }
166
-
167
- public async nextTrack(): Promise<void> {
168
- await this.sendCommand('Next');
169
- }
170
-
171
- public async previousTrack(): Promise<void> {
172
- await this.sendCommand('Prev');
173
- }
174
-
175
- public async selectSource(sourceArg: string): Promise<void> {
176
- const source = sourceArg.trim();
177
- if (!source) {
178
- throw new Error('Sony Bravia TV select_source requires a source name or URI.');
179
- }
180
-
181
- const item = await this.findSource(source);
182
- await this.startSource(item.uri, item.type);
183
- this.updateLocalState({ powerStatus: 'active', power: 'on', source: item.title, sourceUri: item.uri });
184
- }
185
-
186
- public async playMedia(mediaTypeArg: string, mediaIdArg: string): Promise<void> {
187
- const normalizedType = mediaTypeArg.toLowerCase();
188
- if (normalizedType !== 'app' && normalizedType !== 'channel') {
189
- throw new Error(`Sony Bravia TV play_media supports app or channel media only, not ${mediaTypeArg}.`);
190
- }
191
- const source = await this.findSource(mediaIdArg, normalizedType as TBraviatvSourceType);
192
- await this.startSource(source.uri, source.type);
193
- }
194
-
195
- public async sendCommand(commandArg: string): Promise<void> {
196
- const code = await this.commandCode(commandArg);
197
- if (!code) {
198
- throw new Error(`Unsupported Sony Bravia TV IRCC command: ${commandArg}`);
199
- }
200
- await this.sendIrcc(code);
201
- }
202
-
203
- public async sendCommands(commandsArg: string[], repeatsArg = 1): Promise<void> {
204
- const repeats = Math.max(1, Math.floor(repeatsArg));
205
- for (let repeat = 0; repeat < repeats; repeat += 1) {
206
- for (const command of commandsArg) {
207
- await this.sendCommand(command);
208
- }
156
+ private active(signal: AbortSignal, deadline: number): number {
157
+ if (signal.aborted) {
158
+ const reason: unknown = signal.reason;
159
+ throw reason instanceof plugins.ecobridgeDeviceManager.SonyBraviaProtocolError ? reason : this.failure('cancelled');
209
160
  }
161
+ this.assertOpen();
162
+ const remaining = Math.floor(deadline - performance.now());
163
+ if (remaining < 1) throw this.failure('timeout');
164
+ return remaining;
210
165
  }
211
166
 
212
- public async reboot(): Promise<void> {
213
- await this.sendRestQuick('system', 'requestReboot');
167
+ private credentialFailure(): plugins.ecobridgeDeviceManager.SonyBraviaProtocolError {
168
+ return new plugins.ecobridgeDeviceManager.SonyBraviaProtocolError('invalid-options', 'BRAVIA caller credential resolution failed.');
214
169
  }
215
170
 
216
- public async terminateApps(): Promise<void> {
217
- await this.sendRestQuick('appControl', 'terminateApps');
218
- }
219
-
220
- public async destroy(): Promise<void> {}
221
-
222
- private async getLiveSnapshot(): Promise<IBraviatvSnapshot> {
223
- const powerStatus = await this.getPowerStatus();
224
- const systemInfo = await this.getSystemInfo().catch(() => this.systemInfoFromConfig());
225
- const state: IBraviatvState = {
226
- ...this.config.state,
227
- powerStatus,
228
- power: this.powerFromStatus(powerStatus),
229
- available: true,
230
- };
231
-
232
- let sources = this.config.sources || [];
233
- let apps = this.config.apps || [];
234
- let channels = this.config.channels || [];
235
- let commands = this.config.commands;
236
-
237
- if (state.power === 'on') {
238
- const [volumeInfo, playingInfo, liveSources, liveApps, liveChannels, liveCommands] = await Promise.all([
239
- this.getVolumeInfo().catch(() => undefined),
240
- this.getPlayingInfo().catch(() => undefined),
241
- this.getExternalInputsStatus().catch(() => sources),
242
- this.getAppList().catch(() => apps),
243
- this.config.fetchChannels ? this.getContentListAll('tv').catch(() => channels) : Promise.resolve(channels),
244
- this.getCommandList().catch(() => commands),
245
- ]);
246
- sources = liveSources;
247
- apps = liveApps;
248
- channels = liveChannels;
249
- commands = liveCommands;
250
- this.applyVolumeInfo(state, volumeInfo);
251
- this.applyPlayingInfo(state, playingInfo);
252
- }
253
-
254
- return this.normalizeSnapshot({
255
- systemInfo,
256
- state,
257
- sources,
258
- apps,
259
- channels,
260
- commands,
261
- updatedAt: new Date().toISOString(),
171
+ private async resolvePsk(signal: AbortSignal, deadline: number, operation: Promise<unknown>): Promise<string> {
172
+ this.active(signal, deadline);
173
+ let cancel: () => void = () => {};
174
+ const cancellation = new Promise<never>((_resolve, reject) => {
175
+ cancel = () => { try { this.active(signal, deadline); } catch (error) { reject(error); } };
176
+ signal.addEventListener('abort', cancel, { once: true });
262
177
  });
263
- }
264
-
265
- private async getPowerStatus(): Promise<string> {
266
- const response = await this.sendRest('system', 'getPowerStatus', undefined, defaultRestVersion, 5000);
267
- return this.firstResult<{ status?: string }>(response)?.status || 'unknown';
268
- }
269
-
270
- private async getSystemInfo(): Promise<IBraviatvSystemInfo> {
271
- const response = await this.sendRest('system', 'getSystemInformation');
272
- const info = this.firstResult<IBraviatvSystemInfo>(response) || {};
273
- this.config.macAddress = info.macAddr || this.config.macAddress;
274
- this.config.cid = info.cid || this.config.cid;
275
- return info;
276
- }
277
-
278
- private async getVolumeInfo(targetArg = defaultAudioTarget): Promise<IBraviatvVolumeInfo | undefined> {
279
- const response = await this.sendRest('audio', 'getVolumeInformation');
280
- const outputs = this.firstResult<IBraviatvVolumeInfo[]>(response) || [];
281
- return outputs.find((outputArg) => outputArg.target === targetArg) || outputs[0];
282
- }
283
-
284
- private async getPlayingInfo(): Promise<IBraviatvPlayingInfo | undefined> {
285
- const response = await this.sendRest('avContent', 'getPlayingContentInfo');
286
- return this.firstResult<IBraviatvPlayingInfo>(response);
287
- }
288
-
289
- private async getExternalInputsStatus(): Promise<IBraviatvSource[]> {
290
- const response = await this.sendRest('avContent', 'getCurrentExternalInputsStatus');
291
- return (this.firstResult<IBraviatvSource[]>(response) || []).map((sourceArg) => ({ ...sourceArg, type: 'input' }));
292
- }
293
-
294
- private async getAppList(): Promise<IBraviatvApp[]> {
295
- const response = await this.sendRest('appControl', 'getApplicationList');
296
- return (this.firstResult<IBraviatvApp[]>(response) || []).map((appArg) => ({ ...appArg, type: 'app' }));
297
- }
298
-
299
- private async getSourceList(schemeArg: string): Promise<string[]> {
300
- const response = await this.sendRest('avContent', 'getSourceList', { scheme: schemeArg });
301
- return (this.firstResult<Array<{ source?: string }>>(response) || []).map((itemArg) => itemArg.source).filter((itemArg): itemArg is string => Boolean(itemArg));
302
- }
303
-
304
- private async getContentCount(sourceArg: string): Promise<number> {
305
- const response = await this.sendRest('avContent', 'getContentCount', { source: sourceArg }, defaultRestVersion, 20000);
306
- return this.firstResult<{ count?: number }>(response)?.count || 0;
307
- }
308
-
309
- private async getContentList(sourceArg: string, indexArg: number, countArg: number): Promise<IBraviatvChannel[]> {
310
- const response = await this.sendRest('avContent', 'getContentList', { source: sourceArg, stIdx: indexArg, cnt: countArg }, defaultRestVersion, 20000);
311
- return (this.firstResult<IBraviatvChannel[]>(response) || []).map((channelArg) => ({ ...channelArg, type: 'channel' }));
312
- }
313
-
314
- private async getContentListAll(schemeArg: string): Promise<IBraviatvChannel[]> {
315
- const channels: IBraviatvChannel[] = [];
316
- for (const source of await this.getSourceList(schemeArg)) {
317
- const total = await this.getContentCount(source);
318
- for (let index = 0; index < total; index += 50) {
319
- channels.push(...await this.getContentList(source, index, Math.min(50, total - index)));
320
- }
321
- }
322
- return channels;
323
- }
324
-
325
- private async getCommandList(): Promise<Record<string, string>> {
326
- if (this.commandCache) {
327
- return this.commandCache;
328
- }
329
- const response = await this.sendRest('system', 'getRemoteControllerInfo');
330
- const remoteCommands = Array.isArray(response.result?.[1]) ? response.result[1] as Array<{ name?: string; value?: string }> : [];
331
- this.commandCache = {
332
- ...fallbackCommands,
333
- ...Object.fromEntries(remoteCommands.filter((itemArg) => itemArg.name && itemArg.value).map((itemArg) => [itemArg.name as string, itemArg.value as string])),
334
- };
335
- return this.commandCache;
336
- }
337
-
338
- private async stepVolume(stepArg: number): Promise<void> {
339
- const prefix = stepArg > 0 ? '+' : '';
340
- await this.sendRestQuick('audio', 'setAudioVolume', { target: defaultAudioTarget, volume: `${prefix}${stepArg}` });
341
- }
342
-
343
- private async findSource(queryArg: string, sourceTypeArg?: TBraviatvSourceType): Promise<Required<Pick<IBraviatvSource, 'title' | 'uri' | 'type'>>> {
344
- const direct = this.directSource(queryArg, sourceTypeArg);
345
- if (direct) {
346
- return direct;
347
- }
348
-
349
- const snapshot = await this.getSnapshot();
350
- const items = [...snapshot.sources, ...snapshot.apps, ...(snapshot.channels || [])].map((itemArg) => ({
351
- ...itemArg,
352
- type: itemArg.type || this.inferSourceType(itemArg.uri),
353
- }));
354
- const exact = items.find((itemArg) => (!sourceTypeArg || itemArg.type === sourceTypeArg) && (itemArg.uri === queryArg || itemArg.title.toLowerCase() === queryArg.toLowerCase()));
355
- if (exact) {
356
- return { title: exact.title, uri: exact.uri, type: exact.type };
357
- }
358
-
359
- const coarse = items.find((itemArg) => (!sourceTypeArg || itemArg.type === sourceTypeArg) && itemArg.title.toLowerCase().includes(queryArg.toLowerCase()));
360
- if (coarse) {
361
- return { title: coarse.title, uri: coarse.uri, type: coarse.type };
362
- }
363
-
364
- throw new Error(`Sony Bravia TV source is not known: ${queryArg}`);
365
- }
366
-
367
- private directSource(sourceArg: string, sourceTypeArg?: TBraviatvSourceType): Required<Pick<IBraviatvSource, 'title' | 'uri' | 'type'>> | undefined {
368
- if (sourceArg.startsWith('extInput:') || sourceArg.startsWith('tv:')) {
369
- return { title: sourceArg, uri: sourceArg, type: sourceArg.startsWith('tv:') ? 'channel' : 'input' };
370
- }
371
- if (sourceArg.startsWith('com.sony.dtv.') || sourceArg.startsWith('localapp:')) {
372
- return { title: sourceArg, uri: sourceArg, type: sourceTypeArg || 'app' };
373
- }
374
- return undefined;
375
- }
376
-
377
- private async startSource(uriArg: string, sourceTypeArg: TBraviatvSourceType): Promise<void> {
378
- if (sourceTypeArg === 'app') {
379
- await this.sendRestQuick('appControl', 'setActiveApp', { uri: uriArg });
380
- return;
381
- }
382
- await this.sendRestQuick('avContent', 'setPlayContent', { uri: uriArg });
383
- }
384
-
385
- private async sendRestQuick(serviceArg: TBraviatvRestService, methodArg: string, paramsArg?: unknown, versionArg = defaultRestVersion): Promise<boolean> {
386
- const response = await this.sendRest(serviceArg, methodArg, paramsArg, versionArg);
387
- return Boolean(response.result);
388
- }
389
-
390
- private async sendRest(serviceArg: TBraviatvRestService, methodArg: string, paramsArg?: unknown, versionArg = defaultRestVersion, timeoutMsArg?: number): Promise<IBraviatvRestResponse> {
391
- this.assertLivePskSupported(`${serviceArg}.${methodArg}`);
392
- const params = paramsArg === undefined ? [] : Array.isArray(paramsArg) ? paramsArg : [paramsArg];
393
- const response = await this.postJson(this.serviceUrl(serviceArg), {
394
- method: methodArg,
395
- params,
396
- id: 1,
397
- version: versionArg,
398
- }, timeoutMsArg);
399
-
400
- if (response.error) {
401
- const [code, message] = response.error;
402
- const text = String(message || code || 'Unknown REST API error');
403
- if (Number(code) === 401) {
404
- throw new BraviatvAuthError(`Sony Bravia TV authentication failed for ${methodArg}: ${text}`);
405
- }
406
- if (text.includes('not power-on')) {
407
- throw new BraviatvLiveControlError(`Sony Bravia TV is turned off and rejected ${methodArg}.`);
408
- }
409
- throw new BraviatvLiveControlError(`Sony Bravia TV REST ${methodArg} failed: ${text}`);
410
- }
411
- return response;
412
- }
413
-
414
- private async sendIrcc(codeArg: string): Promise<boolean> {
415
- this.assertLivePskSupported('IRCC command');
416
178
  try {
417
- return await this.postIrcc(this.irccEndpoint, codeArg);
418
- } catch (errorArg) {
419
- if (this.errorMessage(errorArg).includes('HTTP 404')) {
420
- this.irccEndpoint = this.irccEndpoint === 'ircc' ? 'IRCC' : 'ircc';
421
- return this.postIrcc(this.irccEndpoint, codeArg);
422
- }
423
- throw errorArg;
424
- }
425
- }
426
-
427
- private async postIrcc(endpointArg: string, codeArg: string): Promise<boolean> {
428
- const response = await this.postText(this.serviceUrl(endpointArg), this.irccBody(codeArg), {
429
- SOAPACTION: '"urn:schemas-sony-com:service:IRCC:1#X_SendIRCC"',
430
- 'Content-Type': 'text/xml; charset=UTF-8',
431
- });
432
- return response;
179
+ const credential = Promise.resolve().then(() => {
180
+ this.active(signal, deadline);
181
+ return this.#options.resolvePsk(Object.freeze({ homeId: this.config.homeId,
182
+ credentialRef: this.config.credentialRef, signal, deadline }));
183
+ });
184
+ // Own the actual callback before entering it; cancelling its request does not settle this work.
185
+ this.#credentialOperations.set(credential, operation);
186
+ void credential.then(() => { this.#credentialOperations.delete(credential); }, (error: unknown) => {
187
+ this.#credentialOperations.delete(credential);
188
+ if (signal.aborted && error !== signal.reason) this.#credentialFailures.set(this.credentialFailure(), operation);
189
+ });
190
+ const psk = await Promise.race([credential, cancellation]);
191
+ this.active(signal, deadline);
192
+ if (typeof psk !== 'string') throw new Error('Invalid credential.');
193
+ return psk;
194
+ } catch {
195
+ this.active(signal, deadline);
196
+ throw this.credentialFailure();
197
+ } finally { signal.removeEventListener('abort', cancel); }
433
198
  }
434
199
 
435
- private async postJson(urlArg: string, bodyArg: unknown, timeoutMsArg?: number): Promise<IBraviatvRestResponse> {
436
- const text = await this.request(urlArg, {
437
- 'Content-Type': 'application/json; charset=UTF-8',
438
- }, JSON.stringify(bodyArg), timeoutMsArg);
200
+ /** Admission deadline includes queue, caller credential resolution and owned transport drain. */
201
+ private run<TResult>(execute: (protocol: plugins.ecobridgeDeviceManager.SonyBraviaProtocol,
202
+ operation: plugins.ecobridgeDeviceManager.ISonyBraviaOperationOptions) => Promise<TResult>, signal?: AbortSignal,
203
+ requireStarted = true): Promise<TResult> {
439
204
  try {
440
- return (text ? JSON.parse(text) : {}) as IBraviatvRestResponse;
441
- } catch (errorArg) {
442
- throw new BraviatvLiveControlError(`Sony Bravia TV returned invalid JSON: ${this.errorMessage(errorArg)}`);
443
- }
444
- }
445
-
446
- private async postText(urlArg: string, bodyArg: string, headersArg: Record<string, string>): Promise<boolean> {
447
- await this.request(urlArg, headersArg, bodyArg);
448
- return true;
449
- }
450
-
451
- private async request(urlArg: string, headersArg: Record<string, string>, bodyArg: string, timeoutMsArg?: number): Promise<string> {
205
+ this.assertOpen();
206
+ if (signal !== undefined && !(signal instanceof AbortSignal)) throw new TypeError('BRAVIA cancellation requires an AbortSignal.');
207
+ if (signal?.aborted) throw this.failure('cancelled');
208
+ if (requireStarted && !this.#started) throw new Error('BRAVIA client has not started.');
209
+ const retained = [...this.#protocols.values()].filter((owned) => owned.failed && !owned.active).length;
210
+ const retainedCredentials = [...this.#credentialOperations.values(), ...this.#credentialFailures.values()]
211
+ .filter((operation) => !this.#operations.has(operation)).length;
212
+ if (this.#operations.size + retained + retainedCredentials >= this.config.maxPendingOperations) throw this.failure('capacity');
213
+ } catch (error) { return Promise.reject(error); }
214
+ const deadline = performance.now() + this.config.timeoutMs;
452
215
  const controller = new AbortController();
453
- const timeout = setTimeout(() => controller.abort(), timeoutMsArg || this.config.timeoutMs || defaultTimeoutMs);
454
- try {
455
- const response = await globalThis.fetch(urlArg, {
456
- method: 'POST',
457
- headers: {
458
- ...headersArg,
459
- 'Cache-Control': 'no-cache',
460
- Connection: 'keep-alive',
461
- 'X-Auth-PSK': this.config.psk as string,
462
- },
463
- body: bodyArg,
464
- signal: controller.signal,
465
- });
466
- const text = await response.text();
467
- if (response.status === 401 || response.status === 403) {
468
- throw new BraviatvAuthError(`Sony Bravia TV authentication failed with HTTP ${response.status}.`);
469
- }
470
- if (!response.ok) {
471
- throw new BraviatvLiveControlError(`Sony Bravia TV request failed with HTTP ${response.status}: ${text}`);
472
- }
473
- return text;
474
- } catch (errorArg) {
475
- if (errorArg instanceof BraviatvAuthError || errorArg instanceof BraviatvLiveControlError) {
476
- throw errorArg;
477
- }
478
- if (errorArg instanceof Error && errorArg.name === 'AbortError') {
479
- throw new BraviatvLiveControlError(`Sony Bravia TV request timed out after ${timeoutMsArg || this.config.timeoutMs || defaultTimeoutMs}ms.`);
480
- }
481
- throw new BraviatvLiveControlError(`Sony Bravia TV request failed: ${this.errorMessage(errorArg)}`);
482
- } finally {
483
- clearTimeout(timeout);
484
- }
485
- }
486
-
487
- private assertLivePskSupported(commandArg: string): void {
488
- if (!this.config.host) {
489
- throw new BraviatvLiveControlError(`Sony Bravia TV host is required for live ${commandArg}.`);
490
- }
491
- if (!this.config.psk) {
492
- if (this.config.pin || this.config.usePsk === false) {
493
- throw new BraviatvLiveControlError(`Sony Bravia TV PIN pairing/cookie authentication is not implemented in this native TypeScript port. Configure a PSK to use live ${commandArg}.`);
494
- }
495
- throw new BraviatvLiveControlError(`Sony Bravia TV PSK is required for live ${commandArg}.`);
496
- }
497
- }
498
-
499
- private hasLivePskConfig(): boolean {
500
- return Boolean(this.config.host && this.config.psk);
501
- }
502
-
503
- private serviceUrl(serviceArg: string): string {
504
- const protocol = this.config.useSsl ? 'https' : 'http';
505
- const port = this.config.port ? `:${this.config.port}` : '';
506
- return `${protocol}://${this.config.host}${port}/sony/${serviceArg}`;
507
- }
508
-
509
- private irccBody(codeArg: string): string {
510
- return `<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:X_SendIRCC xmlns:u="urn:schemas-sony-com:service:IRCC:1"><IRCCCode>${codeArg}</IRCCCode></u:X_SendIRCC></s:Body></s:Envelope>`;
511
- }
512
-
513
- private firstResult<TResult>(responseArg: IBraviatvRestResponse): TResult | undefined {
514
- return responseArg.result?.[0] as TResult | undefined;
515
- }
516
-
517
- private async commandCode(commandArg: string): Promise<string | undefined> {
518
- const command = commandArg.trim();
519
- if (this.looksLikeIrccCode(command)) {
520
- return command;
521
- }
522
-
523
- const commands = await this.getCommandList().catch(() => ({ ...fallbackCommands, ...(this.config.commands || {}) }));
524
- const candidates = [command, this.normalizeCommand(command)].filter(Boolean);
525
- for (const candidate of candidates) {
526
- if (commands[candidate]) {
527
- return commands[candidate];
216
+ const cancel = () => controller.abort(this.failure('cancelled'));
217
+ signal?.addEventListener('abort', cancel, { once: true });
218
+ const combined = AbortSignal.any([controller.signal, this.#lifetime.signal]);
219
+ const timer = setTimeout(() => controller.abort(this.failure('timeout')), this.config.timeoutMs);
220
+ let cancelWaiting: () => void = () => {};
221
+ const waiting = new Promise<never>((_resolve, reject) => {
222
+ cancelWaiting = () => { try { this.active(combined, deadline); } catch (error) { reject(error); } };
223
+ combined.addEventListener('abort', cancelWaiting, { once: true });
224
+ });
225
+ let ownedProtocol: IBraviatvOwnedProtocol | undefined;
226
+ const operation = this.#tail.then(async () => {
227
+ combined.removeEventListener('abort', cancelWaiting);
228
+ this.active(combined, deadline);
229
+ const psk = await this.resolvePsk(combined, deadline, operation);
230
+ const timeoutMs = this.active(combined, deadline);
231
+ const protocol = new plugins.ecobridgeDeviceManager.SonyBraviaProtocol({ address: this.config.host,
232
+ expectedModel: this.config.expectedModel, expectedMacAddress: this.config.expectedMacAddress,
233
+ ...(this.config.expectedSerial === undefined ? {} : { expectedSerial: this.config.expectedSerial }), psk,
234
+ allowUnencryptedLan: true, volumeLimitRaw: this.config.volumeLimitRaw, port: this.config.port,
235
+ timeoutMs, maxPendingOperations: 1, maxResponseBytes: this.config.maxResponseBytes });
236
+ const owned: IBraviatvOwnedProtocol = { protocol, failed: false, active: true };
237
+ ownedProtocol = owned;
238
+ this.#protocols.set(protocol, owned);
239
+ let result: TResult | undefined;
240
+ let failure: unknown;
241
+ try {
242
+ this.active(combined, deadline);
243
+ result = await execute(protocol, { signal: combined, timeoutMs: this.active(combined, deadline) });
244
+ } catch (error) { failure = error; }
245
+ try { await this.closeProtocol(owned); }
246
+ catch {
247
+ const acknowledged = (result as Partial<plugins.ecobridgeDeviceManager.ISonyBraviaControlObservation>)?.commandAcknowledged === true
248
+ || failure instanceof plugins.ecobridgeDeviceManager.SonyBraviaProtocolError && failure.commandAcknowledged;
249
+ throw new plugins.ecobridgeDeviceManager.SonyBraviaProtocolError('transport', 'BRAVIA owned protocol cleanup failed.',
250
+ acknowledged ? 'indeterminate' : failure instanceof plugins.ecobridgeDeviceManager.SonyBraviaProtocolError ? failure.effectOutcome : 'not-sent', acknowledged);
528
251
  }
529
- const lowerCandidate = candidate.toLowerCase();
530
- const entry = Object.entries(commands).find(([name]) => name.toLowerCase() === lowerCandidate);
531
- if (entry) {
532
- return entry[1];
252
+ if (failure !== undefined) throw failure;
253
+ try { this.active(combined, deadline); }
254
+ catch (error) {
255
+ const acknowledged = (result as Partial<plugins.ecobridgeDeviceManager.ISonyBraviaControlObservation>)?.commandAcknowledged === true;
256
+ if (acknowledged) throw new plugins.ecobridgeDeviceManager.SonyBraviaProtocolError(
257
+ error instanceof plugins.ecobridgeDeviceManager.SonyBraviaProtocolError ? error.code : 'cancelled',
258
+ 'BRAVIA operation ended after acknowledgment.', 'indeterminate', true);
259
+ throw error;
533
260
  }
534
- }
535
- return undefined;
536
- }
537
-
538
- private normalizeCommand(commandArg: string): string {
539
- const normalized = commandArg.replace(/[_\s-]+/g, '').toLowerCase();
540
- const aliases: Record<string, string> = {
541
- power: 'Power',
542
- poweron: 'PowerOn',
543
- input: 'Input',
544
- source: 'Input',
545
- hdmi1: 'Hdmi1',
546
- hdmi2: 'Hdmi2',
547
- hdmi3: 'Hdmi3',
548
- hdmi4: 'Hdmi4',
549
- up: 'Up',
550
- down: 'Down',
551
- left: 'Left',
552
- right: 'Right',
553
- ok: 'Confirm',
554
- enter: 'Confirm',
555
- select: 'Confirm',
556
- confirm: 'Confirm',
557
- back: 'Back',
558
- return: 'Back',
559
- home: 'Home',
560
- menu: 'Home',
561
- options: 'Options',
562
- info: 'Display',
563
- display: 'Display',
564
- volumeup: 'VolumeUp',
565
- volup: 'VolumeUp',
566
- volumedown: 'VolumeDown',
567
- voldown: 'VolumeDown',
568
- mute: 'Mute',
569
- channelup: 'ChannelUp',
570
- chup: 'ChannelUp',
571
- channeldown: 'ChannelDown',
572
- chdown: 'ChannelDown',
573
- play: 'Play',
574
- pause: 'Pause',
575
- stop: 'Stop',
576
- next: 'Next',
577
- previous: 'Prev',
578
- prev: 'Prev',
579
- };
580
- return aliases[normalized] || commandArg;
581
- }
582
-
583
- private looksLikeIrccCode(valueArg: string): boolean {
584
- return /^[A-Za-z0-9+/]+={0,2}$/.test(valueArg) && valueArg.length >= 16 && valueArg.includes('Aw');
585
- }
586
-
587
- private snapshotFromManualConfig(errorMessageArg?: string): IBraviatvSnapshot {
588
- const systemInfo = this.systemInfoFromConfig();
589
- const state: IBraviatvState = {
590
- powerStatus: this.config.state?.powerStatus || (this.config.state?.power === 'on' ? 'active' : this.config.state?.power === 'off' ? 'standby' : 'unknown'),
591
- available: Boolean(this.config.snapshot || this.config.state || this.config.systemInfo || this.config.host),
592
- ...this.config.state,
593
- lastError: errorMessageArg || this.config.state?.lastError,
594
- };
595
- return {
596
- systemInfo,
597
- state,
598
- sources: [...(this.config.sources || [])],
599
- apps: [...(this.config.apps || [])],
600
- channels: [...(this.config.channels || [])],
601
- commands: this.config.commands,
602
- updatedAt: new Date().toISOString(),
603
- };
604
- }
605
-
606
- private systemInfoFromConfig(): IBraviatvSystemInfo {
607
- return {
608
- ...this.config.systemInfo,
609
- name: this.config.systemInfo?.name || this.config.name || this.config.host || 'Sony Bravia TV',
610
- model: this.config.systemInfo?.model || this.config.model,
611
- serial: this.config.systemInfo?.serial || this.config.serialNumber,
612
- macAddr: this.config.systemInfo?.macAddr || this.config.macAddress,
613
- cid: this.config.systemInfo?.cid || this.config.cid || this.config.macAddress || this.config.host,
614
- product: this.config.systemInfo?.product || 'TV',
615
- };
616
- }
617
-
618
- private normalizeSnapshot(snapshotArg: IBraviatvSnapshot): IBraviatvSnapshot {
619
- const systemInfo = {
620
- ...this.systemInfoFromConfig(),
621
- ...snapshotArg.systemInfo,
622
- };
623
- const state = this.normalizeState(snapshotArg.state);
624
- return {
625
- ...snapshotArg,
626
- systemInfo,
627
- state,
628
- sources: this.normalizeSources(snapshotArg.sources, 'input'),
629
- apps: this.normalizeSources(snapshotArg.apps, 'app') as IBraviatvApp[],
630
- channels: this.normalizeSources(snapshotArg.channels || [], 'channel') as IBraviatvChannel[],
631
- updatedAt: snapshotArg.updatedAt || new Date().toISOString(),
632
- };
633
- }
634
-
635
- private normalizeState(stateArg: IBraviatvState): IBraviatvState {
636
- const powerStatus = stateArg.powerStatus || (stateArg.power === 'on' ? 'active' : stateArg.power === 'off' ? 'standby' : 'unknown');
637
- const power = stateArg.power || this.powerFromStatus(powerStatus);
638
- let volumeLevel = stateArg.volumeLevel;
639
- if (typeof volumeLevel === 'number' && volumeLevel > 1) {
640
- volumeLevel /= 100;
641
- }
642
- if (typeof volumeLevel !== 'number' && typeof stateArg.volumePercent === 'number') {
643
- volumeLevel = stateArg.volumePercent / 100;
644
- }
645
- return {
646
- ...stateArg,
647
- powerStatus,
648
- power,
649
- playback: stateArg.playback || (power === 'off' ? 'off' : 'idle'),
650
- volumeLevel,
651
- volumePercent: typeof stateArg.volumePercent === 'number' ? stateArg.volumePercent : typeof volumeLevel === 'number' ? Math.round(volumeLevel * 100) : undefined,
652
- };
653
- }
654
-
655
- private normalizeSources(sourcesArg: IBraviatvSource[], typeArg: TBraviatvSourceType): IBraviatvSource[] {
656
- return sourcesArg.filter((sourceArg) => sourceArg.title && sourceArg.uri).map((sourceArg) => ({
657
- ...sourceArg,
658
- type: sourceArg.type || typeArg,
659
- }));
660
- }
661
-
662
- private applyVolumeInfo(stateArg: IBraviatvState, volumeInfoArg: IBraviatvVolumeInfo | undefined): void {
663
- if (!volumeInfoArg) {
664
- return;
665
- }
666
- const volume = typeof volumeInfoArg.volume === 'number' ? volumeInfoArg.volume : Number(volumeInfoArg.volume);
667
- if (Number.isFinite(volume)) {
668
- stateArg.volumePercent = volume;
669
- stateArg.volumeLevel = volume / 100;
670
- }
671
- stateArg.muted = volumeInfoArg.mute;
672
- }
673
-
674
- private applyPlayingInfo(stateArg: IBraviatvState, playingInfoArg: IBraviatvPlayingInfo | undefined): void {
675
- if (!playingInfoArg) {
676
- stateArg.mediaTitle = stateArg.mediaTitle || 'Smart TV';
677
- return;
678
- }
679
- stateArg.mediaTitle = playingInfoArg.programTitle || playingInfoArg.title || stateArg.mediaTitle;
680
- stateArg.mediaContentId = playingInfoArg.uri || playingInfoArg.dispNum || stateArg.mediaContentId;
681
- stateArg.sourceUri = playingInfoArg.uri || stateArg.sourceUri;
682
- stateArg.mediaDuration = playingInfoArg.durationSec;
683
- if (playingInfoArg.uri?.startsWith('extInput:')) {
684
- stateArg.source = playingInfoArg.title || stateArg.source;
685
- }
686
- if (playingInfoArg.uri?.startsWith('tv:')) {
687
- stateArg.mediaChannel = playingInfoArg.title || playingInfoArg.dispNum;
688
- stateArg.mediaContentType = 'channel';
689
- } else if (playingInfoArg.uri) {
690
- stateArg.mediaContentType = this.inferSourceType(playingInfoArg.uri);
691
- }
692
- if (playingInfoArg.startDateTime) {
693
- const startTime = Date.parse(playingInfoArg.startDateTime);
694
- if (Number.isFinite(startTime)) {
695
- stateArg.mediaPosition = Math.max(0, Math.floor((Date.now() - startTime) / 1000));
696
- stateArg.mediaPositionUpdatedAt = new Date().toISOString();
697
- }
698
- }
699
- }
700
-
701
- private inferSourceType(uriArg: string): TBraviatvSourceType {
702
- if (uriArg.startsWith('extInput:')) {
703
- return 'input';
704
- }
705
- if (uriArg.startsWith('tv:')) {
706
- return 'channel';
707
- }
708
- return 'app';
709
- }
710
-
711
- private powerFromStatus(statusArg: string): 'on' | 'off' | 'unknown' {
712
- const status = statusArg.toLowerCase();
713
- if (status === 'active') {
714
- return 'on';
715
- }
716
- if (status === 'standby' || status === 'off') {
717
- return 'off';
718
- }
719
- return 'unknown';
720
- }
721
-
722
- private updateLocalState(stateArg: Partial<IBraviatvState>): void {
723
- const state = this.config.snapshot?.state || this.config.state || {};
724
- Object.assign(state, stateArg);
725
- if (this.config.snapshot) {
726
- this.config.snapshot.state = state;
727
- return;
728
- }
729
- this.config.state = state;
730
- }
731
-
732
- private cloneSnapshot(snapshotArg: IBraviatvSnapshot): IBraviatvSnapshot {
733
- return JSON.parse(JSON.stringify(snapshotArg)) as IBraviatvSnapshot;
734
- }
735
-
736
- private errorMessage(errorArg: unknown): string {
737
- return errorArg instanceof Error ? errorArg.message : String(errorArg);
261
+ return result as TResult;
262
+ }).catch((error: unknown) => { this.#healthy = false; throw error; }).finally(() => {
263
+ clearTimeout(timer);
264
+ signal?.removeEventListener('abort', cancel);
265
+ combined.removeEventListener('abort', cancelWaiting);
266
+ if (ownedProtocol) ownedProtocol.active = false;
267
+ this.#operations.delete(operation);
268
+ });
269
+ this.#operations.add(operation);
270
+ this.#tail = operation.then(() => {}, () => {});
271
+ if (signal?.aborted) cancel();
272
+ if (combined.aborted) cancelWaiting();
273
+ return Promise.race([operation, waiting]);
738
274
  }
739
275
  }