@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,380 +1,128 @@
1
1
  import { DiscoveryDescriptor } from '../../core/classes.discoverydescriptor.js';
2
- import type {
3
- IDiscoveryCandidate,
4
- IDiscoveryContext,
5
- IDiscoveryMatch,
6
- IDiscoveryMatcher,
7
- IDiscoveryProbe,
8
- IDiscoveryProbeResult,
9
- IDiscoveryValidator,
10
- } from '../../core/types.js';
2
+ import type { IDiscoveryCandidate, IDiscoveryMatch, IDiscoveryMatcher, IDiscoveryValidator } from '../../core/types.js';
11
3
  import { DaikinMapper } from './daikin.mapper.js';
12
- import type { IDaikinHttpCandidateRecord, IDaikinManualEntry, IDaikinMdnsRecord, IDaikinRawData, IDaikinSnapshot, IDaikinUdpDiscoveryRecord, IDaikinValueMap } from './daikin.types.js';
13
- import { daikinDefaultHttpPort, daikinDisplayName, daikinDomain, daikinUdpDiscoveryMessage, daikinUdpDiscoveryPort, daikinUdpSourcePort, daikinZeroconfType } from './daikin.types.js';
14
-
15
- export class DaikinUdpDiscoveryProbe implements IDiscoveryProbe {
16
- public id = 'daikin-udp-discovery-probe';
17
- public source = 'custom' as const;
18
- public description = 'Discover Daikin units using the local DAIKIN_UDP/common/basic_info broadcast used by pydaikin.';
19
-
20
- public async probe(contextArg: IDiscoveryContext): Promise<IDiscoveryProbeResult> {
21
- if (contextArg.abortSignal?.aborted) {
22
- return { candidates: [] };
23
- }
24
- return { candidates: await this.discover(1200) };
25
- }
26
-
27
- private async discover(timeoutMsArg: number): Promise<IDiscoveryCandidate[]> {
28
- const { createSocket } = await import('node:dgram');
29
- const matcher = new DaikinUdpMatcher();
30
- const candidates: IDiscoveryCandidate[] = [];
31
- const message = Buffer.from(daikinUdpDiscoveryMessage, 'utf8');
32
-
33
- return new Promise((resolve) => {
34
- const socket = createSocket({ type: 'udp4', reuseAddr: true });
35
- const timer = setTimeout(() => {
36
- closeSocket();
37
- resolve(candidates);
38
- }, timeoutMsArg);
39
-
40
- const closeSocket = () => {
41
- clearTimeout(timer);
42
- try {
43
- socket.close();
44
- } catch {
45
- // Discovery sockets may already be closed after timeout or OS errors.
46
- }
47
- };
48
-
49
- socket.on('message', async (dataArg, remoteArg) => {
50
- const match = await matcher.matches({ host: remoteArg.address, port: remoteArg.port, data: dataArg.toString('utf8') });
51
- if (match.matched && match.candidate && !candidates.some((candidateArg) => candidateArg.id === match.candidate?.id || candidateArg.host === match.candidate?.host)) {
52
- candidates.push(match.candidate);
53
- }
54
- });
55
- socket.on('error', () => {
56
- closeSocket();
57
- resolve(candidates);
58
- });
59
- socket.bind(daikinUdpSourcePort, () => {
60
- socket.setBroadcast(true);
61
- socket.send(message, daikinUdpDiscoveryPort, '255.255.255.255');
62
- });
63
- });
64
- }
65
- }
4
+ import type { IDaikinHttpCandidateRecord, IDaikinManualEntry, IDaikinMdnsRecord, IDaikinUdpDiscoveryRecord } from './daikin.types.js';
5
+ import { daikinDisplayName, daikinDomain, daikinZeroconfType } from './daikin.types.js';
6
+ import { daikinObject } from './daikin.validation.js';
7
+
8
+ const hint = (valueArg: unknown, maximumArg = 256): string | undefined =>
9
+ typeof valueArg === 'string' && valueArg.length > 0 && valueArg.length <= maximumArg && !/[\p{Cc}\p{Cs}]/u.test(valueArg) ? valueArg : undefined;
10
+ const hints = (valueArg: unknown): Record<string, unknown> => {
11
+ if (valueArg === undefined) return {};
12
+ const value = daikinObject(valueArg, 'Daikin discovery hints');
13
+ if (Object.keys(value).length > 64) throw new TypeError('Daikin discovery hints exceed their limit.');
14
+ return value;
15
+ };
16
+ const noMatch = (): IDiscoveryMatch => ({ matched: false, confidence: 'low', reason: 'No bounded Daikin endpoint hints were observed.' });
17
+ const result = (sourceArg: IDiscoveryCandidate['source'], hostArg: unknown, portArg: unknown, macArg: unknown,
18
+ nameArg: unknown, modelArg: unknown, protocolArg: string): IDiscoveryMatch => {
19
+ const host = hint(hostArg, 64);
20
+ if (!host) return noMatch();
21
+ if (portArg !== undefined && (typeof portArg !== 'number' || !Number.isSafeInteger(portArg) || portArg < 1 || portArg > 65535)) return noMatch();
22
+ const mac = DaikinMapper.normalizeMac(hint(macArg, 32));
23
+ const port = typeof portArg === 'number' ? portArg : 80;
24
+ return { matched: true, confidence: 'medium', reason: 'Passive Daikin endpoint hints require independent selected BRP069 verification.',
25
+ normalizedDeviceId: mac ?? `${host}:${port}`, candidate: {
26
+ source: sourceArg, integrationDomain: daikinDomain, id: mac ?? `${host}:${port}`, host, port,
27
+ name: hint(nameArg) ?? daikinDisplayName, manufacturer: 'Daikin', model: hint(modelArg), macAddress: mac,
28
+ metadata: { daikin: true, discoveryProtocol: protocolArg },
29
+ } };
30
+ };
66
31
 
