@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,274 +1,61 @@
1
- import * as plugins from '../../plugins.js';
2
- import type { IIntegrationEntity, IIntegrationEvent } from '../../core/types.js';
3
- import type {
4
- INanoleafEvent,
5
- INanoleafPanelInfo,
6
- INanoleafSnapshot,
7
- INanoleafState,
8
- INanoleafValue,
9
- } from './nanoleaf.types.js';
10
-
11
- const RESERVED_EFFECTS = new Set(['*Solid*', '*Static*', '*Dynamic*']);
1
+ import type * as plugins from '../../plugins.js';
2
+ import type { IIntegrationEntity } from '../../core/types.js';
3
+ import type { INanoleafSnapshot } from './nanoleaf.types.js';
12
4
 
13
5
  export class NanoleafMapper {
6
+ public static deviceId(snapshotArg: Pick<INanoleafSnapshot, 'homeId' | 'serialNumber'>): string {
7
+ return `nanoleaf:${encodeURIComponent(snapshotArg.homeId)}:${encodeURIComponent(snapshotArg.serialNumber)}`;
8
+ }
9
+
10
+ public static lightEntityId(snapshotArg: Pick<INanoleafSnapshot, 'homeId' | 'serialNumber'>): string { return `${this.deviceId(snapshotArg)}:light`; }
11
+ public static effectEntityId(snapshotArg: Pick<INanoleafSnapshot, 'homeId' | 'serialNumber'>): string { return `${this.deviceId(snapshotArg)}:effect`; }
12
+
14
13
  public static toDevices(snapshotArg: INanoleafSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
15
- const devices: plugins.shxInterfaces.data.IDeviceDefinition[] = [];
16
- const updatedAt = new Date().toISOString();
17
- const controllerDeviceId = this.controllerDeviceId(snapshotArg);
18
- const controllerName = this.controllerName(snapshotArg);
14
+ const updatedAt = snapshotArg.observedAt;
19
15
  const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
20
- { id: 'connectivity', capability: 'sensor', name: 'Connectivity', readable: true, writable: false },
21
- { id: 'on', capability: 'light', name: 'Power', readable: true, writable: true },
22
- { id: 'brightness', capability: 'light', name: 'Brightness', readable: true, writable: true, unit: '%' },
23
- { id: 'hue', capability: 'light', name: 'Hue', readable: true, writable: true },
24
- { id: 'saturation', capability: 'light', name: 'Saturation', readable: true, writable: true, unit: '%' },
25
- { id: 'color_temperature', capability: 'light', name: 'Color temperature', readable: true, writable: true, unit: 'K' },
26
- { id: 'color_mode', capability: 'sensor', name: 'Color mode', readable: true, writable: false },
27
- { id: 'effect', capability: 'light', name: 'Effect', readable: true, writable: true },
16
+ { id: 'power', capability: 'light', name: 'Power', readable: true, writable: true },
17
+ { id: 'firmware', capability: 'sensor', name: 'Firmware', readable: true, writable: false },
28
18
  ];
29
19
  const state: plugins.shxInterfaces.data.IDeviceState[] = [
30
- { featureId: 'connectivity', value: 'online', updatedAt },
31
- { featureId: 'on', value: this.stateValue(snapshotArg.state.on) ?? null, updatedAt },
32
- { featureId: 'brightness', value: this.stateValue(snapshotArg.state.brightness) ?? null, updatedAt },
33
- { featureId: 'hue', value: this.stateValue(snapshotArg.state.hue) ?? null, updatedAt },
34
- { featureId: 'saturation', value: this.stateValue(snapshotArg.state.sat) ?? null, updatedAt },
35
- { featureId: 'color_temperature', value: this.stateValue(snapshotArg.state.ct) ?? null, updatedAt },
36
- { featureId: 'color_mode', value: this.colorMode(snapshotArg.state) ?? null, updatedAt },
37
- { featureId: 'effect', value: this.currentEffect(snapshotArg) ?? null, updatedAt },
20
+ { featureId: 'power', value: snapshotArg.power, updatedAt },
21
+ { featureId: 'firmware', value: snapshotArg.firmwareVersion, updatedAt },
38
22
  ];
39
-
40
- if (snapshotArg.controllerInfo.firmwareVersion) {
41
- features.push({ id: 'firmware', capability: 'sensor', name: 'Firmware', readable: true, writable: false });
42
- state.push({ featureId: 'firmware', value: snapshotArg.controllerInfo.firmwareVersion, updatedAt });
43
- }
44
-
45
- const panelCount = this.panelCount(snapshotArg);
46
- if (panelCount !== undefined) {
47
- features.push({ id: 'panel_count', capability: 'sensor', name: 'Panel count', readable: true, writable: false });
48
- state.push({ featureId: 'panel_count', value: panelCount, updatedAt });
49
- }
50
-
51
- const rhythmConnected = this.valueLike(snapshotArg.rhythm?.rhythmConnected);
52
- if (rhythmConnected !== undefined) {
53
- features.push({ id: 'rhythm_connected', capability: 'sensor', name: 'Rhythm connected', readable: true, writable: false });
54
- state.push({ featureId: 'rhythm_connected', value: rhythmConnected, updatedAt });
55
- }
56
-
57
- devices.push({
58
- id: controllerDeviceId,
59
- integrationDomain: 'nanoleaf',
60
- name: controllerName,
61
- protocol: 'http',
62
- manufacturer: snapshotArg.controllerInfo.manufacturer || 'Nanoleaf',
63
- model: snapshotArg.controllerInfo.model || 'Nanoleaf Controller',
64
- online: true,
65
- features,
66
- state,
67
- metadata: {
68
- serialNumber: snapshotArg.controllerInfo.serialNo,
69
- hardwareVersion: snapshotArg.controllerInfo.hardwareVersion,
70
- firmwareVersion: snapshotArg.controllerInfo.firmwareVersion,
71
- effectsList: this.availableEffects(snapshotArg),
72
- },
73
- });
74
-
75
- for (const panel of this.panels(snapshotArg)) {
76
- devices.push(this.panelDevice(snapshotArg, panel, updatedAt));
77
- }
78
-
79
- return devices;
23
+ for (const [id, name, unit, observation] of [
24
+ ['brightness', 'Brightness', '%', snapshotArg.brightness],
25
+ ['color_temperature', 'Color temperature', 'K', snapshotArg.colorTemperatureKelvin],
26
+ ] as const) {
27
+ if (observation) {
28
+ features.push({ id, capability: 'light', name, unit, readable: true, writable: true });
29
+ state.push({ featureId: id, value: observation.value, updatedAt });
30
+ }
31
+ }
32
+ if (snapshotArg.availableEffects.length > 0) features.push({ id: 'effect', capability: 'light', name: 'Advertised scene', readable: snapshotArg.selectedEffect !== undefined,
33
+ writable: true });
34
+ if (snapshotArg.selectedEffect !== undefined) state.push({ featureId: 'effect', value: snapshotArg.selectedEffect, updatedAt });
35
+ if (snapshotArg.colorMode !== undefined) {
36
+ features.push({ id: 'color_mode', capability: 'sensor', name: 'Color mode', readable: true, writable: false });
37
+ state.push({ featureId: 'color_mode', value: snapshotArg.colorMode, updatedAt });
38
+ }
39
+ return [{ id: this.deviceId(snapshotArg), integrationDomain: 'nanoleaf', name: snapshotArg.name,
40
+ manufacturer: 'Nanoleaf', model: snapshotArg.model, protocol: 'http', online: true, features, state,
41
+ metadata: { homeId: snapshotArg.homeId, serialNumber: snapshotArg.serialNumber, origin: snapshotArg.origin,
42
+ observedAt: snapshotArg.observedAt, brightnessRange: snapshotArg.brightness && [snapshotArg.brightness.min, snapshotArg.brightness.max],
43
+ colorTemperatureRange: snapshotArg.colorTemperatureKelvin && [snapshotArg.colorTemperatureKelvin.min, snapshotArg.colorTemperatureKelvin.max],
44
+ availableEffects: [...snapshotArg.availableEffects], transportEncrypted: snapshotArg.origin.startsWith('https:'), physicalCompletion: 'unconfirmed' } }];
80
45
  }
