@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
@@ -0,0 +1,56 @@
1
+ import type { IPanasonicVieraConfig } from './panasonic_viera.types.js';
2
+
3
+ export function panasonicVieraRecord(valueArg: unknown, keysArg?: readonly string[]): Record<string, unknown> {
4
+ if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg) ||
5
+ ![Object.prototype, null].includes(Object.getPrototypeOf(valueArg))) {
6
+ throw new TypeError('Panasonic Viera input must be a plain data object.');
7
+ }
8
+ const result: Record<string, unknown> = {};
9
+ for (const key of Reflect.ownKeys(valueArg)) {
10
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
11
+ if (typeof key !== 'string' || !descriptor || !('value' in descriptor) || !descriptor.enumerable ||
12
+ keysArg && !keysArg.includes(key)) throw new TypeError('Panasonic Viera input contains unsupported fields or accessors.');
13
+ Object.defineProperty(result, key, { value: descriptor.value, enumerable: true });
14
+ }
15
+ return result;
16
+ }
17
+
18
+ export function panasonicVieraText(valueArg: unknown, nameArg: string, maximumArg = 256): string {
19
+ if (typeof valueArg !== 'string' || !valueArg.trim() || valueArg.length > maximumArg || /[\p{Cc}\p{Cs}]/u.test(valueArg)) {
20
+ throw new TypeError(`Panasonic Viera ${nameArg} must be a bounded non-empty string without control characters.`);
21
+ }
22
+ return valueArg;
23
+ }
24
+
25
+ function optionalInteger(valueArg: unknown, minimumArg: number, maximumArg: number): number | undefined {
26
+ if (valueArg === undefined) return undefined;
27
+ if (typeof valueArg !== 'number' || !Number.isSafeInteger(valueArg) || valueArg < minimumArg || valueArg > maximumArg) {
28
+ throw new TypeError('Panasonic Viera numeric bound is invalid.');
29
+ }
30
+ return valueArg;
31
+ }
32
+
33
+ export function normalizePanasonicVieraConfig(valueArg: unknown): Readonly<IPanasonicVieraConfig> {
34
+ const config = panasonicVieraRecord(valueArg, ['homeId', 'host', 'descriptionUrl', 'expectedUdn', 'expectedModelName', 'allowUnencryptedLan', 'name', 'timeoutMs', 'maxResponseBytes']);
35
+ if (config.allowUnencryptedLan !== true) throw new TypeError('Panasonic Viera requires explicit allowUnencryptedLan: true.');
36
+ // The owning protocol validates the selected private address, exact description origin and UPnP identity.
37
+ return Object.freeze({
38
+ homeId: panasonicVieraText(config.homeId, 'homeId'),
39
+ host: panasonicVieraText(config.host, 'host'),
40
+ descriptionUrl: panasonicVieraText(config.descriptionUrl, 'descriptionUrl', 4096),
41
+ expectedUdn: panasonicVieraText(config.expectedUdn, 'expectedUdn'),
42
+ expectedModelName: panasonicVieraText(config.expectedModelName, 'expectedModelName'),
43
+ allowUnencryptedLan: true,
44
+ name: config.name === undefined ? undefined : panasonicVieraText(config.name, 'name'),
45
+ timeoutMs: optionalInteger(config.timeoutMs, 1, 60_000),
46
+ maxResponseBytes: optionalInteger(config.maxResponseBytes, 256, 1024 * 1024),
47
+ });
48
+ }
49
+
50
+ /** Cleanup failures remain observable after every admitted operation has settled. */
51
+ export async function drainPanasonicVieraCleanup(cleanupsArg: readonly Promise<unknown>[], operationsArg: readonly Promise<unknown>[], messageArg: string): Promise<void> {
52
+ const [cleanups] = await Promise.all([Promise.allSettled(cleanupsArg), Promise.allSettled(operationsArg)]);
53
+ const errors: unknown[] = cleanups.filter((resultArg): resultArg is PromiseRejectedResult => resultArg.status === 'rejected').map((resultArg) => resultArg.reason);
54
+ if (errors.length === 1) throw errors[0];
55
+ if (errors.length > 1) throw new AggregateError(errors, messageArg);
56
+ }
@@ -1,462 +1,166 @@
1
1
  import * as plugins from '../../plugins.js';
