@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,97 +1,143 @@
1
- import type * as shxInterfaces from '@smarthome.exchange/interfaces';
1
+ import * as plugins from '../../plugins.js';
2
2
  import { BaseIntegration } from '../../core/classes.baseintegration.js';
3
- import type { IIntegrationEntity, IIntegrationEvent, IIntegrationRuntime, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
3
+ import { NativeIntegrationOwner, type INativeSetupLease } from '../../core/classes.nativeintegrationowner.js';
4
+ import type { IDeviceFeatureWriteRequest, IIntegrationEntity, IIntegrationRuntime, IIntegrationSetupContext,
5
+ IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
4
6
  import { BroadlinkClient } from './broadlink.classes.client.js';
5
7
  import { BroadlinkConfigFlow } from './broadlink.classes.configflow.js';
6
8
  import { createBroadlinkDiscoveryDescriptor } from './broadlink.discovery.js';
7
- import { BroadlinkMapper } from './broadlink.mapper.js';
9
+ import { BroadlinkSelectedMapper } from './broadlink.selected.mapper.js';
10
+ import { readBroadlinkActions } from './broadlink.actions.js';
11
+ import { broadlinkRecord, readBroadlinkSelection } from './broadlink.validation.js';
8
12
  import type { IBroadlinkConfig } from './broadlink.types.js';
9
13
 
14
+ const refused = (messageArg: string): IServiceCallResult => ({ success: false, error: messageArg,
15
+ data: { outcome: 'not-sent', physicalEffectConfirmed: false } });
16
+
17
+ export interface IBroadlinkIntegrationOptions {
18
+ readonly homeId?: string;
19
+ readonly capacity?: number;
20
+ }
21
+
10
22
  export class BroadlinkIntegration extends BaseIntegration<IBroadlinkConfig> {
11
23
  public readonly domain = 'broadlink';
12
24
  public readonly displayName = 'Broadlink';
13
25
  public readonly status = 'control-runtime' as const;
14
26
  public readonly discoveryDescriptor = createBroadlinkDiscoveryDescriptor();
15
- public readonly configFlow = new BroadlinkConfigFlow();
27
+ public readonly configFlow: BroadlinkConfigFlow;
16
28
  public readonly metadata = {
17
- source: 'home-assistant/core',
18
- upstreamPath: 'homeassistant/components/broadlink',
19
- upstreamDomain: 'broadlink',
20
- integrationType: 'device',
21
- iotClass: 'local_polling',
22
- requirements: ['broadlink==0.19.0'],
23
- dependencies: [],
24
- afterDependencies: [],
25
- codeowners: ['@danielhiversen', '@felipediel', '@L-I-Am', '@eifinger'],
26
- documentation: 'https://www.home-assistant.io/integrations/broadlink',
27
- configFlow: true,
28
- discovery: {
29
- dhcp: true,
30
- manual: true,
31
- localHelloRecords: true,
32
- note: 'Home Assistant uses python-broadlink UDP hello/auth. This native port recognizes DHCP/manual/local hello candidates; live UDP is an injected executor boundary.',
33
- },
34
- runtime: {
35
- type: 'control-runtime',
36
- polling: 'snapshot/manual',
37
- services: ['remote.send_command', 'remote.learn_command', 'remote.delete_command', 'switch.turn_on', 'switch.turn_off', 'infrared.send_command', 'radio_frequency.send_command', 'broadlink.send_packet'],
38
- liveUdpAuthImplemented: false,
39
- },
40
- localApi: {
41
- implemented: [
42
- 'Broadlink DHCP/manual/local hello discovery candidate mapping',
43
- 'Config flow shape for host, MAC, device type, timeout, and optional snapshot JSON',
44
- 'Snapshot mapping for RM remote entities, Broadlink switch/outlet slots, custom IR/RF switches, and safe sensor keys',
45
- 'Packet encoding for Broadlink IR timings and 315/433 MHz RF timings',
46
- 'Explicit service command shapes for learned-code send/delete, learn IR/RF, send packet, switch power, IR, and RF commands',
47
- ],
48
- explicitUnsupported: [
49
- 'Native Broadlink UDP discovery broadcast from this package',
50
- 'Native Broadlink encrypted UDP auth/session transport',
51
- 'Claiming live packets were sent without an injected commandExecutor or transport.execute',
52
- ],
53
- },
29
+ integrationType: 'device', iotClass: 'local_polling',
30
+ runtime: { type: 'control-runtime', liveUdpAuthImplemented: true,
31
+ services: ['button.press', 'broadlink.send_ir'], physicalEffectConfirmed: false, hardwareVerified: false },
32
+ localApi: { supportedDeviceTypes: [0x2737, 0x51da], ownerConfiguredRawIrOnly: true,
33
+ cryptographicPeerTrust: false, learning: false, rf: false, retransmission: false },
54
34
  };
35
+ readonly #owner: NativeIntegrationOwner;
36
+
37
+ constructor(optionsArg: IBroadlinkIntegrationOptions = {}) {
38
+ super();
39
+ this.#owner = new NativeIntegrationOwner('broadlink', optionsArg);
40
+ this.configFlow = new BroadlinkConfigFlow(this.#owner.createFlowScope());
41
+ }
55
42
 
56
43
  public async setup(configArg: IBroadlinkConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
57
- void contextArg;
58
- return new BroadlinkRuntime(new BroadlinkClient(configArg));
44
+ const config = broadlinkRecord(configArg, ['homeId', 'host', 'macAddress', 'deviceType', 'port',
45
+ 'localAddress', 'timeoutMs', 'maxPendingOperations', 'name', 'actions']);
46
+ const selection = readBroadlinkSelection(config);
47
+ const actions = config.actions === undefined ? undefined : readBroadlinkActions(config.actions);
48
+ const captured: IBroadlinkConfig = { ...selection, actions: actions?.map((actionArg) => ({ ...actionArg })) };
49
+ return this.#owner.runSetup(contextArg, selection.homeId, async (leaseArg) => {
50
+ const client = new BroadlinkClient(captured, { ...leaseArg.context, abortSignal: leaseArg.signal });
51
+ leaseArg.own(() => client.retryCleanup());
52
+ await client.initialize();
53
+ leaseArg.assertOpen();
54
+ const runtime = new BroadlinkRuntime(client, leaseArg);
55
+ leaseArg.promoteToRuntime();
56
+ return runtime;
57
+ });
59
58
  }
60
59
 
61
- public async destroy(): Promise<void> {}
60
+ public destroy(): Promise<void> { return this.#owner.close(); }
61
+ public retryCleanup(): Promise<void> { return this.#owner.retryCleanup(); }
62
62
  }
63
63
 
64
64
  export class HomeAssistantBroadlinkIntegration extends BroadlinkIntegration {}
65
65
 
66
66
  class BroadlinkRuntime implements IIntegrationRuntime {
67
- public domain = 'broadlink';
68
-
69
- constructor(private readonly client: BroadlinkClient) {}
67
+ public readonly domain = 'broadlink';
68
+ constructor(private readonly client: BroadlinkClient, private readonly lease: INativeSetupLease) {}
69
+ public isHealthy(): boolean { return this.client.isHealthy(); }
70
70
 
71
- public async devices(): Promise<shxInterfaces.data.IDeviceDefinition[]> {
72
- return BroadlinkMapper.toDevices(await this.client.getSnapshot());
71
+ public async devices(signalArg?: AbortSignal): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> {
72
+ return BroadlinkSelectedMapper.toDevices(await this.client.getSnapshot(signalArg));
73
73
  }
74
-
75
74
  public async entities(): Promise<IIntegrationEntity[]> {
76
- return BroadlinkMapper.toEntities(await this.client.getSnapshot());
75
+ return BroadlinkSelectedMapper.toEntities(await this.client.getSnapshot());
77
76
  }
78
77
 
79
- public async subscribe(handlerArg: (eventArg: IIntegrationEvent) => void): Promise<() => Promise<void>> {
80
- const unsubscribe = this.client.onEvent((eventArg) => handlerArg(BroadlinkMapper.toIntegrationEvent(eventArg)));
81
- return async () => unsubscribe();
78
+ public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
79
+ try {
80
+ const request = broadlinkRecord(requestArg, ['domain', 'service', 'target', 'data']);
81
+ const target = broadlinkRecord(request.target, ['entityId', 'deviceId']);
82
+ const snapshot = this.client.currentSnapshot;
83
+ const knownDeviceId = BroadlinkSelectedMapper.deviceId(snapshot.selection);
84
+ if (target.deviceId !== undefined && target.deviceId !== knownDeviceId) return refused('Broadlink service target is outside the selected home and bridge.');
85
+ if (request.domain === 'button' && request.service === 'press') {
86
+ if (request.data !== undefined) broadlinkRecord(request.data, []);
87
+ const action = snapshot.actions.find((actionArg) => BroadlinkSelectedMapper.entityId(snapshot.selection, actionArg.id) === target.entityId);
88
+ if (!action) return refused('Broadlink button press requires one known action entity.');
89
+ return this.transmit(action.id);
90
+ }
91
+ if (request.domain === 'broadlink' && request.service === 'send_ir') {
92
+ const data = broadlinkRecord(request.data, ['actionId']);
93
+ const action = snapshot.actions.find((actionArg) => actionArg.id === data.actionId);
94
+ if (target.deviceId !== knownDeviceId || !action
95
+ || target.entityId !== undefined && target.entityId !== BroadlinkSelectedMapper.entityId(snapshot.selection, action.id)) {
96
+ return refused('Broadlink IR service requires the known bridge and one configured action ID.');
97
+ }
98
+ return this.transmit(action.id);
99
+ }
100
+ return refused('Broadlink supports only configured button.press and broadlink.send_ir actions.');
101
+ } catch { return refused('Broadlink service request is invalid.'); }
82
102
  }
83
103
 
84
- public async callService(requestArg: IServiceCallRequest): Promise<IServiceCallResult> {
85
- const snapshot = await this.client.getSnapshot();
86
- const command = BroadlinkMapper.commandForService(snapshot, requestArg);
87
- if (!command) {
88
- return { success: false, error: `Unsupported Broadlink service or target: ${requestArg.domain}.${requestArg.service}` };
89
- }
90
- const result = await this.client.sendCommand(command);
91
- return { success: result.success, error: result.error, data: result.data };
104
+ public async writeFeature(requestArg: IDeviceFeatureWriteRequest, signalArg?: AbortSignal): Promise<IServiceCallResult> {
105
+ try {
106
+ const request = broadlinkRecord(requestArg, ['device', 'feature', 'value']);
107
+ const device = broadlinkRecord(request.device, ['id', 'integrationDomain', 'name', 'room', 'protocol', 'manufacturer',
108
+ 'model', 'online', 'features', 'state', 'metadata']);
109
+ const metadata = broadlinkRecord(device.metadata, ['homeId', 'macAddress', 'deviceType', 'physicalEffectConfirmed',
110
+ 'cryptographicPeerTrust', 'hardwareVerified']);
111
+ const feature = broadlinkRecord(request.feature, ['id', 'capability', 'name', 'readable', 'writable', 'unit']);
112
+ const snapshot = this.client.currentSnapshot;
113
+ const canonical = BroadlinkSelectedMapper.toDevices(snapshot)[0];
114
+ const current = canonical.features.find((featureArg) => featureArg.id === feature.id && featureArg.writable);
115
+ if (device.id !== canonical.id || device.integrationDomain !== 'broadlink' || device.protocol !== 'udp'
116
+ || metadata.homeId !== snapshot.selection.homeId || metadata.macAddress !== snapshot.selection.macAddress
117
+ || metadata.deviceType !== snapshot.selection.deviceType || !current
118
+ || feature.capability !== current.capability || feature.name !== current.name
119
+ || feature.readable !== false || feature.writable !== true || feature.unit !== undefined || request.value !== true) {
120
+ return refused('Broadlink feature write requires the canonical selected action and trigger value true.');
121
+ }
122
+ if (signalArg !== undefined && !(signalArg instanceof AbortSignal)) return refused('Broadlink cancellation requires an AbortSignal.');
123
+ return this.transmit(current.id.slice(3), signalArg);
124
+ } catch { return refused('Broadlink feature request is invalid.'); }
92
125
  }
93
126
 
94
- public async destroy(): Promise<void> {
95
- await this.client.destroy();
127
+ private async transmit(actionIdArg: string, signalArg?: AbortSignal): Promise<IServiceCallResult> {
128
+ if (!this.client.isHealthy()) return refused('Broadlink selected bridge is unavailable.');
129
+ try {
130
+ const receipt = await this.client.sendAction(actionIdArg, signalArg);
131
+ return { success: true, data: receipt };
132
+ } catch (error) {
133
+ if (error instanceof plugins.ecobridgeDeviceManager.BroadlinkProtocolError) return {
134
+ success: false, error: 'Broadlink IR transmission failed.',
135
+ data: { code: error.code, outcome: error.effectOutcome, physicalEffectConfirmed: false },
136
+ };
137
+ return { success: false, error: 'Broadlink IR transmission failed.',
138
+ data: { outcome: 'indeterminate', physicalEffectConfirmed: false } };
139
+ }
96
140
  }
141
+
142
+ public destroy(): Promise<void> { return this.lease.close(); }
97
143
  }
@@ -18,7 +18,7 @@ import {
18
18
  } from './broadlink.packet.js';
19
19
  import type {
20
20
  IBroadlinkCommand,
21
- IBroadlinkConfig,
21
+ IBroadlinkOfflineConfig,
22
22
  IBroadlinkCustomSwitchConfig,
23
23
  IBroadlinkDevice,
24
24
  IBroadlinkEntityDescriptor,
@@ -38,8 +38,9 @@ interface IBroadlinkSwitchDefinition {
38
38
  custom?: IBroadlinkCustomSwitchConfig;
39
39
  }
40
40
 
41
+ /** Explicit offline mapping helpers; these do not validate or execute live controls. */
41
42
  export class BroadlinkMapper {
42
- public static toSnapshot(configArg: IBroadlinkConfig, connectedArg?: boolean, eventsArg: IBroadlinkEvent[] = []): IBroadlinkSnapshot {
43
+ public static toSnapshot(configArg: IBroadlinkOfflineConfig, connectedArg?: boolean, eventsArg: IBroadlinkEvent[] = []): IBroadlinkSnapshot {
43
44
  const source = configArg.snapshot;
44
45
  const primaryDevice = this.primaryDevice(configArg, source);
45
46
  const devices = this.uniqueDevices([
@@ -461,7 +462,7 @@ export class BroadlinkMapper {
461
462
  };
462
463
  }
463
464
 
464
- private static primaryDevice(configArg: IBroadlinkConfig, sourceArg?: IBroadlinkSnapshot): IBroadlinkDevice | undefined {
465
+ private static primaryDevice(configArg: IBroadlinkOfflineConfig, sourceArg?: IBroadlinkSnapshot): IBroadlinkDevice | undefined {
465
466
  if (!configArg.host && !configArg.name && !configArg.macAddress && !configArg.mac && !configArg.type && !configArg.state && !configArg.sensors && !configArg.codes && !configArg.switches?.length) {
466
467
  return undefined;
467
468
  }
@@ -489,7 +490,7 @@ export class BroadlinkMapper {
489
490
  };
490
491
  }
491
492
 
492
- private static devicesFromManualEntries(configArg: IBroadlinkConfig): IBroadlinkDevice[] {
493
+ private static devicesFromManualEntries(configArg: IBroadlinkOfflineConfig): IBroadlinkDevice[] {
493
494
  const devices: IBroadlinkDevice[] = [];
494
495
  for (const entry of configArg.manualEntries || []) {
495
496
  if (entry.snapshot?.devices) {
@@ -0,0 +1,46 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { IIntegrationEntity } from '../../core/types.js';
3
+ import type { IBroadlinkSelectedSnapshot, IBroadlinkSelection } from './broadlink.types.js';
4
+
5
+ /** Maps verified selected bridge observations, without inferring appliance state. */
6
+ export class BroadlinkSelectedMapper {
7
+ public static deviceId(selectionArg: IBroadlinkSelection): string {
8
+ return `broadlink.${encodeURIComponent(selectionArg.homeId)}.${selectionArg.macAddress}`;
9
+ }
10
+
11
+ public static entityId(selectionArg: IBroadlinkSelection, actionIdArg: string): string {
12
+ return `button.${this.deviceId(selectionArg)}.${actionIdArg}`;
13
+ }
14
+
15
+ public static toDevices(snapshotArg: IBroadlinkSelectedSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
16
+ return [{
17
+ id: this.deviceId(snapshotArg.selection), integrationDomain: 'broadlink',
18
+ name: snapshotArg.selection.name, protocol: 'udp', manufacturer: 'Broadlink',
19
+ model: snapshotArg.selection.deviceType === 0x2737 ? 'RM mini 3' : 'RM4 mini',
20
+ online: snapshotArg.available,
21
+ features: [
22
+ { id: 'connectivity', capability: 'sensor', name: 'Bridge connectivity', readable: true, writable: false },
23
+ { id: 'firmware', capability: 'sensor', name: 'Bridge firmware', readable: true, writable: false },
24
+ ...snapshotArg.actions.map((actionArg) => ({ id: `ir.${actionArg.id}`, capability: 'notification' as const,
25
+ name: actionArg.name, readable: false, writable: true })),
26
+ ],
27
+ state: [
28
+ { featureId: 'connectivity', value: snapshotArg.available ? 'online' : 'offline', updatedAt: snapshotArg.observedAt },
29
+ { featureId: 'firmware', value: snapshotArg.firmwareVersion, updatedAt: snapshotArg.observedAt },
30
+ ],
31
+ metadata: { homeId: snapshotArg.selection.homeId, macAddress: snapshotArg.selection.macAddress,
32
+ deviceType: snapshotArg.selection.deviceType, physicalEffectConfirmed: false,
33
+ cryptographicPeerTrust: false, hardwareVerified: false },
34
+ }];
35
+ }
36
+
37
+ public static toEntities(snapshotArg: IBroadlinkSelectedSnapshot): IIntegrationEntity[] {
38
+ return snapshotArg.actions.map((actionArg) => ({
39
+ id: this.entityId(snapshotArg.selection, actionArg.id),
40
+ uniqueId: this.entityId(snapshotArg.selection, actionArg.id), integrationDomain: 'broadlink',
41
+ deviceId: this.deviceId(snapshotArg.selection), platform: 'button', name: actionArg.name,
42
+ state: null, available: snapshotArg.available,
43
+ attributes: { actionId: actionArg.id, writable: true, readable: false, physicalEffectConfirmed: false },
44
+ }));
45
+ }
46
+ }
@@ -114,11 +114,8 @@ export interface IBroadlinkDevice {
114
114
  metadata?: Record<string, unknown>;
115
115
  }
116
116
 
117
- export interface IBroadlinkTransport {
118
- execute(commandArg: IBroadlinkCommand): Promise<IBroadlinkCommandResult | unknown>;
119
- }
120
-
121
- export interface IBroadlinkConfig {
117
+ /** Pure offline snapshot/mapping input. It never creates a live runtime. */
118
+ export interface IBroadlinkOfflineConfig {
122
119
  host?: string;
123
120
  port?: number;
124
121
  timeout?: number;
@@ -146,8 +143,51 @@ export interface IBroadlinkConfig {
146
143
  manualEntries?: IBroadlinkManualEntry[];
147
144
  snapshot?: IBroadlinkSnapshot;
148
145
  metadata?: Record<string, unknown>;
149
- commandExecutor?: (commandArg: IBroadlinkCommand) => Promise<IBroadlinkCommandResult | unknown>;
150
- transport?: IBroadlinkTransport;
146
+ }
147
+
148
+ export type TBroadlinkSelectedDeviceType = 0x2737 | 0x51da;
149
+
150
+ export interface IBroadlinkIrAction {
151
+ id: string;
152
+ name: string;
153
+ /** Canonical base64 of an owner-supplied native type-0x26, repeat-zero IR packet. */
154
+ packetBase64: string;
155
+ }
156
+
157
+ export interface IBroadlinkConfig {
158
+ /** Must match the independently selected home in the trusted host context. */
159
+ homeId: string;
160
+ host: string;
161
+ macAddress: string;
162
+ deviceType: TBroadlinkSelectedDeviceType;
163
+ port?: number;
164
+ localAddress?: string;
165
+ timeoutMs?: number;
166
+ maxPendingOperations?: number;
167
+ name?: string;
168
+ /** Explicit owner actions need no store. Omit only to restore from an admitted encrypted scoped store. */
169
+ actions?: IBroadlinkIrAction[];
170
+ }
171
+
172
+ export interface IBroadlinkSelection {
173
+ readonly homeId: string;
174
+ readonly host: string;
175
+ readonly macAddress: string;
176
+ readonly deviceType: TBroadlinkSelectedDeviceType;
177
+ readonly port: number;
178
+ readonly localAddress?: string;
179
+ readonly timeoutMs: number;
180
+ readonly maxPendingOperations: number;
181
+ readonly name: string;
182
+ }
183
+
184
+ /** Contains observed bridge information and action labels, never IR bytes or keys. */
185
+ export interface IBroadlinkSelectedSnapshot {
186
+ readonly selection: IBroadlinkSelection;
187
+ readonly available: boolean;
188
+ readonly firmwareVersion: number;
189
+ readonly observedAt: string;
190
+ readonly actions: ReadonlyArray<Readonly<Pick<IBroadlinkIrAction, 'id' | 'name'>>>;
151
191
  }
152
192
 
153
193
  export interface IBroadlinkSnapshot {
@@ -247,4 +287,4 @@ export interface IBroadlinkCandidateMetadata extends Record<string, unknown> {
247
287
  snapshot?: IBroadlinkSnapshot;
248
288
  }
249
289
 
250
- export type IHomeAssistantBroadlinkConfig = IBroadlinkConfig;
290
+ export type IHomeAssistantBroadlinkConfig = IBroadlinkOfflineConfig;
@@ -0,0 +1,66 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { IBroadlinkSelection } from './broadlink.types.js';
3
+
4
+ /** Reads only plain, enumerable data fields, without invoking caller accessors. */
5
+ export const broadlinkRecord = (valueArg: unknown, allowedArg: ReadonlyArray<string>): Record<string, unknown> => {
6
+ if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg)
7
+ || Object.getPrototypeOf(valueArg) !== Object.prototype) throw new TypeError('Broadlink requires a plain object.');
8
+ const captured: Record<string, unknown> = {};
9
+ for (const key of Reflect.ownKeys(valueArg)) {
10
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
11
+ if (typeof key !== 'string' || !allowedArg.includes(key) || !descriptor?.enumerable || !('value' in descriptor)) {
12
+ throw new TypeError('Broadlink input contains unsupported fields or accessors.');
13
+ }
14
+ captured[key] = descriptor.value;
15
+ }
16
+ return captured;
17
+ };
18
+
19
+ export const broadlinkName = (valueArg: unknown, nameArg: string, maximumArg: number): string => {
20
+ if (typeof valueArg !== 'string' || valueArg.length < 1 || valueArg.length > maximumArg
21
+ || valueArg !== valueArg.trim() || /[\p{Cc}\p{Cs}]/u.test(valueArg)) {
22
+ throw new TypeError(`Broadlink ${nameArg} must be nonempty text without control characters, at most ${maximumArg} characters.`);
23
+ }
24
+ return valueArg;
25
+ };
26
+
27
+ const integer = (valueArg: unknown, nameArg: string, maximumArg: number): number => {
28
+ if (typeof valueArg !== 'number' || !Number.isSafeInteger(valueArg) || valueArg < 1 || valueArg > maximumArg) {
29
+ throw new RangeError(`Broadlink ${nameArg} must be an integer from 1 through ${maximumArg}.`);
30
+ }
31
+ return valueArg;
32
+ };
33
+
34
+ const selectedAddress = (valueArg: unknown): string => {
35
+ if (typeof valueArg !== 'string' || plugins.net.isIP(valueArg) !== 4) throw new TypeError('Broadlink requires an explicit private IPv4 address.');
36
+ const [first, second, , last] = valueArg.split('.').map(Number);
37
+ if (last === 0 || last === 255 || !(first === 10 || first === 127 || first === 172 && second >= 16 && second <= 31
38
+ || first === 192 && second === 168)) throw new TypeError('Broadlink requires a private unicast IPv4 address; loopback is reserved for local fixtures.');
39
+ return valueArg;
40
+ };
41
+
42
+ export const readBroadlinkSelection = (configArg: unknown): IBroadlinkSelection => {
43
+ const config = broadlinkRecord(configArg, ['homeId', 'host', 'macAddress', 'deviceType', 'port', 'localAddress',
44
+ 'timeoutMs', 'maxPendingOperations', 'name', 'actions']);
45
+ const homeId = broadlinkName(config.homeId, 'homeId', 256);
46
+ if (typeof config.macAddress !== 'string' || !/^(?:[\da-f]{12}|[\da-f]{2}(?::[\da-f]{2}){5}|[\da-f]{2}(?:-[\da-f]{2}){5})$/i.test(config.macAddress)) {
47
+ throw new TypeError('Broadlink requires an exact six-byte MAC address.');
48
+ }
49
+ const macAddress = config.macAddress.replace(/[:-]/g, '').toLowerCase();
50
+ if (parseInt(macAddress.slice(0, 2), 16) & 1 || /^0{12}$/.test(macAddress)) throw new TypeError('Broadlink requires a nonzero unicast MAC address.');
51
+ if (config.deviceType !== 0x2737 && config.deviceType !== 0x51da) throw new TypeError('Broadlink supports only RM mini 3 type 0x2737 and RM4 mini type 0x51da.');
52
+ return Object.freeze({
53
+ homeId, host: selectedAddress(config.host), macAddress, deviceType: config.deviceType,
54
+ port: integer(config.port ?? 80, 'port', 65535),
55
+ localAddress: config.localAddress === undefined ? undefined : selectedAddress(config.localAddress),
56
+ timeoutMs: integer(config.timeoutMs ?? 5000, 'timeoutMs', 60000),
57
+ maxPendingOperations: integer(config.maxPendingOperations ?? 32, 'maxPendingOperations', 128),
58
+ name: config.name === undefined ? 'Broadlink IR bridge' : broadlinkName(config.name, 'name', 128),
59
+ });
60
+ };
61
+
62
+ export const broadlinkConfigKey = (selectionArg: IBroadlinkSelection): string => `bridge.${selectionArg.macAddress}`;
63
+
64
+ export const sameBroadlinkSelection = (leftArg: IBroadlinkSelection, rightArg: IBroadlinkSelection): boolean =>
65
+ leftArg.homeId === rightArg.homeId && leftArg.host === rightArg.host && leftArg.macAddress === rightArg.macAddress
66
+ && leftArg.deviceType === rightArg.deviceType && leftArg.port === rightArg.port && leftArg.localAddress === rightArg.localAddress;