@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,216 +1,135 @@
1
- import type * as shxInterfaces from '@smarthome.exchange/interfaces';
1
+ import * as plugins from '../../plugins.js';
2
2
  import { BaseIntegration } from '../../core/classes.baseintegration.js';
3
- import type { IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
3
+ import { NativeIntegrationOwner, type INativeSetupLease } from '../../core/classes.nativeintegrationowner.js';
4
+ import type { IDeviceFeatureWriteRequest, IIntegrationEntity, IIntegrationRuntime, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
4
5
  import { KodiClient } from './kodi.classes.client.js';
5
6
  import { KodiConfigFlow } from './kodi.classes.configflow.js';
6
7
  import { createKodiDiscoveryDescriptor } from './kodi.discovery.js';
7
8
  import { KodiMapper } from './kodi.mapper.js';
8
- import type { IKodiConfig, TKodiMediaType } from './kodi.types.js';
9
+ import type { IKodiConfig, IKodiIntegrationOptions, IKodiNativeSnapshot, IKodiSetupContext } from './kodi.types.js';
10
+ import { kodiBoolean, kodiInteger, kodiKeys, kodiRecord, kodiSignal, normalizeKodiConfig } from './kodi.validation.js';
9
11
 
10
12
  export class KodiIntegration extends BaseIntegration<IKodiConfig> {
11
13
  public readonly domain = 'kodi';
12
14
  public readonly displayName = 'Kodi';
13
15
  public readonly status = 'control-runtime' as const;
14
16
  public readonly discoveryDescriptor = createKodiDiscoveryDescriptor();
15
- public readonly configFlow = new KodiConfigFlow();
17
+ public readonly configFlow: KodiConfigFlow;
16
18
  public readonly metadata = {
17
- source: 'home-assistant/core',
18
- upstreamPath: 'homeassistant/components/kodi',
19
- upstreamDomain: 'kodi',
20
- integrationType: 'service',
21
- iotClass: 'local_push',
22
- requirements: ['pykodi==0.2.7'],
23
- dependencies: [],
24
- afterDependencies: ['media_source'],
25
- codeowners: ['@OnFreund'],
26
- configFlow: true,
27
- documentation: 'https://www.home-assistant.io/integrations/kodi',
19
+ source: 'native-typescript', integrationType: 'device', iotClass: 'local_poll',
20
+ localApi: { status: 'Selected Kodi HTTP JSON-RPC API13 through devicemanager.',
21
+ implemented: ['fresh application observation', 'read-only default', 'explicit owner-trusted absolute volume and boolean mute', 'home-scoped endpoint targets', 'joined terminal lifetime'],
22
+ explicitUnsupported: ['unique or cryptographic server identity', 'arbitrary JSON-RPC', 'media transport', 'library and power operations', 'toggle or increment', 'notification transport', 'retry or replay', 'Home Assistant bridge'] },
28
23
  };
24
+ readonly #owner: NativeIntegrationOwner;
25
+ #getBasicCredentials?: IKodiIntegrationOptions['getBasicCredentials'];
26
+ #closePromise?: Promise<void>;
29
27
 
30
- public async setup(configArg: IKodiConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
31
- void contextArg;
32
- return new KodiRuntime(new KodiClient(configArg));
28
+ public constructor(options: IKodiIntegrationOptions = {}) {
29
+ super();
30
+ const value = kodiRecord(options, 'integration options');
31
+ kodiKeys(value, ['homeId', 'getBasicCredentials']);
32
+ if (value.getBasicCredentials !== undefined && typeof value.getBasicCredentials !== 'function') throw new TypeError('Kodi Basic provider must be a function.');
33
+ this.#owner = new NativeIntegrationOwner('kodi', { homeId: value.homeId as string | undefined });
34
+ this.#getBasicCredentials = value.getBasicCredentials as IKodiIntegrationOptions['getBasicCredentials'];
35
+ this.configFlow = new KodiConfigFlow(this.#owner);
33
36
  }
34
37
 
35
- public async destroy(): Promise<void> {}
38
+ public setup(config: IKodiConfig, context: IKodiSetupContext): Promise<IIntegrationRuntime> {
39
+ try {
40
+ const captured = normalizeKodiConfig(config);
41
+ return this.#owner.runSetup(context, captured.homeId, async (lease) => {
42
+ const client = new KodiClient(captured, { ...lease.context, abortSignal: lease.signal }, { getBasicCredentials: this.#getBasicCredentials });
43
+ lease.own(() => client.destroy());
44
+ const initial = await client.getSnapshot();
45
+ lease.assertOpen();
46
+ const runtime = new KodiRuntime(client, initial, lease);
47
+ lease.promoteToRuntime();
48
+ return runtime;
49
+ });
50
+ } catch (error) { return Promise.reject(error); }
51
+ }
52
+
53
+ public destroy(): Promise<void> {
54
+ if (!this.#closePromise) {
55
+ this.#closePromise = Promise.resolve().then(async () => {
56
+ try { await this.#owner.close(); }
57
+ finally { this.#getBasicCredentials = undefined; }
58
+ });
59
+ // Install the facade memo before synchronously closing admission or dispatching abort.
60
+ void this.#owner.close().catch(() => undefined);
61
+ }
62
+ return this.#closePromise;
63
+ }
64
+
65
+ public retryCleanup(): Promise<void> { return this.#owner.retryCleanup(); }
36
66
  }
37
67
 
38
68
  export class HomeAssistantKodiIntegration extends KodiIntegration {}
39
69
 
40
70
  class KodiRuntime implements IIntegrationRuntime {
41
- public domain = 'kodi';
42
-
43
- constructor(private readonly client: KodiClient) {}
71
+ public readonly domain = 'kodi';
72
+ readonly #deviceId: string;
73
+ readonly #entityId: string;
44
74
 
45
- public async devices(): Promise<shxInterfaces.data.IDeviceDefinition[]> {
46
- return KodiMapper.toDevices(await this.client.getSnapshot());
75
+ public constructor(private readonly client: KodiClient, initial: IKodiNativeSnapshot, private readonly lease: INativeSetupLease) {
76
+ this.#deviceId = KodiMapper.deviceId(initial);
77
+ this.#entityId = KodiMapper.entityId(initial);
47
78
  }
48
79
 
49
- public async entities(): Promise<IIntegrationEntity[]> {
50
- return KodiMapper.toEntities(await this.client.getSnapshot());
51
- }
80
+ public isHealthy(): boolean { return this.client.isHealthy(); }
81
+ public async devices(signal?: AbortSignal): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> { return KodiMapper.toNativeDevices(await this.client.getSnapshot(signal)); }
82
+ public async entities(): Promise<IIntegrationEntity[]> { return KodiMapper.toNativeEntities(await this.client.getSnapshot()); }
52
83
 
53
- public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
84
+ public async callService(input: IServiceCallRequest): Promise<IServiceCallResult> {
54
85
  try {
55
- if (requestArg.domain === 'media_player') {
56
- return await this.callMediaPlayerService(requestArg);
57
- }
58
- if (requestArg.domain === 'kodi') {
59
- return await this.callKodiService(requestArg);
86
+ const request = kodiRecord(input, 'service request');
87
+ kodiKeys(request, ['domain', 'service', 'target', 'data']);
88
+ this.assertTarget(request.target);
89
+ const data = request.data === undefined ? {} : kodiRecord(request.data, 'service data');
90
+ if (request.domain === 'kodi' && request.service === 'snapshot') {
91
+ kodiKeys(data, []); return { success: true, data: await this.client.getSnapshot() };
60
92
  }
61
- if (requestArg.domain === 'notify') {
62
- return await this.callNotifyService(requestArg);
93
+ if (request.domain === 'kodi' && request.service === 'set_volume') {
94
+ kodiKeys(data, ['volume']); return { success: true, data: await this.client.setVolume(kodiInteger(data.volume, 0, 100, 'absolute volume')) };
63
95
  }
64
- if (requestArg.domain === 'remote') {
65
- return await this.callRemoteService(requestArg);
96
+ if ((request.domain === 'kodi' && request.service === 'set_muted') || (request.domain === 'media_player' && request.service === 'volume_mute')) {
97
+ kodiKeys(data, ['muted']); return { success: true, data: await this.client.setMuted(kodiBoolean(data.muted)) };
66
98
  }
67
- return { success: false, error: `Unsupported Kodi service domain: ${requestArg.domain}` };
68
- } catch (errorArg) {
69
- return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
70
- }
71
- }
72
-
73
- public async destroy(): Promise<void> {
74
- await this.client.destroy();
99
+ throw new TypeError('Kodi service is unsupported; only snapshot, absolute volume and explicit mute are admitted.');
100
+ } catch (error) { return kodiFailure(error); }
75
101
  }
76
102
 
77
- private async callMediaPlayerService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
78
- if (requestArg.service === 'turn_on') {
79
- return { success: true, data: { event: 'kodi.turn_on', entityId: requestArg.target.entityId } };
80
- }
81
- if (requestArg.service === 'turn_off') {
82
- await this.client.quit();
83
- return { success: true };
84
- }
85
- if (requestArg.service === 'play' || requestArg.service === 'media_play') {
86
- await this.client.play();
87
- return { success: true };
88
- }
89
- if (requestArg.service === 'pause' || requestArg.service === 'media_pause') {
90
- await this.client.pause();
91
- return { success: true };
92
- }
93
- if (requestArg.service === 'play_pause' || requestArg.service === 'media_play_pause') {
94
- await this.client.playPause();
95
- return { success: true };
96
- }
97
- if (requestArg.service === 'stop' || requestArg.service === 'media_stop') {
98
- await this.client.stop();
99
- return { success: true };
100
- }
101
- if (requestArg.service === 'next_track' || requestArg.service === 'media_next_track') {
102
- await this.client.nextTrack();
103
- return { success: true };
104
- }
105
- if (requestArg.service === 'previous_track' || requestArg.service === 'media_previous_track') {
106
- await this.client.previousTrack();
107
- return { success: true };
108
- }
109
- if (requestArg.service === 'seek' || requestArg.service === 'media_seek') {
110
- const position = requestArg.data?.seek_position ?? requestArg.data?.position;
111
- if (typeof position !== 'number') {
112
- return { success: false, error: 'Kodi seek requires data.seek_position.' };
113
- }
114
- await this.client.seek(position);
115
- return { success: true };
116
- }
117
- if (requestArg.service === 'volume_set') {
118
- const level = requestArg.data?.volume_level;
119
- if (typeof level !== 'number') {
120
- return { success: false, error: 'Kodi volume_set requires data.volume_level.' };
121
- }
122
- await this.client.setVolumeLevel(level);
123
- return { success: true };
124
- }
125
- if (requestArg.service === 'volume_up' || requestArg.service === 'volume_down') {
126
- await this.client.stepVolume(requestArg.service === 'volume_up' ? 'increment' : 'decrement');
127
- return { success: true };
128
- }
129
- if (requestArg.service === 'volume_mute') {
130
- const muted = requestArg.data?.is_volume_muted ?? requestArg.data?.muted;
131
- if (typeof muted !== 'boolean') {
132
- return { success: false, error: 'Kodi volume_mute requires data.is_volume_muted.' };
133
- }
134
- await this.client.setMuted(muted);
135
- return { success: true };
136
- }
137
- if (requestArg.service === 'play_media') {
138
- const mediaId = requestArg.data?.media_content_id ?? requestArg.data?.uri;
139
- const mediaType = requestArg.data?.media_content_type ?? requestArg.data?.media_type ?? 'file';
140
- if ((typeof mediaId !== 'string' && typeof mediaId !== 'number') || mediaId === '') {
141
- return { success: false, error: 'Kodi play_media requires data.media_content_id or data.uri.' };
142
- }
143
- await this.client.playMedia(typeof mediaType === 'string' ? mediaType : 'file', mediaId);
144
- return { success: true };
145
- }
146
- return { success: false, error: `Unsupported Kodi media_player service: ${requestArg.service}` };
147
- }
148
-
149
- private async callKodiService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
150
- if (requestArg.service === 'call_method') {
151
- const method = requestArg.data?.method;
152
- if (typeof method !== 'string' || !method) {
153
- return { success: false, error: 'Kodi call_method requires data.method.' };
154
- }
155
- const params = this.callMethodParams(requestArg);
156
- return { success: true, data: await this.client.callMethod(method, params) };
157
- }
158
- if (requestArg.service === 'add_to_playlist') {
159
- const mediaType = requestArg.data?.media_type;
160
- const mediaId = requestArg.data?.media_id;
161
- if (typeof mediaType !== 'string' || (typeof mediaId !== 'string' && typeof mediaId !== 'number')) {
162
- return { success: false, error: 'Kodi add_to_playlist requires data.media_type and data.media_id.' };
163
- }
164
- await this.client.addToPlaylist(mediaType as TKodiMediaType, mediaId);
165
- return { success: true };
166
- }
167
- if (requestArg.service === 'show_notification') {
168
- return this.callNotifyService(requestArg);
169
- }
170
- return { success: false, error: `Unsupported Kodi service: ${requestArg.service}` };
103
+ public async writeFeature(input: IDeviceFeatureWriteRequest, signal?: AbortSignal): Promise<IServiceCallResult> {
104
+ try {
105
+ kodiSignal(signal);
106
+ const request = kodiRecord(input, 'feature write');
107
+ kodiKeys(request, ['device', 'feature', 'value']);
108
+ const device = kodiRecord(request.device, 'feature device');
109
+ const feature = kodiRecord(request.feature, 'feature');
110
+ if (device.id !== this.#deviceId || device.integrationDomain !== 'kodi') throw new TypeError('Kodi feature target is outside this home and selected endpoint.');
111
+ if (feature.capability !== 'media') throw new TypeError('Kodi feature capability differs from the canonical feature.');
112
+ if (feature.id === 'volume') return { success: true, data: await this.client.setVolume(kodiInteger(request.value, 0, 100, 'absolute volume'), signal) };
113
+ if (feature.id === 'muted') return { success: true, data: await this.client.setMuted(kodiBoolean(request.value), signal) };
114
+ throw new TypeError('Kodi feature is not writable.');
115
+ } catch (error) { return kodiFailure(error); }
171
116
  }
172
117
 
173
- private async callNotifyService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
174
- const message = requestArg.data?.message;
175
- if (typeof message !== 'string') {
176
- return { success: false, error: 'Kodi notification requires data.message.' };
177
- }
178
- const title = typeof requestArg.data?.title === 'string' ? requestArg.data.title : 'Home Assistant';
179
- const icon = typeof requestArg.data?.icon === 'string' ? requestArg.data.icon : 'info';
180
- const displayTime = typeof requestArg.data?.displaytime === 'number' ? requestArg.data.displaytime : 10000;
181
- await this.client.showNotification(title, message, icon, displayTime);
182
- return { success: true };
118
+ public destroy(): Promise<void> {
119
+ return this.lease.close();
183
120
  }
184
121
 
185
- private async callRemoteService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
186
- if (requestArg.service !== 'send_command') {
187
- return { success: false, error: `Unsupported Kodi remote service: ${requestArg.service}` };
188
- }
189
- const command = requestArg.data?.command;
190
- const commands = typeof command === 'string' ? [command] : Array.isArray(command) ? command.filter((itemArg): itemArg is string => typeof itemArg === 'string') : [];
191
- if (!commands.length) {
192
- return { success: false, error: 'Kodi remote.send_command requires data.command.' };
193
- }
194
- for (const item of commands) {
195
- await this.client.input(item);
196
- }
197
- return { success: true };
122
+ private assertTarget(input: unknown): void {
123
+ const target = kodiRecord(input, 'service target');
124
+ kodiKeys(target, ['deviceId', 'entityId']);
125
+ if (target.deviceId === undefined && target.entityId === undefined ||
126
+ target.deviceId !== undefined && target.deviceId !== this.#deviceId ||
127
+ target.entityId !== undefined && target.entityId !== this.#entityId) throw new TypeError('Kodi requires an exact owned device or entity target.');
198
128
  }
129
+ }
199
130
 
200
- private callMethodParams(requestArg: IServiceCallRequest): Record<string, unknown> | unknown[] | undefined {
201
- const explicitParams = requestArg.data?.params;
202
- if (Array.isArray(explicitParams)) {
203
- return explicitParams;
204
- }
205
- if (explicitParams && typeof explicitParams === 'object') {
206
- return explicitParams as Record<string, unknown>;
207
- }
208
- const params: Record<string, unknown> = {};
209
- for (const [key, value] of Object.entries(requestArg.data || {})) {
210
- if (key !== 'method') {
211
- params[key] = value;
212
- }
213
- }
214
- return Object.keys(params).length ? params : undefined;
215
- }
131
+ function kodiFailure(error: unknown): IServiceCallResult {
132
+ const protocolError = error instanceof plugins.ecobridgeDeviceManager.KodiProtocolError ? error : undefined;
133
+ return { success: false, error: protocolError?.message ?? 'Kodi operation was refused or failed.',
134
+ data: { code: protocolError?.code ?? 'invalid-operation', effectOutcome: protocolError?.effectOutcome ?? 'not-sent', ...(protocolError?.rpcErrorCode === undefined ? {} : { rpcErrorCode: protocolError.rpcErrorCode }) } };
216
135
  }
@@ -1,9 +1,9 @@
1
+ import * as plugins from '../../plugins.js';
1
2
  import { DiscoveryDescriptor } from '../../core/classes.discoverydescriptor.js';
2
3
  import type { IDiscoveryCandidate, IDiscoveryMatch, IDiscoveryMatcher, IDiscoveryValidator } from '../../core/types.js';
3
4
  import type { IKodiManualEntry, IKodiMdnsRecord } from './kodi.types.js';
4
5
 
5
6
  const defaultPort = 8080;
6
- const defaultWsPort = 9090;
7
7
  const kodiMdnsType = '_xbmc-jsonrpc-h._tcp.local';
8
8
 
9
9
  export class KodiMdnsMatcher implements IDiscoveryMatcher<IKodiMdnsRecord> {
@@ -20,25 +20,33 @@ export class KodiMdnsMatcher implements IDiscoveryMatcher<IKodiMdnsRecord> {
20
20
  if (!matched) {
21
21
  return { matched: false, confidence: 'low', reason: 'mDNS record is not a Kodi JSON-RPC advertisement.' };
22
22
  }
23
+ let endpoint = kodiEndpoint(recordArg.host, recordArg.port);
24
+ for (const address of recordArg.addresses || []) {
25
+ if (endpoint) break;
26
+ endpoint = kodiEndpoint(address, recordArg.port);
27
+ }
28
+ if (!endpoint) {
29
+ return { matched: false, confidence: 'low', reason: 'Kodi advertisement does not contain a supported numeric HTTP endpoint.' };
30
+ }
23
31
  return {
24
32
  matched: true,
25
- confidence: uuid ? 'certain' : 'high',
26
- reason: 'mDNS record matches Kodi JSON-RPC metadata.',
27
- normalizedDeviceId: uuid,
33
+ confidence: 'high',
34
+ reason: 'mDNS record is a Kodi endpoint hint; application selection still requires a live observation.',
28
35
  candidate: {
29
36
  source: 'mdns',
30
37
  integrationDomain: 'kodi',
31
- id: uuid,
32
- host: recordArg.host || recordArg.addresses?.[0],
33
- port: recordArg.port || defaultPort,
38
+ host: endpoint.host,
39
+ port: endpoint.port,
34
40
  name,
35
41
  manufacturer: 'Kodi',
36
42
  model: valueForKey(properties, 'version') ? 'Kodi Media Center' : undefined,
37
43
  metadata: {
38
44
  mdnsName: recordArg.name,
39
45
  mdnsType: recordArg.type,
40
- txt: properties,
41
- wsPort: defaultWsPort,
46
+ mdnsHost: recordArg.host,
47
+ advertisedId: uuid,
48
+ advertisedVersion: valueForKey(properties, 'version'),
49
+ selectionVerified: false,
42
50
  },
43
51
  },
44
52
  };
@@ -51,30 +59,24 @@ export class KodiManualMatcher implements IDiscoveryMatcher<IKodiManualEntry> {
51
59
  public description = 'Recognize manual Kodi setup entries.';
52
60
 
53
61
  public async matches(inputArg: IKodiManualEntry): Promise<IDiscoveryMatch> {
54
- const haystack = `${inputArg.name || ''} ${inputArg.model || ''} ${inputArg.manufacturer || ''}`.toLowerCase();
55
- const matched = Boolean(inputArg.host || inputArg.metadata?.kodi || haystack.includes('kodi') || haystack.includes('xbmc'));
56
- if (!matched) {
57
- return { matched: false, confidence: 'low', reason: 'Manual entry does not contain Kodi setup hints.' };
62
+ const endpoint = kodiEndpoint(inputArg.host, inputArg.port);
63
+ if (!endpoint) {
64
+ return { matched: false, confidence: 'low', reason: 'Manual Kodi setup requires a supported numeric HTTP endpoint.' };
58
65
  }
59
- const id = inputArg.uuid || inputArg.id;
60
66
  return {
61
67
  matched: true,
62
- confidence: inputArg.host ? 'high' : 'medium',
68
+ confidence: 'high',
63
69
  reason: 'Manual entry can start Kodi setup.',
64
- normalizedDeviceId: id,
65
70
  candidate: {
66
71
  source: 'manual',
67
72
  integrationDomain: 'kodi',
68
- id,
69
- host: inputArg.host,
70
- port: inputArg.port || defaultPort,
73
+ host: endpoint.host,
74
+ port: endpoint.port,
71
75
  name: inputArg.name,
72
76
  manufacturer: inputArg.manufacturer || 'Kodi',
73
77
  model: inputArg.model,
74
78
  metadata: {
75
- ...inputArg.metadata,
76
- wsPort: inputArg.wsPort || defaultWsPort,
77
- ssl: inputArg.ssl,
79
+ selectionVerified: false,
78
80
  },
79
81
  },
80
82
  };
@@ -89,19 +91,25 @@ export class KodiCandidateValidator implements IDiscoveryValidator {
89
91
  const manufacturer = candidateArg.manufacturer?.toLowerCase() || '';
90
92
  const model = candidateArg.model?.toLowerCase() || '';
91
93
  const name = candidateArg.name?.toLowerCase() || '';
92
- const matched = candidateArg.integrationDomain === 'kodi'
94
+ const recognized = candidateArg.integrationDomain === 'kodi'
93
95
  || manufacturer.includes('kodi')
94
96
  || manufacturer.includes('xbmc')
95
97
  || model.includes('kodi')
96
98
  || model.includes('xbmc')
97
99
  || name.includes('kodi')
98
100
  || Boolean(candidateArg.metadata?.kodi);
101
+ if (!recognized) {
102
+ return { matched: false, confidence: 'low', reason: 'Candidate is not Kodi.' };
103
+ }
104
+ const endpoint = kodiEndpoint(candidateArg.host, candidateArg.port);
105
+ if (!endpoint) {
106
+ return { matched: false, confidence: 'low', reason: 'Kodi candidate does not contain a supported numeric HTTP endpoint.' };
107
+ }
99
108
  return {
100
- matched,
101
- confidence: matched && candidateArg.host ? 'high' : matched ? 'medium' : 'low',
102
- reason: matched ? 'Candidate has Kodi metadata.' : 'Candidate is not Kodi.',
103
- candidate: matched ? candidateArg : undefined,
104
- normalizedDeviceId: candidateArg.id,
109
+ matched: true,
110
+ confidence: 'high',
111
+ reason: 'Candidate has Kodi metadata and a numeric endpoint hint; application selection still requires a live observation.',
112
+ candidate: { ...candidateArg, host: endpoint.host, port: endpoint.port },
105
113
  };
106
114
  }
107
115
  }
@@ -113,6 +121,19 @@ export const createKodiDiscoveryDescriptor = (): DiscoveryDescriptor => {
113
121
  .addValidator(new KodiCandidateValidator());
114
122
  };
115
123
 
124
+ /** Select only supplied endpoints; the public foundation owns origin policy. */
125
+ const kodiEndpoint = (hostArg: string | undefined, portArg: number | undefined): { host: string; port: number } | undefined => {
126
+ const port = portArg === undefined ? defaultPort : portArg;
127
+ if (typeof hostArg !== 'string' || typeof port !== 'number' || !Number.isSafeInteger(port)) return undefined;
128
+ try {
129
+ const origin = plugins.ecobridgeDeviceManager.validateKodiOrigin(`http://${hostArg}:${port}`);
130
+ return { host: new URL(origin).hostname, port };
131
+ } catch (error) {
132
+ if (error instanceof plugins.ecobridgeDeviceManager.KodiProtocolError && error.code === 'invalid-options') return undefined;
133
+ throw error;
134
+ }
135
+ };
136
+
116
137
  const normalizeType = (valueArg?: string): string => {
117
138
  return (valueArg || '').toLowerCase().replace(/\.$/, '');
118
139
  };
@@ -1,6 +1,6 @@
1
1
  import * as plugins from '../../plugins.js';
2
2
  import type { IIntegrationEntity } from '../../core/types.js';
3
- import type { IKodiMediaItem, IKodiSnapshot, IKodiTime } from './kodi.types.js';
3
+ import type { IKodiMediaItem, IKodiNativeSnapshot, IKodiSnapshot, IKodiTime } from './kodi.types.js';
4
4
 
5
5
  const kodiMediaTypes: Record<string, string> = {
6
6
  music: 'music',
@@ -19,24 +19,64 @@ const kodiMediaTypes: Record<string, string> = {
19
19
  };
20
20
 
21
21
  export class KodiMapper {
22
+ public static deviceId(snapshot: Pick<IKodiNativeSnapshot, 'homeId' | 'origin'>): string {
23
+ return `kodi:${encodeURIComponent(snapshot.homeId)}:${encodeURIComponent(snapshot.origin)}`;
24
+ }
25
+
26
+ public static entityId(snapshot: Pick<IKodiNativeSnapshot, 'homeId' | 'origin'>): string {
27
+ return `media_player.${this.deviceId(snapshot)}`;
28
+ }
29
+
30
+ public static toNativeDevices(snapshot: IKodiNativeSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
31
+ return [{
32
+ id: this.deviceId(snapshot), integrationDomain: 'kodi', name: snapshot.name, protocol: 'http',
33
+ manufacturer: 'Kodi', model: snapshot.applicationName, online: snapshot.online,
34
+ features: [
35
+ { id: 'volume', capability: 'media', name: 'Application volume', readable: true, writable: snapshot.capabilities.canSetVolume, unit: '%' },
36
+ { id: 'muted', capability: 'media', name: 'Application muted', readable: true, writable: snapshot.capabilities.canSetMuted },
37
+ ],
38
+ state: [
39
+ { featureId: 'volume', value: snapshot.volume, updatedAt: snapshot.observedAt },
40
+ { featureId: 'muted', value: snapshot.muted, updatedAt: snapshot.observedAt },
41
+ ],
42
+ metadata: {
43
+ homeId: snapshot.homeId, origin: snapshot.origin, applicationVersion: snapshot.applicationVersion,
44
+ apiVersion: snapshot.apiVersion, selection: snapshot.selection, uniqueDeviceIdentityVerified: false,
45
+ cryptographicServerIdentityVerified: false, volumeRange: snapshot.capabilities.volumeRange,
46
+ runtimeAuthority: 'native-observation', playbackObserved: false,
47
+ },
48
+ }];
49
+ }
50
+
51
+ public static toNativeEntities(snapshot: IKodiNativeSnapshot): IIntegrationEntity[] {
52
+ return [{
53
+ id: this.entityId(snapshot), uniqueId: this.deviceId(snapshot), integrationDomain: 'kodi',
54
+ deviceId: this.deviceId(snapshot), platform: 'media_player', name: snapshot.name, state: 'unknown', available: snapshot.online,
55
+ attributes: { applicationVolume: snapshot.volume, isVolumeMuted: snapshot.muted, playbackObserved: false,
56
+ applicationName: snapshot.applicationName, applicationVersion: snapshot.applicationVersion, apiVersion: snapshot.apiVersion,
57
+ selection: snapshot.selection, uniqueDeviceIdentityVerified: false, cryptographicServerIdentityVerified: false,
58
+ capabilities: snapshot.capabilities, observedAt: snapshot.observedAt },
59
+ }];
60
+ }
61
+
62
+ /** Converts offline imported data without granting runtime availability or writes. */
22
63
  public static toDevices(snapshotArg: IKodiSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
23
64
  const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
24
65
  const application = snapshotArg.application;
25
66
  return [{
26
- id: this.deviceId(snapshotArg),
67
+ id: this.offlineDeviceId(snapshotArg),
27
68
  integrationDomain: 'kodi',
28
69
  name: this.deviceName(snapshotArg),
29
70
  protocol: 'http',
30
71
  manufacturer: snapshotArg.deviceInfo.manufacturer || 'Kodi',
31
72
  model: snapshotArg.deviceInfo.model || application?.name,
32
- online: snapshotArg.online,
73
+ online: false,
33
74
  features: [
34
- { id: 'playback', capability: 'media', name: 'Playback', readable: true, writable: true },
35
- { id: 'volume', capability: 'media', name: 'Volume', readable: true, writable: true, unit: '%' },
36
- { id: 'muted', capability: 'media', name: 'Muted', readable: true, writable: true },
75
+ { id: 'playback', capability: 'media', name: 'Playback', readable: true, writable: false },
76
+ { id: 'volume', capability: 'media', name: 'Volume', readable: true, writable: false, unit: '%' },
77
+ { id: 'muted', capability: 'media', name: 'Muted', readable: true, writable: false },
37
78
  { id: 'active_player', capability: 'media', name: 'Active player', readable: true, writable: false },
38
79
  { id: 'current_title', capability: 'media', name: 'Current title', readable: true, writable: false },
39
- { id: 'notification', capability: 'media', name: 'Notification', readable: false, writable: true },
40
80
  ],
41
81
  state: [
42
82
  { featureId: 'playback', value: this.mediaState(snapshotArg), updatedAt },
@@ -46,6 +86,7 @@ export class KodiMapper {
46
86
  { featureId: 'current_title', value: this.mediaTitle(snapshotArg.item) || null, updatedAt },
47
87
  ],
48
88
  metadata: {
89
+ runtimeAuthority: 'offline-import', uniqueDeviceIdentityVerified: false,
49
90
  uuid: snapshotArg.deviceInfo.uuid,
50
91
  host: snapshotArg.deviceInfo.host,
51
92
  port: snapshotArg.deviceInfo.port,
@@ -62,11 +103,12 @@ export class KodiMapper {
62
103
  id: `media_player.${this.slug(this.deviceName(snapshotArg))}`,
63
104
  uniqueId: `kodi_${this.uniqueBase(snapshotArg)}`,
64
105
  integrationDomain: 'kodi',
65
- deviceId: this.deviceId(snapshotArg),
106
+ deviceId: this.offlineDeviceId(snapshotArg),
66
107
  platform: 'media_player',
67
108
  name: this.deviceName(snapshotArg),
68
109
  state: this.mediaState(snapshotArg),
69
110
  attributes: {
111
+ runtimeAuthority: 'offline-import', uniqueDeviceIdentityVerified: false,
70
112
  volumeLevel: typeof snapshotArg.application?.volume === 'number' ? snapshotArg.application.volume / 100 : undefined,
71
113
  isVolumeMuted: snapshotArg.application?.muted,
72
114
  mediaContentId: this.mediaContentId(item),
@@ -86,7 +128,7 @@ export class KodiMapper {
86
128
  live: snapshotArg.playerProperties?.live,
87
129
  dynamicRange: this.dynamicRange(item),
88
130
  },
89
- available: snapshotArg.online,
131
+ available: false,
90
132
  }];
91
133
  }
92
134
 
@@ -151,7 +193,7 @@ export class KodiMapper {
151
193
  return Array.isArray(valueArg) ? valueArg[0] : valueArg;
152
194
  }
153
195
 
154
- private static deviceId(snapshotArg: IKodiSnapshot): string {
196
+ private static offlineDeviceId(snapshotArg: IKodiSnapshot): string {
155
197
  return `kodi.device.${this.uniqueBase(snapshotArg)}`;
156
198
  }
157
199