67
32
  export class DaikinZeroconfMatcher implements IDiscoveryMatcher<IDaikinMdnsRecord> {
68
- public id = 'daikin-zeroconf-match';
69
- public source = 'mdns' as const;
70
- public description = 'Recognize Daikin _dkapi._tcp.local zeroconf advertisements from the Home Assistant manifest.';
71
-
33
+ public readonly id = 'daikin-zeroconf-match';
34
+ public readonly source = 'mdns' as const;
72
35
  public async matches(recordArg: IDaikinMdnsRecord): Promise<IDiscoveryMatch> {
73
- const txt = normalizeKeys({ ...recordArg.txt, ...recordArg.properties });
74
- const type = normalizeMdnsType(recordArg.type || recordArg.serviceType || '');
75
- const host = recordArg.host || recordArg.hostname || recordArg.addresses?.[0];
76
- const name = stringValue(txt.name) || cleanServiceName(recordArg.name) || daikinDisplayName;
77
- const mac = DaikinMapper.normalizeMac(txt.mac || txt.macaddress || txt.id);
78
- const matched = type === normalizeMdnsType(daikinZeroconfType) || type.includes('_dkapi') || recordArg.metadata?.daikin === true;
79
- if (!matched) {
80
- return { matched: false, confidence: 'low', reason: 'mDNS record is not a Daikin _dkapi advertisement.' };
81
- }
82
- return {
83
- matched: true,
84
- confidence: host && mac ? 'certain' : host ? 'high' : 'medium',
85
- reason: 'mDNS service matches _dkapi._tcp.local.',
86
- normalizedDeviceId: mac || recordArg.name || host,
87
- candidate: {
88
- source: 'mdns',
89
- integrationDomain: daikinDomain,
90
- id: mac || recordArg.name || host,
91
- host,
92
- port: recordArg.port || daikinDefaultHttpPort,
93
- name,
94
- manufacturer: 'Daikin',
95
- model: txt.model || txt.type || 'Daikin AC',
96
- macAddress: mac,
97
- metadata: {
98
- ...recordArg.metadata,
99
- daikin: true,
100
- discoveryProtocol: 'zeroconf',
101
- mdnsType: type,
102
- mdnsName: recordArg.name,
103
- txt,
104
- },
105
- },
106
- };
36
+ try {
37
+ const record = hints(recordArg);
38
+ if (hint(record.type ?? record.serviceType)?.replace(/\.$/, '').toLowerCase() !== daikinZeroconfType.replace(/\.$/, '')) return noMatch();
39
+ const txt = { ...hints(record.txt), ...hints(record.properties) };
40
+ const address = firstAddress(record.addresses);
41
+ return result('mdns', record.host ?? record.hostname ?? address, record.port, txt.mac ?? txt.macaddress,
42
+ txt.name ?? hint(record.name)?.replace(/\._.*$/, ''), txt.model, 'zeroconf');
43
+ } catch { return noMatch(); }
107
44
  }
108
45
  }
