@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,147 +1,44 @@
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 { IBraviatvSnapshot, IBraviatvState } from './braviatv.types.js';
3
+ import type { IBraviatvSnapshot, TBraviatvControl } from './braviatv.types.js';
4
4
 
5
5
  export class BraviatvMapper {
6
- public static toDevices(snapshotArg: IBraviatvSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
7
- const state = this.state(snapshotArg);
8
- const updatedAt = snapshotArg.updatedAt || new Date().toISOString();
9
- return [{
10
- id: this.deviceId(snapshotArg),
11
- integrationDomain: 'braviatv',
12
- name: this.deviceName(snapshotArg),
13
- protocol: 'http',
14
- manufacturer: 'Sony',
15
- model: snapshotArg.systemInfo.model,
16
- online: state.available !== false && state.power !== 'off',
17
- features: [
18
- { id: 'power', capability: 'media', name: 'Power', readable: true, writable: true },
19
- { id: 'playback', capability: 'media', name: 'Playback', readable: true, writable: true },
20
- { id: 'source', capability: 'media', name: 'Source', readable: true, writable: true },
21
- { id: 'volume', capability: 'media', name: 'Volume', readable: true, writable: true, unit: '%' },
22
- { id: 'muted', capability: 'media', name: 'Muted', readable: true, writable: true },
23
- { id: 'remote_command', capability: 'media', name: 'Remote command', readable: false, writable: true },
24
- ],
25
- state: [
26
- { featureId: 'power', value: state.power, updatedAt },
27
- { featureId: 'playback', value: state.playback, updatedAt },
28
- { featureId: 'source', value: this.source(snapshotArg) || null, updatedAt },
29
- { featureId: 'volume', value: state.volumePercent ?? null, updatedAt },
30
- { featureId: 'muted', value: state.muted ?? null, updatedAt },
31
- ],
32
- metadata: {
33
- cid: snapshotArg.systemInfo.cid,
34
- serialNumber: snapshotArg.systemInfo.serial,
35
- macAddress: snapshotArg.systemInfo.macAddr,
36
- generation: snapshotArg.systemInfo.generation,
37
- sources: snapshotArg.sources.map((sourceArg) => ({ title: sourceArg.title, uri: sourceArg.uri, type: sourceArg.type })),
38
- apps: snapshotArg.apps.map((appArg) => ({ title: appArg.title, uri: appArg.uri, icon: appArg.icon })),
39
- },
40
- }];
41
- }
42
-
43
- public static toEntities(snapshotArg: IBraviatvSnapshot): IIntegrationEntity[] {
44
- const state = this.state(snapshotArg);
45
- return [{
46
- id: `media_player.${this.slug(this.deviceName(snapshotArg))}`,
47
- uniqueId: `braviatv_${this.slug(this.identity(snapshotArg))}`,
48
- integrationDomain: 'braviatv',
49
- deviceId: this.deviceId(snapshotArg),
50
- platform: 'media_player',
51
- name: this.deviceName(snapshotArg),
52
- state: this.mediaState(state),
53
- attributes: {
54
- source: this.source(snapshotArg),
55
- sourceUri: state.sourceUri,
56
- sourceList: this.sourceList(snapshotArg),
57
- volumeLevel: state.volumeLevel,
58
- isVolumeMuted: state.muted,
59
- mediaTitle: state.mediaTitle,
60
- mediaChannel: state.mediaChannel,
61
- mediaContentId: state.mediaContentId,
62
- mediaContentType: state.mediaContentType,
63
- mediaDuration: state.mediaDuration,
64
- mediaPosition: state.mediaPosition,
65
- mediaPositionUpdatedAt: state.mediaPositionUpdatedAt,
66
- model: snapshotArg.systemInfo.model,
67
- powerStatus: state.powerStatus,
68
- },
69
- available: state.available !== false,
70
- }];
71
- }
72
-
73
- public static deviceId(snapshotArg: IBraviatvSnapshot): string {
74
- return `braviatv.device.${this.slug(this.identity(snapshotArg))}`;
75
- }
76
-
77
- private static state(snapshotArg: IBraviatvSnapshot): IBraviatvState & Required<Pick<IBraviatvState, 'power' | 'playback'>> {
78
- const state = snapshotArg.state || {};
79
- const power = state.power || this.powerFromStatus(state.powerStatus);
80
- return {
81
- ...state,
82
- power,
83
- playback: state.playback || (power === 'off' ? 'off' : 'idle'),
84
- volumePercent: typeof state.volumePercent === 'number' ? state.volumePercent : typeof state.volumeLevel === 'number' ? Math.round(state.volumeLevel * 100) : undefined,
85
- };
86
- }
87
-
88
- private static mediaState(stateArg: IBraviatvState): string {
89
- if (stateArg.available === false) {
90
- return 'unavailable';
91
- }
92
- if (stateArg.power === 'off') {
93
- return 'off';
94
- }
95
- if (stateArg.playback === 'playing') {
96
- return 'playing';
97
- }
98
- if (stateArg.playback === 'paused') {
99
- return 'paused';
100
- }
101
- if (stateArg.power === 'unknown') {
102
- return 'unknown';
103
- }
104
- return stateArg.source || stateArg.mediaTitle ? 'on' : 'idle';
105
- }
106
-
107
- private static source(snapshotArg: IBraviatvSnapshot): string | undefined {
108
- return snapshotArg.state.source || this.sourceTitle(snapshotArg, snapshotArg.state.sourceUri) || snapshotArg.state.appTitle;
109
- }
110
-
111
- private static sourceList(snapshotArg: IBraviatvSnapshot): string[] {
112
- const values = [...snapshotArg.sources, ...snapshotArg.apps, ...(snapshotArg.channels || [])]
113
- .map((sourceArg) => sourceArg.title)
114
- .filter(Boolean);
115
- return [...new Set(values)];
116
- }
117
-
118
- private static sourceTitle(snapshotArg: IBraviatvSnapshot, uriArg: string | undefined): string | undefined {
119
- if (!uriArg) {
120
- return undefined;
121
- }
122
- return [...snapshotArg.sources, ...snapshotArg.apps, ...(snapshotArg.channels || [])].find((sourceArg) => sourceArg.uri === uriArg)?.title;
123
- }
124
-
125
- private static powerFromStatus(statusArg: string | undefined): 'on' | 'off' | 'unknown' {
126
- const status = (statusArg || '').toLowerCase();
127
- if (status === 'active') {
128
- return 'on';
129
- }
130
- if (status === 'standby' || status === 'off') {
131
- return 'off';
132
- }
133
- return 'unknown';
134
- }
135
-
136
- private static deviceName(snapshotArg: IBraviatvSnapshot): string {
137
- return snapshotArg.systemInfo.name || snapshotArg.systemInfo.model || 'Sony Bravia TV';
138
- }
139
-
140
- private static identity(snapshotArg: IBraviatvSnapshot): string {
141
- return snapshotArg.systemInfo.cid || snapshotArg.systemInfo.macAddr || snapshotArg.systemInfo.serial || this.deviceName(snapshotArg);
142
- }
143
-
144
- private static slug(valueArg: string): string {
145
- return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'braviatv';
6
+ public static deviceId(homeId: string, macAddress: string): string {
7
+ return `braviatv.display.${encodeURIComponent(homeId)}.${macAddress.replace(/:/g, '').toLowerCase()}`;
8
+ }
9
+ public static entityId(homeId: string, macAddress: string, feature: TBraviatvControl['feature']): string {
10
+ return `${feature === 'speaker_volume_raw' ? 'number' : 'switch'}.braviatv.${encodeURIComponent(homeId)}.${macAddress.replace(/:/g, '').toLowerCase()}.${feature}`;
11
+ }
12
+ public static toDevices(snapshot: IBraviatvSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
13
+ const features: plugins.shxInterfaces.data.IDeviceFeature[] = [];
14
+ const state: plugins.shxInterfaces.data.IDeviceState[] = [];
15
+ if (snapshot.power !== undefined) {
16
+ features.push({ id: 'power', capability: 'switch', name: 'Reported display power', readable: true, writable: snapshot.capabilities.power });
17
+ state.push({ featureId: 'power', value: snapshot.power, updatedAt: snapshot.observedAt });
18
+ }
19
+ if (snapshot.speaker) {
20
+ features.push({ id: 'device_mute', capability: 'switch', name: 'Device mute (speaker observation)', readable: true, writable: snapshot.capabilities.deviceMute },
21
+ { id: 'speaker_volume_raw', capability: 'sensor', name: 'Reported speaker volume', unit: 'raw level', readable: true, writable: snapshot.capabilities.speakerVolume });
22
+ state.push({ featureId: 'device_mute', value: snapshot.speaker.muted, updatedAt: snapshot.observedAt },
23
+ { featureId: 'speaker_volume_raw', value: snapshot.speaker.volumeRaw, updatedAt: snapshot.observedAt });
24
+ }
25
+ return [{ id: this.deviceId(snapshot.homeId, snapshot.identity.macAddress), integrationDomain: 'braviatv',
26
+ name: snapshot.name, protocol: 'http', manufacturer: 'Sony', model: snapshot.identity.model, online: true, features, state,
27
+ metadata: { homeId: snapshot.homeId, host: snapshot.host, port: snapshot.port, macAddress: snapshot.identity.macAddress,
28
+ serialNumber: snapshot.identity.serial, stateSource: 'independent-display-report', identityAuthentication: 'psk-does-not-prove-peer-identity',
29
+ unencryptedLan: true, volumeLimitRaw: snapshot.capabilities.volumeLimitRaw,
30
+ ...(snapshot.speaker ? { minimumVolumeRaw: snapshot.speaker.minimumVolumeRaw, maximumVolumeRaw: snapshot.speaker.maximumVolumeRaw } : {}) } }];
31
+ }
32
+ public static toEntities(snapshot: IBraviatvSnapshot): IIntegrationEntity[] {
33
+ const device = this.toDevices(snapshot)[0];
34
+ return device.features.map((feature) => ({
35
+ id: this.entityId(snapshot.homeId, snapshot.identity.macAddress, feature.id as TBraviatvControl['feature']),
36
+ uniqueId: `${device.id}.${feature.id}`, integrationDomain: 'braviatv', deviceId: device.id,
37
+ platform: feature.id === 'speaker_volume_raw' ? 'number' : 'switch', name: `${snapshot.name} ${feature.name}`,
38
+ state: device.state.find((entry) => entry.featureId === feature.id)!.value, available: true,
39
+ attributes: { ...device.metadata, observedAt: snapshot.observedAt, writable: feature.writable,
40
+ ...(feature.id === 'speaker_volume_raw' ? { step: 1, minimum: snapshot.speaker!.minimumVolumeRaw,
41
+ maximum: snapshot.speaker!.maximumVolumeRaw,
42
+ ...(snapshot.capabilities.speakerVolume ? { maximumWritableRaw: Math.min(snapshot.speaker!.maximumVolumeRaw, snapshot.capabilities.volumeLimitRaw) } : {}) } : {}) } }));
146
43
  }
147
44
  }
@@ -1,194 +1,74 @@
1
- export type TBraviatvPowerStatus = 'active' | 'standby' | 'off' | 'unknown' | string;
2
-
3
- export type TBraviatvPowerState = 'on' | 'off' | 'unknown';
4
-
5
- export type TBraviatvPlaybackState = 'playing' | 'paused' | 'idle' | 'off' | 'unknown';
6
-
7
- export type TBraviatvSourceType = 'input' | 'app' | 'channel';
8
-
9
- export type TBraviatvRestService = 'accessControl' | 'appControl' | 'audio' | 'avContent' | 'guide' | 'system' | 'video' | 'videoScreen';
1
+ import type * as plugins from '../../plugins.js';
2
+ import type { IIntegrationSetupContext } from '../../core/types.js';
10
3
 
4
+ /** Selected BRAVIA Professional v1.0 endpoint; this object contains no credential. */
11
5
  export interface IBraviatvConfig {
12
- host?: string;
13
- port?: number;
14
- useSsl?: boolean;
15
- psk?: string;
16
- pin?: string;
17
- usePsk?: boolean;
18
- clientId?: string;
19
- nickname?: string;
6
+ homeId: string;
7
+ host: string;
8
+ expectedModel: string;
9
+ expectedMacAddress: string;
10
+ expectedSerial?: string;
11
+ credentialRef: string;
12
+ allowUnencryptedLan: true;
13
+ volumeLimitRaw: number;
20
14
  name?: string;
21
- model?: string;
22
- manufacturer?: string;
23
- macAddress?: string;
24
- serialNumber?: string;
25
- cid?: string;
15
+ port?: number;
26
16
  timeoutMs?: number;
27
- irccEndpoint?: 'ircc' | 'IRCC' | string;
28
- fetchChannels?: boolean;
29
- systemInfo?: IBraviatvSystemInfo;
30
- state?: IBraviatvState;
31
- sources?: IBraviatvSource[];
32
- apps?: IBraviatvApp[];
33
- channels?: IBraviatvChannel[];
34
- commands?: Record<string, string>;
35
- snapshot?: IBraviatvSnapshot;
36
- scalarWebApiBaseUrl?: string;
17
+ maxPendingOperations?: number;
18
+ maxResponseBytes?: number;
37
19
  }
38
-
39
20
  export interface IHomeAssistantBraviatvConfig extends IBraviatvConfig {}
40
21
 
41
- export interface IBraviatvSystemInfo {
42
- product?: string;
43
- region?: string;
44
- language?: string;
45
- model?: string;
46
- serial?: string;
47
- macAddr?: string;
48
- name?: string;
49
- generation?: string;
50
- area?: string;
51
- cid?: string;
52
- [key: string]: unknown;
53
- }
54
-
55
- export interface IBraviatvVolumeInfo {
56
- target?: string;
57
- volume?: number | string;
58
- minVolume?: number;
59
- maxVolume?: number;
60
- mute?: boolean;
61
- [key: string]: unknown;
62
- }
63
-
64
- export interface IBraviatvPlayingInfo {
65
- title?: string;
66
- uri?: string;
67
- source?: string;
68
- programTitle?: string;
69
- dispNum?: string;
70
- durationSec?: number;
71
- startDateTime?: string;
72
- mediaType?: string;
73
- [key: string]: unknown;
74
- }
75
-
76
- export interface IBraviatvSource {
77
- title: string;
78
- uri: string;
79
- type?: TBraviatvSourceType;
80
- icon?: string;
81
- label?: string;
82
- connection?: string;
83
- status?: string;
84
- dispNum?: string;
85
- [key: string]: unknown;
86
- }
87
-
88
- export interface IBraviatvApp extends IBraviatvSource {
89
- type?: 'app';
90
- }
91
-
92
- export interface IBraviatvChannel extends IBraviatvSource {
93
- type?: 'channel';
94
- dispNum?: string;
95
- }
96
-
97
- export interface IBraviatvState {
98
- powerStatus?: TBraviatvPowerStatus;
99
- power?: TBraviatvPowerState;
100
- playback?: TBraviatvPlaybackState;
101
- available?: boolean;
102
- source?: string;
103
- sourceUri?: string;
104
- appTitle?: string;
105
- volumeLevel?: number;
106
- volumePercent?: number;
107
- muted?: boolean;
108
- mediaTitle?: string;
109
- mediaChannel?: string;
110
- mediaContentId?: string;
111
- mediaContentType?: string;
112
- mediaDuration?: number;
113
- mediaPosition?: number;
114
- mediaPositionUpdatedAt?: string;
115
- lastError?: string;
116
- }
117
-
118
- export interface IBraviatvSnapshot {
119
- systemInfo: IBraviatvSystemInfo;
120
- state: IBraviatvState;
121
- sources: IBraviatvSource[];
122
- apps: IBraviatvApp[];
123
- channels?: IBraviatvChannel[];
124
- commands?: Record<string, string>;
125
- updatedAt?: string;
126
- }
127
-
128
- export interface IBraviatvRestCommand {
129
- type: 'rest';
130
- service: TBraviatvRestService;
131
- method: string;
132
- params?: unknown[];
133
- version?: string;
134
- }
135
-
136
- export interface IBraviatvIrccCommand {
137
- type: 'ircc';
138
- command?: string;
139
- code?: string;
140
- }
141
-
142
- export interface IBraviatvSourceCommand {
143
- type: 'source';
144
- source: string;
145
- }
146
-
147
- export type TBraviatvCommand = IBraviatvRestCommand | IBraviatvIrccCommand | IBraviatvSourceCommand;
148
-
149
- export interface IBraviatvEvent {
150
- type: 'snapshot' | 'command' | 'error';
151
- command?: TBraviatvCommand;
152
- snapshot?: IBraviatvSnapshot;
153
- message?: string;
154
- timestamp: number;
155
- }
156
-
22
+ export interface IBraviatvCredentialRequest {
23
+ readonly homeId: string;
24
+ readonly credentialRef: string;
25
+ readonly signal: AbortSignal;
26
+ readonly deadline: number;
27
+ }
28
+ /** Caller owns credential retrieval, storage and its cancellation implementation. */
29
+ export type TBraviatvPskResolver = (request: IBraviatvCredentialRequest) => Promise<string>;
30
+ export interface IBraviatvIntegrationOptions {
31
+ readonly homeId?: string;
32
+ readonly capacity?: number;
33
+ readonly resolvePsk: TBraviatvPskResolver;
34
+ }
35
+ export interface IBraviatvSetupContext extends IIntegrationSetupContext { homeId: string; }
36
+
37
+ export interface IBraviatvSnapshot extends plugins.ecobridgeDeviceManager.ISonyBraviaState {
38
+ readonly homeId: string;
39
+ readonly host: string;
40
+ readonly port: number;
41
+ readonly name: string;
42
+ }
43
+ export interface IBraviatvEffectResult {
44
+ readonly control: plugins.ecobridgeDeviceManager.ISonyBraviaControlObservation['control'];
45
+ readonly requested: boolean | number;
46
+ readonly commandAcknowledged: true;
47
+ readonly causalityConfirmed: false;
48
+ readonly observation: plugins.ecobridgeDeviceManager.ISonyBraviaControlObservation['observation'];
49
+ readonly snapshot: IBraviatvSnapshot;
50
+ }
51
+ export type TBraviatvControl = { feature: 'power'; value: boolean }
52
+ | { feature: 'device_mute'; value: boolean }
53
+ | { feature: 'speaker_volume_raw'; value: number };
54
+
55
+ /** Unverified discovery hints do not establish identity or authorize control. */
157
56
  export interface IBraviatvSsdpRecord {
158
- st?: string;
159
- usn?: string;
160
- location?: string;
57
+ st?: string; usn?: string; location?: string;
161
58
  headers?: Record<string, string | undefined>;
162
59
  upnp?: Record<string, unknown>;
163
- ssdp_st?: string;
164
- ssdp_usn?: string;
165
- ssdp_location?: string;
60
+ ssdp_st?: string; ssdp_usn?: string; ssdp_location?: string;
166
61
  [key: string]: unknown;
167
62
  }
168
-
169
63
  export interface IBraviatvMdnsRecord {
170
- type?: string;
171
- name?: string;
172
- host?: string;
173
- port?: number;
64
+ type?: string; name?: string; host?: string; port?: number;
174
65
  txt?: Record<string, string | undefined>;
175
66
  properties?: Record<string, string | undefined>;
176
67
  metadata?: Record<string, unknown>;
177
68
  }
178
-
179
69
  export interface IBraviatvManualEntry {
180
- host?: string;
181
- port?: number;
182
- id?: string;
183
- name?: string;
184
- model?: string;
185
- manufacturer?: string;
186
- macAddress?: string;
187
- serialNumber?: string;
188
- cid?: string;
189
- psk?: string;
190
- useSsl?: boolean;
70
+ host?: string; port?: number; id?: string; name?: string; model?: string;
71
+ manufacturer?: string; macAddress?: string; serialNumber?: string; cid?: string;
191
72
  metadata?: Record<string, unknown>;
192
73
  }
193
-
194
74
  export type TBraviatvDiscoveryRecord = IBraviatvSsdpRecord | IBraviatvMdnsRecord | IBraviatvManualEntry;
@@ -0,0 +1,68 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { IBraviatvConfig, IBraviatvIntegrationOptions, TBraviatvControl } from './braviatv.types.js';
3
+
4
+ export function braviatvRecord(value: unknown, allowed?: readonly string[]): Record<string, unknown> {
5
+ if (!value || typeof value !== 'object' || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) {
6
+ throw new TypeError('BRAVIA input must be a plain data object.');
7
+ }
8
+ const result: Record<string, unknown> = {};
9
+ for (const key of Reflect.ownKeys(value)) {
10
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
11
+ if (typeof key !== 'string' || allowed && !allowed.includes(key) || !descriptor || !('value' in descriptor) || !descriptor.enumerable) {
12
+ throw new TypeError('BRAVIA input contains an unsupported field or accessor.');
13
+ }
14
+ Object.defineProperty(result, key, { value: descriptor.value, enumerable: true });
15
+ }
16
+ return result;
17
+ }
18
+ export function braviatvText(value: unknown, label: string, maximum = 128): string {
19
+ if (typeof value !== 'string' || !value || value !== value.trim() || value.length > maximum || /[\p{Cc}\p{Cs}]/u.test(value)) {
20
+ throw new TypeError(`BRAVIA ${label} must be bounded text without control characters.`);
21
+ }
22
+ return value;
23
+ }
24
+ export function braviatvInteger(value: unknown, minimum: number, maximum: number): number {
25
+ if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum || value > maximum) {
26
+ throw new TypeError('BRAVIA integer is outside its supported bounds.');
27
+ }
28
+ return value;
29
+ }
30
+ export function normalizeBraviatvConfig(value: unknown): Readonly<Required<Omit<IBraviatvConfig, 'expectedSerial' | 'name'>> & Pick<IBraviatvConfig, 'expectedSerial' | 'name'>> {
31
+ const config = braviatvRecord(value, ['homeId', 'host', 'expectedModel', 'expectedMacAddress', 'expectedSerial',
32
+ 'credentialRef', 'allowUnencryptedLan', 'volumeLimitRaw', 'name', 'port', 'timeoutMs', 'maxPendingOperations', 'maxResponseBytes']);
33
+ const host = braviatvText(config.host, 'selected IPv4', 15);
34
+ const [first, second, , last] = host.split('.').map(Number);
35
+ if (plugins.net.isIP(host) !== 4 || !(first === 10 || first === 127 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168) || last === 0 || last === 255) {
36
+ throw new TypeError('BRAVIA requires a selected private or loopback host IPv4 address.');
37
+ }
38
+ const mac = braviatvText(config.expectedMacAddress, 'selected active-network MAC', 17);
39
+ if (!/^(?:[0-9a-f]{2}:){5}[0-9a-f]{2}$/i.test(mac) || /^(?:00:){5}00$|^(?:ff:){5}ff$/i.test(mac) || (Number.parseInt(mac.slice(0, 2), 16) & 1) !== 0) {
40
+ throw new TypeError('BRAVIA requires an exact usable active-network MAC.');
41
+ }
42
+ if (config.allowUnencryptedLan !== true) throw new TypeError('BRAVIA requires explicit unencrypted LAN consent.');
43
+ return Object.freeze({ homeId: braviatvText(config.homeId, 'home ID', 256), host,
44
+ expectedModel: braviatvText(config.expectedModel, 'selected model'), expectedMacAddress: mac.toUpperCase(),
45
+ ...(config.expectedSerial === undefined ? {} : { expectedSerial: braviatvText(config.expectedSerial, 'selected serial') }),
46
+ credentialRef: braviatvText(config.credentialRef, 'credential reference', 256), allowUnencryptedLan: true,
47
+ volumeLimitRaw: braviatvInteger(config.volumeLimitRaw, 0, 100),
48
+ ...(config.name === undefined ? {} : { name: braviatvText(config.name, 'display name') }),
49
+ port: braviatvInteger(config.port ?? 80, 1, 65535), timeoutMs: braviatvInteger(config.timeoutMs ?? 5000, 1, 30000),
50
+ maxPendingOperations: braviatvInteger(config.maxPendingOperations ?? 16, 1, 128),
51
+ maxResponseBytes: braviatvInteger(config.maxResponseBytes ?? 32768, 1024, 65536) });
52
+ }
53
+ export function normalizeBraviatvOptions(value: unknown): Readonly<IBraviatvIntegrationOptions> {
54
+ const options = braviatvRecord(value, ['homeId', 'capacity', 'resolvePsk']);
55
+ if (typeof options.resolvePsk !== 'function') throw new TypeError('BRAVIA requires a caller-owned PSK resolver.');
56
+ return Object.freeze({
57
+ ...(options.homeId === undefined ? {} : { homeId: braviatvText(options.homeId, 'caller home ID', 256) }),
58
+ ...(options.capacity === undefined ? {} : { capacity: braviatvInteger(options.capacity, 1, Number.MAX_SAFE_INTEGER) }),
59
+ resolvePsk: options.resolvePsk as IBraviatvIntegrationOptions['resolvePsk'],
60
+ });
61
+ }
62
+ export function validateBraviatvControl(value: unknown): TBraviatvControl {
63
+ const control = braviatvRecord(value, ['feature', 'value']);
64
+ if (control.feature === 'power' && typeof control.value === 'boolean') return { feature: 'power', value: control.value };
65
+ if (control.feature === 'device_mute' && typeof control.value === 'boolean') return { feature: 'device_mute', value: control.value };
66
+ if (control.feature === 'speaker_volume_raw') return { feature: 'speaker_volume_raw', value: braviatvInteger(control.value, 0, 100) };
67
+ throw new TypeError('BRAVIA supports absolute power, device mute and integer speaker volume only.');
68
+ }
@@ -0,0 +1,31 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import { broadlinkRecord, broadlinkName } from './broadlink.validation.js';
3
+ import type { IBroadlinkIrAction } from './broadlink.types.js';
4
+
5
+ export const readBroadlinkActions = (valueArg: unknown): ReadonlyArray<Readonly<IBroadlinkIrAction>> => {
6
+ if (!Array.isArray(valueArg) || Object.getPrototypeOf(valueArg) !== Array.prototype
7
+ || valueArg.length < 1 || valueArg.length > 32 || Reflect.ownKeys(valueArg).length !== valueArg.length + 1) {
8
+ throw new TypeError('Broadlink requires 1 through 32 owner-configured IR actions in a dense array.');
9
+ }
10
+ const ids = new Set<string>();
11
+ const actions: Readonly<IBroadlinkIrAction>[] = [];
12
+ for (let index = 0; index < valueArg.length; index++) {
13
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, String(index));
14
+ if (!descriptor?.enumerable || !('value' in descriptor)) throw new TypeError('Broadlink actions may not contain accessors or holes.');
15
+ const action = broadlinkRecord(descriptor.value, ['id', 'name', 'packetBase64']);
16
+ if (typeof action.id !== 'string' || !/^[a-z][a-z0-9_-]{0,63}$/.test(action.id) || ids.has(action.id)) {
17
+ throw new TypeError('Broadlink action IDs must be unique lowercase identifiers, at most 64 characters.');
18
+ }
19
+ const name = broadlinkName(action.name, 'action name', 128);
20
+ if (typeof action.packetBase64 !== 'string' || action.packetBase64.length > 1368) throw new TypeError('Broadlink IR action requires bounded canonical base64.');
21
+ const packet = Buffer.from(action.packetBase64, 'base64');
22
+ try {
23
+ if (packet.toString('base64') !== action.packetBase64) throw new TypeError('Broadlink IR action requires canonical base64.');
24
+ const validated = plugins.ecobridgeDeviceManager.copyBroadlinkIrPacket(packet);
25
+ validated.fill(0);
26
+ } finally { packet.fill(0); }
27
+ ids.add(action.id);
28
+ actions.push(Object.freeze({ id: action.id, name, packetBase64: action.packetBase64 }));
29
+ }
30
+ return Object.freeze(actions);
31
+ };