@smarthome.exchange/integrations 1.0.0 → 2.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 (294) hide show
  1. package/changelog.md +49 -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 +79 -0
  8. package/dist_ts/core/classes.nativeintegrationowner.js +269 -0
  9. package/dist_ts/core/index.d.ts +2 -0
  10. package/dist_ts/core/index.js +3 -1
  11. package/dist_ts/core/types.d.ts +14 -0
  12. package/dist_ts/integrations/braviatv/braviatv.classes.client.d.ts +23 -72
  13. package/dist_ts/integrations/braviatv/braviatv.classes.client.js +265 -625
  14. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.d.ts +7 -7
  15. package/dist_ts/integrations/braviatv/braviatv.classes.configflow.js +51 -68
  16. package/dist_ts/integrations/braviatv/braviatv.classes.integration.d.ts +8 -11
  17. package/dist_ts/integrations/braviatv/braviatv.classes.integration.js +186 -135
  18. package/dist_ts/integrations/braviatv/braviatv.discovery.js +12 -11
  19. package/dist_ts/integrations/braviatv/braviatv.mapper.d.ts +6 -14
  20. package/dist_ts/integrations/braviatv/braviatv.mapper.js +37 -131
  21. package/dist_ts/integrations/braviatv/braviatv.types.d.ts +55 -133
  22. package/dist_ts/integrations/braviatv/braviatv.validation.d.ts +7 -0
  23. package/dist_ts/integrations/braviatv/braviatv.validation.js +72 -0
  24. package/dist_ts/integrations/broadlink/broadlink.actions.d.ts +2 -0
  25. package/dist_ts/integrations/broadlink/broadlink.actions.js +36 -0
  26. package/dist_ts/integrations/broadlink/broadlink.classes.client.d.ts +21 -19
  27. package/dist_ts/integrations/broadlink/broadlink.classes.client.js +185 -124
  28. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.d.ts +5 -4
  29. package/dist_ts/integrations/broadlink/broadlink.classes.configflow.js +64 -83
  30. package/dist_ts/integrations/broadlink/broadlink.classes.integration.d.ts +16 -19
  31. package/dist_ts/integrations/broadlink/broadlink.classes.integration.js +114 -59
  32. package/dist_ts/integrations/broadlink/broadlink.mapper.d.ts +3 -2
  33. package/dist_ts/integrations/broadlink/broadlink.mapper.js +2 -1
  34. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.d.ts +10 -0
  35. package/dist_ts/integrations/broadlink/broadlink.selected.mapper.js +41 -0
  36. package/dist_ts/integrations/broadlink/broadlink.types.d.ts +43 -7
  37. package/dist_ts/integrations/broadlink/broadlink.validation.d.ts +7 -0
  38. package/dist_ts/integrations/broadlink/broadlink.validation.js +63 -0
  39. package/dist_ts/integrations/daikin/daikin.classes.client.d.ts +10 -52
  40. package/dist_ts/integrations/daikin/daikin.classes.client.js +55 -614
  41. package/dist_ts/integrations/daikin/daikin.classes.configflow.d.ts +8 -12
  42. package/dist_ts/integrations/daikin/daikin.classes.configflow.js +77 -138
  43. package/dist_ts/integrations/daikin/daikin.classes.integration.d.ts +7 -24
  44. package/dist_ts/integrations/daikin/daikin.classes.integration.js +175 -67
  45. package/dist_ts/integrations/daikin/daikin.discovery.d.ts +11 -24
  46. package/dist_ts/integrations/daikin/daikin.discovery.js +98 -305
  47. package/dist_ts/integrations/daikin/daikin.mapper.d.ts +6 -7
  48. package/dist_ts/integrations/daikin/daikin.mapper.js +95 -155
  49. package/dist_ts/integrations/daikin/daikin.types.d.ts +24 -44
  50. package/dist_ts/integrations/daikin/daikin.types.js +1 -1
  51. package/dist_ts/integrations/daikin/daikin.validation.d.ts +5 -0
  52. package/dist_ts/integrations/daikin/daikin.validation.js +53 -0
  53. package/dist_ts/integrations/denonavr/denonavr.classes.client.d.ts +31 -40
  54. package/dist_ts/integrations/denonavr/denonavr.classes.client.js +149 -404
  55. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.d.ts +7 -2
  56. package/dist_ts/integrations/denonavr/denonavr.classes.configflow.js +44 -36
  57. package/dist_ts/integrations/denonavr/denonavr.classes.integration.d.ts +6 -11
  58. package/dist_ts/integrations/denonavr/denonavr.classes.integration.js +192 -113
  59. package/dist_ts/integrations/denonavr/denonavr.discovery.d.ts +10 -18
  60. package/dist_ts/integrations/denonavr/denonavr.discovery.js +71 -193
  61. package/dist_ts/integrations/denonavr/denonavr.mapper.d.ts +5 -13
  62. package/dist_ts/integrations/denonavr/denonavr.mapper.js +35 -159
  63. package/dist_ts/integrations/denonavr/denonavr.types.d.ts +55 -90
  64. package/dist_ts/integrations/denonavr/denonavr.validation.d.ts +10 -0
  65. package/dist_ts/integrations/denonavr/denonavr.validation.js +86 -0
  66. package/dist_ts/integrations/kodi/kodi.classes.client.d.ts +11 -45
  67. package/dist_ts/integrations/kodi/kodi.classes.client.js +84 -310
  68. package/dist_ts/integrations/kodi/kodi.classes.configflow.d.ts +9 -8
  69. package/dist_ts/integrations/kodi/kodi.classes.configflow.js +53 -48
  70. package/dist_ts/integrations/kodi/kodi.classes.integration.d.ts +11 -11
  71. package/dist_ts/integrations/kodi/kodi.classes.integration.js +114 -171
  72. package/dist_ts/integrations/kodi/kodi.discovery.js +53 -29
  73. package/dist_ts/integrations/kodi/kodi.mapper.d.ts +7 -2
  74. package/dist_ts/integrations/kodi/kodi.mapper.js +48 -10
  75. package/dist_ts/integrations/kodi/kodi.types.d.ts +32 -28
  76. package/dist_ts/integrations/kodi/kodi.validation.d.ts +9 -0
  77. package/dist_ts/integrations/kodi/kodi.validation.js +62 -0
  78. package/dist_ts/integrations/modbus/modbus.classes.client.d.ts +15 -61
  79. package/dist_ts/integrations/modbus/modbus.classes.client.js +117 -776
  80. package/dist_ts/integrations/modbus/modbus.classes.configflow.d.ts +9 -5
  81. package/dist_ts/integrations/modbus/modbus.classes.configflow.js +70 -38
  82. package/dist_ts/integrations/modbus/modbus.classes.integration.d.ts +6 -17
  83. package/dist_ts/integrations/modbus/modbus.classes.integration.js +133 -57
  84. package/dist_ts/integrations/modbus/modbus.discovery.d.ts +5 -8
  85. package/dist_ts/integrations/modbus/modbus.discovery.js +38 -93
  86. package/dist_ts/integrations/modbus/modbus.mapper.d.ts +8 -32
  87. package/dist_ts/integrations/modbus/modbus.mapper.js +71 -431
  88. package/dist_ts/integrations/modbus/modbus.types.d.ts +82 -332
  89. package/dist_ts/integrations/modbus/modbus.validation.d.ts +10 -0
  90. package/dist_ts/integrations/modbus/modbus.validation.js +128 -0
  91. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.d.ts +12 -34
  92. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.js +143 -231
  93. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.d.ts +6 -1
  94. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.js +105 -18
  95. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.d.ts +8 -8
  96. package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.js +141 -155
  97. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.d.ts +9 -0
  98. package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.js +35 -0
  99. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.d.ts +6 -18
  100. package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.js +45 -220
  101. package/dist_ts/integrations/nanoleaf/nanoleaf.types.d.ts +33 -147
  102. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.d.ts +6 -0
  103. package/dist_ts/integrations/nanoleaf/nanoleaf.validation.js +82 -0
  104. package/dist_ts/integrations/onkyo/onkyo.classes.client.d.ts +15 -20
  105. package/dist_ts/integrations/onkyo/onkyo.classes.client.js +161 -404
  106. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.d.ts +9 -4
  107. package/dist_ts/integrations/onkyo/onkyo.classes.configflow.js +51 -6
  108. package/dist_ts/integrations/onkyo/onkyo.classes.integration.d.ts +22 -6
  109. package/dist_ts/integrations/onkyo/onkyo.classes.integration.js +144 -11
  110. package/dist_ts/integrations/onkyo/onkyo.discovery.d.ts +6 -1
  111. package/dist_ts/integrations/onkyo/onkyo.discovery.js +40 -4
  112. package/dist_ts/integrations/onkyo/onkyo.mapper.d.ts +7 -8
  113. package/dist_ts/integrations/onkyo/onkyo.mapper.js +45 -12
  114. package/dist_ts/integrations/onkyo/onkyo.types.d.ts +58 -8
  115. package/dist_ts/integrations/onkyo/onkyo.types.js +13 -102
  116. package/dist_ts/integrations/onkyo/onkyo.validation.d.ts +16 -0
  117. package/dist_ts/integrations/onkyo/onkyo.validation.js +77 -0
  118. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.d.ts +25 -25
  119. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.js +116 -360
  120. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.d.ts +11 -3
  121. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.js +76 -6
  122. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.d.ts +26 -4
  123. package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.js +142 -9
  124. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.d.ts +2 -1
  125. package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.js +31 -4
  126. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.d.ts +9 -9
  127. package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.js +31 -149
  128. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.d.ts +51 -11
  129. package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.js +22 -87
  130. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.d.ts +6 -0
  131. package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.js +56 -0
  132. package/dist_ts/integrations/pioneer/pioneer.classes.client.d.ts +31 -16
  133. package/dist_ts/integrations/pioneer/pioneer.classes.client.js +167 -409
  134. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.d.ts +10 -3
  135. package/dist_ts/integrations/pioneer/pioneer.classes.configflow.js +66 -6
  136. package/dist_ts/integrations/pioneer/pioneer.classes.integration.d.ts +13 -5
  137. package/dist_ts/integrations/pioneer/pioneer.classes.integration.js +239 -11
  138. package/dist_ts/integrations/pioneer/pioneer.discovery.d.ts +14 -1
  139. package/dist_ts/integrations/pioneer/pioneer.discovery.js +51 -4
  140. package/dist_ts/integrations/pioneer/pioneer.mapper.d.ts +14 -8
  141. package/dist_ts/integrations/pioneer/pioneer.mapper.js +54 -12
  142. package/dist_ts/integrations/pioneer/pioneer.types.d.ts +79 -12
  143. package/dist_ts/integrations/pioneer/pioneer.types.js +12 -76
  144. package/dist_ts/integrations/pioneer/pioneer.validation.d.ts +10 -0
  145. package/dist_ts/integrations/pioneer/pioneer.validation.js +85 -0
  146. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.d.ts +13 -36
  147. package/dist_ts/integrations/soundtouch/soundtouch.classes.client.js +179 -502
  148. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.d.ts +6 -1
  149. package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.js +50 -40
  150. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.d.ts +14 -15
  151. package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.js +108 -128
  152. package/dist_ts/integrations/soundtouch/soundtouch.discovery.d.ts +2 -20
  153. package/dist_ts/integrations/soundtouch/soundtouch.discovery.js +23 -113
  154. package/dist_ts/integrations/soundtouch/soundtouch.mapper.d.ts +3 -12
  155. package/dist_ts/integrations/soundtouch/soundtouch.mapper.js +35 -189
  156. package/dist_ts/integrations/soundtouch/soundtouch.types.d.ts +57 -142
  157. package/dist_ts/integrations/soundtouch/soundtouch.types.js +18 -3
  158. package/dist_ts/integrations/soundtouch/soundtouch.validation.d.ts +22 -0
  159. package/dist_ts/integrations/soundtouch/soundtouch.validation.js +65 -0
  160. package/dist_ts/integrations/wiz/index.d.ts +1 -0
  161. package/dist_ts/integrations/wiz/index.js +2 -1
  162. package/dist_ts/integrations/wiz/wiz.classes.client.d.ts +14 -28
  163. package/dist_ts/integrations/wiz/wiz.classes.client.js +93 -229
  164. package/dist_ts/integrations/wiz/wiz.classes.configflow.d.ts +6 -4
  165. package/dist_ts/integrations/wiz/wiz.classes.configflow.js +38 -67
  166. package/dist_ts/integrations/wiz/wiz.classes.integration.d.ts +10 -21
  167. package/dist_ts/integrations/wiz/wiz.classes.integration.js +204 -44
  168. package/dist_ts/integrations/wiz/wiz.discovery.d.ts +10 -31
  169. package/dist_ts/integrations/wiz/wiz.discovery.js +48 -249
  170. package/dist_ts/integrations/wiz/wiz.mapper.d.ts +7 -51
  171. package/dist_ts/integrations/wiz/wiz.mapper.js +82 -668
  172. package/dist_ts/integrations/wiz/wiz.types.d.ts +34 -208
  173. package/dist_ts/integrations/wiz/wiz.validation.d.ts +8 -0
  174. package/dist_ts/integrations/wiz/wiz.validation.js +72 -0
  175. package/dist_ts/integrations/yamaha/index.d.ts +1 -0
  176. package/dist_ts/integrations/yamaha/index.js +2 -1
  177. package/dist_ts/integrations/yamaha/yamaha.classes.client.d.ts +30 -4
  178. package/dist_ts/integrations/yamaha/yamaha.classes.client.js +162 -6
  179. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.d.ts +10 -3
  180. package/dist_ts/integrations/yamaha/yamaha.classes.configflow.js +106 -6
  181. package/dist_ts/integrations/yamaha/yamaha.classes.integration.d.ts +22 -4
  182. package/dist_ts/integrations/yamaha/yamaha.classes.integration.js +243 -8
  183. package/dist_ts/integrations/yamaha/yamaha.discovery.d.ts +13 -1
  184. package/dist_ts/integrations/yamaha/yamaha.discovery.js +57 -4
  185. package/dist_ts/integrations/yamaha/yamaha.mapper.d.ts +16 -8
  186. package/dist_ts/integrations/yamaha/yamaha.mapper.js +58 -12
  187. package/dist_ts/integrations/yamaha/yamaha.types.d.ts +73 -6
  188. package/dist_ts/integrations/yamaha/yamaha.types.js +8 -94
  189. package/dist_ts/integrations/yamaha/yamaha.validation.d.ts +12 -0
  190. package/dist_ts/integrations/yamaha/yamaha.validation.js +89 -0
  191. package/package.json +3 -3
  192. package/readme.md +514 -2
  193. package/ts/00_commitinfo_data.ts +1 -1
  194. package/ts/core/classes.configstore.ts +84 -27
  195. package/ts/core/classes.nativehomeadmission.ts +96 -0
  196. package/ts/core/classes.nativeintegrationowner.ts +297 -0
  197. package/ts/core/index.ts +2 -0
  198. package/ts/core/types.ts +16 -0
  199. package/ts/integrations/braviatv/braviatv.classes.client.ts +245 -709
  200. package/ts/integrations/braviatv/braviatv.classes.configflow.ts +47 -76
  201. package/ts/integrations/braviatv/braviatv.classes.integration.ts +167 -147
  202. package/ts/integrations/braviatv/braviatv.discovery.ts +11 -10
  203. package/ts/integrations/braviatv/braviatv.mapper.ts +39 -142
  204. package/ts/integrations/braviatv/braviatv.types.ts +53 -173
  205. package/ts/integrations/braviatv/braviatv.validation.ts +68 -0
  206. package/ts/integrations/broadlink/broadlink.actions.ts +31 -0
  207. package/ts/integrations/broadlink/broadlink.classes.client.ts +170 -144
  208. package/ts/integrations/broadlink/broadlink.classes.configflow.ts +59 -89
  209. package/ts/integrations/broadlink/broadlink.classes.integration.ts +110 -64
  210. package/ts/integrations/broadlink/broadlink.mapper.ts +5 -4
  211. package/ts/integrations/broadlink/broadlink.selected.mapper.ts +46 -0
  212. package/ts/integrations/broadlink/broadlink.types.ts +48 -8
  213. package/ts/integrations/broadlink/broadlink.validation.ts +66 -0
  214. package/ts/integrations/daikin/daikin.classes.client.ts +52 -661
  215. package/ts/integrations/daikin/daikin.classes.configflow.ts +72 -152
  216. package/ts/integrations/daikin/daikin.classes.integration.ts +166 -71
  217. package/ts/integrations/daikin/daikin.discovery.ts +94 -346
  218. package/ts/integrations/daikin/daikin.mapper.ts +83 -166
  219. package/ts/integrations/daikin/daikin.types.ts +27 -48
  220. package/ts/integrations/daikin/daikin.validation.ts +51 -0
  221. package/ts/integrations/daikin/readme.md +83 -0
  222. package/ts/integrations/denonavr/denonavr.classes.client.ts +132 -421
  223. package/ts/integrations/denonavr/denonavr.classes.configflow.ts +44 -37
  224. package/ts/integrations/denonavr/denonavr.classes.integration.ts +171 -117
  225. package/ts/integrations/denonavr/denonavr.discovery.ts +67 -220
  226. package/ts/integrations/denonavr/denonavr.mapper.ts +36 -182
  227. package/ts/integrations/denonavr/denonavr.types.ts +48 -111
  228. package/ts/integrations/denonavr/denonavr.validation.ts +87 -0
  229. package/ts/integrations/kodi/kodi.classes.client.ts +72 -352
  230. package/ts/integrations/kodi/kodi.classes.configflow.ts +52 -55
  231. package/ts/integrations/kodi/kodi.classes.integration.ts +97 -178
  232. package/ts/integrations/kodi/kodi.discovery.ts +49 -28
  233. package/ts/integrations/kodi/kodi.mapper.ts +52 -10
  234. package/ts/integrations/kodi/kodi.types.ts +33 -58
  235. package/ts/integrations/kodi/kodi.validation.ts +60 -0
  236. package/ts/integrations/modbus/modbus.classes.client.ts +100 -842
  237. package/ts/integrations/modbus/modbus.classes.configflow.ts +70 -41
  238. package/ts/integrations/modbus/modbus.classes.integration.ts +115 -60
  239. package/ts/integrations/modbus/modbus.discovery.ts +38 -106
  240. package/ts/integrations/modbus/modbus.mapper.ts +64 -467
  241. package/ts/integrations/modbus/modbus.types.ts +64 -381
  242. package/ts/integrations/modbus/modbus.validation.ts +119 -0
  243. package/ts/integrations/nanoleaf/nanoleaf.classes.client.ts +115 -249
  244. package/ts/integrations/nanoleaf/nanoleaf.classes.configflow.ts +90 -19
  245. package/ts/integrations/nanoleaf/nanoleaf.classes.integration.ts +130 -181
  246. package/ts/integrations/nanoleaf/nanoleaf.credentials.ts +39 -0
  247. package/ts/integrations/nanoleaf/nanoleaf.mapper.ts +47 -260
  248. package/ts/integrations/nanoleaf/nanoleaf.types.ts +29 -147
  249. package/ts/integrations/nanoleaf/nanoleaf.validation.ts +77 -0
  250. package/ts/integrations/onkyo/onkyo.classes.client.ts +148 -457
  251. package/ts/integrations/onkyo/onkyo.classes.configflow.ts +52 -6
  252. package/ts/integrations/onkyo/onkyo.classes.integration.ts +121 -12
  253. package/ts/integrations/onkyo/onkyo.discovery.ts +41 -3
  254. package/ts/integrations/onkyo/onkyo.mapper.ts +46 -19
  255. package/ts/integrations/onkyo/onkyo.types.ts +55 -110
  256. package/ts/integrations/onkyo/onkyo.validation.ts +85 -0
  257. package/ts/integrations/onkyo/readme.md +126 -0
  258. package/ts/integrations/panasonic_viera/panasonic_viera.classes.client.ts +101 -398
  259. package/ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.ts +69 -5
  260. package/ts/integrations/panasonic_viera/panasonic_viera.classes.integration.ts +141 -9
  261. package/ts/integrations/panasonic_viera/panasonic_viera.discovery.ts +32 -3
  262. package/ts/integrations/panasonic_viera/panasonic_viera.mapper.ts +34 -161
  263. package/ts/integrations/panasonic_viera/panasonic_viera.types.ts +52 -96
  264. package/ts/integrations/panasonic_viera/panasonic_viera.validation.ts +56 -0
  265. package/ts/integrations/pioneer/pioneer.classes.client.ts +132 -428
  266. package/ts/integrations/pioneer/pioneer.classes.configflow.ts +67 -5
  267. package/ts/integrations/pioneer/pioneer.classes.integration.ts +225 -11
  268. package/ts/integrations/pioneer/pioneer.discovery.ts +45 -3
  269. package/ts/integrations/pioneer/pioneer.mapper.ts +57 -13
  270. package/ts/integrations/pioneer/pioneer.types.ts +87 -85
  271. package/ts/integrations/pioneer/pioneer.validation.ts +84 -0
  272. package/ts/integrations/soundtouch/soundtouch.classes.client.ts +152 -571
  273. package/ts/integrations/soundtouch/soundtouch.classes.configflow.ts +47 -42
  274. package/ts/integrations/soundtouch/soundtouch.classes.integration.ts +95 -150
  275. package/ts/integrations/soundtouch/soundtouch.discovery.ts +21 -133
  276. package/ts/integrations/soundtouch/soundtouch.mapper.ts +36 -207
  277. package/ts/integrations/soundtouch/soundtouch.types.ts +50 -195
  278. package/ts/integrations/soundtouch/soundtouch.validation.ts +60 -0
  279. package/ts/integrations/wiz/index.ts +1 -0
  280. package/ts/integrations/wiz/wiz.classes.client.ts +84 -254
  281. package/ts/integrations/wiz/wiz.classes.configflow.ts +39 -70
  282. package/ts/integrations/wiz/wiz.classes.integration.ts +189 -45
  283. package/ts/integrations/wiz/wiz.discovery.ts +48 -291
  284. package/ts/integrations/wiz/wiz.mapper.ts +81 -754
  285. package/ts/integrations/wiz/wiz.types.ts +24 -224
  286. package/ts/integrations/wiz/wiz.validation.ts +73 -0
  287. package/ts/integrations/yamaha/index.ts +1 -0
  288. package/ts/integrations/yamaha/yamaha.classes.client.ts +150 -6
  289. package/ts/integrations/yamaha/yamaha.classes.configflow.ts +100 -5
  290. package/ts/integrations/yamaha/yamaha.classes.integration.ts +236 -8
  291. package/ts/integrations/yamaha/yamaha.discovery.ts +52 -3
  292. package/ts/integrations/yamaha/yamaha.mapper.ts +65 -13
  293. package/ts/integrations/yamaha/yamaha.types.ts +77 -97
  294. package/ts/integrations/yamaha/yamaha.validation.ts +86 -0