109
46
 
110
47
  export class DaikinUdpMatcher implements IDiscoveryMatcher<IDaikinUdpDiscoveryRecord> {
111
- public id = 'daikin-udp-match';
112
- public source = 'custom' as const;
113
- public description = 'Recognize pydaikin DAIKIN_UDP/basic_info discovery responses.';
114
-
48
+ public readonly id = 'daikin-udp-match';
49
+ public readonly source = 'custom' as const;
115
50
  public async matches(recordArg: IDaikinUdpDiscoveryRecord): Promise<IDiscoveryMatch> {
116
- const values = this.values(recordArg);
117
- const host = recordArg.host || recordArg.address || recordArg.ip;
118
- const mac = DaikinMapper.normalizeMac(values.mac);
119
- const name = safeDecode(values.name) || (mac ? `Daikin ${mac.slice(-5).replace(':', '')}` : daikinDisplayName);
120
- const matched = Boolean(mac || values.type === 'aircon' || values.adp_kind || recordArg.metadata?.daikin === true);
121
- if (!matched) {
122
- return { matched: false, confidence: 'low', reason: 'UDP payload is not a Daikin discovery response.' };
123
- }
124
- return {
125
- matched: true,
126
- confidence: host && mac ? 'certain' : host ? 'high' : 'medium',
127
- reason: mac ? 'UDP response contains a Daikin MAC address.' : 'UDP response contains Daikin adapter metadata.',
128
- normalizedDeviceId: mac || host,
129
- candidate: {
130
- source: 'custom',
131
- integrationDomain: daikinDomain,
132
- id: mac || host,
133
- host,
134
- port: daikinDefaultHttpPort,
135
- name,
136
- manufacturer: 'Daikin',
137
- model: values.model || values.type || 'Daikin AC',
138
- macAddress: mac,
139
- metadata: {
140
- ...recordArg.metadata,
141
- daikin: true,
142
- discoveryProtocol: 'udp',
143
- discoveryPort: recordArg.port,
144
- values,
145
- },
146
- },
147
- };
148
- }
149
-
150
- private values(recordArg: IDaikinUdpDiscoveryRecord): IDaikinValueMap {
151
- const raw = recordArg.values || recordArg.response || recordArg.data || {};
152
- if (typeof raw === 'string') {
153
- try {
154
- return DaikinMapper.parseKeyValueResponse(raw);
155
- } catch {
156
- return {};
157
- }
158
- }
159
- return raw;
51
+ try {
52
+ const record = hints(recordArg);
53
+ const raw = record.values ?? record.response ?? record.data;
54
+ const values = typeof raw === 'string' ? discoveryBody(raw) : hints(raw);
55
+ if (values.type !== 'aircon' || !DaikinMapper.normalizeMac(hint(values.mac, 32))) return noMatch();
56
+ return result('custom', record.host ?? record.address ?? record.ip, 80, values.mac, values.name, values.model, 'received-udp');
57
+ } catch { return noMatch(); }
160
58
  }
161
59
  }