81
46
 
82
47
  public static toEntities(snapshotArg: INanoleafSnapshot): IIntegrationEntity[] {
83
- const deviceId = this.controllerDeviceId(snapshotArg);
84
- const deviceSlug = this.slug(this.controllerName(snapshotArg));
85
- const entities: IIntegrationEntity[] = [
86
- {
87
- id: `light.${deviceSlug}`,
88
- uniqueId: `nanoleaf_${this.slug(snapshotArg.controllerInfo.serialNo || deviceId)}_light`,
89
- integrationDomain: 'nanoleaf',
90
- deviceId,
91
- platform: 'light',
92
- name: this.controllerName(snapshotArg),
93
- state: this.stateValue(snapshotArg.state.on) ? 'on' : 'off',
94
- attributes: {
95
- brightness: this.stateValue(snapshotArg.state.brightness),
96
- hue: this.stateValue(snapshotArg.state.hue),
97
- saturation: this.stateValue(snapshotArg.state.sat),
98
- color_temp_kelvin: this.stateValue(snapshotArg.state.ct),
99
- color_mode: this.colorMode(snapshotArg.state),
100
- effect: this.currentEffect(snapshotArg),
101
- effect_list: this.availableEffects(snapshotArg),
102
- },
103
- available: true,
104
- },
105
- {
106
- id: `button.${deviceSlug}_identify`,
107
- uniqueId: `nanoleaf_${this.slug(snapshotArg.controllerInfo.serialNo || deviceId)}_identify`,
108
- integrationDomain: 'nanoleaf',
109
- deviceId,
110
- platform: 'button',
111
- name: `${this.controllerName(snapshotArg)} identify`,
112
- state: null,
113
- attributes: { deviceClass: 'identify' },
114
- available: true,
115
- },
116
- ];
117
-
118
- entities.push({
119
- id: `select.${deviceSlug}_effect`,
120
- uniqueId: `nanoleaf_${this.slug(snapshotArg.controllerInfo.serialNo || deviceId)}_effect`,
121
- integrationDomain: 'nanoleaf',
122
- deviceId,
123
- platform: 'select',
124
- name: `${this.controllerName(snapshotArg)} effect`,
125
- state: this.currentEffect(snapshotArg) ?? null,
126
- attributes: { options: this.availableEffects(snapshotArg) },
127
- available: true,
128
- });
129
-
130
- this.pushSensorEntity(entities, deviceId, `nanoleaf_${this.slug(deviceId)}_color_mode`, `sensor.${deviceSlug}_color_mode`, `${this.controllerName(snapshotArg)} color mode`, this.colorMode(snapshotArg.state));
131
- this.pushSensorEntity(entities, deviceId, `nanoleaf_${this.slug(deviceId)}_firmware`, `sensor.${deviceSlug}_firmware`, `${this.controllerName(snapshotArg)} firmware`, snapshotArg.controllerInfo.firmwareVersion);
132
- this.pushSensorEntity(entities, deviceId, `nanoleaf_${this.slug(deviceId)}_panel_count`, `sensor.${deviceSlug}_panel_count`, `${this.controllerName(snapshotArg)} panel count`, this.panelCount(snapshotArg));
133
- this.pushSensorEntity(entities, deviceId, `nanoleaf_${this.slug(deviceId)}_rhythm_connected`, `sensor.${deviceSlug}_rhythm_connected`, `${this.controllerName(snapshotArg)} rhythm connected`, this.valueLike(snapshotArg.rhythm?.rhythmConnected));
134
- this.pushSensorEntity(entities, deviceId, `nanoleaf_${this.slug(deviceId)}_rhythm_active`, `sensor.${deviceSlug}_rhythm_active`, `${this.controllerName(snapshotArg)} rhythm active`, this.valueLike(snapshotArg.rhythm?.rhythmActive));
135
-
136
- for (const panel of this.panels(snapshotArg)) {
137
- const panelDeviceId = this.panelDeviceId(snapshotArg, panel);
138
- entities.push({
139
- id: `sensor.${deviceSlug}_panel_${panel.panelId}`,
140
- uniqueId: `nanoleaf_${this.slug(deviceId)}_panel_${panel.panelId}`,
141
- integrationDomain: 'nanoleaf',
142
- deviceId: panelDeviceId,
143
- platform: 'sensor',
144
- name: `${this.controllerName(snapshotArg)} panel ${panel.panelId}`,
145
- state: panel.panelId,
146
- attributes: {
147
- x: panel.x,
148
- y: panel.y,
149
- orientation: panel.o,
150
- shapeType: panel.shapeType,
151
- },
152
- available: true,
153
- });
48
+ const lightId = this.lightEntityId(snapshotArg);
49
+ const entities: IIntegrationEntity[] = [{ id: lightId, uniqueId: lightId, deviceId: this.deviceId(snapshotArg), integrationDomain: 'nanoleaf',
50
+ platform: 'light', name: snapshotArg.name, state: snapshotArg.power ? 'on' : 'off', available: true,
51
+ attributes: { brightness: snapshotArg.brightness?.value, colorTemperatureKelvin: snapshotArg.colorTemperatureKelvin?.value,
52
+ colorMode: snapshotArg.colorMode, observedAt: snapshotArg.observedAt } }];
53
+ if (snapshotArg.availableEffects.length) {
54
+ const effectId = this.effectEntityId(snapshotArg);
55
+ entities.push({ id: effectId, uniqueId: effectId, deviceId: this.deviceId(snapshotArg), integrationDomain: 'nanoleaf',
56
+ platform: 'select', name: `${snapshotArg.name} scene`, state: snapshotArg.selectedEffect ?? null, available: true,
57
+ attributes: { options: [...snapshotArg.availableEffects], observedAt: snapshotArg.observedAt } });
154
58
  }
155
-
156
59
  return entities;
157
60
  }
158
-
159
- public static toIntegrationEvent(eventArg: INanoleafEvent): IIntegrationEvent {
160
- return {
161
- type: 'state_changed',
162
- integrationDomain: 'nanoleaf',
163
- data: eventArg,
164
- timestamp: eventArg.timestamp ?? Date.now(),
165
- };
166
- }
167
-
168
- private static panelDevice(snapshotArg: INanoleafSnapshot, panelArg: INanoleafPanelInfo, updatedAtArg: string): plugins.shxInterfaces.data.IDeviceDefinition {
169
- const features: plugins.shxInterfaces.data.IDeviceFeature[] = [
170
- { id: 'layout_x', capability: 'sensor', name: 'Layout X', readable: true, writable: false },
171
- { id: 'layout_y', capability: 'sensor', name: 'Layout Y', readable: true, writable: false },
172
- { id: 'orientation', capability: 'sensor', name: 'Orientation', readable: true, writable: false },
173
- { id: 'shape_type', capability: 'sensor', name: 'Shape type', readable: true, writable: false },
174
- ];
175
- return {
176
- id: this.panelDeviceId(snapshotArg, panelArg),
177
- integrationDomain: 'nanoleaf',
178
- name: `${this.controllerName(snapshotArg)} Panel ${panelArg.panelId}`,
179
- protocol: 'http',
180
- manufacturer: 'Nanoleaf',
181
- model: panelArg.shapeType === undefined ? 'Panel' : `Panel shape ${panelArg.shapeType}`,
182
- online: true,
183
- features,
184
- state: [
185
- { featureId: 'layout_x', value: panelArg.x ?? null, updatedAt: updatedAtArg },
186
- { featureId: 'layout_y', value: panelArg.y ?? null, updatedAt: updatedAtArg },
187
- { featureId: 'orientation', value: panelArg.o ?? null, updatedAt: updatedAtArg },
188
- { featureId: 'shape_type', value: panelArg.shapeType ?? null, updatedAt: updatedAtArg },
189
- ],
190
- metadata: {
191
- panelId: panelArg.panelId,
192
- controllerDeviceId: this.controllerDeviceId(snapshotArg),
193
- },
194
- };
195
- }
196
-
197
- private static pushSensorEntity(
198
- entitiesArg: IIntegrationEntity[],
199
- deviceIdArg: string,
200
- uniqueIdArg: string,
201
- idArg: string,
202
- nameArg: string,
203
- valueArg: unknown
204
- ): void {
205
- if (valueArg === undefined) {
206
- return;
207
- }
208
- entitiesArg.push({
209
- id: idArg,
210
- uniqueId: uniqueIdArg,
211
- integrationDomain: 'nanoleaf',
212
- deviceId: deviceIdArg,
213
- platform: 'sensor',
214
- name: nameArg,
215
- state: valueArg,
216
- available: true,
217
- });
218
- }
219
-
220
- private static controllerDeviceId(snapshotArg: INanoleafSnapshot): string {
221
- return `nanoleaf.controller.${this.slug(snapshotArg.controllerInfo.serialNo || snapshotArg.controllerInfo.name || 'unknown')}`;
222
- }
223
-
224
- private static panelDeviceId(snapshotArg: INanoleafSnapshot, panelArg: INanoleafPanelInfo): string {
225
- return `nanoleaf.panel.${this.slug(snapshotArg.controllerInfo.serialNo || snapshotArg.controllerInfo.name || 'unknown')}.${panelArg.panelId}`;
226
- }
227
-
228
- private static controllerName(snapshotArg: INanoleafSnapshot): string {
229
- return snapshotArg.controllerInfo.name || snapshotArg.controllerInfo.model || 'Nanoleaf';
230
- }
231
-
232
- private static panels(snapshotArg: INanoleafSnapshot): INanoleafPanelInfo[] {
233
- return snapshotArg.panelLayout?.layout?.positionData ?? [];
234
- }
235
-
236
- private static panelCount(snapshotArg: INanoleafSnapshot): number | undefined {
237
- return snapshotArg.panelLayout?.layout?.numPanels ?? snapshotArg.panelLayout?.layout?.positionData?.length;
238
- }
239
-
240
- private static currentEffect(snapshotArg: INanoleafSnapshot): string | undefined {
241
- const effect = snapshotArg.effects.select;
242
- if (!effect || RESERVED_EFFECTS.has(effect)) {
243
- return undefined;
244
- }
245
- return effect;
246
- }
247
-
248
- private static availableEffects(snapshotArg: INanoleafSnapshot): string[] {
249
- return (snapshotArg.effects.effectsList ?? []).filter((effectArg) => !RESERVED_EFFECTS.has(effectArg));
250
- }
251
-
252
- private static colorMode(stateArg: INanoleafState): string | undefined {
253
- return this.valueLike(stateArg.colorMode);
254
- }
255
-
256
- private static stateValue<TValue>(valueArg: INanoleafValue<TValue> | undefined): TValue | undefined {
257
- return valueArg?.value;
258
- }
259
-
260
- private static valueLike<TValue>(valueArg: INanoleafValue<TValue> | TValue | undefined): TValue | undefined {
261
- if (this.isRecord(valueArg) && 'value' in valueArg) {
262
- return valueArg.value as TValue;
263
- }
264
- return valueArg as TValue | undefined;
265
- }
266
-
267
- private static slug(valueArg: string): string {
268
- return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'nanoleaf';
269
- }
270
-
271
- private static isRecord(valueArg: unknown): valueArg is Record<string, unknown> {
272
- return typeof valueArg === 'object' && valueArg !== null && !Array.isArray(valueArg);
273
- }
274
61
  }