@@ -1,239 +1,86 @@
1
1
  import { DiscoveryDescriptor } from '../../core/classes.discoverydescriptor.js';
2
2
  import type { IDiscoveryCandidate, IDiscoveryMatch, IDiscoveryMatcher, IDiscoveryValidator } from '../../core/types.js';
3
- import type { IDenonavrManualEntry, IDenonavrMdnsRecord, IDenonavrSsdpRecord } from './denonavr.types.js';
3
+ import type { IDenonavrManualEntry, IDenonavrSsdpRecord } from './denonavr.types.js';
4
+ import { denonavrDescription, denonavrHost, denonavrModel, denonavrRecord, denonavrUdn } from './denonavr.validation.js';
4
5
 
5
- const supportedManufacturers = ['denon', 'denon professional', 'marantz'];
6
- const supportedDeviceTypes = [
7
- 'urn:schemas-upnp-org:device:mediarenderer:1',
8
- 'urn:schemas-upnp-org:device:mediaserver:1',
9
- 'urn:schemas-denon-com:device:aiosdevice:1',
10
- ];
11
- const ignoredModels = ['heos 1', 'heos 3', 'heos 5', 'heos 7'];
6
+ const miss = (reason: string): IDiscoveryMatch => ({ matched: false, confidence: 'low', reason });
12
7
 