162
60
 
163
61
  export class DaikinHttpMatcher implements IDiscoveryMatcher<IDaikinHttpCandidateRecord> {
164
- public id = 'daikin-http-match';
165
- public source = 'http' as const;
166
- public description = 'Recognize local HTTP candidates that look like Daikin common/aircon, SkyFi, or dsiot endpoints.';
167
-
62
+ public readonly id = 'daikin-http-match';
63
+ public readonly source = 'http' as const;
168
64
  public async matches(recordArg: IDaikinHttpCandidateRecord): Promise<IDiscoveryMatch> {
169
- const parsed = parseEndpoint(recordArg.url || recordArg.location);
170
- const headers = normalizeKeys(recordArg.headers || {});
171
- const path = recordArg.path || parsed?.path || '';
172
- const body = recordArg.body || recordArg.responseText || '';
173
- const text = [recordArg.url, recordArg.location, path, body, headers.server, recordArg.name, recordArg.manufacturer, recordArg.model].filter(Boolean).join(' ').toLowerCase();
174
- const values = this.parseBody(body);
175
- const mac = DaikinMapper.normalizeMac(values.mac);
176
- const matched = Boolean(recordArg.metadata?.daikin)
177
- || path.includes('/common/basic_info')
178
- || path.includes('/aircon/')
179
- || path.includes('/skyfi/')
180
- || path.includes('/dsiot/')
181
- || text.includes('daikin')
182
- || Boolean(mac && values.type === 'aircon');
183
- if (!matched) {
184
- return { matched: false, confidence: 'low', reason: 'HTTP candidate does not look like a Daikin local API.' };
185
- }
186
- const host = recordArg.host || parsed?.host;
187
- const port = recordArg.port || parsed?.port || daikinDefaultHttpPort;
188
- return {
189
- matched: true,
190
- confidence: host && (mac || path.includes('/common/basic_info')) ? 'high' : host ? 'medium' : 'low',
191
- reason: 'HTTP candidate has Daikin API path, body, or metadata hints.',
192
- normalizedDeviceId: mac || (host ? `${host}:${port}` : undefined),
193
- candidate: {
194
- source: 'http',
195
- integrationDomain: daikinDomain,
196
- id: mac || (host ? `${host}:${port}` : undefined),
197
- host,
198
- port,
199
- name: safeDecode(values.name) || recordArg.name || daikinDisplayName,
200
- manufacturer: recordArg.manufacturer || 'Daikin',
201
- model: recordArg.model || values.model || 'Daikin AC',
202
- macAddress: mac,
203
- metadata: {
204
- ...recordArg.metadata,
205
- daikin: true,
206
- url: recordArg.url || recordArg.location,
207
- ssl: recordArg.ssl ?? parsed?.ssl ?? false,
208
- values: Object.keys(values).length ? values : undefined,
209
- headers,
210
- },
211
- },
212
- };
213
- }
214
-
215
- private parseBody(valueArg: string): IDaikinValueMap {
216
- if (!valueArg.trim()) {
217
- return {};
218
- }
219
65
  try {
220
- return DaikinMapper.parseKeyValueResponse(valueArg);
221
- } catch {
222
- return {};
223
- }
66
+ const record = hints(recordArg);
67
+ const location = hint(record.url ?? record.location, 2048);
68
+ const url = location === undefined ? undefined : new URL(location);
69
+ if (url && (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash)) return noMatch();
70
+ const path = hint(record.path, 256) ?? url?.pathname;
71
+ const body = record.body ?? record.responseText;
72
+ const values = body === undefined ? {} : typeof body === 'string' ? discoveryBody(body) : {};
73
+ if (!['/common/basic_info', '/aircon/get_control_info', '/aircon/get_model_info'].includes(path ?? '') && values.type !== 'aircon') return noMatch();
74
+ return result('http', record.host ?? url?.hostname, record.port ?? (url?.port ? Number(url.port) : undefined),
75
+ values.mac, record.name ?? values.name, record.model ?? values.model, 'received-http');
76
+ } catch { return noMatch(); }
224
77
  }