@@ -1,160 +1,42 @@
1
- export type TNanoleafProtocol = 'http' | 'https';
2
- export type TNanoleafColorMode = 'hs' | 'ct' | 'effect' | string;
3
- export type TNanoleafGesture = 'swipe_up' | 'swipe_down' | 'swipe_left' | 'swipe_right';
1
+ import type * as plugins from '../../plugins.js';
2
+ import type { IConfigEncryptionKeyProvider } from '../../core/classes.configstore.js';
4
3
 
5
4
  export interface INanoleafConfig {
6
- host?: string;
7
- port?: number;
8
- protocol?: TNanoleafProtocol;
9
- authToken?: string;
10
- token?: string;
11
- controllerInfo?: INanoleafControllerInfo;
12
- state?: INanoleafState;
13
- effects?: INanoleafEffects;
14
- panelLayout?: INanoleafPanelLayout;
15
- rhythm?: INanoleafRhythmInfo;
16
- snapshot?: INanoleafSnapshot;
17
- }
18
-
19
- export interface INanoleafValue<TValue> {
20
- value: TValue;
21
- min?: number;
22
- max?: number;
23
- }
24
-
25
- export interface INanoleafState {
26
- on?: INanoleafValue<boolean>;
27
- brightness?: INanoleafValue<number>;
28
- hue?: INanoleafValue<number>;
29
- sat?: INanoleafValue<number>;
30
- ct?: INanoleafValue<number>;
31
- colorMode?: TNanoleafColorMode | INanoleafValue<TNanoleafColorMode>;
32
- }
33
-
34
- export interface INanoleafPanelInfo {
35
- panelId: number;
36
- x?: number;
37
- y?: number;
38
- o?: number;
39
- shapeType?: number;
40
- }
41
-
42
- export interface INanoleafPanelLayout {
43
- globalOrientation?: INanoleafValue<number>;
44
- layout?: {
45
- numPanels?: number;
46
- sideLength?: number;
47
- positionData?: INanoleafPanelInfo[];
48
- };
49
- }
50
-
51
- export interface INanoleafRhythmInfo {
52
- rhythmConnected?: boolean | INanoleafValue<boolean>;
53
- rhythmActive?: boolean | INanoleafValue<boolean>;
54
- rhythmId?: number | INanoleafValue<number>;
55
- hardwareVersion?: string | INanoleafValue<string>;
56
- firmwareVersion?: string | INanoleafValue<string>;
57
- auxAvailable?: boolean | INanoleafValue<boolean>;
58
- rhythmMode?: number | string | INanoleafValue<number | string>;
59
- rhythmPos?: number | INanoleafValue<number>;
60
- }
61
-
62
- export interface INanoleafEffects {
63
- select?: string;
64
- effectsList?: string[];
65
- write?: INanoleafEffectsCommand;
66
- }
67
-
68
- export interface INanoleafEffectPaletteColor {
69
- hue?: number;
70
- saturation?: number;
71
- brightness?: number;
72
- probability?: number;
73
- }
74
-
75
- export interface INanoleafEffectPluginOption {
76
- name: string;
77
- value?: string | number | boolean;
78
- type?: string;
79
- defaultValue?: string | number | boolean;
80
- minValue?: number;
81
- maxValue?: number;
82
- strings?: string[];
83
- }
84
-
85
- export interface INanoleafEffectsCommand {
86
- command: 'add' | 'request' | 'delete' | 'display' | 'displayTemp' | 'rename' | 'requestAll' | 'requestPlugins' | string;
87
- version?: string;
88
- duration?: number;
89
- animName?: string;
90
- newName?: string;
91
- animType?: string;
92
- animData?: string | null;
93
- colorType?: string;
94
- palette?: INanoleafEffectPaletteColor[];
95
- Palette?: INanoleafEffectPaletteColor[];
96
- pluginUuid?: string;
97
- pluginType?: string;
98
- pluginOptions?: INanoleafEffectPluginOption[];
99
- loop?: boolean;
100
- [key: string]: unknown;
101
- }
102
-
103
- export interface INanoleafStateCommand {
104
- on?: INanoleafValue<boolean>;
105
- brightness?: INanoleafValue<number> & { duration?: number; increment?: number };
106
- hue?: INanoleafValue<number> & { increment?: number };
107
- sat?: INanoleafValue<number> & { increment?: number };
108
- ct?: INanoleafValue<number> & { increment?: number };
109
- }
110
-
111
- export interface INanoleafControllerInfo {
112
- name?: string;
113
- serialNo?: string;
114
- manufacturer?: string;
115
- firmwareVersion?: string;
116
- hardwareVersion?: string;
117
- model?: string;
118
- state?: INanoleafState;
119
- effects?: INanoleafEffects;
120
- panelLayout?: INanoleafPanelLayout;
121
- rhythm?: INanoleafRhythmInfo;
122
- }
123
-
124
- export interface INanoleafSnapshot {
125
- controllerInfo: INanoleafControllerInfo;
126
- state: INanoleafState;
127
- effects: INanoleafEffects;
128
- panelLayout?: INanoleafPanelLayout;
129
- rhythm?: INanoleafRhythmInfo;
130
- }
131
-
132
- export interface INanoleafAuthTokenResult {
133
- success: boolean;
134
- authToken?: string;
135
- error?: string;
5
+ homeId: string;
6
+ origin: string;
7
+ expectedSerialNumber: string;
8
+ expectedModel: string;
9
+ /** Existing token reference in the encrypted home/domain configuration store. */
10
+ credentialKey: string;
11
+ allowUnencryptedHttp?: boolean;
12
+ certificateAuthority?: string;
13
+ timeoutMs?: number;
14
+ maxResponseBytes?: number;
15
+ maxPendingOperations?: number;
136
16
  }