2
- import { SimpleLocalClient, SimpleLocalMapper, type ISimpleLocalEntitySnapshot, type IServiceCallRequest, type IServiceCallResult } from '../../core/index.js';
3
- import type { IPioneerConfig, IPioneerSnapshot } from './pioneer.types.js';
4
- import { pioneerDefaultName, pioneerDefaultPort, pioneerMaxSourceNumbers, pioneerMaxVolume, pioneerProfile } from './pioneer.types.js';
5
-
6
- export class PioneerClient extends SimpleLocalClient<IPioneerConfig> {
7
- private liveSnapshot?: IPioneerSnapshot;
8
-
9
- constructor(private readonly configArg: IPioneerConfig) {
10
- super(pioneerProfile, configArg);
11
- }
12
-
13
- public override async getSnapshot(forceRefreshArg = false): Promise<IPioneerSnapshot> {
14
- if (!forceRefreshArg && this.liveSnapshot) {
15
- return SimpleLocalMapper.clone(this.liveSnapshot);
16
- }
17
-
18
- if (this.shouldUseNativeTelnet(forceRefreshArg)) {
19
- try {
20
- this.liveSnapshot = await this.fetchSnapshot();
21
- } catch (errorArg) {
22
- this.liveSnapshot = this.createOfflineSnapshot(errorMessage(errorArg));
23
- }
24
- return SimpleLocalMapper.clone(this.liveSnapshot);
25
- }
26
-
27
- this.liveSnapshot = await super.getSnapshot(forceRefreshArg) as IPioneerSnapshot;
28
- return SimpleLocalMapper.clone(this.liveSnapshot);
29
- }
30
-
31
- public override async refresh(): Promise<IServiceCallResult> {
32
- this.liveSnapshot = undefined;
33
- const snapshot = await this.getSnapshot(true);
34
- const success = snapshot.online && !snapshot.error;
35
- return { success, error: success ? undefined : snapshot.error, data: snapshot };
2
+ import type { INativeIntegrationSetupContext } from '../../core/types.js';
3
+ import { NativeHomeAdmission, type INativeAdmissionContext } from '../../core/classes.nativehomeadmission.js';
4
+ import type { IPioneerConfig, IPioneerEffectResult, IPioneerSnapshot, TPioneerControl } from './pioneer.types.js';
5
+ import { normalizePioneerConfig, validatePioneerControl } from './pioneer.validation.js';
6
+
7
+ /** Home admission and caller work belong here; the published foundation owns the wire. */
8
+ export class PioneerClient {
9
+ public readonly config: ReturnType<typeof normalizePioneerConfig>;
10
+ private readonly protocol: plugins.ecobridgeDeviceManager.PioneerProtocol;
11
+ private readonly admission = new NativeHomeAdmission('pioneer');
12
+ private readonly context: INativeAdmissionContext;
13
+ private readonly lifetime = new AbortController();
14
+ private operationTail: Promise<void> = Promise.resolve();
15
+ private pendingOperations = 0;
16
+ private startPromise?: Promise<IPioneerSnapshot>;
17
+ private snapshot?: IPioneerSnapshot;
18
+ private closePromise?: Promise<void>;
19
+ private retryPromise?: Promise<void>;
20
+
21
+ public constructor(config: IPioneerConfig, context: INativeIntegrationSetupContext) {
22
+ this.config = normalizePioneerConfig(config);
23
+ this.context = this.admission.admit(context, this.config.homeId);
24
+ this.protocol = new plugins.ecobridgeDeviceManager.PioneerProtocol({
25
+ address: this.config.host, descriptionUrl: this.config.descriptionUrl, expectedUdn: this.config.expectedUdn,
26
+ expectedModel: this.config.model, allowUnencryptedLan: this.config.allowUnencryptedLan,
27
+ maximumVolumeRaw: this.config.maximumVolumeRaw, port: this.config.port, timeoutMs: this.config.timeoutMs,
28
+ maxPendingOperations: this.config.maxPendingOperations, maxDescriptionBytes: this.config.maxDescriptionBytes,
29
+ maxFrameBytes: this.config.maxFrameBytes,
30
+ });
36
31
  }
37
32
 
38
- public override async execute(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
39
- if (this.configArg.client?.execute || this.configArg.commandExecutor || !this.endpoint()) {
40
- return super.execute(requestArg);
41
- }
42
-
43
- try {
44
- const command = await this.commandForService(requestArg);
45
- const endpoint = this.requireEndpoint();
46
- await sendPioneerCommand(endpoint, command, this.configArg.timeoutMs || 3000);
47
- this.liveSnapshot = undefined;
48
- return { success: true, data: { command } };
49
- } catch (errorArg) {
50
- return { success: false, error: errorMessage(errorArg) };
51
- }
33
+ public isHealthy(): boolean {
34
+ try { this.assertOpen(); return this.snapshot !== undefined; } catch { return false; }
52
35
  }
53
36
 
54
- private shouldUseNativeTelnet(forceRefreshArg: boolean): boolean {
55
- if (!this.endpoint() || this.configArg.client || this.configArg.snapshotProvider) {
56
- return false;
37
+ public start(signal?: AbortSignal): Promise<IPioneerSnapshot> {
38
+ try { this.assertOpen(); this.assertSignal(signal); } catch (error) { return Promise.reject(error); }
39
+ if (!this.startPromise) {
40
+ this.startPromise = this.run(async (operationSignal, timeoutMs) => this.observe(await this.protocol.inspect({ signal: operationSignal, timeoutMs })), signal, false)
41
+ .catch(async (error: unknown) => {
42
+ this.lifetime.abort(error);
43
+ try { await this.protocol.close(); }
44
+ catch (cleanupError) { throw new AggregateError([error, cleanupError], 'Pioneer startup and cleanup failed.'); }
45
+ throw error;
46
+ });
57
47
  }
58
- if (!forceRefreshArg && this.configArg.snapshot) {
59
- return false;
60
- }
61
- if (!forceRefreshArg && (this.configArg.rawData !== undefined || this.configArg.rawText !== undefined || this.configArg.entities?.length)) {
62
- return false;
63
- }
64
- return true;
48
+ return this.startPromise;
65
49
  }
66
50
 
67
- private async fetchSnapshot(): Promise<IPioneerSnapshot> {
68
- const endpoint = this.requireEndpoint();
69
- const connection = await PioneerTelnetConnection.connect(endpoint, this.configArg.timeoutMs || 3000);
70
- try {
71
- const commandTimeoutMs = this.configArg.commandTimeoutMs || 250;
72
- const powerRaw = await connection.request('?P', 'PWR', commandTimeoutMs);
73
- const volumeRaw = await connection.request('?V', 'VOL', commandTimeoutMs);
74
- const muteRaw = await connection.request('?M', 'MUT', commandTimeoutMs);
75
- const sourceNameToNumber = await this.sourceNameToNumber(connection, commandTimeoutMs);
76
- const sourceNumberToName = reverseSourceMap(sourceNameToNumber);
77
- const sourceRaw = await connection.request('?F', 'FN', commandTimeoutMs);
78
- const sourceNumber = sourceRaw?.slice(2);
79
- const source = sourceNumber ? sourceNumberToName[sourceNumber] || sourceNumber : undefined;
80
- const volume = volumeRaw ? numberValue(volumeRaw.slice(3)) : undefined;
81
- const state = pioneerPowerState(powerRaw);
82
- const name = this.configArg.name || pioneerDefaultName;
83
- const entity: ISimpleLocalEntitySnapshot = {
84
- id: 'media_player',
85
- uniqueId: `${pioneerProfile.domain}_${SimpleLocalMapper.slug(this.configArg.uniqueId || this.configArg.deviceId || endpoint.host)}_media_player`,
86
- name,
87
- platform: 'media_player',
88
- state,
89
- available: true,
90
- writable: true,
91
- attributes: cleanAttributes({
92
- powerRaw,
93
- volumeRaw,
94
- volume,
95
- volumeLevel: volume === undefined ? undefined : volume / pioneerMaxVolume,
96
- isVolumeMuted: muteRaw === undefined ? undefined : muteRaw === 'MUT0',
97
- muteRaw,
98
- source,
99
- sourceNumber,
100
- sourceList: Object.keys(sourceNameToNumber).length ? Object.keys(sourceNameToNumber).sort() : undefined,
101
- sources: Object.keys(sourceNameToNumber).length ? sourceNameToNumber : undefined,
102
- }),
103
- };
104
-
105
- return {
106
- device: {
107
- id: this.configArg.uniqueId || this.configArg.deviceId || `${endpoint.host}:${endpoint.port}`,
108
- name,
109
- manufacturer: 'Pioneer',
110
- model: stringValue(this.configArg.model) || 'Pioneer AVR',
111
- serialNumber: this.configArg.macAddress,
112
- host: endpoint.host,
113
- port: endpoint.port,
114
- protocol: 'telnet',
115
- },
116
- entities: [entity],
117
- online: true,
118
- updatedAt: new Date().toISOString(),
119
- source: 'tcp',
120
- rawData: {
121
- powerRaw,
122
- volumeRaw,
123
- muteRaw,
124
- sourceRaw,
125
- sources: sourceNameToNumber,
126
- },
127
- capabilities: {
128
- localRead: true,
129
- localControl: true,
130
- telnet: true,
131
- },
132
- };
133
- } finally {
134
- connection.close();
135
- }
51
+ public getObservedSnapshot(): IPioneerSnapshot {
52
+ this.assertOpen();
53
+ if (!this.snapshot) throw new Error('Pioneer has no admitted observation.');
54
+ return this.snapshot;
136
55
  }
137
56
 
138
- private async sourceNameToNumber(connectionArg: PioneerTelnetConnection, commandTimeoutMsArg: number): Promise<Record<string, string>> {
139
- const configured = recordValue(this.configArg.sources) || recordValue(this.configArg.metadata?.sources);
140
- if (configured) {
141
- return configured;
142
- }
143
-
144
- const sources: Record<string, string> = {};
145
- const limit = Math.max(0, Math.min(pioneerMaxSourceNumbers, this.configArg.sourceScanLimit ?? pioneerMaxSourceNumbers));
146
- for (let index = 0; index < limit; index++) {
147
- const response = await connectionArg.request(`?RGB${String(index).padStart(2, '0')}`, 'RGB', commandTimeoutMsArg);
148
- const source = parseSourceResponse(response);
149
- if (source) {
150
- sources[source.name] = source.number;
151
- }
152
- }
153
- return sources;
57
+ public getSnapshot(signal?: AbortSignal): Promise<IPioneerSnapshot> {
58
+ return this.run(async (operationSignal, timeoutMs) => this.observe(await this.protocol.inspect({ signal: operationSignal, timeoutMs })), signal);
154
59
  }
155
60
 
156
- private async commandForService(requestArg: IServiceCallRequest): Promise<string> {
157
- const data = requestArg.data || {};
158
- if (typeof data.command === 'string' && data.command.trim()) {
159
- return data.command.trim();
160
- }
161
- if (requestArg.service === 'turn_on') {
162
- return 'PO';
163
- }
164
- if (requestArg.service === 'turn_off') {
165
- return 'PF';
166
- }
167
- if (requestArg.service === 'volume_up') {
168
- return 'VU';
169
- }
170
- if (requestArg.service === 'volume_down') {
171
- return 'VD';
172
- }
173
- if (requestArg.service === 'volume_mute' || requestArg.service === 'mute_volume') {
174
- return boolValue(data.mute ?? data.is_volume_muted ?? data.muted ?? true) ? 'MO' : 'MF';
175
- }
176
- if (requestArg.service === 'set_volume_level' || requestArg.service === 'volume_set' || requestArg.service === 'set_level') {
177
- const requested = numberValue(data.volume_level ?? data.volume ?? data.level);
178
- const percentage = numberValue(data.percentage);
179
- const value = percentage !== undefined ? (percentage / 100) * pioneerMaxVolume : requested !== undefined && requested <= 1 ? requested * pioneerMaxVolume : requested;
180
- if (value === undefined) {
181
- throw new Error('Pioneer set_volume_level requires data.volume_level, data.volume, data.level, or data.percentage.');
182
- }
183
- return `${String(Math.max(0, Math.min(pioneerMaxVolume, Math.round(value)))).padStart(3, '0')}VL`;
184
- }
185
- if (requestArg.service === 'select_source') {
186
- const sourceNumber = stringValue(data.sourceNumber) || stringValue(data.source_number) || stringValue(data.input);
187
- if (sourceNumber && /^\d{2}$/.test(sourceNumber)) {
188
- return `${sourceNumber}FN`;
189
- }
190
- const source = stringValue(data.source) || stringValue(data.source_name);
191
- const sourceMap = recordValue(this.configArg.sources) || recordValue(this.configArg.metadata?.sources) || recordValue((await this.getSnapshot()).entities[0]?.attributes?.sources);
192
- const mapped = source ? sourceMap?.[source] : undefined;
193
- if (!mapped) {
194
- throw new Error('Pioneer select_source requires data.sourceNumber or data.source matching configured/discovered sources.');
61
+ public async setControl(input: TPioneerControl, signal?: AbortSignal): Promise<IPioneerEffectResult> {
62
+ const control = validatePioneerControl(input);
63
+ if (control.feature === 'volume_raw' && control.value > this.config.maximumVolumeRaw) throw new TypeError('Pioneer volume exceeds the owner ceiling.');
64
+ return this.run(async (operationSignal, timeoutMs) => {
65
+ const options = { signal: operationSignal, timeoutMs };
66
+ const result = control.feature === 'power' ? await this.protocol.setPower(control.value, options)
67
+ : control.feature === 'muted' ? await this.protocol.setMuted(control.value, options)
68
+ : control.feature === 'volume_raw' ? await this.protocol.setVolumeRaw(control.value, options)
69
+ : await this.protocol.setInput(control.value, options);
70
+ try {
71
+ return Object.freeze({ dispatch: result.dispatch, outcome: result.outcome,
72
+ commandAcknowledged: result.commandAcknowledged, causalityConfirmed: result.causalityConfirmed,
73
+ snapshot: this.observe(result.observation) });
74
+ } catch {
75
+ throw new plugins.ecobridgeDeviceManager.PioneerProtocolError('identity-mismatch', 'Pioneer observation could not be admitted after dispatch.', 'indeterminate');
195
76
  }
196
- return `${mapped}FN`;
197
- }
198
- throw new Error(`Unsupported Pioneer native service: ${requestArg.domain}.${requestArg.service}`);
77
+ }, signal);
199
78
  }
200
79
 
201
- private requireEndpoint(): IPioneerEndpoint {
202
- const endpoint = this.endpoint();
203
- if (!endpoint) {
204
- throw new Error('Pioneer Telnet requires config.host or config.url.');
80
+ public destroy(): Promise<void> {
81
+ if (!this.closePromise) {
82
+ // Publish the memo before protocol abort listeners can reenter this facade.
83
+ this.closePromise = Promise.resolve().then(() => this.drain());
84
+ this.lifetime.abort(new Error('Pioneer client is closed.'));
205
85
  }
206
- return endpoint;
86
+ return this.closePromise;
207
87
  }
208
88
 
209
- private endpoint(): IPioneerEndpoint | undefined {
210
- const rawUrl = stringValue(this.configArg.url) || stringValue(this.configArg.metadata?.url);
211
- if (rawUrl) {
212
- const parsed = parseUrl(rawUrl);
213
- if (parsed) {
214
- return { host: parsed.hostname, port: this.configArg.port || numberValue(parsed.port) || pioneerDefaultPort };
215
- }
216
- }
217
- const host = stringValue(this.configArg.host);
218
- if (!host) {
219
- return undefined;
89
+ /** Retries retained terminal cleanup only; never repeats protocol observations or effects. */
90
+ public retryCleanup(): Promise<void> {
91
+ const closed = this.closePromise;
92
+ if (!closed) return Promise.reject(new Error('Pioneer cleanup retry requires terminal destruction.'));
93
+ if (!this.retryPromise) {
94
+ const retry = Promise.resolve().then(async () => {
95
+ await closed.catch(() => undefined);
96
+ await this.drain();
97
+ });
98
+ this.retryPromise = retry;
99
+ const settled = (): void => { this.retryPromise = undefined; };
100
+ void retry.then(settled, settled);
220
101
  }
221
- const parsedHost = parseUrl(host);
222
- if (parsedHost) {
223
- return { host: parsedHost.hostname, port: this.configArg.port || numberValue(parsedHost.port) || pioneerDefaultPort };
224
- }
225
- const hostPort = splitHostPort(host);
226
- return { host: hostPort.host, port: this.configArg.port || hostPort.port || pioneerDefaultPort };
102
+ return this.retryPromise;
227
103
  }
228
104
 
229
- private createOfflineSnapshot(errorArg: string): IPioneerSnapshot {
230
- return SimpleLocalMapper.toSnapshot({ profile: pioneerProfile, config: this.configArg, online: false, source: 'runtime', error: errorArg }) as IPioneerSnapshot;
105
+ private async drain(): Promise<void> {
106
+ const results = await Promise.allSettled([this.protocol.close(), this.operationTail, this.startPromise]);
107
+ this.snapshot = undefined;
108
+ const closure = results[0];
109
+ if (closure.status === 'rejected') throw closure.reason;
231
110
  }
232
- }
233
-
234
- interface IPioneerEndpoint {
235
- host: string;
236
- port: number;
237
- }
238
-
239
- class PioneerTelnetConnection {
240
- private buffer = '';
241
- private lines: string[] = [];
242
- private waiters: Array<() => void> = [];
243
- private closed = false;
244
- private lastError?: Error;
245
111
 
246
- private constructor(private readonly socket: plugins.net.Socket) {
247
- socket.on('data', (chunkArg) => this.pushData(Buffer.isBuffer(chunkArg) ? chunkArg : Buffer.from(chunkArg)));
248
- socket.on('close', () => {
249
- this.closed = true;
250
- this.notify();
251
- });
252
- socket.on('end', () => {
253
- this.closed = true;
254
- this.notify();
255
- });
256
- socket.on('error', (errorArg) => {
257
- this.lastError = errorArg;
258
- this.closed = true;
259
- this.notify();
112
+ private observe(state: plugins.ecobridgeDeviceManager.IPioneerState): IPioneerSnapshot {
113
+ this.assertOpen();
114
+ this.snapshot = Object.freeze({
115
+ homeId: this.config.homeId, host: this.config.host, port: this.config.port,
116
+ name: this.config.name ?? state.identity.name, identity: Object.freeze({ ...state.identity }),
117
+ power: state.power, muted: state.muted, volumeRaw: state.volumeRaw, inputId: state.inputId,
118
+ observedInputs: Object.freeze([...this.protocol.observedInputs]), maximumVolumeRaw: this.config.maximumVolumeRaw,
119
+ observedAt: state.observedAt,
260
120
  });
121
+ return this.snapshot;
261
122
  }
262
123
 
263
- public static async connect(endpointArg: IPioneerEndpoint, timeoutMsArg: number): Promise<PioneerTelnetConnection> {
264
- return new Promise<PioneerTelnetConnection>((resolve, reject) => {
265
- const socket = plugins.net.createConnection({ host: endpointArg.host, port: endpointArg.port });
266
- let settled = false;
267
- const finish = (connectionArg?: PioneerTelnetConnection, errorArg?: Error) => {
268
- if (settled) {
269
- return;
270
- }
271
- settled = true;
272
- socket.off('connect', onConnect);
273
- socket.off('error', onError);
274
- socket.off('timeout', onTimeout);
275
- if (errorArg) {
276
- socket.destroy();
277
- reject(errorArg);
278
- return;
279
- }
280
- resolve(connectionArg!);
281
- };
282
- const onConnect = () => finish(new PioneerTelnetConnection(socket));
283
- const onError = (errorArg: Error) => finish(undefined, errorArg);
284
- const onTimeout = () => finish(undefined, new Error(`Pioneer Telnet connection to ${endpointArg.host}:${endpointArg.port} timed out after ${timeoutMsArg}ms.`));
285
- socket.setTimeout(timeoutMsArg);
286
- socket.once('connect', onConnect);
287
- socket.once('error', onError);
288
- socket.once('timeout', onTimeout);
289
- });
124
+ private assertOpen(): void {
125
+ this.lifetime.signal.throwIfAborted();
126
+ if (this.protocol.isClosed) throw new plugins.ecobridgeDeviceManager.PioneerProtocolError('closed', 'Pioneer protocol is terminally closed.');
127
+ this.admission.admit(this.context, this.config.homeId);
290
128
  }
291
129
 
292
- public async request(commandArg: string, expectedPrefixArg: string, timeoutMsArg: number): Promise<string | undefined> {
293
- await this.write(`${commandArg}\r`);
294
- for (let index = 0; index < 3; index++) {
295
- const line = await this.readLine(timeoutMsArg);
296
- if (!line) {
297
- return undefined;
298
- }
299
- if (line.startsWith(expectedPrefixArg)) {
300
- return line;
301
- }
302
- }
303
- return undefined;
130
+ private assertSignal(signal?: AbortSignal): void {
131
+ if (signal !== undefined && !(signal instanceof AbortSignal)) throw new TypeError('Pioneer cancellation requires an AbortSignal.');
132
+ signal?.throwIfAborted();
304
133
  }
305
134
 
306
- public async write(dataArg: string): Promise<void> {
307
- if (this.lastError) {
308
- throw this.lastError;
309
- }
310
- await new Promise<void>((resolve, reject) => {
311
- this.socket.write(dataArg, 'ascii', (errorArg) => errorArg ? reject(errorArg) : resolve());
135
+ /** Scope is checked when adapter work runs, before admission to the foundation's FIFO. */
136
+ private run<TResult>(execute: (signal: AbortSignal, timeoutMs: number) => Promise<TResult>, signal?: AbortSignal, started = true): Promise<TResult> {
137
+ try {
138
+ this.assertOpen(); this.assertSignal(signal);
139
+ if (started && !this.snapshot) throw new Error('Pioneer client has not started.');
140
+ if (this.pendingOperations >= this.config.maxPendingOperations) throw new Error('Pioneer operation capacity reached.');
141
+ } catch (error) { return Promise.reject(error); }
142
+ const deadline = performance.now() + this.config.timeoutMs;
143
+ const controller = new AbortController();
144
+ const combined = AbortSignal.any([this.lifetime.signal, controller.signal,
145
+ ...(this.context.abortSignal ? [this.context.abortSignal] : []), ...(signal ? [signal] : [])]);
146
+ const timer = setTimeout(() => controller.abort(new plugins.ecobridgeDeviceManager.PioneerProtocolError('timeout', 'Pioneer adapter deadline expired.')), this.config.timeoutMs);
147
+ this.pendingOperations++;
148
+ let rejectWaiting: () => void = () => {};
149
+ const waitingCancelled = new Promise<never>((_resolve, reject) => {
150
+ rejectWaiting = () => reject(combined.reason);
151
+ combined.addEventListener('abort', rejectWaiting, { once: true });
312
152
  });
313
- }
314
-
315
- public close(): void {
316
- this.closed = true;
317
- this.socket.destroy();
318
- this.notify();
319
- }
320
-
321
- private async readLine(timeoutMsArg: number): Promise<string | undefined> {
322
- if (this.lastError) {
323
- throw this.lastError;
324
- }
325
- if (this.lines.length) {
326
- return this.lines.shift();
327
- }
328
- if (this.closed) {
329
- return undefined;
330
- }
331
- return new Promise<string | undefined>((resolve, reject) => {
332
- let settled = false;
333
- const cleanup = () => {
334
- clearTimeout(timer);
335
- this.waiters = this.waiters.filter((waiterArg) => waiterArg !== waiter);
336
- };
337
- const done = (valueArg?: string, errorArg?: Error) => {
338
- if (settled) {
339
- return;
340
- }
341
- settled = true;
342
- cleanup();
343
- if (errorArg) {
344
- reject(errorArg);
345
- return;
346
- }
347
- resolve(valueArg);
348
- };
349
- const waiter = () => {
350
- if (this.lastError) {
351
- done(undefined, this.lastError);
352
- return;
353
- }
354
- if (this.lines.length) {
355
- done(this.lines.shift());
356
- return;
357
- }
358
- if (this.closed) {
359
- done(undefined);
360
- }
361
- };
362
- const timer = setTimeout(() => done(undefined), timeoutMsArg);
363
- this.waiters.push(waiter);
153
+ const operation = this.operationTail.then(async () => {
154
+ combined.removeEventListener('abort', rejectWaiting);
155
+ combined.throwIfAborted(); this.assertOpen();
156
+ const remaining = Math.floor(deadline - performance.now());
157
+ if (remaining < 1) throw new plugins.ecobridgeDeviceManager.PioneerProtocolError('timeout', 'Pioneer queued operation expired.');
158
+ return execute(combined, remaining);
159
+ }).finally(() => {
160
+ combined.removeEventListener('abort', rejectWaiting); clearTimeout(timer); this.pendingOperations--;
364
161
  });
365
- }
366
-
367
- private pushData(chunkArg: Buffer): void {
368
- this.buffer += chunkArg.toString('ascii');
369
- let match = /\r\n|\r|\n/.exec(this.buffer);
370
- while (match?.index !== undefined) {
371
- const line = this.buffer.slice(0, match.index).trim();
372
- this.buffer = this.buffer.slice(match.index + match[0].length);
373
- if (line) {
374
- this.lines.push(line);
375
- }
376
- match = /\r\n|\r|\n/.exec(this.buffer);
377
- }
378
- this.notify();
379
- }
380
-
381
- private notify(): void {
382
- const waiters = this.waiters.splice(0);
383
- for (const waiter of waiters) {
384
- waiter();
385
- }
162
+ this.operationTail = operation.then(() => {}, () => {});
163
+ if (combined.aborted) rejectWaiting();
164
+ return Promise.race([operation, waitingCancelled]);
386
165
  }
387
166
  }
388
-
389
- const sendPioneerCommand = async (endpointArg: IPioneerEndpoint, commandArg: string, timeoutMsArg: number): Promise<void> => {
390
- const connection = await PioneerTelnetConnection.connect(endpointArg, timeoutMsArg);
391
- try {
392
- await connection.write(`${commandArg}\r`);
393
- await delay(40);
394
- } finally {
395
- connection.close();
396
- }
397
- };
398
-
399
- const parseSourceResponse = (responseArg: string | undefined): { number: string; name: string } | undefined => {
400
- const match = responseArg ? /^RGB(\d{2})\s*(.+)$/.exec(responseArg) : undefined;
401
- const name = match?.[2]?.trim();
402
- return match && name ? { number: match[1], name } : undefined;
403
- };
404
-
405
- const pioneerPowerState = (valueArg: string | undefined): string => {
406
- if (valueArg === 'PWR0') {
407
- return 'on';
408
- }
409
- if (valueArg === 'PWR1' || valueArg === 'PWR2') {
410
- return 'off';
411
- }
412
- return 'unknown';
413
- };
414
-
415
- const reverseSourceMap = (sourcesArg: Record<string, string>): Record<string, string> => Object.fromEntries(Object.entries(sourcesArg).map(([nameArg, numberArg]) => [numberArg, nameArg]));
416
-
417
- const recordValue = (valueArg: unknown): Record<string, string> | undefined => {
418
- if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)) {
419
- return undefined;
420
- }
421
- const entries = Object.entries(valueArg).filter((entryArg): entryArg is [string, string] => typeof entryArg[1] === 'string' && entryArg[1].trim().length > 0);
422
- return entries.length ? Object.fromEntries(entries) : undefined;
423
- };
424
-
425
- const stringValue = (valueArg: unknown): string | undefined => typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
426
-
427
- const numberValue = (valueArg: unknown): number | undefined => {
428
- if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
429
- return valueArg;
430
- }
431
- if (typeof valueArg === 'string' && valueArg.trim() && Number.isFinite(Number(valueArg))) {
432
- return Number(valueArg);
433
- }
434
- return undefined;
435
- };
436
-
437
- const boolValue = (valueArg: unknown): boolean => valueArg === true || valueArg === 'true' || valueArg === '1' || valueArg === 1;
438
-
439
- const cleanAttributes = (attributesArg: Record<string, unknown>): Record<string, unknown> | undefined => {
440
- const clean = Object.fromEntries(Object.entries(attributesArg).filter(([, valueArg]) => valueArg !== undefined));
441
- return Object.keys(clean).length ? clean : undefined;
442
- };
443
-
444
- const parseUrl = (valueArg: string): URL | undefined => {
445
- if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(valueArg)) {
446
- return undefined;
447
- }
448
- try {
449
- return new URL(valueArg);
450
- } catch {
451
- return undefined;
452
- }
453
- };
454
-
455
- const splitHostPort = (valueArg: string): { host: string; port?: number } => {
456
- const match = /^([^:]+):(\d+)$/.exec(valueArg);
457
- return match ? { host: match[1], port: Number(match[2]) } : { host: valueArg };
458
- };
459
-
460
- const delay = async (msArg: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, msArg));
461
-
462
- const errorMessage = (errorArg: unknown): string => errorArg instanceof Error ? errorArg.message : String(errorArg);