225
78
  }
226
79
 
227
80
  export class DaikinManualMatcher implements IDiscoveryMatcher<IDaikinManualEntry> {
228
- public id = 'daikin-manual-match';
229
- public source = 'manual' as const;
230
- public description = 'Recognize manual Daikin host, API key/password, snapshot, client, and raw-data setup entries.';
231
-
81
+ public readonly id = 'daikin-manual-match';
82
+ public readonly source = 'manual' as const;
232
83
  public async matches(inputArg: IDaikinManualEntry): Promise<IDiscoveryMatch> {
233
- const metadata = inputArg.metadata || {};
234
- const parsed = parseEndpoint(inputArg.url || inputArg.host);
235
- const snapshot = snapshotValue(inputArg.snapshot || metadata.snapshot);
236
- const rawData = rawDataValue(inputArg.rawData || metadata.rawData);
237
- const hasManualData = Boolean(snapshot || rawData || inputArg.values || metadata.client);
238
- const text = [inputArg.name, inputArg.manufacturer, inputArg.model, metadata.name, metadata.manufacturer, metadata.model].filter(Boolean).join(' ').toLowerCase();
239
- const matched = Boolean(inputArg.host || inputArg.url || inputArg.apiKey || inputArg.password || metadata.daikin || hasManualData || text.includes('daikin'));
240
- if (!matched) {
241
- return { matched: false, confidence: 'low', reason: 'Manual entry does not contain Daikin setup hints.' };
242
- }
243
- const host = parsed?.host || (inputArg.url ? undefined : inputArg.host) || snapshot?.device.host;
244
- const port = inputArg.port || parsed?.port || snapshot?.device.port || (inputArg.apiVariant === 'skyfi' || inputArg.password ? 2000 : daikinDefaultHttpPort);
245
- const id = inputArg.id || inputArg.uniqueId || snapshot?.device.id || snapshot?.device.macAddress || (host ? `${host}:${port}` : undefined);
246
- return {
247
- matched: true,
248
- confidence: host || hasManualData ? 'high' : 'medium',
249
- reason: 'Manual entry can start Daikin setup.',
250
- normalizedDeviceId: id,
251
- candidate: {
252
- source: 'manual',
253
- integrationDomain: daikinDomain,
254
- id,
255
- host,
256
- port,
257
- name: inputArg.name || snapshot?.device.name || daikinDisplayName,
258
- manufacturer: inputArg.manufacturer || snapshot?.device.manufacturer || 'Daikin',
259
- model: inputArg.model || snapshot?.device.model,
260
- macAddress: inputArg.macAddress || snapshot?.device.macAddress,
261
- metadata: {
262
- ...metadata,
263
- daikin: true,
264
- discoveryProtocol: 'manual',
265
- ssl: inputArg.ssl ?? inputArg.tls ?? parsed?.ssl ?? metadata.ssl,
266
- apiVariant: inputArg.apiVariant || metadata.apiVariant,
267
- apiKey: inputArg.apiKey || metadata.apiKey,
268
- uuid: inputArg.uuid || metadata.uuid,
269
- password: inputArg.password || metadata.password,
270
- snapshot,
271
- rawData,
272
- values: inputArg.values || metadata.values,
273
- client: inputArg.client || metadata.client,
274
- commandExecutor: inputArg.commandExecutor || metadata.commandExecutor,
275
- },
276
- },
277
- };
84
+ try {
85
+ const input = hints(inputArg);
86
+ const metadata = hints(input.metadata);
87
+ const vendor = [hint(input.name), hint(input.manufacturer), hint(input.model)].filter(Boolean).join(' ').toLowerCase();
88
+ if (metadata.daikin !== true && input.apiVariant !== 'brp069' && !vendor.includes('daikin')) return noMatch();
89
+ return result('manual', input.host, input.port, input.macAddress ?? metadata.expectedMac, input.name, input.model, 'manual');
90
+ } catch { return noMatch(); }
278
91
  }
279
92
  }