137
17
 
138
- export interface INanoleafEvent<TData = unknown> {
139
- type: 'state' | 'effects' | 'layout' | 'touch' | string;
140
- data: TData;
141
- timestamp?: number;
18
+ export interface INanoleafIntegrationOptions {
19
+ readonly homeId?: string;
20
+ readonly db?: plugins.nosqldb.SmartdataDb;
21
+ readonly keyProvider?: IConfigEncryptionKeyProvider;
142
22
  }
143
23
 
144
- export interface INanoleafStateEventData {
145
- attribute: keyof INanoleafState | string;
146
- value: unknown;
24
+ export interface INanoleafCredential {
25
+ version: 1;
26
+ origin: string;
27
+ serialNumber: string;
28
+ model: string;
29
+ authToken: string;
147
30
  }
148
31
 
149
- export interface INanoleafEffectsEventData {
150
- effect?: string;
151
- effectsList?: string[];
32
+ export interface INanoleafSnapshot extends plugins.ecobridgeDeviceManager.INanoleafSnapshot {
33
+ readonly homeId: string;
34
+ readonly origin: string;
152
35
  }
153
36
 
154
- export interface INanoleafTouchEventData {
155
- panelId?: number;
156
- gestureId?: number;
157
- gesture?: TNanoleafGesture;
37
+ export interface INanoleafWriteResult {
38
+ readonly acceptance: 'accepted';
39
+ readonly snapshot: INanoleafSnapshot;
158
40
  }
159
41
 
160
42
  export interface INanoleafMdnsRecord {
@@ -0,0 +1,77 @@
1
+ import * as plugins from '../../plugins.js';
2
+ import type { INanoleafConfig } from './nanoleaf.types.js';
3
+
4
+ export function nanoleafRecord(valueArg: unknown, nameArg: string): Record<string, unknown> {
5
+ if (!valueArg || typeof valueArg !== 'object' || Array.isArray(valueArg) ||
6
+ ![Object.prototype, null].includes(Object.getPrototypeOf(valueArg))) {
7
+ throw new TypeError(`Nanoleaf ${nameArg} must be a plain data object.`);
8
+ }
9
+ const result: Record<string, unknown> = {};
10
+ for (const key of Reflect.ownKeys(valueArg)) {
11
+ const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
12
+ if (typeof key !== 'string' || !descriptor || !('value' in descriptor) || !descriptor.enumerable) {
13
+ throw new TypeError(`Nanoleaf ${nameArg} may not contain symbols, accessors or hidden fields.`);
14
+ }
15
+ Object.defineProperty(result, key, { value: descriptor.value, enumerable: true });
16
+ }
17
+ return result;
18
+ }
19
+
20
+ export function nanoleafKeys(recordArg: Record<string, unknown>, keysArg: readonly string[]): void {
21
+ if (Object.keys(recordArg).some((keyArg) => !keysArg.includes(keyArg))) throw new TypeError('Nanoleaf data contains unsupported fields.');
22
+ }
23
+
24
+ export function nanoleafText(valueArg: unknown, nameArg: string, maximumArg = 256): string {
25
+ if (typeof valueArg !== 'string' || !valueArg.trim() || valueArg.length > maximumArg || /[\p{Cc}\p{Cs}]/u.test(valueArg)) {
26
+ throw new TypeError(`Nanoleaf ${nameArg} must be a bounded non-empty string without control characters.`);
27
+ }
28
+ return valueArg;
29
+ }
30
+
31
+ export function nanoleafInteger(valueArg: unknown, minimumArg: number, maximumArg: number, nameArg: string): number {
32
+ if (typeof valueArg !== 'number' || !Number.isSafeInteger(valueArg) || valueArg < minimumArg || valueArg > maximumArg) {
33
+ throw new TypeError(`Nanoleaf ${nameArg} must be an integer from ${minimumArg} through ${maximumArg}.`);
34
+ }
35
+ return valueArg;
36
+ }
37
+
38
+ export function normalizeNanoleafConfig(valueArg: unknown): Readonly<INanoleafConfig> {
39
+ const config = nanoleafRecord(valueArg, 'configuration');
40
+ nanoleafKeys(config, ['homeId', 'origin', 'expectedSerialNumber', 'expectedModel', 'credentialKey',
41
+ 'allowUnencryptedHttp', 'certificateAuthority', 'timeoutMs', 'maxResponseBytes', 'maxPendingOperations']);
42
+ const homeId = nanoleafText(config.homeId, 'homeId');
43
+ const rawOrigin = nanoleafText(config.origin, 'origin', 2048);
44
+ let origin: URL;
45
+ try { origin = new URL(rawOrigin); } catch { throw new TypeError('Nanoleaf origin must be a selected local HTTP(S) origin.'); }
46
+ const [first, second, third, fourth] = origin.hostname.split('.').map(Number);
47
+ const selectedOrigin = /^https?:\/\/((?:[0-9]{1,3}\.){3}[0-9]{1,3})(?::([0-9]{1,5}))?\/?$/.exec(rawOrigin);
48
+ const local = plugins.net.isIP(origin.hostname) === 4 && (first === 10 || first === 127 ||
49
+ first === 192 && second === 168 || first === 172 && second >= 16 && second <= 31 || first === 169 && second === 254);
50
+ if (!local || fourth === 255 || first === 169 && second === 254 && (third === 0 || third === 255) ||
51
+ !selectedOrigin || selectedOrigin[1] !== origin.hostname || selectedOrigin[2] !== undefined && Number(selectedOrigin[2]) === 0 ||
52
+ origin.username || origin.password || origin.search || origin.hash || origin.pathname !== '/' ||
53
+ !['http:', 'https:'].includes(origin.protocol)) {
54
+ throw new TypeError('Nanoleaf origin must select one private, loopback or link-local unicast IPv4 HTTP(S) controller.');
55
+ }
56
+ if (config.allowUnencryptedHttp !== undefined && typeof config.allowUnencryptedHttp !== 'boolean') throw new TypeError('Nanoleaf HTTP consent must be a boolean.');
57
+ if (origin.protocol === 'http:' && config.allowUnencryptedHttp !== true) throw new TypeError('Nanoleaf plaintext HTTP requires explicit allowUnencryptedHttp: true consent.');
58
+ const expectedModel = nanoleafText(config.expectedModel, 'expectedModel', 64);
59
+ if (!plugins.ecobridgeDeviceManager.nanoleafSupportedModels.some((modelArg) => modelArg === expectedModel)) {
60
+ throw new TypeError('Nanoleaf expectedModel must identify a documented Light Panels API controller.');
61
+ }
62
+ const certificateAuthority = config.certificateAuthority;
63
+ if (certificateAuthority !== undefined && (typeof certificateAuthority !== 'string' || certificateAuthority.length > 524288 ||
64
+ !certificateAuthority.includes('-----BEGIN CERTIFICATE-----'))) throw new TypeError('Nanoleaf certificateAuthority must be a bounded PEM certificate.');
65
+ const credentialKey = nanoleafText(config.credentialKey, 'credentialKey');
66
+ if (encodeURIComponent(credentialKey).length > 900) throw new TypeError('Nanoleaf credentialKey exceeds the encrypted store key bound.');
67
+ return Object.freeze({
68
+ homeId, origin: origin.origin,
69
+ expectedSerialNumber: nanoleafText(config.expectedSerialNumber, 'expectedSerialNumber', 128), expectedModel,
70
+ credentialKey,
71
+ allowUnencryptedHttp: config.allowUnencryptedHttp === true,
72
+ certificateAuthority,
73
+ timeoutMs: nanoleafInteger(config.timeoutMs === undefined ? 5000 : config.timeoutMs, 1, 60000, 'timeoutMs'),
74
+ maxResponseBytes: nanoleafInteger(config.maxResponseBytes === undefined ? 1048576 : config.maxResponseBytes, 256, 1048576, 'maxResponseBytes'),
75
+ maxPendingOperations: nanoleafInteger(config.maxPendingOperations === undefined ? 32 : config.maxPendingOperations, 1, 64, 'maxPendingOperations'),
76
+ });
77
+ }