13
- export class DenonavrSsdpMatcher implements IDiscoveryMatcher<IDenonavrSsdpRecord> {
14
- public id = 'denonavr-ssdp-match';
15
- public source = 'ssdp' as const;
16
- public description = 'Recognize Denon and Marantz AVR SSDP advertisements.';
17
-
18
- public async matches(recordArg: IDenonavrSsdpRecord): Promise<IDiscoveryMatch> {
19
- const st = header(recordArg, 'st') || recordArg.upnp?.deviceType;
20
- const usn = header(recordArg, 'usn');
21
- const location = header(recordArg, 'location');
22
- const manufacturer = upnp(recordArg, 'manufacturer');
23
- const model = cleanModel(upnp(recordArg, 'modelName'));
24
- const serialNumber = upnp(recordArg, 'serialNumber') || upnp(recordArg, 'serial');
25
- const friendlyName = upnp(recordArg, 'friendlyName');
26
- const deviceType = upnp(recordArg, 'deviceType') || st;
27
-
28
- const matchedManufacturer = isSupportedManufacturer(manufacturer);
29
- const matchedType = Boolean(deviceType && supportedDeviceTypes.includes(deviceType.toLowerCase()));
30
- const matchedUsn = Boolean(usn?.toLowerCase().includes('denon') || usn?.toLowerCase().includes('marantz'));
31
-
32
- if (!matchedManufacturer && !matchedType && !matchedUsn) {
33
- return { matched: false, confidence: 'low', reason: 'SSDP record is not a Denon/Marantz AVR.' };
34
- }
35
- if (isIgnoredModel(model)) {
36
- return { matched: false, confidence: 'low', reason: 'SSDP record is a HEOS speaker, not an AVR.' };
37
- }
38
-
39
- const url = parseUrl(location);
40
- const id = uniqueId(model, serialNumber) || stripUuid(usn);
41
- return {
42
- matched: true,
43
- confidence: id && matchedManufacturer ? 'certain' : matchedManufacturer || matchedType ? 'high' : 'medium',
44
- reason: 'SSDP record matches Denon/Marantz AVR metadata.',
45
- normalizedDeviceId: id,
46
- candidate: {
47
- source: 'ssdp',
48
- integrationDomain: 'denonavr',
49
- id,
50
- host: url?.hostname,
51
- port: url?.port ? Number(url.port) : undefined,
52
- name: friendlyName,
53
- manufacturer: normalizedManufacturer(manufacturer),
54
- model,
55
- serialNumber,
56
- metadata: { st, usn, location, deviceType },
57
- },
58
- };
59
- }
8
+ function strings(value: unknown): Record<string, unknown> {
9
+ const record = denonavrRecord(value);
10
+ if (Object.keys(record).length > 64 || Object.values(record).some((entry) => entry !== undefined && (typeof entry !== 'string' || entry.length > 2048))) throw new TypeError('DenonAVR discovery fields must be bounded strings.');
11
+ return record;
60
12
  }
61
13
 
62
- export class DenonavrMdnsMatcher implements IDiscoveryMatcher<IDenonavrMdnsRecord> {
63
- public id = 'denonavr-mdns-match';
64
- public source = 'mdns' as const;
65
- public description = 'Recognize Denon and Marantz AVR mDNS advertisements.';
66
-
67
- public async matches(recordArg: IDenonavrMdnsRecord): Promise<IDiscoveryMatch> {
68
- const name = recordArg.name || '';
69
- const type = recordArg.type || '';
70
- const manufacturer = recordArg.txt?.manufacturer || recordArg.txt?.brand || recordArg.txt?.Manufacturer;
71
- const model = cleanModel(recordArg.txt?.model || recordArg.txt?.modelName || recordArg.txt?.ModelName);
72
- const serialNumber = recordArg.txt?.serial || recordArg.txt?.serialNumber || recordArg.txt?.SerialNumber;
73
- const haystack = `${name} ${type} ${manufacturer || ''} ${model || ''}`.toLowerCase();
74
- const matched = isSupportedManufacturer(manufacturer) || haystack.includes('denon') || haystack.includes('marantz');
14
+ function field(record: Record<string, unknown>, name: string): string | undefined {
15
+ const matches = Object.keys(record).filter((key) => key.toLowerCase() === name.toLowerCase());
16
+ if (matches.length > 1) throw new TypeError('DenonAVR discovery contains duplicate fields.');
17
+ const value = matches.length ? record[matches[0]] : undefined;
18
+ return typeof value === 'string' ? value : undefined;
19
+ }
75
20
 
76
- if (!matched) {
77
- return { matched: false, confidence: 'low', reason: 'mDNS record is not a Denon/Marantz advertisement.' };
78
- }
79
- if (isIgnoredModel(model)) {
80
- return { matched: false, confidence: 'low', reason: 'mDNS record is a HEOS speaker, not an AVR.' };
81
- }
21
+ function candidate(host: unknown, description: unknown, udn: unknown, modelValue: unknown, manufacturer: unknown,
22
+ source: 'ssdp' | 'manual', name?: string): IDiscoveryMatch {
23
+ const address = denonavrHost(host);
24
+ const descriptionUrl = denonavrDescription(description, address);
25
+ const id = denonavrUdn(udn);
26
+ const model = denonavrModel(modelValue);
27
+ const expectedManufacturer = model.startsWith('AVR-') ? 'Denon' : 'Marantz';
28
+ if (manufacturer !== undefined && (typeof manufacturer !== 'string' || manufacturer.toLowerCase() !== expectedManufacturer.toLowerCase())) throw new TypeError('DenonAVR discovery manufacturer does not match the model profile.');
29
+ return { matched: true, confidence: 'medium', reason: 'Selected-receiver setup hint; fresh descriptor and receiver observations are required for admission.',
30
+ normalizedDeviceId: id, candidate: { source, integrationDomain: 'denonavr', id, host: address, name,
31
+ manufacturer: expectedManufacturer, model, metadata: { descriptionUrl, identityEvidence: 'unauthenticated-discovery-hint' } } };
32
+ }
82
33
 
83
- const id = uniqueId(model, serialNumber) || recordArg.txt?.id || name;
84
- return {
85
- matched: true,
86
- confidence: serialNumber ? 'certain' : 'medium',
87
- reason: 'mDNS record matches Denon/Marantz metadata.',
88
- normalizedDeviceId: id,
89
- candidate: {
90
- source: 'mdns',
91
- integrationDomain: 'denonavr',
92
- id,
93
- host: recordArg.host,
94
- port: recordArg.port,
95
- name,
96
- manufacturer: normalizedManufacturer(manufacturer),
97
- model,
98
- serialNumber,
99
- metadata: { mdnsName: name, mdnsType: type, txt: recordArg.txt },
100
- },
101
- };
34
+ export class DenonavrSsdpMatcher implements IDiscoveryMatcher<IDenonavrSsdpRecord> {
35
+ public readonly id = 'denonavr-ssdp-match';
36
+ public readonly source = 'ssdp' as const;
37
+ public readonly description = 'Recognize explicitly described, documented Denon/Marantz receiver setup hints.';
38
+
39
+ public async matches(input: IDenonavrSsdpRecord): Promise<IDiscoveryMatch> {
40
+ try {
41
+ const record = denonavrRecord(input, ['st', 'usn', 'location', 'headers', 'upnp']);
42
+ const headers = record.headers === undefined ? {} : strings(record.headers);
43
+ const upnp = record.upnp === undefined ? {} : strings(record.upnp);
44
+ const location = record.location ?? field(headers, 'location');
45
+ if (typeof location !== 'string') return miss('Selected descriptor URL is missing.');
46
+ const url = new URL(location);
47
+ const udn = field(upnp, 'UDN');
48
+ const usn = record.usn ?? field(headers, 'usn');
49
+ if (typeof usn === 'string' && denonavrUdn(usn.split('::')[0]) !== denonavrUdn(udn)) return miss('SSDP and descriptor identities conflict.');
50
+ return candidate(url.hostname, location, udn, field(upnp, 'modelName'), field(upnp, 'manufacturer'), 'ssdp', field(upnp, 'friendlyName'));
51
+ } catch { return miss('SSDP record lacks an exact supported model and selected descriptor identity.'); }
102
52
  }
103
53
  }
104
54
 
105
55
  export class DenonavrManualMatcher implements IDiscoveryMatcher<IDenonavrManualEntry> {
106
- public id = 'denonavr-manual-match';
107
- public source = 'manual' as const;
108
- public description = 'Recognize manual Denon/Marantz AVR setup entries.';
109
-
110
- public async matches(inputArg: IDenonavrManualEntry): Promise<IDiscoveryMatch> {
111
- const model = cleanModel(inputArg.model);
112
- const matched = Boolean(
113
- inputArg.host
114
- || isSupportedManufacturer(inputArg.manufacturer)
115
- || model?.toLowerCase().includes('denon')
116
- || model?.toLowerCase().includes('marantz')
117
- || inputArg.metadata?.denonavr
118
- );
119
- if (!matched) {
120
- return { matched: false, confidence: 'low', reason: 'Manual entry does not contain Denon AVR setup hints.' };
121
- }
122
- const id = uniqueId(model, inputArg.serialNumber) || inputArg.id;
123
- return {
124
- matched: true,
125
- confidence: inputArg.host ? 'high' : 'medium',
126
- reason: 'Manual entry can start Denon AVR setup.',
127
- normalizedDeviceId: id,
128
- candidate: {
129
- source: 'manual',
130
- integrationDomain: 'denonavr',
131
- id,
132
- host: inputArg.host,
133
- port: inputArg.port || 80,
134
- name: inputArg.name,
135
- manufacturer: normalizedManufacturer(inputArg.manufacturer),
136
- model,
137
- serialNumber: inputArg.serialNumber,
138
- metadata: inputArg.metadata,
139
- },
140
- };
56
+ public readonly id = 'denonavr-manual-match';
57
+ public readonly source = 'manual' as const;
58
+ public async matches(input: IDenonavrManualEntry): Promise<IDiscoveryMatch> {
59
+ try {
60
+ const record = denonavrRecord(input, ['host', 'descriptionUrl', 'expectedUdn', 'id', 'name', 'manufacturer', 'model', 'metadata']);
61
+ const metadata = record.metadata === undefined ? {} : denonavrRecord(record.metadata, ['descriptionUrl']);
62
+ if (record.name !== undefined && typeof record.name !== 'string') return miss('Receiver name is invalid.');
63
+ const id = record.expectedUdn ?? record.id;
64
+ if (record.expectedUdn !== undefined && record.id !== undefined && denonavrUdn(record.expectedUdn) !== denonavrUdn(record.id)) return miss('Manual receiver identities conflict.');
65
+ return candidate(record.host, record.descriptionUrl ?? metadata.descriptionUrl, id, record.model, record.manufacturer,
66
+ 'manual', typeof record.name === 'string' ? record.name : undefined);
67
+ } catch { return miss('Manual setup must select a supported model, private IP, descriptor URL and exact UDN.'); }
141
68
  }
142
69
  }
143
70
 
144
71
  export class DenonavrCandidateValidator implements IDiscoveryValidator {
145
- public id = 'denonavr-candidate-validator';
146
- public description = 'Validate Denon/Marantz AVR candidate metadata.';
147
-
148
- public async validate(candidateArg: IDiscoveryCandidate): Promise<IDiscoveryMatch> {
149
- const manufacturer = candidateArg.manufacturer?.toLowerCase() || '';
150
- const model = candidateArg.model?.toLowerCase() || '';
151
- const matched = candidateArg.integrationDomain === 'denonavr'
152
- || isSupportedManufacturer(manufacturer)
153
- || model.includes('denon')
154
- || model.includes('marantz')
155
- || model.includes('avr')
156
- || model.includes('sr');
157
- const rejected = isIgnoredModel(model);
158
-
159
- return {
160
- matched: matched && !rejected,
161
- confidence: matched && !rejected && candidateArg.host ? 'high' : matched && !rejected ? 'medium' : 'low',
162
- reason: rejected ? 'Candidate is a HEOS speaker, not an AVR.' : matched ? 'Candidate has Denon/Marantz AVR metadata.' : 'Candidate is not a Denon AVR.',
163
- candidate: matched && !rejected ? candidateArg : undefined,
164
- normalizedDeviceId: uniqueId(candidateArg.model, candidateArg.serialNumber) || candidateArg.id,
165
- };
72
+ public readonly id = 'denonavr-candidate-validator';
73
+ public async validate(input: IDiscoveryCandidate): Promise<IDiscoveryMatch> {
74
+ try {
75
+ const record = denonavrRecord(input, ['source', 'integrationDomain', 'id', 'host', 'port', 'name', 'manufacturer', 'model', 'metadata']);
76
+ if (record.integrationDomain !== 'denonavr' || (record.source !== 'manual' && record.source !== 'ssdp')) return miss('Candidate does not belong to selected DenonAVR discovery.');
77
+ const metadata = denonavrRecord(record.metadata, ['descriptionUrl', 'identityEvidence']);
78
+ return candidate(record.host, metadata.descriptionUrl, record.id, record.model, record.manufacturer, record.source,
79
+ typeof record.name === 'string' ? record.name : undefined);
80
+ } catch { return miss('Candidate cannot satisfy selected DenonAVR setup.'); }
166
81
  }
167
82
  }
168
83
 
169
- export const createDenonavrDiscoveryDescriptor = (): DiscoveryDescriptor => {
170
- return new DiscoveryDescriptor({ integrationDomain: 'denonavr', displayName: 'Denon AVR Network Receivers' })
171
- .addMatcher(new DenonavrSsdpMatcher())
172
- .addMatcher(new DenonavrMdnsMatcher())
173
- .addMatcher(new DenonavrManualMatcher())
174
- .addValidator(new DenonavrCandidateValidator());
175
- };
176
-
177
- const header = (recordArg: IDenonavrSsdpRecord, keyArg: string): string | undefined => {
178
- return recordArg[keyArg as keyof IDenonavrSsdpRecord] as string | undefined
179
- || valueForKey(recordArg.headers, keyArg);
180
- };
181
-
182
- const upnp = (recordArg: IDenonavrSsdpRecord, keyArg: string): string | undefined => {
183
- return valueForKey(recordArg.upnp, keyArg) || valueForKey(recordArg.headers, keyArg);
184
- };
185
-
186
- const valueForKey = (recordArg: Record<string, string | undefined> | undefined, keyArg: string): string | undefined => {
187
- if (!recordArg) {
188
- return undefined;
189
- }
190
- const lowerKey = keyArg.toLowerCase();
191
- for (const [key, value] of Object.entries(recordArg)) {
192
- if (key.toLowerCase() === lowerKey) {
193
- return value;
194
- }
195
- }
196
- return undefined;
197
- };
198
-
199
- const parseUrl = (valueArg: string | undefined): URL | undefined => {
200
- if (!valueArg) {
201
- return undefined;
202
- }
203
- try {
204
- return new URL(valueArg);
205
- } catch {
206
- return undefined;
207
- }
208
- };
209
-
210
- const stripUuid = (valueArg: string | undefined): string | undefined => {
211
- return valueArg?.replace(/^uuid:/i, '').split('::')[0];
212
- };
213
-
214
- const cleanModel = (valueArg: string | undefined): string | undefined => {
215
- return valueArg?.replace(/\*/g, '').trim() || undefined;
216
- };
217
-
218
- const isSupportedManufacturer = (valueArg: string | undefined): boolean => {
219
- const value = valueArg?.toLowerCase().trim();
220
- return Boolean(value && supportedManufacturers.includes(value));
221
- };
222
-
223
- const normalizedManufacturer = (valueArg: string | undefined): string | undefined => {
224
- if (!valueArg) {
225
- return undefined;
226
- }
227
- return valueArg.toLowerCase().includes('marantz') ? 'Marantz' : valueArg.toLowerCase().includes('denon') ? 'Denon' : valueArg;
228
- };
229
-
230
- const isIgnoredModel = (valueArg: string | undefined): boolean => {
231
- return Boolean(valueArg && ignoredModels.includes(valueArg.toLowerCase()));
232
- };
233
-
234
- const uniqueId = (modelArg: string | undefined, serialArg: string | undefined): string | undefined => {
235
- if (modelArg && serialArg) {
236
- return `${cleanModel(modelArg)}-${serialArg}`;
237
- }
238
- return serialArg;
239
- };
84
+ export const createDenonavrDiscoveryDescriptor = (): DiscoveryDescriptor =>
85
+ new DiscoveryDescriptor({ integrationDomain: 'denonavr', displayName: 'Denon and Marantz selected receivers' })
86
+ .addMatcher(new DenonavrSsdpMatcher()).addMatcher(new DenonavrManualMatcher()).addValidator(new DenonavrCandidateValidator());
@@ -1,193 +1,47 @@
1
- import * as plugins from '../../plugins.js';
1
+ import type * as plugins from '../../plugins.js';
2
2
  import type { IIntegrationEntity } from '../../core/types.js';
3
- import type { IDenonavrReceiverInfo, IDenonavrSnapshot, IDenonavrZoneState } from './denonavr.types.js';
3
+ import type { IDenonavrSnapshot } from './denonavr.types.js';
4
4
 
5
5
  export class DenonavrMapper {
6
- public static toDevices(snapshotArg: IDenonavrSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
7
- const updatedAt = new Date().toISOString();
8
- const features: plugins.shxInterfaces.data.IDeviceFeature[] = [];
9
- const state: plugins.shxInterfaces.data.IDeviceState[] = [];
10
-
11
- for (const zone of snapshotArg.zones) {
12
- const zoneSlug = this.slug(zone.zone);
13
- features.push(
14
- { id: `${zoneSlug}_power`, capability: 'media', name: `${this.zoneName(zone)} power`, readable: true, writable: true },
15
- { id: `${zoneSlug}_source`, capability: 'media', name: `${this.zoneName(zone)} source`, readable: true, writable: true },
16
- { id: `${zoneSlug}_volume`, capability: 'media', name: `${this.zoneName(zone)} volume`, readable: true, writable: true, unit: '%' },
17
- { id: `${zoneSlug}_muted`, capability: 'media', name: `${this.zoneName(zone)} muted`, readable: true, writable: true },
18
- );
19
- state.push(
20
- { featureId: `${zoneSlug}_power`, value: this.powerState(zone), updatedAt },
21
- { featureId: `${zoneSlug}_source`, value: zone.source || null, updatedAt },
22
- { featureId: `${zoneSlug}_volume`, value: typeof this.volumeLevel(zone) === 'number' ? Math.round((this.volumeLevel(zone) || 0) * 100) : null, updatedAt },
23
- { featureId: `${zoneSlug}_muted`, value: zone.muted ?? null, updatedAt },
24
- );
25
- if (zone.soundMode || zone.soundModeRaw) {
26
- features.push({ id: `${zoneSlug}_sound_mode`, capability: 'media', name: `${this.zoneName(zone)} sound mode`, readable: true, writable: true });
27
- state.push({ featureId: `${zoneSlug}_sound_mode`, value: zone.soundMode || zone.soundModeRaw || null, updatedAt });
28
- }
29
- }
30
-
31
- return [{
32
- id: this.deviceId(snapshotArg),
33
- integrationDomain: 'denonavr',
34
- name: this.receiverName(snapshotArg.receiverInfo),
35
- protocol: 'http',
36
- manufacturer: snapshotArg.receiverInfo.manufacturer || 'Denon',
37
- model: snapshotArg.receiverInfo.modelName || snapshotArg.receiverInfo.modelNumber,
38
- online: snapshotArg.zones.some((zoneArg) => zoneArg.available !== false),
39
- features,
40
- state,
41
- metadata: {
42
- host: snapshotArg.receiverInfo.host,
43
- port: snapshotArg.receiverInfo.port,
44
- serialNumber: snapshotArg.receiverInfo.serialNumber,
45
- receiverType: snapshotArg.receiverInfo.receiverType,
46
- softwareVersion: snapshotArg.receiverInfo.softwareVersion,
47
- },
48
- }];
49
- }
50
-
51
- public static toEntities(snapshotArg: IDenonavrSnapshot): IIntegrationEntity[] {
52
- const entities: IIntegrationEntity[] = [];
53
- for (const zone of snapshotArg.zones) {
54
- const zoneEntityBase = this.entityBase(snapshotArg, zone);
55
- entities.push({
56
- id: `media_player.${zoneEntityBase}`,
57
- uniqueId: `denonavr_${this.uniqueBase(snapshotArg)}_${this.slug(zone.zone)}`,
58
- integrationDomain: 'denonavr',
59
- deviceId: this.deviceId(snapshotArg),
60
- platform: 'media_player',
61
- name: this.mediaEntityName(snapshotArg.receiverInfo, zone),
62
- state: this.mediaState(zone),
63
- attributes: {
64
- deviceClass: 'receiver',
65
- zone: zone.zone,
66
- power: zone.power,
67
- volumeLevel: this.volumeLevel(zone),
68
- volumeDb: zone.volumeDb,
69
- isVolumeMuted: zone.muted,
70
- source: zone.source,
71
- sourceList: zone.sourceList,
72
- soundMode: zone.soundMode,
73
- soundModeRaw: zone.soundModeRaw,
74
- soundModeList: zone.soundModeList,
75
- mediaTitle: zone.media?.title || (!zone.media ? zone.source : undefined),
76
- mediaArtist: zone.media?.artist || zone.media?.band,
77
- mediaAlbumName: zone.media?.album || zone.media?.station,
78
- mediaImageUrl: zone.media?.imageUrl,
79
- mediaContentType: zone.media?.contentType,
80
- dynamicEq: zone.dynamicEq,
81
- ecoMode: zone.ecoMode,
82
- },
83
- available: zone.available !== false,
84
- });
85
-
86
- entities.push({
87
- id: `sensor.${zoneEntityBase}_source`,
88
- uniqueId: `denonavr_${this.uniqueBase(snapshotArg)}_${this.slug(zone.zone)}_source`,
89
- integrationDomain: 'denonavr',
90
- deviceId: this.deviceId(snapshotArg),
91
- platform: 'sensor',
92
- name: `${this.mediaEntityName(snapshotArg.receiverInfo, zone)} Source`,
93
- state: zone.source || 'unknown',
94
- attributes: { zone: zone.zone, soundMode: zone.soundMode || zone.soundModeRaw, ecoMode: zone.ecoMode },
95
- available: zone.available !== false,
96
- });
97
-
98
- if (typeof zone.muted === 'boolean') {
99
- entities.push({
100
- id: `switch.${zoneEntityBase}_mute`,
101
- uniqueId: `denonavr_${this.uniqueBase(snapshotArg)}_${this.slug(zone.zone)}_mute`,
102
- integrationDomain: 'denonavr',
103
- deviceId: this.deviceId(snapshotArg),
104
- platform: 'switch',
105
- name: `${this.mediaEntityName(snapshotArg.receiverInfo, zone)} Mute`,
106
- state: zone.muted,
107
- attributes: { zone: zone.zone },
108
- available: zone.available !== false,
109
- });
110
- }
111
-
112
- if (typeof zone.dynamicEq === 'boolean') {
113
- entities.push({
114
- id: `switch.${zoneEntityBase}_dynamic_eq`,
115
- uniqueId: `denonavr_${this.uniqueBase(snapshotArg)}_${this.slug(zone.zone)}_dynamic_eq`,
116
- integrationDomain: 'denonavr',
117
- deviceId: this.deviceId(snapshotArg),
118
- platform: 'switch',
119
- name: `${this.mediaEntityName(snapshotArg.receiverInfo, zone)} Dynamic EQ`,
120
- state: zone.dynamicEq,
121
- attributes: { zone: zone.zone },
122
- available: zone.available !== false,
123
- });
124
- }
125
- }
126
- return entities;
127
- }
128
-
129
- private static mediaState(zoneArg: IDenonavrZoneState): string {
130
- if (this.powerState(zoneArg) === 'off') {
131
- return 'off';
132
- }
133
- const state = zoneArg.state?.toLowerCase();
134
- if (state === 'playing' || state === 'paused') {
135
- return state;
136
- }
137
- if (state === 'stopped') {
138
- return 'idle';
139
- }
140
- return 'on';
6
+ public static deviceId(homeId: string, udn: string): string {
7
+ return `denonavr.receiver.${encodeURIComponent(homeId)}.${encodeURIComponent(udn)}`;
141
8
  }
142
9
 
143
- private static powerState(zoneArg: IDenonavrZoneState): string {
144
- const power = zoneArg.power?.toLowerCase();
145
- if (power === 'off' || power === 'standby') {
146
- return 'off';
147
- }
148
- if (!power && zoneArg.state?.toLowerCase() === 'off') {
149
- return 'off';
150
- }
151
- return 'on';
10
+ public static entityId(homeId: string, udn: string): string {
11
+ return `media_player.denonavr.${encodeURIComponent(homeId)}.${encodeURIComponent(udn)}`;
152
12
  }
153
13
 
154
- private static volumeLevel(zoneArg: IDenonavrZoneState): number | undefined {
155
- if (typeof zoneArg.volumeLevel === 'number') {
156
- return Math.max(0, Math.min(1, zoneArg.volumeLevel));
157
- }
158
- if (typeof zoneArg.volumeDb === 'number') {
159
- return Math.max(0, Math.min(1, (zoneArg.volumeDb + 80) / 100));
160
- }
161
- return undefined;
162
- }
163
-
164
- private static deviceId(snapshotArg: IDenonavrSnapshot): string {
165
- return `denonavr.receiver.${this.uniqueBase(snapshotArg)}`;
166
- }
167
-
168
- private static entityBase(snapshotArg: IDenonavrSnapshot, zoneArg: IDenonavrZoneState): string {
169
- const suffix = zoneArg.zone === 'Main' ? '' : `_${this.slug(zoneArg.zone)}`;
170
- return `${this.slug(this.receiverName(snapshotArg.receiverInfo))}${suffix}`;
171
- }
172
-
173
- private static uniqueBase(snapshotArg: IDenonavrSnapshot): string {
174
- return this.slug(snapshotArg.receiverInfo.serialNumber || snapshotArg.receiverInfo.modelName || snapshotArg.receiverInfo.host || this.receiverName(snapshotArg.receiverInfo));
175
- }
176
-
177
- private static receiverName(infoArg: IDenonavrReceiverInfo): string {
178
- return infoArg.name || infoArg.friendlyName || infoArg.modelName || 'Denon AVR';
179
- }
180
-
181
- private static mediaEntityName(infoArg: IDenonavrReceiverInfo, zoneArg: IDenonavrZoneState): string {
182
- const name = zoneArg.name || this.zoneName(zoneArg);
183
- return zoneArg.zone === 'Main' ? this.receiverName(infoArg) : `${this.receiverName(infoArg)} ${name}`;
184
- }
185
-
186
- private static zoneName(zoneArg: IDenonavrZoneState): string {
187
- return zoneArg.name || (zoneArg.zone === 'Main' ? 'Main Zone' : zoneArg.zone);
14
+ public static toDevices(snapshot: IDenonavrSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
15
+ return [{
16
+ id: this.deviceId(snapshot.homeId, snapshot.identity.udn), integrationDomain: 'denonavr', name: snapshot.name,
17
+ protocol: 'tcp', manufacturer: snapshot.identity.manufacturer, model: snapshot.identity.model, online: true,
18
+ features: [
19
+ { id: 'power', capability: 'media', name: 'Receiver power', readable: true, writable: true },
20
+ { id: 'muted', capability: 'media', name: 'Main-zone mute', readable: true, writable: true },
21
+ { id: 'volume_db', capability: 'media', name: 'Main-zone absolute volume', unit: 'dB', readable: true, writable: true },
22
+ { id: 'input', capability: 'media', name: 'Main-zone input', readable: true, writable: snapshot.observedInputs.length > 0 },
23
+ ],
24
+ state: [
25
+ { featureId: 'power', value: snapshot.power === 'on', updatedAt: snapshot.observedAt },
26
+ { featureId: 'muted', value: snapshot.muted, updatedAt: snapshot.observedAt },
27
+ { featureId: 'volume_db', value: snapshot.volumeDb, updatedAt: snapshot.observedAt },
28
+ { featureId: 'input', value: snapshot.input, updatedAt: snapshot.observedAt },
29
+ ],
30
+ metadata: { homeId: snapshot.homeId, udn: snapshot.identity.udn, host: snapshot.host, port: snapshot.port,
31
+ serialNumber: snapshot.identity.serialNumber, identitySource: snapshot.identity.source,
32
+ observedInputs: [...snapshot.observedInputs], maximumVolumeDb: snapshot.maximumVolumeDb,
33
+ stateSource: 'receiver-observation', identityAuthentication: 'unauthenticated-lan' },
34
+ }];
188
35
  }
189
36
 
190
- private static slug(valueArg: string): string {
191
- return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'denonavr';
37
+ public static toEntities(snapshot: IDenonavrSnapshot): IIntegrationEntity[] {
38
+ return [{
39
+ id: this.entityId(snapshot.homeId, snapshot.identity.udn), uniqueId: this.deviceId(snapshot.homeId, snapshot.identity.udn),
40
+ integrationDomain: 'denonavr', deviceId: this.deviceId(snapshot.homeId, snapshot.identity.udn), platform: 'media_player',
41
+ name: snapshot.name, state: snapshot.power === 'on' ? 'on' : 'off', available: true,
42
+ attributes: { homeId: snapshot.homeId, udn: snapshot.identity.udn, zone: 'Main', power: snapshot.power,
43
+ volumeDb: snapshot.volumeDb, muted: snapshot.muted, source: snapshot.input, sourceList: [...snapshot.observedInputs],
44
+ maximumVolumeDb: snapshot.maximumVolumeDb, observedAt: snapshot.observedAt, stateSource: 'receiver-observation' },
45
+ }];
192
46
  }
193
47
  }