@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,217 +1,46 @@
1
- import * as plugins from '../../plugins.js';
1
+ import type * as plugins from '../../plugins.js';
2
2
  import type { IIntegrationEntity } from '../../core/types.js';
3
- import type { ISoundtouchPreset, ISoundtouchSnapshot, ISoundtouchStatus } from './soundtouch.types.js';
3
+ import type { ISoundtouchSnapshot } from './soundtouch.types.js';
4
4
 
5
5
  export class SoundtouchMapper {
6
+ public static deviceId(snapshotArg: Pick<ISoundtouchSnapshot, 'homeId' | 'deviceId'>): string {
7
+ return `soundtouch:${encodeURIComponent(snapshotArg.homeId)}:${snapshotArg.deviceId}`;
8
+ }
9
+ public static mediaEntityId(snapshotArg: Pick<ISoundtouchSnapshot, 'homeId' | 'deviceId'>): string { return `${this.deviceId(snapshotArg)}:speaker`; }
6
10
  public static toDevices(snapshotArg: ISoundtouchSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
7
- const updatedAt = snapshotArg.lastUpdated || new Date().toISOString();
8
- const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
9
- { id: 'playback', capability: 'media', name: 'Playback', readable: true, writable: true },
10
- { id: 'source', capability: 'media', name: 'Source', readable: true, writable: true },
11
- { id: 'volume', capability: 'media', name: 'Volume', readable: true, writable: true, unit: '%' },
12
- { id: 'muted', capability: 'media', name: 'Muted', readable: true, writable: true },
13
- { id: 'presets', capability: 'media', name: 'Presets', readable: true, writable: true },
14
- ];
15
- const state: plugins.shxInterfaces.data.IDeviceState[] = [
16
- { featureId: 'playback', value: this.mediaState(snapshotArg.status), updatedAt },
17
- { featureId: 'source', value: snapshotArg.status?.source || null, updatedAt },
18
- { featureId: 'volume', value: typeof snapshotArg.volume?.actual === 'number' ? snapshotArg.volume.actual : null, updatedAt },
19
- { featureId: 'muted', value: typeof snapshotArg.volume?.muted === 'boolean' ? snapshotArg.volume.muted : null, updatedAt },
20
- { featureId: 'presets', value: snapshotArg.presets?.length || 0, updatedAt },
21
- ];
22
-
23
- if (this.mediaTitle(snapshotArg.status)) {
24
- features.push({ id: 'current_title', capability: 'media', name: 'Current title', readable: true, writable: false });
25
- state.push({ featureId: 'current_title', value: this.mediaTitle(snapshotArg.status) || null, updatedAt });
26
- }
27
-
28
- return [{
29
- id: this.playerDeviceId(snapshotArg),
30
- integrationDomain: 'soundtouch',
31
- name: this.deviceName(snapshotArg),
32
- protocol: 'http',
33
- manufacturer: 'Bose Corporation',
34
- model: snapshotArg.config.type,
35
- online: snapshotArg.available !== false,
36
- features,
37
- state,
38
- metadata: {
39
- deviceId: snapshotArg.config.deviceId,
40
- host: snapshotArg.config.host,
41
- port: snapshotArg.config.port,
42
- macAddress: this.macAddress(snapshotArg),
43
- accountUuid: snapshotArg.config.accountUuid,
44
- moduleType: snapshotArg.config.moduleType,
45
- variant: snapshotArg.config.variant,
46
- softwareVersions: snapshotArg.config.components?.map((componentArg) => componentArg.softwareVersion).filter(Boolean),
47
- },
11
+ const settled = snapshotArg.targetVolume === snapshotArg.actualVolume;
12
+ const optionalCapabilities = snapshotArg.optionalCapabilities.map((capability) => ({ ...capability }));
13
+ return [{ id: this.deviceId(snapshotArg), integrationDomain: 'soundtouch', name: snapshotArg.displayName ?? snapshotArg.name, manufacturer: 'Bose',
14
+ protocol: 'http', online: snapshotArg.online,
15
+ features: [
16
+ { id: 'connectivity', capability: 'sensor', name: 'Connectivity', readable: true, writable: false },
17
+ { id: 'identity', capability: 'sensor', name: 'Speaker identity', readable: true, writable: false },
18
+ { id: 'optional_capabilities', capability: 'sensor', name: 'Declared optional capabilities', readable: true, writable: false },
19
+ { id: 'target_volume', capability: 'media', name: 'Observed target volume', readable: true, writable: false, unit: 'SoundTouch units' },
20
+ { id: 'volume', capability: 'media', name: 'Absolute volume', readable: true, writable: settled, unit: 'SoundTouch units' },
21
+ { id: 'mute', capability: 'media', name: 'Mute', readable: true,
22
+ writable: settled && snapshotArg.capabilities.mute && snapshotArg.actualVolume <= snapshotArg.volumeLimit },
23
+ ],
24
+ state: [
25
+ { featureId: 'connectivity', value: 'online', updatedAt: snapshotArg.observedAt },
26
+ { featureId: 'identity', value: { deviceId: snapshotArg.deviceId, type: snapshotArg.type }, updatedAt: snapshotArg.observedAt },
27
+ { featureId: 'optional_capabilities', value: { capabilities: optionalCapabilities }, updatedAt: snapshotArg.observedAt },
28
+ { featureId: 'target_volume', value: snapshotArg.targetVolume, updatedAt: snapshotArg.observedAt },
29
+ { featureId: 'volume', value: snapshotArg.actualVolume, updatedAt: snapshotArg.observedAt },
30
+ { featureId: 'mute', value: snapshotArg.muted, updatedAt: snapshotArg.observedAt },
31
+ ],
32
+ metadata: { homeId: snapshotArg.homeId, deviceId: snapshotArg.deviceId, type: snapshotArg.type, lanAuthenticated: false,
33
+ observedName: snapshotArg.name, volumeLimit: snapshotArg.volumeLimit, volumeRange: { minimum: 0, maximum: 100, step: 1 },
34
+ ownerWriteVolumeRange: { minimum: 0, maximum: snapshotArg.volumeLimit, step: 1 },
35
+ optionalCapabilities, observedAt: snapshotArg.observedAt, standbySupported: false },
48
36
  }];
49
37
  }
50
-
51
38
  public static toEntities(snapshotArg: ISoundtouchSnapshot): IIntegrationEntity[] {
52
- const base = this.entityBase(snapshotArg);
53
- const entities: IIntegrationEntity[] = [{
54
- id: `media_player.${base}`,
55
- uniqueId: `soundtouch_${this.uniqueBase(snapshotArg)}`,
56
- integrationDomain: 'soundtouch',
57
- deviceId: this.playerDeviceId(snapshotArg),
58
- platform: 'media_player',
59
- name: this.deviceName(snapshotArg),
60
- state: this.mediaState(snapshotArg.status),
61
- attributes: {
62
- deviceClass: 'speaker',
63
- deviceId: snapshotArg.config.deviceId,
64
- model: snapshotArg.config.type,
65
- macAddress: this.macAddress(snapshotArg),
66
- volumeLevel: typeof snapshotArg.volume?.actual === 'number' ? Math.max(0, Math.min(1, snapshotArg.volume.actual / 100)) : undefined,
67
- volume: snapshotArg.volume?.actual,
68
- targetVolume: snapshotArg.volume?.target,
69
- isVolumeMuted: snapshotArg.volume?.muted,
70
- source: snapshotArg.status?.source,
71
- sourceList: snapshotArg.sourceList || [],
72
- presetList: this.presetList(snapshotArg),
73
- mediaContentType: snapshotArg.status?.contentItem?.type || snapshotArg.status?.streamType,
74
- mediaContentId: snapshotArg.status?.contentItem?.location || snapshotArg.status?.trackId,
75
- mediaTitle: this.mediaTitle(snapshotArg.status),
76
- mediaArtist: snapshotArg.status?.artist,
77
- mediaTrack: snapshotArg.status?.track,
78
- mediaAlbumName: snapshotArg.status?.album,
79
- mediaImageUrl: snapshotArg.status?.image,
80
- mediaDuration: snapshotArg.status?.duration,
81
- mediaPosition: snapshotArg.status?.position,
82
- shuffle: snapshotArg.status?.shuffleSetting,
83
- repeat: snapshotArg.status?.repeatSetting,
84
- stationName: snapshotArg.status?.stationName,
85
- stationLocation: snapshotArg.status?.stationLocation,
86
- soundtouchZone: this.zoneAttribute(snapshotArg),
87
- soundtouchGroup: this.groupAttribute(snapshotArg),
88
- },
89
- available: snapshotArg.available !== false,
39
+ return [{ id: this.mediaEntityId(snapshotArg), uniqueId: this.mediaEntityId(snapshotArg), deviceId: this.deviceId(snapshotArg),
40
+ integrationDomain: 'soundtouch', platform: 'media_player', name: snapshotArg.displayName ?? snapshotArg.name, state: 'unknown', available: snapshotArg.online,
41
+ attributes: { type: snapshotArg.type, volume: snapshotArg.actualVolume, targetVolume: snapshotArg.targetVolume, muted: snapshotArg.muted,
42
+ volumeLimit: snapshotArg.volumeLimit, optionalCapabilities: snapshotArg.optionalCapabilities.map((capability) => ({ ...capability })),
43
+ observedAt: snapshotArg.observedAt, standbySupported: false },
90
44
  }];
91
-
92
- entities.push({
93
- id: `sensor.${base}_soundtouch_presets`,
94
- uniqueId: `soundtouch_${this.uniqueBase(snapshotArg)}_presets`,
95
- integrationDomain: 'soundtouch',
96
- deviceId: this.playerDeviceId(snapshotArg),
97
- platform: 'sensor',
98
- name: `${this.deviceName(snapshotArg)} SoundTouch Presets`,
99
- state: snapshotArg.presets?.length || 0,
100
- attributes: { presets: this.presetList(snapshotArg) },
101
- available: snapshotArg.available !== false,
102
- });
103
-
104
- entities.push({
105
- id: `sensor.${base}_soundtouch_sources`,
106
- uniqueId: `soundtouch_${this.uniqueBase(snapshotArg)}_sources`,
107
- integrationDomain: 'soundtouch',
108
- deviceId: this.playerDeviceId(snapshotArg),
109
- platform: 'sensor',
110
- name: `${this.deviceName(snapshotArg)} SoundTouch Sources`,
111
- state: snapshotArg.sourceList?.length || 0,
112
- attributes: { sourceList: snapshotArg.sourceList || [] },
113
- available: snapshotArg.available !== false,
114
- });
115
-
116
- entities.push({
117
- id: `sensor.${base}_soundtouch_media`,
118
- uniqueId: `soundtouch_${this.uniqueBase(snapshotArg)}_media`,
119
- integrationDomain: 'soundtouch',
120
- deviceId: this.playerDeviceId(snapshotArg),
121
- platform: 'sensor',
122
- name: `${this.deviceName(snapshotArg)} SoundTouch Media`,
123
- state: this.mediaTitle(snapshotArg.status) || snapshotArg.status?.source || 'None',
124
- attributes: { status: snapshotArg.status },
125
- available: snapshotArg.available !== false,
126
- });
127
-
128
- return entities;
129
- }
130
-
131
- public static playerDeviceId(snapshotArg: ISoundtouchSnapshot): string {
132
- return `soundtouch.player.${this.uniqueBase(snapshotArg)}`;
133
- }
134
-
135
- public static slug(valueArg: string | undefined): string {
136
- return (valueArg || 'soundtouch').toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'soundtouch';
137
- }
138
-
139
- private static mediaState(statusArg: ISoundtouchStatus | undefined): string {
140
- if (!statusArg || statusArg.source === 'STANDBY' || statusArg.playStatus === 'STOP_STATE') {
141
- return 'off';
142
- }
143
- if (statusArg.source === 'INVALID_SOURCE') {
144
- return 'unknown';
145
- }
146
- if (statusArg.playStatus === 'PLAY_STATE' || statusArg.playStatus === 'BUFFERING_STATE') {
147
- return 'playing';
148
- }
149
- if (statusArg.playStatus === 'PAUSE_STATE') {
150
- return 'paused';
151
- }
152
- return 'idle';
153
- }
154
-
155
- private static mediaTitle(statusArg: ISoundtouchStatus | undefined): string | undefined {
156
- if (!statusArg) {
157
- return undefined;
158
- }
159
- if (statusArg.stationName) {
160
- return statusArg.stationName;
161
- }
162
- if (statusArg.artist && statusArg.track) {
163
- return `${statusArg.artist} - ${statusArg.track}`;
164
- }
165
- return statusArg.track || statusArg.contentItem?.name || statusArg.description;
166
- }
167
-
168
- private static presetList(snapshotArg: ISoundtouchSnapshot): Array<Record<string, unknown>> {
169
- return (snapshotArg.presets || []).map((presetArg: ISoundtouchPreset) => ({
170
- presetId: presetArg.presetId,
171
- name: presetArg.name,
172
- source: presetArg.source,
173
- type: presetArg.type,
174
- location: presetArg.location,
175
- sourceAccount: presetArg.sourceAccount,
176
- isPresetable: presetArg.isPresetable,
177
- }));
178
- }
179
-
180
- private static zoneAttribute(snapshotArg: ISoundtouchSnapshot): Record<string, unknown> | undefined {
181
- if (!snapshotArg.zone) {
182
- return undefined;
183
- }
184
- return {
185
- master: snapshotArg.zone.masterId,
186
- masterIp: snapshotArg.zone.masterIp,
187
- isMaster: snapshotArg.zone.isMaster,
188
- slaves: snapshotArg.zone.slaves,
189
- };
190
- }
191
-
192
- private static groupAttribute(snapshotArg: ISoundtouchSnapshot): string[] | undefined {
193
- if (!snapshotArg.zone) {
194
- return undefined;
195
- }
196
- return [
197
- snapshotArg.zone.masterId || snapshotArg.zone.masterIp,
198
- ...snapshotArg.zone.slaves.map((slaveArg) => slaveArg.deviceId || slaveArg.ipAddress),
199
- ].filter((valueArg): valueArg is string => Boolean(valueArg));
200
- }
201
-
202
- private static deviceName(snapshotArg: ISoundtouchSnapshot): string {
203
- return snapshotArg.config.name || snapshotArg.config.type || 'Bose SoundTouch';
204
- }
205
-
206
- private static entityBase(snapshotArg: ISoundtouchSnapshot): string {
207
- return this.slug(this.deviceName(snapshotArg));
208
- }
209
-
210
- private static uniqueBase(snapshotArg: ISoundtouchSnapshot): string {
211
- return this.slug(snapshotArg.config.deviceId || this.macAddress(snapshotArg) || snapshotArg.config.host || this.deviceName(snapshotArg));
212
- }
213
-
214
- private static macAddress(snapshotArg: ISoundtouchSnapshot): string | undefined {
215
- return snapshotArg.config.networks?.find((networkArg) => networkArg.type === 'SMSC')?.macAddress || snapshotArg.config.networks?.[0]?.macAddress;
216
45
  }
217
46
  }
@@ -1,199 +1,54 @@
1
- export const soundtouchDefaultPort = 8090;
2
- export const soundtouchDefaultDlnaPort = 8091;
3
- export const soundtouchDefaultSourceList = ['AUX', 'BLUETOOTH'] as const;
4
-
5
- export type TSoundtouchPlayStatus = 'PLAY_STATE' | 'BUFFERING_STATE' | 'PAUSE_STATE' | 'STOP_STATE' | string;
6
-
7
- export type TSoundtouchSource =
8
- | 'SLAVE_SOURCE'
9
- | 'INTERNET_RADIO'
10
- | 'PANDORA'
11
- | 'AIRPLAY'
12
- | 'STORED_MUSIC'
13
- | 'AUX'
14
- | 'OFF_SOURCE'
15
- | 'CURRATED_RADIO'
16
- | 'STANDBY'
17
- | 'UPDATE'
18
- | 'DEEZER'
19
- | 'SPOTIFY'
20
- | 'IHEART'
21
- | 'LOCAL_MUSIC'
22
- | 'BLUETOOTH'
23
- | 'INVALID_SOURCE'
24
- | string;
25
-
26
- export type TSoundtouchContentType = 'uri' | 'track' | 'album' | 'playlist' | string;
27
-
28
- export type TSoundtouchCommand =
29
- | 'turn_on'
30
- | 'turn_off'
31
- | 'play'
32
- | 'pause'
33
- | 'play_pause'
34
- | 'previous_track'
35
- | 'next_track'
36
- | 'volume_up'
37
- | 'volume_down'
38
- | 'set_volume'
39
- | 'mute'
40
- | 'select_source'
41
- | 'play_media'
42
- | 'play_preset';
1
+ import type * as plugins from '../../plugins.js';
2
+ import type { INativeConfigFlowContext, INativeIntegrationSetupContext } from '../../core/types.js';
3
+ import type { INativeIntegrationOwnerOptions } from '../../core/classes.nativeintegrationowner.js';
43
4
 
5
+ export const soundtouchDomain = 'soundtouch';
6
+ export const soundtouchDefaultPort = 8090;
7
+ export const soundtouchDefaultTimeoutMs = 5000;
8
+ export interface ISoundtouchHomeOptions extends INativeIntegrationOwnerOptions {}
9
+ export interface ISoundtouchSetupContext extends INativeIntegrationSetupContext {}
10
+ export interface ISoundtouchConfigFlowContext extends INativeConfigFlowContext {}
44
11
  export interface ISoundtouchConfig {
45
- host?: string;
46
- port?: number;
47
- dlnaPort?: number;
48
- name?: string;
49
- deviceId?: string;
50
- model?: string;
51
- macAddress?: string;
52
- sourceList?: string[];
53
- timeoutMs?: number;
54
- snapshot?: ISoundtouchSnapshot;
55
- commandExecutor?: ISoundtouchCommandExecutor;
12
+ readonly homeId: string;
13
+ readonly host: string;
14
+ /** Exact uppercase unicast deviceID previously observed on the selected device. */
15
+ readonly deviceId: string;
16
+ /** Documented /info type; the protocol supplies no model field. */
17
+ readonly type: string;
18
+ readonly allowUnencryptedLan: true;
19
+ /** Owner's absolute integer volume ceiling, 0–100. */
20
+ readonly volumeLimit: number;
21
+ readonly port?: number;
22
+ /** Optional local display label; observed /info name remains in the snapshot. */
23
+ readonly name?: string;
24
+ readonly requestTimeoutMs?: number;
25
+ readonly maxPendingOperations?: number;
26
+ readonly maxResponseBytes?: number;
56
27
  }
57
-
58
28
  export interface IHomeAssistantSoundtouchConfig extends ISoundtouchConfig {}
59
-
60
- export interface ISoundtouchCommandExecutor {
61
- execute(requestArg: ISoundtouchRawCommandRequest): Promise<unknown>;
62
- }
63
-
64
- export interface ISoundtouchRawCommandRequest {
65
- command: TSoundtouchCommand | 'refresh';
66
- method: 'GET' | 'POST';
67
- path: string;
68
- url: string;
69
- host?: string;
70
- port: number;
71
- body?: string;
72
- headers?: Record<string, string>;
73
- }
74
-
75
- export interface ISoundtouchCommandRequest {
76
- command: TSoundtouchCommand;
77
- source?: string;
78
- presetId?: string;
79
- presetName?: string;
80
- mediaId?: string;
81
- mediaType?: string;
82
- url?: string;
83
- volumeLevel?: number;
84
- volume?: number;
85
- muted?: boolean;
86
- contentItem?: ISoundtouchContentItem;
87
- }
88
-
89
- export interface ISoundtouchSnapshot {
90
- config: ISoundtouchDeviceInfo;
91
- status?: ISoundtouchStatus;
92
- volume?: ISoundtouchVolume;
93
- presets?: ISoundtouchPreset[];
94
- zone?: ISoundtouchZoneStatus;
95
- sourceList?: string[];
96
- available?: boolean;
97
- lastUpdated?: string;
98
- error?: string;
99
- }
100
-
101
- export interface ISoundtouchDeviceInfo {
102
- deviceId?: string;
103
- name?: string;
104
- type?: string;
105
- accountUuid?: string;
106
- moduleType?: string;
107
- variant?: string;
108
- variantMode?: string;
109
- countryCode?: string;
110
- regionCode?: string;
111
- host?: string;
112
- port?: number;
113
- networks?: ISoundtouchNetworkInfo[];
114
- components?: ISoundtouchComponentInfo[];
115
- }
116
-
117
- export interface ISoundtouchNetworkInfo {
118
- type?: string;
119
- macAddress?: string;
120
- ipAddress?: string;
121
- }
122
-
123
- export interface ISoundtouchComponentInfo {
124
- category?: string;
125
- softwareVersion?: string;
126
- serialNumber?: string;
127
- }
128
-
129
- export interface ISoundtouchContentItem {
130
- name?: string;
131
- source?: TSoundtouchSource;
132
- type?: TSoundtouchContentType;
133
- location?: string;
134
- sourceAccount?: string;
135
- isPresetable?: boolean;
136
- }
137
-
138
- export interface ISoundtouchStatus {
139
- source?: TSoundtouchSource;
140
- contentItem?: ISoundtouchContentItem;
141
- track?: string;
142
- artist?: string;
143
- album?: string;
144
- image?: string;
145
- duration?: number;
146
- position?: number;
147
- playStatus?: TSoundtouchPlayStatus;
148
- shuffleSetting?: string;
149
- repeatSetting?: string;
150
- streamType?: string;
151
- trackId?: string;
152
- stationName?: string;
153
- description?: string;
154
- stationLocation?: string;
155
- }
156
-
157
- export interface ISoundtouchVolume {
158
- actual?: number;
159
- target?: number;
160
- muted?: boolean;
161
- }
162
-
163
- export interface ISoundtouchPreset extends ISoundtouchContentItem {
164
- presetId: string;
165
- sourceXml?: string;
166
- }
167
-
168
- export interface ISoundtouchZoneStatus {
169
- masterId?: string;
170
- masterIp?: string;
171
- isMaster?: boolean;
172
- slaves: ISoundtouchZoneMember[];
173
- }
174
-
175
- export interface ISoundtouchZoneMember {
176
- deviceId?: string;
177
- ipAddress?: string;
178
- role?: string;
179
- }
180
-
181
- export interface ISoundtouchMdnsRecord {
182
- name?: string;
183
- type?: string;
184
- host?: string;
185
- port?: number;
186
- txt?: Record<string, string | undefined>;
187
- }
188
-
189
- export interface ISoundtouchManualEntry {
190
- host?: string;
191
- port?: number;
192
- id?: string;
193
- name?: string;
194
- manufacturer?: string;
195
- model?: string;
196
- deviceId?: string;
197
- macAddress?: string;
198
- metadata?: Record<string, unknown>;
199
- }
29
+ export interface ISoundtouchSnapshot extends plugins.ecobridgeDeviceManager.IBoseSoundTouchState {
30
+ readonly homeId: string;
31
+ readonly displayName?: string;
32
+ readonly volumeLimit: number;
33
+ readonly online: true;
34
+ }
35
+ export type TSoundtouchRawData = ISoundtouchSnapshot;
36
+ export type TSoundtouchClientEvent =
37
+ | { readonly type: 'snapshot'; readonly snapshot: ISoundtouchSnapshot }
38
+ | { readonly type: 'control'; readonly observation: plugins.ecobridgeDeviceManager.IBoseSoundTouchControlResult }
39
+ | { readonly type: 'error'; readonly error: Error };
40
+ export const soundtouchProfile = {
41
+ domain: soundtouchDomain, displayName: 'Bose SoundTouch', status: 'control-runtime',
42
+ metadata: {
43
+ source: 'home-assistant/core', upstreamDomain: soundtouchDomain, configFlow: true,
44
+ localApi: {
45
+ status: 'Selected native SoundTouch HTTP/XML through devicemanager.',
46
+ implemented: ['exact selected home/private IPv4/deviceID/type binding', 'live sanitized identity, optional capability declarations and actual volume/mute',
47
+ 'fresh settled-volume admission and owner-bounded absolute volume/mute', 'status acknowledgment and independent state observation without causal claims',
48
+ 'caller-owned optional home/domain config store', 'explicit observation events and joined terminal cleanup'],
49
+ explicitUnsupported: ['automatic discovery', 'cloud access or fallback', 'injected clients, snapshots and executors',
50
+ 'power, standby, key/toggle/increment, source, preset, media and zone controls', 'defined command-success vocabulary',
51
+ 'automatic retry, replay, reconnect or push subscription', 'cryptographic LAN peer authentication'],
52
+ },
53
+ },
54
+ } as const;
@@ -0,0 +1,60 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { ISoundtouchConfig } from './soundtouch.types.js';
3
+ import { soundtouchDefaultPort, soundtouchDefaultTimeoutMs } from './soundtouch.types.js';
4
+
5
+ export function soundtouchRecord(valueArg: unknown, nameArg: string): Record<string, unknown> {
6
+ if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)
7
+ || ![Object.prototype, null].includes(Object.getPrototypeOf(valueArg))) throw new TypeError(`SoundTouch ${nameArg} must be a plain data object.`);
8
+ const result: Record<string, unknown> = {};
9
+ for (const key of Reflect.ownKeys(valueArg)) {
10
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
11
+ if (typeof key !== 'string' || !descriptor || !('value' in descriptor) || !descriptor.enumerable) {
12
+ throw new TypeError(`SoundTouch ${nameArg} may not contain symbols, accessors or hidden fields.`);
13
+ }
14
+ Object.defineProperty(result, key, { value: descriptor.value, enumerable: true });
15
+ }
16
+ return result;
17
+ }
18
+ export function soundtouchKeys(valueArg: Record<string, unknown>, keysArg: readonly string[]): void {
19
+ if (Object.keys(valueArg).some((key) => !keysArg.includes(key))) throw new TypeError('SoundTouch data contains unsupported fields.');
20
+ }
21
+ export function soundtouchText(valueArg: unknown, nameArg: string, maximumArg = 128): string {
22
+ if (typeof valueArg !== 'string' || !valueArg.trim() || valueArg.length > maximumArg || /[\p{Cc}\p{Cs}]/u.test(valueArg)) {
23
+ throw new TypeError(`SoundTouch ${nameArg} must be a non-empty string without control characters, at most ${maximumArg} characters.`);
24
+ }
25
+ return valueArg;
26
+ }
27
+ export function soundtouchInteger(valueArg: unknown, minimumArg: number, maximumArg: number, nameArg: string): number {
28
+ if (typeof valueArg !== 'number' || !Number.isSafeInteger(valueArg) || valueArg < minimumArg || valueArg > maximumArg) {
29
+ throw new RangeError(`SoundTouch ${nameArg} must be an integer from ${minimumArg} through ${maximumArg}.`);
30
+ }
31
+ return valueArg;
32
+ }
33
+ export function soundtouchBoolean(valueArg: unknown): boolean {
34
+ if (typeof valueArg !== 'boolean') throw new TypeError('SoundTouch mute requires an explicit boolean.');
35
+ return valueArg;
36
+ }
37
+ export function readSoundtouchEndpoint(hostArg: unknown, idArg: unknown, typeArg: unknown, portArg?: unknown): Pick<ISoundtouchConfig, 'host' | 'deviceId' | 'type'> & { port: number } {
38
+ if (typeof hostArg !== 'string' || plugins.net.isIP(hostArg) !== 4) throw new TypeError('SoundTouch host must be a selected private IPv4 address.');
39
+ const [first, second, , last] = hostArg.split('.').map(Number);
40
+ if (!(first === 10 || first === 127 || first === 192 && second === 168 || first === 172 && second >= 16 && second <= 31)
41
+ || last === 0 || last === 255) throw new TypeError('SoundTouch host must be a selected private or loopback unicast IPv4 address.');
42
+ if (typeof idArg !== 'string' || !/^[0-9A-F]{12}$/.test(idArg) || /^(0{12}|F{12})$/.test(idArg)
43
+ || (Number.parseInt(idArg.slice(0, 2), 16) & 1) !== 0) throw new TypeError('SoundTouch deviceId must be the exact uppercase unicast twelve-digit deviceID.');
44
+ return { host: hostArg, deviceId: idArg, type: soundtouchText(typeArg, 'selected type'),
45
+ port: soundtouchInteger(portArg === undefined ? soundtouchDefaultPort : portArg, 1, 65535, 'port') };
46
+ }
47
+ export function normalizeSoundtouchConfig(valueArg: unknown) {
48
+ const values = soundtouchRecord(valueArg, 'configuration');
49
+ soundtouchKeys(values, ['homeId', 'host', 'deviceId', 'type', 'allowUnencryptedLan', 'volumeLimit', 'port', 'name',
50
+ 'requestTimeoutMs', 'maxPendingOperations', 'maxResponseBytes']);
51
+ if (values.allowUnencryptedLan !== true) throw new TypeError('SoundTouch requires explicit allowUnencryptedLan: true admission.');
52
+ return Object.freeze({ homeId: soundtouchText(values.homeId, 'homeId', 256),
53
+ ...readSoundtouchEndpoint(values.host, values.deviceId, values.type, values.port), allowUnencryptedLan: true as const,
54
+ volumeLimit: soundtouchInteger(values.volumeLimit, 0, 100, 'volumeLimit'),
55
+ ...(values.name === undefined ? {} : { name: soundtouchText(values.name, 'name') }),
56
+ requestTimeoutMs: soundtouchInteger(values.requestTimeoutMs === undefined ? soundtouchDefaultTimeoutMs : values.requestTimeoutMs, 1, 30000, 'requestTimeoutMs'),
57
+ maxPendingOperations: soundtouchInteger(values.maxPendingOperations === undefined ? 16 : values.maxPendingOperations, 1, 128, 'maxPendingOperations'),
58
+ maxResponseBytes: soundtouchInteger(values.maxResponseBytes === undefined ? 16384 : values.maxResponseBytes, 256, 65536, 'maxResponseBytes'),
59
+ });
60
+ }
@@ -1,25 +1,36 @@
1
1
  # Native Tasmota runtime
2
2
 
3
- This integration connects directly to a MQTT broker through the package's shared `MqttClient`. Configure each Tasmota device's broker and unique `Topic` before setup. No Home Assistant connection is required.
3
+ This integration connects directly to a MQTT broker through the package's shared `MqttSession`, which owns credential resolution and its `MqttClient` transport. Configure each Tasmota device's broker and unique `Topic` before setup. No Home Assistant connection is required.
4
4
 
5
5
  ```typescript
6
6
  import { HomeAssistantTasmotaIntegration } from '@smarthome.exchange/integrations';
7
7
 
8
- const runtime = await new HomeAssistantTasmotaIntegration().setup({
9
- broker: { host: 'mqtt.home', protocol: 'mqtts', username, password },
8
+ const integration = new HomeAssistantTasmotaIntegration({ enableControls: true });
9
+ const runtime = await integration.setup({
10
+ homeId: selectedHomeId,
11
+ authentication: { mode: 'credential-reference', credentialRef: 'broker-main' },
12
+ broker: { host: 'mqtt.home', protocol: 'mqtts' },
10
13
  devices: [{ topic: 'desk', relays: [1], brightness: true }],
11
14
  initialSnapshotTimeoutMs: 10_000,
12
- }, { abortSignal });
15
+ }, { homeId: selectedHomeId, configStore: borrowedEncryptedStore, abortSignal });
13
16
 
14
17
  try {
15
18
  const [device] = await runtime.devices();
16
19
  const feature = device.features.find((feature) => feature.id === 'power_1');
17
20
  if (feature) await runtime.writeFeature({ device, feature, value: false });
18
21
  } finally {
19
- await runtime.destroy();
22
+ await integration.destroy();
20
23
  }
21
24
  ```
22
25
 
26
+ The embedding host must independently supply its selected `homeId` in setup and config-flow context. The configured home must match it. An optional constructor `homeId` adds an immutable constraint; without it, the first admitted setup or flow fixes the instance's home even if setup fails. Discovery metadata, editable values and store scope cannot select the home. Default registry construction remains inert. Entity identifiers include the captured host home. This contract relies on the embedding host's authorization boundary; a home string is not an authentication token.
27
+
28
+ Authentication is explicit: `authentication: { mode: 'anonymous' }` selects a broker requiring no authentication. Otherwise, a credential reference requires an actual matching borrowed `NoSqlConfigStore` or a runtime-only constructor `credentialResolver`. Legacy plaintext broker username/password configuration fails with an explicit reconfiguration requirement. Flow secret inputs are transient; an admitted encrypted store creates an insert-only reference and the returned configuration contains no secrets. A cancelled late credential write is joined and removed before flow shutdown completes. Anonymous mode never substitutes for a missing or failed credential source.
29
+
30
+ A constructor resolver receives frozen `{ homeId, credentialRef, broker: { host, port, protocol }, signal, deadlineMonotonicMs }`; the deadline uses `performance.now()`. It returns a plain version1 record containing exactly that broker identity and optional username/password or TLS ca/cert/key/servername. Certificate and private key must be paired; TLS material requires mqtts. A result for another broker is rejected before connecting. Tasmota adapts this broker-bound contract to the shared MQTT session resolver. The session fences startup on cancellation or deadline and retains the actual resolver promise for shutdown, so an ignored cancellation or late result cannot connect. Resolver failures are sanitized and remain observable through session cleanup; explicit `retryCleanup()` acknowledges drained failures without resolving credentials again. The caller owns its resolver, store, database and key provider; the integration closes none of them.
31
+
32
+ Relay and brightness writes require the embedding owner's runtime-only constructor `enableControls: true`. This permission is not accepted from config forms. Without it, controls remain readable and writes fail before publishing. Every admitted command shares the owner's bounded capacity with pending setups, flows, runtimes and failed cleanup handles (default16, adjustable with constructor `capacity`). Integration destruction is terminal, drains every owned runtime and pending operation, and returns a stable close promise. Runtime destruction releases its owned lease. Failed cleanup remains retained; `integration.retryCleanup()` retries resource cleanup only, never setup, authentication, subscription or control commands.
33
+
23
34
  `relays` defaults to `[1]`; use `[]` for sensor-only devices. `brightness: true` enables the single-channel `Dimmer` command with integer percentage values from 0 through 100. Device identifiers default to `tasmota:<encoded-topic>` and can be assigned explicitly through `id`. `fullTopic` defaults to `%prefix%/%topic%/`; custom patterns must end in `/` and include each token exactly once. Only those two substitution tokens are supported. Custom `prefixes` specify all three command, status and telemetry prefixes. `powerOnPayload` and `powerOffPayload` describe customized `StateText` output; commands still use the standard `ON` and `OFF` arguments.
24
35
 
25
36
  Setup shares one deadline across the broker connection, subscription acknowledgments, state queries and first fresh snapshots. It requests `State` and `Status 10` for every selected device. A fresh nonretained `STATE`, `STATUS11` or complete `RESULT` state response must report every configured control before that device becomes ready. Retained state can provide an offline snapshot, but cannot establish readiness or overwrite ready state. The protocol does not correlate MQTT 3.1.1 command responses; readiness establishes current nonretained state after a query, rather than proving which request caused the message.