@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,462 +1,153 @@
1
1
  import * as plugins from '../../plugins.js';
2
- import { SimpleLocalClient, SimpleLocalMapper, type IServiceCallRequest, type IServiceCallResult } from '../../core/index.js';
3
- import type { IOnkyoConfig, IOnkyoSnapshot } from './onkyo.types.js';
4
- import { onkyoDefaultName, onkyoDefaultPort, onkyoDefaultTimeoutMs, onkyoProfile } from './onkyo.types.js';
5
-
6
- interface IOnkyoReceiverState {
7
- power: 'on' | 'off' | 'unknown';
8
- volumeRaw?: number;
9
- volumeLevel?: number;
10
- muted?: boolean;
11
- sourceCode?: string;
12
- source?: string;
13
- listeningModeCode?: string;
14
- listeningMode?: string;
15
- }
16
-
17
- const eiscpHeaderSize = 16;
18
- const onkyoSourceCodes: Record<string, string> = {
19
- '00': 'VCR/DVR',
20
- '01': 'CBL/SAT',
21
- '02': 'Game',
22
- '03': 'Aux',
23
- '04': 'Game 2',
24
- '05': 'PC',
25
- '10': 'BD/DVD',
26
- '11': 'Stream Box',
27
- '12': 'TV',
28
- '22': 'Phono',
29
- '23': 'CD',
30
- '24': 'FM',
31
- '25': 'AM',
32
- '26': 'Tuner',
33
- '27': 'Music Server',
34
- '28': 'Internet Radio',
35
- '29': 'USB',
36
- '2B': 'NET',
37
- '2E': 'Bluetooth',
38
- '2F': 'USB DAC',
39
- '40': 'Universal Port',
40
- '44': 'Optical',
41
- '45': 'Coaxial',
42
- };
43
-
44
- const onkyoListeningModes: Record<string, string> = {
45
- '00': 'Stereo',
46
- '01': 'Direct',
47
- '02': 'Surround',
48
- '0C': 'All Channel Stereo',
49
- '0F': 'Mono',
50
- '11': 'Pure Audio',
51
- '40': 'Straight Decode',
52
- FF: 'Auto Surround',
53
- };
54
-
55
- const hdmiOutputCodes: Record<string, string> = {
56
- no: '00',
57
- analog: '00',
58
- yes: '01',
59
- out: '01',
60
- main: '01',
61
- 'out-sub': '02',
62
- sub: '03',
63
- hdbaset: '02',
64
- both: '03',
65
- up: 'UP',
66
- };
67
-
68
- export class OnkyoClient extends SimpleLocalClient<IOnkyoConfig> {
69
- private currentOnkyoSnapshot?: IOnkyoSnapshot;
70
-
71
- constructor(private readonly configArg: IOnkyoConfig) {
72
- super(onkyoProfile, configArg);
73
- }
74
-
75
- public async getSnapshot(forceRefreshArg = false): Promise<IOnkyoSnapshot> {
76
- if (!forceRefreshArg && this.currentOnkyoSnapshot) {
77
- return SimpleLocalMapper.clone(this.currentOnkyoSnapshot) as IOnkyoSnapshot;
78
- }
79
-
80
- if (!forceRefreshArg && this.configArg.snapshot) {
81
- this.currentOnkyoSnapshot = await super.getSnapshot(false) as IOnkyoSnapshot;
82
- return SimpleLocalMapper.clone(this.currentOnkyoSnapshot) as IOnkyoSnapshot;
83
- }
84
-
85
- if (this.configArg.client || this.configArg.snapshotProvider) {
86
- this.currentOnkyoSnapshot = await super.getSnapshot(forceRefreshArg) as IOnkyoSnapshot;
87
- return SimpleLocalMapper.clone(this.currentOnkyoSnapshot) as IOnkyoSnapshot;
88
- }
89
-
90
- if (this.configArg.host && this.configArg.transport !== 'snapshot') {
91
- try {
92
- this.currentOnkyoSnapshot = await this.readEiscpSnapshot();
93
- } catch (errorArg) {
94
- this.currentOnkyoSnapshot = this.createOfflineSnapshot(errorMessage(errorArg));
95
- }
96
- return SimpleLocalMapper.clone(this.currentOnkyoSnapshot) as IOnkyoSnapshot;
97
- }
98
-
99
- this.currentOnkyoSnapshot = await super.getSnapshot(forceRefreshArg) as IOnkyoSnapshot;
100
- return SimpleLocalMapper.clone(this.currentOnkyoSnapshot) as IOnkyoSnapshot;
101
- }
102
-
103
- public async refresh(): Promise<IServiceCallResult> {
104
- this.currentOnkyoSnapshot = undefined;
105
- const snapshot = await this.getSnapshot(true);
106
- const success = snapshot.online && !snapshot.error;
107
- return { success, error: success ? undefined : snapshot.error, data: snapshot };
108
- }
109
-
110
- public async execute(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
111
- if (!this.configArg.host || this.configArg.transport === 'snapshot') {
112
- return super.execute(requestArg);
113
- }
114
-
115
- try {
116
- const data = await this.executeEiscpCommand(requestArg);
117
- this.currentOnkyoSnapshot = undefined;
118
- return { success: true, data };
119
- } catch (errorArg) {
120
- return { success: false, error: errorMessage(errorArg) };
121
- }
122
- }
123
-
124
- private async readEiscpSnapshot(): Promise<IOnkyoSnapshot> {
125
- const state = await this.queryReceiverState();
126
- const name = this.configArg.name || stringConfig(this.configArg, 'modelName') || onkyoDefaultName;
127
- const uniqueBase = this.configArg.uniqueId || this.configArg.deviceId || this.configArg.macAddress || `${this.host()}:${this.port()}`;
128
- const rawData = {
129
- state,
130
- sourceList: sourceList(this.configArg),
131
- volumeResolution: this.volumeResolution(),
132
- fetchedAt: new Date().toISOString(),
133
- };
134
-
135
- return {
136
- device: {
137
- id: uniqueBase,
138
- name,
139
- manufacturer: 'Onkyo / Pioneer',
140
- model: stringConfig(this.configArg, 'modelName') || stringConfig(this.configArg, 'model') || 'eISCP receiver',
141
- serialNumber: this.configArg.macAddress || this.configArg.deviceId,
142
- host: this.host(),
143
- port: this.port(),
144
- protocol: 'tcp',
145
- configurationUrl: `tcp://${this.host()}:${this.port()}`,
146
- },
147
- entities: [{
148
- id: 'media_player',
149
- uniqueId: `${onkyoProfile.domain}_${SimpleLocalMapper.slug(uniqueBase)}_media_player`,
150
- name,
151
- platform: 'media_player',
152
- state: state.power,
153
- available: state.power !== 'unknown',
154
- writable: true,
155
- attributes: {
156
- source: state.source,
157
- source_code: state.sourceCode,
158
- source_list: sourceList(this.configArg),
159
- volume_level: state.volumeLevel,
160
- volume_raw: state.volumeRaw,
161
- is_volume_muted: state.muted,
162
- sound_mode: state.listeningMode,
163
- sound_mode_code: state.listeningModeCode,
164
- },
165
- }],
166
- online: true,
167
- updatedAt: new Date().toISOString(),
168
- source: 'tcp',
169
- rawData,
170
- capabilities: {
171
- localRead: true,
172
- localControl: true,
173
- liveControlRequiresExecutor: false,
174
- },
175
- };
176
- }
177
-
178
- private async queryReceiverState(): Promise<IOnkyoReceiverState> {
179
- const powerValue = await this.queryValue('PWR');
180
- if (!powerValue) {
181
- throw new Error('Onkyo eISCP power query returned no usable PWR status.');
182
- }
183
- const [volumeValue, muteValue, sourceValue, listeningModeValue] = await Promise.all([
184
- optional(() => this.queryValue('MVL')),
185
- optional(() => this.queryValue('AMT')),
186
- optional(() => this.queryValue('SLI')),
187
- optional(() => this.queryValue('LMD')),
188
- ]);
189
- const volumeRaw = volumeValue ? Number.parseInt(volumeValue, 16) : undefined;
190
- const sourceCode = sourceValue?.toUpperCase();
191
- const listeningModeCode = listeningModeValue?.toUpperCase();
192
-
193
- return {
194
- power: powerValue === '01' ? 'on' : powerValue === '00' ? 'off' : 'unknown',
195
- volumeRaw: Number.isFinite(volumeRaw) ? volumeRaw : undefined,
196
- volumeLevel: Number.isFinite(volumeRaw) ? clamp(Number(((volumeRaw as number) / (this.volumeResolution() * (this.maxVolume() / 100))).toFixed(3)), 0, 1) : undefined,
197
- muted: muteValue === undefined ? undefined : muteValue === '01',
198
- sourceCode,
199
- source: sourceCode ? sourceName(sourceCode, this.configArg) : undefined,
200
- listeningModeCode,
201
- listeningMode: listeningModeCode ? onkyoListeningModes[listeningModeCode] || listeningModeCode : undefined,
202
- };
203
- }
204
-
205
- private async executeEiscpCommand(requestArg: IServiceCallRequest): Promise<unknown> {
206
- const service = requestArg.service;
207
- if (service === 'turn_on') {
208
- return { response: await this.sendCommand('PWR01') };
209
- }
210
- if (service === 'turn_off') {
211
- return { response: await this.sendCommand('PWR00') };
212
- }
213
- if (service === 'toggle') {
214
- const power = await this.queryValue('PWR');
215
- return { response: await this.sendCommand(power === '01' ? 'PWR00' : 'PWR01') };
216
- }
217
- if (service === 'volume_up') {
218
- return { response: await this.sendCommand('MVLUP') };
219
- }
220
- if (service === 'volume_down') {
221
- return { response: await this.sendCommand('MVLDOWN') };
222
- }
223
- if (service === 'volume_set' || service === 'set_volume' || service === 'set_volume_level') {
224
- const level = numberData(requestArg, 'volume_level') ?? numberData(requestArg, 'volumeLevel') ?? numberData(requestArg, 'level');
225
- if (level === undefined) {
226
- throw new Error('Onkyo volume_set requires data.volume_level.');
227
- }
228
- const raw = clamp(Math.round(level * (this.maxVolume() / 100) * this.volumeResolution()), 0, this.volumeResolution());
229
- return { response: await this.sendCommand(`MVL${hex(raw)}`), volumeRaw: raw };
230
- }
231
- if (service === 'volume_mute' || service === 'mute') {
232
- const muted = booleanData(requestArg, 'is_volume_muted') ?? booleanData(requestArg, 'mute') ?? booleanData(requestArg, 'muted');
233
- if (muted === undefined) {
234
- throw new Error('Onkyo volume_mute requires data.is_volume_muted or data.mute.');
235
- }
236
- return { response: await this.sendCommand(`AMT${muted ? '01' : '00'}`) };
237
- }
238
- if (service === 'media_play') {
239
- return { response: await this.sendCommand('NTCPLAY') };
240
- }
241
- if (service === 'media_pause') {
242
- return { response: await this.sendCommand('NTCPAUSE') };
243
- }
244
- if (service === 'media_stop') {
245
- return { response: await this.sendCommand('NTCSTOP') };
246
- }
247
- if (service === 'select_source' || service === 'set_source') {
248
- const source = stringData(requestArg, 'source');
249
- if (!source) {
250
- throw new Error('Onkyo select_source requires data.source.');
251
- }
252
- const code = sourceCode(source, this.configArg);
253
- if (!code) {
254
- throw new Error(`Unsupported Onkyo input source: ${source}.`);
255
- }
256
- return { response: await this.sendCommand(`SLI${code}`), source, sourceCode: code };
257
- }
258
- if (service === 'onkyo_select_hdmi_output' || service === 'select_hdmi_output') {
259
- const output = stringData(requestArg, 'hdmi_output') || stringData(requestArg, 'output');
260
- const code = output ? hdmiOutputCodes[normalizeKey(output)] : undefined;
261
- if (!code) {
262
- throw new Error('Onkyo HDMI output selection requires data.hdmi_output with a supported value.');
263
- }
264
- return { response: await this.sendCommand(`HDO${code}`), hdmiOutput: output };
265
- }
266
- throw new Error(`Unsupported Onkyo eISCP service: ${requestArg.domain}.${service}`);
267
- }
268
-
269
- private async queryValue(prefixArg: string): Promise<string | undefined> {
270
- const response = await this.sendCommand(`${prefixArg}QSTN`, prefixArg);
271
- return response.startsWith(prefixArg) ? response.slice(prefixArg.length) : undefined;
272
- }
273
-
274
- private async sendCommand(commandArg: string, responsePrefixArg = commandArg.slice(0, 3)): Promise<string> {
275
- const frame = buildEiscpFrame(commandArg);
276
- const host = this.host();
277
- const port = this.port();
278
- const timeoutMs = this.timeoutMs();
279
-
280
- return new Promise<string>((resolve, reject) => {
281
- const socket = plugins.net.createConnection({ host, port });
282
- let buffer = Buffer.alloc(0);
283
- let settled = false;
284
-
285
- const finish = (errorArg?: Error, responseArg?: string) => {
286
- if (settled) {
287
- return;
288
- }
289
- settled = true;
290
- socket.removeAllListeners();
291
- socket.destroy();
292
- if (errorArg) {
293
- reject(errorArg);
294
- return;
295
- }
296
- resolve(responseArg || '');
297
- };
298
-
299
- socket.setTimeout(timeoutMs, () => finish(new Error(`Onkyo eISCP request to ${host}:${port} timed out after ${timeoutMs}ms.`)));
300
- socket.on('connect', () => socket.write(frame));
301
- socket.on('data', (chunkArg) => {
302
- buffer = Buffer.concat([buffer, Buffer.isBuffer(chunkArg) ? chunkArg : Buffer.from(chunkArg)]);
303
- const parsed = parseEiscpResponses(buffer);
304
- buffer = Buffer.from(parsed.remaining);
305
- const response = parsed.messages.find((messageArg) => messageArg.startsWith(responsePrefixArg));
306
- if (response) {
307
- finish(undefined, response);
308
- }
309
- });
310
- socket.on('end', () => finish(new Error(`Onkyo eISCP connection to ${host}:${port} closed before a response was received.`)));
311
- socket.on('close', () => finish(new Error(`Onkyo eISCP connection to ${host}:${port} closed before a response was received.`)));
312
- socket.on('error', (errorArg) => finish(errorArg));
2
+ import { NativeHomeAdmission } from '../../core/classes.nativehomeadmission.js';
3
+ import type { INativeIntegrationSetupContext } from '../../core/types.js';
4
+ import { OnkyoMapper } from './onkyo.mapper.js';
5
+ import type { IOnkyoConfig, IOnkyoSnapshot, TOnkyoClientEvent } from './onkyo.types.js';
6
+ import { normalizeOnkyoConfig, onkyoBoolean, onkyoInputId, onkyoInteger } from './onkyo.validation.js';
7
+
8
+ interface IOnkyoSubscriber {
9
+ handler: (eventArg: TOnkyoClientEvent) => void;
10
+ unsubscribe: () => void;
11
+ }
12
+
13
+ export class OnkyoClient {
14
+ readonly #config: ReturnType<typeof normalizeOnkyoConfig>;
15
+ readonly #homeId: string;
16
+ readonly #protocol: plugins.ecobridgeDeviceManager.OnkyoProtocol;
17
+ readonly #lifetime = new AbortController();
18
+ readonly #operations = new Set<Promise<unknown>>();
19
+ readonly #subscribers = new Set<IOnkyoSubscriber>();
20
+ readonly #parentSignal?: AbortSignal;
21
+ readonly #onParentAbort: () => void;
22
+ #healthy = false;
23
+ #closed = false;
24
+ #closePromise?: Promise<void>;
25
+
26
+ constructor(configArg: IOnkyoConfig, contextArg: INativeIntegrationSetupContext, signalArg?: AbortSignal) {
27
+ this.#config = normalizeOnkyoConfig(configArg);
28
+ const context = new NativeHomeAdmission('onkyo').admit(contextArg, this.#config.homeId);
29
+ this.#homeId = context.homeId;
30
+ if (signalArg !== undefined && !(signalArg instanceof AbortSignal)) throw new TypeError('Onkyo lifetime signal must be an AbortSignal.');
31
+ signalArg = signalArg && context.abortSignal ? AbortSignal.any([signalArg, context.abortSignal]) : signalArg ?? context.abortSignal;
32
+ this.#protocol = new plugins.ecobridgeDeviceManager.OnkyoProtocol({
33
+ address: this.#config.host, port: this.#config.port, expectedMacAddress: this.#config.macAddress, expectedModel: this.#config.model,
34
+ timeoutMs: this.#config.requestTimeoutMs, maxQueuedOperations: this.#config.maxPendingOperations,
313
35
  });
314
- }
315
-
316
- private host(): string {
317
- if (!this.configArg.host) {
318
- throw new Error('Onkyo eISCP requires config.host.');
319
- }
320
- return this.configArg.host;
321
- }
322
-
323
- private port(): number {
324
- return this.configArg.port || onkyoDefaultPort;
325
- }
326
-
327
- private timeoutMs(): number {
328
- return this.configArg.timeoutMs || onkyoDefaultTimeoutMs;
329
- }
330
-
331
- private volumeResolution(): number {
332
- return numberConfig(this.configArg, 'volumeResolution') || numberConfig(this.configArg, 'volume_resolution') || 50;
333
- }
334
-
335
- private maxVolume(): number {
336
- return numberConfig(this.configArg, 'maxVolume') || numberConfig(this.configArg, 'max_volume') || 100;
337
- }
338
-
339
- private createOfflineSnapshot(errorArg: string): IOnkyoSnapshot {
340
- return SimpleLocalMapper.toSnapshot({ profile: onkyoProfile, config: this.configArg, rawData: this.configArg.rawData, online: false, source: 'runtime', error: errorArg }) as IOnkyoSnapshot;
341
- }
342
- }
343
-
344
- function buildEiscpFrame(commandArg: string): Buffer {
345
- const data = Buffer.from(`!1${commandArg}\r`, 'ascii');
346
- const header = Buffer.alloc(eiscpHeaderSize);
347
- header.write('ISCP', 0, 'ascii');
348
- header.writeUInt32BE(eiscpHeaderSize, 4);
349
- header.writeUInt32BE(data.length, 8);
350
- header.writeUInt8(1, 12);
351
- return Buffer.concat([header, data]);
352
- }
353
-
354
- function parseEiscpResponses(bufferArg: Buffer): { messages: string[]; remaining: Buffer } {
355
- const messages: string[] = [];
356
- let offset = 0;
357
- while (bufferArg.length - offset >= eiscpHeaderSize) {
358
- if (bufferArg.subarray(offset, offset + 4).toString('ascii') !== 'ISCP') {
359
- offset++;
360
- continue;
361
- }
362
- const headerSize = bufferArg.readUInt32BE(offset + 4);
363
- const dataSize = bufferArg.readUInt32BE(offset + 8);
364
- const frameSize = headerSize + dataSize;
365
- if (bufferArg.length - offset < frameSize) {
366
- break;
367
- }
368
- const body = bufferArg.subarray(offset + headerSize, offset + frameSize).toString('ascii').replace(/[\u0000\u001a\r\n]+$/g, '');
369
- if (body.startsWith('!') && body.length >= 5) {
370
- messages.push(body.slice(2));
36
+ this.#parentSignal = signalArg;
37
+ // The terminal memo remains rejected for its owning lease or explicit caller.
38
+ this.#onParentAbort = () => { void this.destroy().catch(() => undefined); };
39
+ signalArg?.addEventListener('abort', this.#onParentAbort, { once: true });
40
+ if (signalArg?.aborted) this.#onParentAbort();
41
+ }
42
+
43
+ public isHealthy(): boolean { return this.#healthy && !this.#closed && !this.#protocol.isClosed; }
44
+ public getSnapshot(signalArg?: AbortSignal): Promise<IOnkyoSnapshot> {
45
+ return this.#run((signal) => this.#inspect(signal), signalArg);
46
+ }
47
+ public setPower(valueArg: boolean, signalArg?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IOnkyoControlObservation> {
48
+ const value = onkyoBoolean(valueArg, 'power');
49
+ return this.#run((signal) => this.#control('power', value, signal), signalArg);
50
+ }
51
+ public setMuted(valueArg: boolean, signalArg?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IOnkyoControlObservation> {
52
+ const value = onkyoBoolean(valueArg, 'mute');
53
+ return this.#run((signal) => this.#control('mute', value, signal), signalArg);
54
+ }
55
+ public setVolume(valueArg: number, signalArg?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IOnkyoControlObservation> {
56
+ const value = onkyoInteger(valueArg, 0, this.#config.volumeLimitRaw, 'raw volume');
57
+ return this.#run((signal) => this.#control('volume_raw', value, signal), signalArg);
58
+ }
59
+ public setInput(valueArg: string, signalArg?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IOnkyoControlObservation> {
60
+ const value = onkyoInputId(valueArg);
61
+ return this.#run((signal) => this.#control('input', value, signal), signalArg);
62
+ }
63
+ public writeFeature(idArg: string, valueArg: plugins.shxInterfaces.data.TDeviceStateValue, signalArg?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IOnkyoControlObservation> {
64
+ const value = idArg === 'power' || idArg === 'mute' ? onkyoBoolean(valueArg, idArg) :
65
+ idArg === 'volume_raw' ? onkyoInteger(valueArg, 0, this.#config.volumeLimitRaw, 'raw volume') :
66
+ idArg === 'input' ? onkyoInputId(valueArg) : undefined;
67
+ if (value === undefined) throw new TypeError('Onkyo feature is not writable.');
68
+ return this.#run(async (signal) => {
69
+ const current = OnkyoMapper.toDevices(await this.#inspect(signal))[0].features.find((featureArg) => featureArg.id === idArg);
70
+ if (!current?.writable) throw new TypeError('Onkyo current canonical feature is not writable.');
71
+ signal.throwIfAborted();
72
+ return this.#control(idArg, value, signal);
73
+ }, signalArg);
74
+ }
75
+ public subscribe(handlerArg: (eventArg: TOnkyoClientEvent) => void, signalArg?: AbortSignal): () => void {
76
+ if (this.#closed || this.#protocol.isClosed) throw new Error('Onkyo client is closed.');
77
+ if (typeof handlerArg !== 'function') throw new TypeError('Onkyo subscriber must be a function.');
78
+ if (signalArg !== undefined && !(signalArg instanceof AbortSignal)) throw new TypeError('Onkyo subscription signal must be an AbortSignal.');
79
+ signalArg?.throwIfAborted();
80
+ const subscriber: IOnkyoSubscriber = { handler: handlerArg, unsubscribe: () => {
81
+ signalArg?.removeEventListener('abort', subscriber.unsubscribe);
82
+ this.#subscribers.delete(subscriber);
83
+ } };
84
+ this.#subscribers.add(subscriber);
85
+ signalArg?.addEventListener('abort', subscriber.unsubscribe, { once: true });
86
+ return subscriber.unsubscribe;
87
+ }
88
+ public destroy(): Promise<void> {
89
+ if (this.#closePromise) return this.#closePromise;
90
+ this.#closed = true;
91
+ this.#healthy = false;
92
+ this.#parentSignal?.removeEventListener('abort', this.#onParentAbort);
93
+ for (const subscriber of this.#subscribers) subscriber.unsubscribe();
94
+ this.#closePromise = Promise.resolve().then(async () => {
95
+ const close = Promise.resolve().then(() => this.#protocol.close());
96
+ const results = await Promise.allSettled([close, ...this.#operations]);
97
+ if (results[0].status === 'rejected') throw results[0].reason;
98
+ });
99
+ this.#lifetime.abort(new Error('Onkyo client is destroyed.'));
100
+ return this.#closePromise;
101
+ }
102
+ async #inspect(signalArg: AbortSignal): Promise<IOnkyoSnapshot> {
103
+ const state = await this.#protocol.inspect({ signal: signalArg });
104
+ const snapshot: IOnkyoSnapshot = Object.freeze({ ...state, homeId: this.#homeId,
105
+ name: this.#config.name ?? `${state.receiver.model} main zone`, volumeLimitRaw: this.#config.volumeLimitRaw, online: true });
106
+ this.#emit({ type: 'snapshot', snapshot });
107
+ return snapshot;
108
+ }
109
+ async #control(idArg: string, valueArg: boolean | number | string, signalArg: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IOnkyoControlObservation> {
110
+ const options = { signal: signalArg };
111
+ let observation: plugins.ecobridgeDeviceManager.IOnkyoControlObservation;
112
+ if (idArg === 'power' && typeof valueArg === 'boolean') observation = await this.#protocol.setPower(valueArg, options);
113
+ else if (idArg === 'mute' && typeof valueArg === 'boolean') observation = await this.#protocol.setMuted(valueArg, options);
114
+ else if (idArg === 'volume_raw' && typeof valueArg === 'number') observation = await this.#protocol.setVolume(valueArg, options);
115
+ else if (idArg === 'input' && typeof valueArg === 'string') observation = await this.#protocol.setInput(valueArg, options);
116
+ else throw new TypeError('Onkyo control requires an explicit supported value.');
117
+ this.#emit({ type: 'control', observation });
118
+ return observation;
119
+ }
120
+ #run<TResult>(workArg: (signalArg: AbortSignal) => Promise<TResult>, signalArg?: AbortSignal): Promise<TResult> {
121
+ if (this.#closed || this.#protocol.isClosed) return Promise.reject(new plugins.ecobridgeDeviceManager.OnkyoProtocolError('closed', 'Onkyo client is terminally closed.'));
122
+ if (signalArg !== undefined && !(signalArg instanceof AbortSignal)) return Promise.reject(new TypeError('Onkyo operation signal must be an AbortSignal.'));
123
+ if (signalArg?.aborted) return Promise.reject(new plugins.ecobridgeDeviceManager.OnkyoProtocolError('cancelled', 'Onkyo operation was cancelled before admission.'));
124
+ if (this.#operations.size >= this.#config.maxPendingOperations) return Promise.reject(new plugins.ecobridgeDeviceManager.OnkyoProtocolError('capacity', 'Onkyo client operation capacity is full.'));
125
+ const deadline = new AbortController();
126
+ const signal = AbortSignal.any([this.#lifetime.signal, deadline.signal, ...(signalArg ? [signalArg] : [])]);
127
+ const timer = setTimeout(() => deadline.abort(), this.#config.requestTimeoutMs);
128
+ timer.unref();
129
+ const operation = Promise.resolve().then(() => { signal.throwIfAborted(); return workArg(signal); }).then((resultArg) => {
130
+ this.#healthy = !this.#closed && !signal.aborted && !this.#protocol.isClosed;
131
+ return resultArg;
132
+ }, (errorArg: unknown) => {
133
+ this.#healthy = false;
134
+ const failure = deadline.signal.aborted && errorArg instanceof plugins.ecobridgeDeviceManager.OnkyoProtocolError ?
135
+ new plugins.ecobridgeDeviceManager.OnkyoProtocolError('timeout', 'Onkyo consumer operation deadline exceeded.', errorArg.effectOutcome) : errorArg;
136
+ if (!this.#closed && failure instanceof Error) this.#emit({ type: 'error', error: failure });
137
+ throw failure;
138
+ }).finally(() => { clearTimeout(timer); this.#operations.delete(operation); });
139
+ this.#operations.add(operation);
140
+ return operation;
141
+ }
142
+ #emit(eventArg: TOnkyoClientEvent): void {
143
+ if (this.#closed) return;
144
+ for (const subscriber of [...this.#subscribers]) {
145
+ if (!this.#subscribers.has(subscriber)) continue;
146
+ try { subscriber.handler(structuredClone(eventArg)); }
147
+ catch {
148
+ subscriber.unsubscribe();
149
+ this.#emit({ type: 'error', error: new Error('Onkyo subscriber callback failed and was removed.') });
150
+ }
371
151
  }
372
- offset += frameSize;
373
- }
374
- return { messages, remaining: Buffer.from(bufferArg.subarray(offset)) };
375
- }
376
-
377
- async function optional<TValue>(callbackArg: () => Promise<TValue>): Promise<TValue | undefined> {
378
- try {
379
- return await callbackArg();
380
- } catch {
381
- return undefined;
382
- }
383
- }
384
-
385
- function sourceList(configArg: IOnkyoConfig): string[] {
386
- const configured = recordConfig(configArg, 'sourceMap') || recordConfig(configArg, 'inputSources') || recordConfig(configArg, 'input_sources');
387
- if (configured) {
388
- return Object.values(configured).filter((valueArg): valueArg is string => typeof valueArg === 'string' && valueArg.trim().length > 0);
389
152
  }
390
- return Object.values(onkyoSourceCodes);
391
- }
392
-
393
- function sourceName(codeArg: string, configArg: IOnkyoConfig): string {
394
- const configured = recordConfig(configArg, 'sourceMap') || recordConfig(configArg, 'inputSources') || recordConfig(configArg, 'input_sources');
395
- const configuredName = configured?.[codeArg];
396
- return typeof configuredName === 'string' && configuredName.trim() ? configuredName : onkyoSourceCodes[codeArg] || codeArg;
397
- }
398
-
399
- function sourceCode(sourceArg: string, configArg: IOnkyoConfig): string | undefined {
400
- const normalized = normalizeKey(sourceArg);
401
- const configured = recordConfig(configArg, 'sourceMap') || recordConfig(configArg, 'inputSources') || recordConfig(configArg, 'input_sources');
402
- const configuredMatch = configured ? Object.entries(configured).find(([codeArg, nameArg]) => normalizeKey(codeArg) === normalized || normalizeKey(String(nameArg)) === normalized) : undefined;
403
- if (configuredMatch) {
404
- return configuredMatch[0].toUpperCase();
405
- }
406
- return Object.entries(onkyoSourceCodes).find(([codeArg, nameArg]) => normalizeKey(codeArg) === normalized || normalizeKey(nameArg) === normalized)?.[0];
407
- }
408
-
409
- function normalizeKey(valueArg: string): string {
410
- return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '');
411
- }
412
-
413
- function hex(valueArg: number): string {
414
- return Math.round(valueArg).toString(16).toUpperCase().padStart(2, '0');
415
- }
416
-
417
- function clamp(valueArg: number, minArg: number, maxArg: number): number {
418
- return Math.max(minArg, Math.min(maxArg, valueArg));
419
- }
420
-
421
- function numberData(requestArg: IServiceCallRequest, keyArg: string): number | undefined {
422
- const value = requestArg.data?.[keyArg];
423
- if (typeof value === 'number' && Number.isFinite(value)) {
424
- return value;
425
- }
426
- if (typeof value === 'string' && value.trim() && Number.isFinite(Number(value))) {
427
- return Number(value);
428
- }
429
- return undefined;
430
- }
431
-
432
- function booleanData(requestArg: IServiceCallRequest, keyArg: string): boolean | undefined {
433
- const value = requestArg.data?.[keyArg];
434
- return typeof value === 'boolean' ? value : undefined;
435
- }
436
-
437
- function stringData(requestArg: IServiceCallRequest, keyArg: string): string | undefined {
438
- const value = requestArg.data?.[keyArg];
439
- return typeof value === 'string' && value.trim() ? value.trim() : undefined;
440
- }
441
-
442
- function numberConfig(configArg: IOnkyoConfig, keyArg: string): number | undefined {
443
- const value = configArg[keyArg];
444
- return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
445
- }
446
-
447
- function stringConfig(configArg: IOnkyoConfig, keyArg: string): string | undefined {
448
- const value = configArg[keyArg];
449
- return typeof value === 'string' && value.trim() ? value.trim() : undefined;
450
- }
451
-
452
- function recordConfig(configArg: IOnkyoConfig, keyArg: string): Record<string, string> | undefined {
453
- const value = configArg[keyArg];
454
- if (!value || typeof value !== 'object' || Array.isArray(value)) {
455
- return undefined;
456
- }
457
- return Object.fromEntries(Object.entries(value as Record<string, unknown>).filter(([, valueArg]) => typeof valueArg === 'string')) as Record<string, string>;
458
- }
459
-
460
- function errorMessage(errorArg: unknown): string {
461
- return errorArg instanceof Error ? errorArg.message : String(errorArg);
462
153
  }