280
93
 
281
94
  export class DaikinCandidateValidator implements IDiscoveryValidator {
282
- public id = 'daikin-candidate-validator';
283
- public description = 'Validate Daikin candidates from zeroconf, UDP, HTTP, and manual setup.';
284
-
95
+ public readonly id = 'daikin-candidate-validator';
285
96
  public async validate(candidateArg: IDiscoveryCandidate): Promise<IDiscoveryMatch> {
286
- const metadata = candidateArg.metadata || {};
287
- const snapshot = snapshotValue(metadata.snapshot);
288
- const rawData = rawDataValue(metadata.rawData);
289
- const mdnsType = typeof metadata.mdnsType === 'string' ? metadata.mdnsType.toLowerCase() : '';
290
- const discoveryProtocol = typeof metadata.discoveryProtocol === 'string' ? metadata.discoveryProtocol : undefined;
291
- const text = [candidateArg.integrationDomain, candidateArg.name, candidateArg.manufacturer, candidateArg.model, mdnsType].filter(Boolean).join(' ').toLowerCase();
292
- const matched = candidateArg.integrationDomain === daikinDomain
293
- || metadata.daikin === true
294
- || text.includes('daikin')
295
- || mdnsType.includes('_dkapi')
296
- || discoveryProtocol === 'udp';
297
- const hasUsableSource = Boolean(candidateArg.host || snapshot || rawData || metadata.values || metadata.client);
298
- const normalizedDeviceId = DaikinMapper.normalizeMac(candidateArg.macAddress) || candidateArg.id || snapshot?.device.macAddress || (candidateArg.host ? `${candidateArg.host}:${candidateArg.port || daikinDefaultHttpPort}` : undefined);
299
- if (!matched || !hasUsableSource) {
300
- return {
301
- matched: false,
302
- confidence: matched ? 'medium' : 'low',
303
- reason: matched ? 'Daikin candidate lacks a host, injected client, snapshot, or manual data.' : 'Candidate is not Daikin.',
304
- normalizedDeviceId,
305
- };
306
- }
307
- return {
308
- matched: true,
309
- confidence: candidateArg.host && normalizedDeviceId ? 'certain' : candidateArg.host ? 'high' : 'medium',
310
- reason: 'Candidate has Daikin metadata and a usable local endpoint, client, snapshot, or manual data.',
311
- normalizedDeviceId,
312
- candidate: {
313
- ...candidateArg,
314
- integrationDomain: daikinDomain,
315
- port: candidateArg.port || daikinDefaultHttpPort,
316
- manufacturer: candidateArg.manufacturer || 'Daikin',
317
- },
318
- };
97
+ try {
98
+ const candidate = hints(candidateArg);
99
+ if (candidate.integrationDomain !== daikinDomain) return noMatch();
100
+ return result(candidateArg.source, candidate.host, candidate.port, candidate.macAddress, candidate.name, candidate.model, 'validated-hint');
101
+ } catch { return noMatch(); }
319
102
  }
320
103
  }
321
104
 
322
- export const createDaikinDiscoveryDescriptor = (): DiscoveryDescriptor => {
323
- return new DiscoveryDescriptor({ integrationDomain: daikinDomain, displayName: daikinDisplayName })
324
- .addProbe(new DaikinUdpDiscoveryProbe())
325
- .addMatcher(new DaikinZeroconfMatcher())
326
- .addMatcher(new DaikinUdpMatcher())
327
- .addMatcher(new DaikinHttpMatcher())
328
- .addMatcher(new DaikinManualMatcher())
329
- .addValidator(new DaikinCandidateValidator());
330
- };
331
-
332
- const normalizeMdnsType = (valueArg: string): string => valueArg.toLowerCase().replace(/\.$/, '');
105
+ /** Passive record matching only; setup independently validates the explicitly selected controller. */
106
+ export const createDaikinDiscoveryDescriptor = (): DiscoveryDescriptor =>
107
+ new DiscoveryDescriptor({ integrationDomain: daikinDomain, displayName: daikinDisplayName })
108
+ .addMatcher(new DaikinZeroconfMatcher()).addMatcher(new DaikinUdpMatcher())
109
+ .addMatcher(new DaikinHttpMatcher()).addMatcher(new DaikinManualMatcher()).addValidator(new DaikinCandidateValidator());
333
110
 
334
- const cleanServiceName = (valueArg: string | undefined): string | undefined => {
335
- if (!valueArg) {
336
- return undefined;
337
- }
338
- return valueArg.replace(/\._.*$/u, '').replace(/\.local\.?$/i, '').trim() || undefined;
111
+ const discoveryBody = (bodyArg: string): Record<string, unknown> => {
112
+ if (bodyArg.length > 16384) throw new TypeError('Daikin discovery payload exceeds its limit.');
113
+ const parsed = DaikinMapper.parseKeyValueResponse(bodyArg);
114
+ return { type: hint(parsed.type), mac: hint(parsed.mac, 32), name: hint(parsed.name), model: hint(parsed.model) };
339
115
  };
340
116
 
341
- const parseEndpoint = (valueArg: string | undefined): { host: string; port?: number; ssl: boolean; path: string } | undefined => {
342
- if (!valueArg || !/^[a-z][a-z0-9+.-]*:\/\//i.test(valueArg)) {
343
- return undefined;
344
- }
345
- try {
346
- const url = new URL(valueArg);
347
- return { host: url.hostname, port: url.port ? Number(url.port) : undefined, ssl: url.protocol === 'https:', path: url.pathname };
348
- } catch {
349
- return undefined;
350
- }
351
- };
352
-
353
- const normalizeKeys = (recordArg: Record<string, string | undefined>): Record<string, string | undefined> => {
354
- const normalized: Record<string, string | undefined> = {};
355
- for (const [key, value] of Object.entries(recordArg)) {
356
- normalized[key.toLowerCase()] = value;
357
- }
358
- return normalized;
359
- };
360
-
361
- const stringValue = (valueArg: unknown): string | undefined => typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
362
-
363
- const safeDecode = (valueArg: string | undefined): string | undefined => {
364
- if (valueArg === undefined) {
365
- return undefined;
366
- }
367
- try {
368
- return decodeURIComponent(valueArg.replace(/\+/g, '%20'));
369
- } catch {
370
- return valueArg;
117
+ const firstAddress = (valueArg: unknown): unknown => {
118
+ if (valueArg === undefined) return undefined;
119
+ if (!Array.isArray(valueArg) || valueArg.length > 16) throw new TypeError('Daikin advertised addresses must be a bounded array.');
120
+ for (const key of Reflect.ownKeys(valueArg)) {
121
+ if (key === 'length') continue;
122
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
123
+ if (typeof key !== 'string' || !/^(0|[1-9]\d*)$/.test(key) || !descriptor || !('value' in descriptor) || !descriptor.enumerable) {
124
+ throw new TypeError('Daikin advertised addresses must contain own data fields.');
125
+ }
371
126
  }
372
- };
373
-
374
- const snapshotValue = (valueArg: unknown): IDaikinSnapshot | undefined => {
375
- return valueArg && typeof valueArg === 'object' && 'device' in valueArg && 'climate' in valueArg ? valueArg as IDaikinSnapshot : undefined;
376
- };
377
-
378
- const rawDataValue = (valueArg: unknown): Partial<IDaikinRawData> | undefined => {
379
- return valueArg && typeof valueArg === 'object' && !Array.isArray(valueArg) ? valueArg as Partial<IDaikinRawData> : undefined;
127
+ return Object.getOwnPropertyDescriptor(valueArg, '0')?.value;
380
128
  };