homematic-manager 3.0.0-beta.2 → 3.0.0-beta.21

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 (332) hide show
  1. package/README.md +2 -1
  2. package/data/easymode-time-selectors.json +285 -0
  3. package/data/icons/106_hm-lc-sw1-dr.webp +0 -0
  4. package/data/icons/108_hm-rc-dis-h-x-eu.webp +0 -0
  5. package/data/icons/109_hm-lc-sw1-pl-ct.webp +0 -0
  6. package/data/icons/110_hm-es-pmsw1-dr.webp +0 -0
  7. package/data/icons/112_hmip-wrc2.webp +0 -0
  8. package/data/icons/113_hmip-psm-ch.webp +0 -0
  9. package/data/icons/113_hmip-psm-it.webp +0 -0
  10. package/data/icons/113_hmip-psm-pe.webp +0 -0
  11. package/data/icons/113_hmip-psm-uk.webp +0 -0
  12. package/data/icons/113_hmip-psm.webp +0 -0
  13. package/data/icons/114_hm-lc-dim1t-fm-lf_3.webp +0 -0
  14. package/data/icons/116_hm-rc-4-3_brc-h3.webp +0 -0
  15. package/data/icons/118_hmip-swdo.webp +0 -0
  16. package/data/icons/119_hmip-rc8.webp +0 -0
  17. package/data/icons/120_hmip-etrv.webp +0 -0
  18. package/data/icons/121_hmip-wth.webp +0 -0
  19. package/data/icons/123_oligo.smart.ip.hm.webp +0 -0
  20. package/data/icons/125_hmip-smi.webp +0 -0
  21. package/data/icons/130_hmip-srh.webp +0 -0
  22. package/data/icons/131_hmip-wrc6.webp +0 -0
  23. package/data/icons/132_hmip-smo.webp +0 -0
  24. package/data/icons/133_hmip-asir.webp +0 -0
  25. package/data/icons/134_hmip-fsm.webp +0 -0
  26. package/data/icons/135_hmip-fsm16.webp +0 -0
  27. package/data/icons/136_hmip-miob.webp +0 -0
  28. package/data/icons/137_hmip-fal-c6.webp +0 -0
  29. package/data/icons/138_hmip-fal-c10.webp +0 -0
  30. package/data/icons/140_alpha-ip-rgb.webp +0 -0
  31. package/data/icons/141_alpha-ip-rgba.webp +0 -0
  32. package/data/icons/144_hmip-wgc.webp +0 -0
  33. package/data/icons/145_hmip-froll_hmip-fbl.webp +0 -0
  34. package/data/icons/146_hmip-sth.webp +0 -0
  35. package/data/icons/147_hmip-sthd.webp +0 -0
  36. package/data/icons/148_hmip-stho.webp +0 -0
  37. package/data/icons/149_hmip-sam.webp +0 -0
  38. package/data/icons/151_hmip-pcbs-bat.webp +0 -0
  39. package/data/icons/152_hmip-swdo-i.webp +0 -0
  40. package/data/icons/153_hmip-spi.webp +0 -0
  41. package/data/icons/154_hmip-spdr.webp +0 -0
  42. package/data/icons/155_hmip-whs2.webp +0 -0
  43. package/data/icons/156_hmip-mod-oc8.webp +0 -0
  44. package/data/icons/158_hmip-etrv-uk.webp +0 -0
  45. package/data/icons/159_hmip-mod-rc8.webp +0 -0
  46. package/data/icons/160_hmipw-drs4.webp +0 -0
  47. package/data/icons/161_hmipw-drs8.webp +0 -0
  48. package/data/icons/162_hmipw-drap.webp +0 -0
  49. package/data/icons/163_hmipw-drbl4.webp +0 -0
  50. package/data/icons/164_hmipw-dri16.webp +0 -0
  51. package/data/icons/165_hmipw-fio6.webp +0 -0
  52. package/data/icons/166_hmipw-drd3.webp +0 -0
  53. package/data/icons/167_hmipw-dri32.webp +0 -0
  54. package/data/icons/168_hmip-smi55.webp +0 -0
  55. package/data/icons/169_hmip-swo-pr.webp +0 -0
  56. package/data/icons/170_hmip-swo-pl.webp +0 -0
  57. package/data/icons/171_hmip-swo-b.webp +0 -0
  58. package/data/icons/172_hmip-swd.webp +0 -0
  59. package/data/icons/173_hmip-bsl.webp +0 -0
  60. package/data/icons/174_hmip-slo.webp +0 -0
  61. package/data/icons/175_hmip-group-heating.webp +0 -0
  62. package/data/icons/177_hmip-dbb.webp +0 -0
  63. package/data/icons/178_hmip-etrv-b1.webp +0 -0
  64. package/data/icons/179_hmip-swdm-b2.webp +0 -0
  65. package/data/icons/180_hmip-etrv-b.webp +0 -0
  66. package/data/icons/181_hmip-swdm.webp +0 -0
  67. package/data/icons/182_hmip-fci1.webp +0 -0
  68. package/data/icons/183_hmip-mod-tm.webp +0 -0
  69. package/data/icons/184_hmip-pcbs2.webp +0 -0
  70. package/data/icons/185_hmip-FCI6.webp +0 -0
  71. package/data/icons/186_hmip-mp3p.webp +0 -0
  72. package/data/icons/187_hmip-rcb1.webp +0 -0
  73. package/data/icons/188_hmip-etrv-c.webp +0 -0
  74. package/data/icons/190_hmip-sci.webp +0 -0
  75. package/data/icons/191_hmip-mod-ho.webp +0 -0
  76. package/data/icons/192_hmip-asir-o.webp +0 -0
  77. package/data/icons/193_hmip-wt.webp +0 -0
  78. package/data/icons/194_hmip-wrcd.webp +0 -0
  79. package/data/icons/195_hmipw-smi55.webp +0 -0
  80. package/data/icons/196_hmip-ASIR-2.webp +0 -0
  81. package/data/icons/197_hmip-swdo-pl.webp +0 -0
  82. package/data/icons/198_hmip-falmot-c12.webp +0 -0
  83. package/data/icons/199_hmip-mio16-pcb.webp +0 -0
  84. package/data/icons/200_hmip-wth-b.webp +0 -0
  85. package/data/icons/201_hmip-stv.webp +0 -0
  86. package/data/icons/202_hmip-wrcr.webp +0 -0
  87. package/data/icons/203_hmip-fsi16.webp +0 -0
  88. package/data/icons/204_hmip-drdi3.webp +0 -0
  89. package/data/icons/205_hmip-drsi4.webp +0 -0
  90. package/data/icons/206_hmip-drbli4.webp +0 -0
  91. package/data/icons/207_hmip-srdo.webp +0 -0
  92. package/data/icons/208_hmip-dsd-pcb.webp +0 -0
  93. package/data/icons/209_hmip-etrv-b-uk.webp +0 -0
  94. package/data/icons/210_hmip-ste2-pcb.webp +0 -0
  95. package/data/icons/211_hmip-drg-dali.webp +0 -0
  96. package/data/icons/211_hmip-drsi1.webp +0 -0
  97. package/data/icons/212_hmip-sfd.webp +0 -0
  98. package/data/icons/212_hmipw-scthd.webp +0 -0
  99. package/data/icons/213_hmip-smo230.webp +0 -0
  100. package/data/icons/213_hmip-wua.webp +0 -0
  101. package/data/icons/214_hmip-dld.webp +0 -0
  102. package/data/icons/215_hmip-psm-pe-2.webp +0 -0
  103. package/data/icons/215_hmip-scth230.webp +0 -0
  104. package/data/icons/216_hmip-etrv-e.webp +0 -0
  105. package/data/icons/216_hmip-psm-ch-2.webp +0 -0
  106. package/data/icons/217_hmip-usbsm.webp +0 -0
  107. package/data/icons/218_hmip-dls.webp +0 -0
  108. package/data/icons/219_hmip-fwi.webp +0 -0
  109. package/data/icons/220_hmip-wsc.webp +0 -0
  110. package/data/icons/221_hmip-sti.webp +0 -0
  111. package/data/icons/221_hmip-wkp.webp +0 -0
  112. package/data/icons/222_hmipw-wgd.webp +0 -0
  113. package/data/icons/223_hmip-mod-wd-vk.webp +0 -0
  114. package/data/icons/224_hmip-etrv-cl.webp +0 -0
  115. package/data/icons/225_hmip-rgbw.webp +0 -0
  116. package/data/icons/226_hmip-esi.webp +0 -0
  117. package/data/icons/227_hmip-lsc.webp +0 -0
  118. package/data/icons/228_elv-sh-sw1-bat.webp +0 -0
  119. package/data/icons/229_elv-sh-bm-s.webp +0 -0
  120. package/data/icons/230_hmip-etrv-f.webp +0 -0
  121. package/data/icons/231_elv-sh-cth.webp +0 -0
  122. package/data/icons/232_elv-sh-taco.webp +0 -0
  123. package/data/icons/233_hmip-flc.webp +0 -0
  124. package/data/icons/234_hmip-etrv-3.webp +0 -0
  125. package/data/icons/235_hmip-psmco.webp +0 -0
  126. package/data/icons/236_elv-sh-sb8.webp +0 -0
  127. package/data/icons/237_elv-sh-ctv.webp +0 -0
  128. package/data/icons/238_elv-sh-cap.webp +0 -0
  129. package/data/icons/239_hmip-wgs-f.webp +0 -0
  130. package/data/icons/240_hmip-wgtc-f.webp +0 -0
  131. package/data/icons/241_hmip-wgt-f.webp +0 -0
  132. package/data/icons/242_elv-sh-smsi.webp +0 -0
  133. package/data/icons/243_elv-sh-crc.webp +0 -0
  134. package/data/icons/244_elv-sh-krco.webp +0 -0
  135. package/data/icons/245_hmip-falmot-c8.webp +0 -0
  136. package/data/icons/246_elv-sh-wsm.webp +0 -0
  137. package/data/icons/247_hmip-hap-2.webp +0 -0
  138. package/data/icons/248_hmip-dlp.webp +0 -0
  139. package/data/icons/249_elv-sh-psmci.webp +0 -0
  140. package/data/icons/250_elv-sh-sps25.webp +0 -0
  141. package/data/icons/252_elv-sh-pti2.webp +0 -0
  142. package/data/icons/253_hmip-udi-smi55.webp +0 -0
  143. package/data/icons/254_hmip-udi-pb2.webp +0 -0
  144. package/data/icons/256_ELV-SH-SMS2.webp +0 -0
  145. package/data/icons/257_ELV-SH-FSI.webp +0 -0
  146. package/data/icons/258_hmip-m-td15.webp +0 -0
  147. package/data/icons/259_elv-sh-dusi.webp +0 -0
  148. package/data/icons/260_hmip-wss.webp +0 -0
  149. package/data/icons/54a_lc-ddc1-pcb.webp +0 -0
  150. package/data/icons/72_hm-rc-brc-h.webp +0 -0
  151. package/data/icons/73_hm-atent.webp +0 -0
  152. package/data/icons/79_hm-lc-dim1pwm-cv.webp +0 -0
  153. package/data/icons/84_hm-rc-4-3.webp +0 -0
  154. package/data/icons/85_hm-rc-sec4-3.webp +0 -0
  155. package/data/icons/86_hm-rc-key4-3.webp +0 -0
  156. package/data/icons/CCU3-1-50.webp +0 -0
  157. package/data/icons/CCU3.webp +0 -0
  158. package/data/icons/hm-coupling-dim.webp +0 -0
  159. package/data/icons/hm-coupling-group.webp +0 -0
  160. package/data/icons/hm-coupling-onoff.webp +0 -0
  161. package/data/icons/hm-coupling-rgb-dim.webp +0 -0
  162. package/data/icons/hm-coupling-rgb.webp +0 -0
  163. package/data/icons/hm-coupling-rgbw-dim.webp +0 -0
  164. package/data/icons/hm-coupling-rgbw.webp +0 -0
  165. package/data/icons/hm-coupling-white-dim.webp +0 -0
  166. package/data/icons/hm-coupling-white.webp +0 -0
  167. package/data/icons/hm-hue_gateway.webp +0 -0
  168. package/data/icons/hm-lightify_gateway.webp +0 -0
  169. package/data/icons/hm_resc-win-pcb-sc.webp +0 -0
  170. package/data/icons/unknown_device.webp +0 -0
  171. package/data/manifest.json +7 -1
  172. package/data/master-metadata.json +1997 -33
  173. package/data/profiles/ACCESS_RECEIVER.json +26 -13
  174. package/data/profiles/ACOUSTIC_SIGNAL_VIRTUAL_RECEIVER.json +3270 -76
  175. package/data/profiles/ACTOR_SECURITY.json +90 -10
  176. package/data/profiles/ACTOR_WINDOW.json +580 -43
  177. package/data/profiles/ALARMACTUATOR.json +564 -37
  178. package/data/profiles/ALARM_COND_SWITCH_RECEIVER.json +36 -4
  179. package/data/profiles/ALARM_SWITCH_VIRTUAL_RECEIVER.json +735 -33
  180. package/data/profiles/ARMING.json +115 -5
  181. package/data/profiles/BLIND.json +1038 -49
  182. package/data/profiles/BLIND_VIRTUAL_RECEIVER.json +4624 -124
  183. package/data/profiles/CLIMATECONTROL_FLOOR_PUMP_TRANSCEIVER.json +27 -1
  184. package/data/profiles/DIMMER.json +2233 -71
  185. package/data/profiles/DIMMER_VIRTUAL_RECEIVER.json +5773 -102
  186. package/data/profiles/DIMMER_woLongKeyPress.json +117 -4
  187. package/data/profiles/DOOR_RECEIVER.json +138 -10
  188. package/data/profiles/DUAL_WHITE_BRIGHTNESS.json +305 -11
  189. package/data/profiles/DUAL_WHITE_COLOR.json +730 -23
  190. package/data/profiles/HEATING_KEY_RECEIVER.json +127 -10
  191. package/data/profiles/HMW_BLIND.json +555 -20
  192. package/data/profiles/HMW_DIMMER.json +1337 -47
  193. package/data/profiles/HMW_INPUT_OUTPUT.json +375 -20
  194. package/data/profiles/HMW_SWITCH.json +375 -20
  195. package/data/profiles/JALOUSIE.json +1320 -52
  196. package/data/profiles/KEYMATIC.json +120 -12
  197. package/data/profiles/REMOTECONTROL_RECEIVER.json +10 -2
  198. package/data/profiles/RGBW_AUTOMATIC.json +46 -6
  199. package/data/profiles/RGBW_COLOR.json +14 -4
  200. package/data/profiles/SERVO_VIRTUAL_RECEIVER.json +117 -3
  201. package/data/profiles/SHUTTER_VIRTUAL_RECEIVER.json +4263 -128
  202. package/data/profiles/SIGNAL_CHIME.json +195 -14
  203. package/data/profiles/SIGNAL_CHIMEM.json +195 -14
  204. package/data/profiles/SIGNAL_LED.json +195 -14
  205. package/data/profiles/SIGNAL_LEDM.json +195 -14
  206. package/data/profiles/SIMPLE_SWITCH_RECEIVER.json +113 -9
  207. package/data/profiles/STATUS_INDICATOR.json +1073 -45
  208. package/data/profiles/SWITCH.json +1412 -60
  209. package/data/profiles/SWITCH_PANIC.json +315 -13
  210. package/data/profiles/SWITCH_SENSOR.json +243 -11
  211. package/data/profiles/SWITCH_VIRTUAL_RECEIVER.json +3963 -131
  212. package/data/profiles/UNIVERSAL_ACTOR.json +4319 -90
  213. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_LSC.json +6094 -196
  214. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_PWM.json +4920 -101
  215. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_RGB(W).json +2353 -80
  216. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_RGBW_DALI.json +6116 -176
  217. package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_TW.json +3844 -104
  218. package/data/profiles/VIRTUAL_DIMMER.json +305 -11
  219. package/data/profiles/VIRTUAL_DUAL_WHITE_COLOR.json +730 -23
  220. package/data/profiles/WATER_SWITCH_VIRTUAL_RECEIVER.json +3903 -128
  221. package/data/profiles/WINDOW_DRIVE_RECEIVER.json +220 -8
  222. package/data/profiles/WINMATIC.json +505 -23
  223. package/dist/cli.js +24 -0
  224. package/dist/occulite.d.ts +86 -0
  225. package/dist/occulite.js +140 -0
  226. package/dist/options.d.ts +37 -6
  227. package/dist/options.js +49 -6
  228. package/dist/server.d.ts +47 -4
  229. package/dist/server.js +237 -27
  230. package/dist/sessions.d.ts +9 -1
  231. package/dist/sessions.js +8 -2
  232. package/dist/testSupport.js +9 -2
  233. package/node_modules/@homematic-manager/backend/dist/api/backend.d.ts +33 -0
  234. package/node_modules/@homematic-manager/backend/dist/api/backend.js +558 -46
  235. package/node_modules/@homematic-manager/backend/dist/cache/names.d.ts +9 -0
  236. package/node_modules/@homematic-manager/backend/dist/cache/names.js +21 -0
  237. package/node_modules/@homematic-manager/backend/dist/config/defaults.js +10 -1
  238. package/node_modules/@homematic-manager/backend/dist/config/store.d.ts +28 -1
  239. package/node_modules/@homematic-manager/backend/dist/config/store.js +59 -3
  240. package/node_modules/@homematic-manager/backend/dist/devices/installMode.js +9 -0
  241. package/node_modules/@homematic-manager/backend/dist/errors.d.ts +18 -0
  242. package/node_modules/@homematic-manager/backend/dist/errors.js +51 -2
  243. package/node_modules/@homematic-manager/backend/dist/images/deviceImages.d.ts +6 -0
  244. package/node_modules/@homematic-manager/backend/dist/images/deviceImages.js +38 -2
  245. package/node_modules/@homematic-manager/backend/dist/index.d.ts +3 -1
  246. package/node_modules/@homematic-manager/backend/dist/index.js +4 -1
  247. package/node_modules/@homematic-manager/backend/dist/interfaces/manager.d.ts +70 -8
  248. package/node_modules/@homematic-manager/backend/dist/interfaces/manager.js +333 -44
  249. package/node_modules/@homematic-manager/backend/dist/meta/client.d.ts +120 -0
  250. package/node_modules/@homematic-manager/backend/dist/meta/client.js +307 -0
  251. package/node_modules/@homematic-manager/backend/dist/meta/credentials.d.ts +38 -0
  252. package/node_modules/@homematic-manager/backend/dist/meta/credentials.js +53 -0
  253. package/node_modules/@homematic-manager/backend/dist/meta/index.d.ts +12 -0
  254. package/node_modules/@homematic-manager/backend/dist/meta/index.js +12 -0
  255. package/node_modules/@homematic-manager/backend/dist/meta/localProvider.d.ts +47 -0
  256. package/node_modules/@homematic-manager/backend/dist/meta/localProvider.js +119 -0
  257. package/node_modules/@homematic-manager/backend/dist/meta/occuliteProvider.d.ts +79 -0
  258. package/node_modules/@homematic-manager/backend/dist/meta/occuliteProvider.js +305 -0
  259. package/node_modules/@homematic-manager/backend/dist/meta/provider.d.ts +68 -0
  260. package/node_modules/@homematic-manager/backend/dist/meta/provider.js +19 -0
  261. package/node_modules/@homematic-manager/backend/dist/meta/regaProvider.d.ts +84 -0
  262. package/node_modules/@homematic-manager/backend/dist/meta/regaProvider.js +403 -0
  263. package/node_modules/@homematic-manager/backend/dist/meta/service.d.ts +137 -0
  264. package/node_modules/@homematic-manager/backend/dist/meta/service.js +412 -0
  265. package/node_modules/@homematic-manager/backend/dist/rega/client.d.ts +11 -0
  266. package/node_modules/@homematic-manager/backend/dist/rega/client.js +13 -0
  267. package/node_modules/@homematic-manager/backend/dist/rega/scripts.d.ts +51 -0
  268. package/node_modules/@homematic-manager/backend/dist/rega/scripts.js +171 -0
  269. package/node_modules/@homematic-manager/backend/dist/rpc/client.d.ts +18 -5
  270. package/node_modules/@homematic-manager/backend/dist/rpc/client.js +11 -5
  271. package/node_modules/@homematic-manager/backend/dist/rpc/log.d.ts +86 -0
  272. package/node_modules/@homematic-manager/backend/dist/rpc/log.js +241 -0
  273. package/node_modules/@homematic-manager/backend/dist/rpc/origin.d.ts +30 -0
  274. package/node_modules/@homematic-manager/backend/dist/rpc/origin.js +35 -0
  275. package/node_modules/@homematic-manager/backend/dist/rpc/server.d.ts +12 -0
  276. package/node_modules/@homematic-manager/backend/dist/rpc/server.js +37 -5
  277. package/node_modules/@homematic-manager/backend/dist/util/net.d.ts +86 -1
  278. package/node_modules/@homematic-manager/backend/dist/util/net.js +223 -9
  279. package/node_modules/@homematic-manager/backend/package.json +1 -1
  280. package/node_modules/@homematic-manager/core/dist/api/types.d.ts +397 -10
  281. package/node_modules/@homematic-manager/core/dist/api/types.js +23 -2
  282. package/node_modules/@homematic-manager/core/dist/data/memory.d.ts +3 -1
  283. package/node_modules/@homematic-manager/core/dist/data/memory.js +3 -0
  284. package/node_modules/@homematic-manager/core/dist/data/types.d.ts +60 -0
  285. package/node_modules/@homematic-manager/core/dist/data/types.js +2 -0
  286. package/node_modules/@homematic-manager/core/dist/devices/index.d.ts +19 -0
  287. package/node_modules/@homematic-manager/core/dist/devices/index.js +53 -0
  288. package/node_modules/@homematic-manager/core/dist/easymodes/engine.d.ts +3 -1
  289. package/node_modules/@homematic-manager/core/dist/easymodes/engine.js +1 -0
  290. package/node_modules/@homematic-manager/core/dist/easymodes/form.d.ts +43 -0
  291. package/node_modules/@homematic-manager/core/dist/easymodes/form.js +84 -0
  292. package/node_modules/@homematic-manager/core/dist/i18n/messages.js +61 -0
  293. package/node_modules/@homematic-manager/core/dist/index.d.ts +3 -0
  294. package/node_modules/@homematic-manager/core/dist/index.js +4 -0
  295. package/node_modules/@homematic-manager/core/dist/interfaces/table.d.ts +23 -2
  296. package/node_modules/@homematic-manager/core/dist/interfaces/table.js +18 -1
  297. package/node_modules/@homematic-manager/core/dist/meta/document.d.ts +71 -0
  298. package/node_modules/@homematic-manager/core/dist/meta/document.js +260 -0
  299. package/node_modules/@homematic-manager/core/dist/meta/follow.d.ts +27 -0
  300. package/node_modules/@homematic-manager/core/dist/meta/follow.js +180 -0
  301. package/node_modules/@homematic-manager/core/dist/meta/index.d.ts +16 -0
  302. package/node_modules/@homematic-manager/core/dist/meta/index.js +16 -0
  303. package/node_modules/@homematic-manager/core/dist/meta/paths.d.ts +96 -0
  304. package/node_modules/@homematic-manager/core/dist/meta/paths.js +182 -0
  305. package/node_modules/@homematic-manager/core/dist/meta/slug.d.ts +22 -0
  306. package/node_modules/@homematic-manager/core/dist/meta/slug.js +59 -0
  307. package/node_modules/@homematic-manager/core/dist/meta/store.d.ts +147 -0
  308. package/node_modules/@homematic-manager/core/dist/meta/store.js +537 -0
  309. package/node_modules/@homematic-manager/core/dist/meta/tree.d.ts +19 -0
  310. package/node_modules/@homematic-manager/core/dist/meta/tree.js +53 -0
  311. package/node_modules/@homematic-manager/core/dist/meta/types.d.ts +143 -0
  312. package/node_modules/@homematic-manager/core/dist/meta/types.js +63 -0
  313. package/node_modules/@homematic-manager/core/dist/meta/view.d.ts +50 -0
  314. package/node_modules/@homematic-manager/core/dist/meta/view.js +103 -0
  315. package/node_modules/@homematic-manager/core/dist/rpc/methods.d.ts +10 -0
  316. package/node_modules/@homematic-manager/core/dist/rpc/methods.js +51 -1
  317. package/node_modules/@homematic-manager/core/dist/rpc/text.d.ts +22 -0
  318. package/node_modules/@homematic-manager/core/dist/rpc/text.js +46 -0
  319. package/node_modules/@homematic-manager/core/dist/rssi/index.d.ts +125 -13
  320. package/node_modules/@homematic-manager/core/dist/rssi/index.js +146 -29
  321. package/node_modules/@homematic-manager/core/dist/serviceMessages/index.d.ts +28 -2
  322. package/node_modules/@homematic-manager/core/dist/serviceMessages/index.js +44 -6
  323. package/node_modules/@homematic-manager/core/package.json +1 -1
  324. package/package.json +3 -3
  325. package/ui/assets/index-D-NsbBVS.css +1 -0
  326. package/ui/assets/index-DNUNMBbb.js +16 -0
  327. package/ui/favicon.ico +0 -0
  328. package/ui/index.html +3 -2
  329. package/node_modules/@homematic-manager/backend/dist/write/log.d.ts +0 -51
  330. package/node_modules/@homematic-manager/backend/dist/write/log.js +0 -151
  331. package/ui/assets/index-lB-HxsKR.js +0 -13
  332. package/ui/assets/index-qbhgN2pA.css +0 -1
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Who asked for an RPC call: the console, a UI action, or the backend on its own.
3
+ *
4
+ * Task 48: the RPC log shows every outgoing call, and the background ones - `init`, `ping`, the
5
+ * service-message poll, the sweeps after an event - can be frequent, so every entry carries where
6
+ * it came from and the drawer can hide them. The origin is a property of the call chain, not of a
7
+ * function: `#refreshDevices` runs for the Devices tab's refresh button and for a `newDevices`
8
+ * callback alike. Threading a parameter through the forty call sites of `#read`/`#write` and every
9
+ * helper between them would change signatures for nothing, so the origin travels in Node's
10
+ * `AsyncLocalStorage`: `Backend.request` opens a `ui` (or `console`) context, and whatever is
11
+ * awaited inside it inherits that.
12
+ *
13
+ * Two things must be explicit, and the tests hold them:
14
+ * - Anything long-lived that is *created* inside a request would inherit its context forever - the
15
+ * watchdog interval, the callback servers, the polling timers after a `config.set`. The places
16
+ * that create such things run under `background` on purpose (`Backend.#connect`, the timers, the
17
+ * manager's callbacks), and the manager's own calls name their origin outright.
18
+ * - A queued write runs from the timer that drained the queue, which is the *previous* task's
19
+ * context; `Backend.#write` therefore captures the origin at enqueue time.
20
+ *
21
+ * The RPC client itself does not read this module: it takes a resolver (`originOf`) and an
22
+ * explicit origin per call, so the logging layer stays free of Node (task 52 wants the same engine
23
+ * in a browser host one day, where an explicit parameter would replace the storage).
24
+ */
25
+ import { AsyncLocalStorage } from 'node:async_hooks';
26
+ const storage = new AsyncLocalStorage();
27
+ /** The origin of the current call chain; `background` outside of any request. */
28
+ export function currentOrigin() {
29
+ return storage.getStore() ?? 'background';
30
+ }
31
+ /** Runs `fn` with `origin` as the answer of {@link currentOrigin} for everything it awaits. */
32
+ export function runWithOrigin(origin, fn) {
33
+ return storage.run(origin, fn);
34
+ }
35
+ //# sourceMappingURL=origin.js.map
@@ -88,11 +88,23 @@ export declare class CallbackServers implements CallbackServerSet {
88
88
  constructor(options: {
89
89
  handler: CallbackHandler;
90
90
  host?: string;
91
+ /** The configured ports; `0` means none is configured. */
91
92
  ports: {
92
93
  xmlrpc: number;
93
94
  binrpc: number;
94
95
  };
96
+ /**
97
+ * Task 35 (D-43): the port a protocol takes while its configured port is `0` - the CCU
98
+ * addon's fixed pair, so that a restart registers the very URL it registered before.
99
+ * Unlike a configured port, a default that is taken is no error: the server falls back to
100
+ * a free port for this start, and `onFallback` hears about it once.
101
+ */
102
+ defaultPorts?: {
103
+ xmlrpc: number;
104
+ binrpc: number;
105
+ };
95
106
  onError?: (error: unknown) => void;
107
+ onFallback?: (protocol: RpcProtocol, port: number, error: unknown) => void;
96
108
  });
97
109
  /** Starts the server for a protocol if it is not running yet, and returns its port. */
98
110
  ensure(protocol: RpcProtocol): Promise<number>;
@@ -17,7 +17,7 @@
17
17
  */
18
18
  import binrpc from 'binrpc';
19
19
  import xmlrpc from 'homematic-xmlrpc';
20
- import { interfaceNameFromIdent } from '@homematic-manager/core';
20
+ import { interfaceNameFromIdent, normaliseDescription, } from '@homematic-manager/core';
21
21
  import { connectionError, errorMessage } from '../errors.js';
22
22
  /** The callback methods this server answers, in the order `system.listMethods` returns them. */
23
23
  export const CALLBACK_METHODS = [
@@ -199,11 +199,18 @@ export class CallbackServer {
199
199
  return new Promise((resolve, reject) => {
200
200
  const server = xmlrpc.createServer({ host: this.host, port: this.#requestedPort });
201
201
  this.#xmlrpcServer = server;
202
+ let listening = false;
202
203
  server.on('error', (error) => {
203
- reject(connectionError(`xmlrpc callback server on port ${String(this.#requestedPort)}: ${error.message}`, error));
204
+ // a bind that fails is the rejection's to report, once; `onError` is for a server
205
+ // that is running
206
+ if (!listening) {
207
+ reject(connectionError(`xmlrpc callback server on port ${String(this.#requestedPort)}: ${error.message}`, error));
208
+ return;
209
+ }
204
210
  this.#onError(error);
205
211
  });
206
212
  server.on('listening', () => {
213
+ listening = true;
207
214
  const address = server.httpServer.address();
208
215
  resolve(typeof address === 'object' && address !== null ? address.port : this.#requestedPort);
209
216
  });
@@ -221,11 +228,16 @@ export class CallbackServer {
221
228
  return new Promise((resolve, reject) => {
222
229
  const server = binrpc.createServer({ host: this.host, port: this.#requestedPort });
223
230
  this.#binrpcServer = server;
231
+ let listening = false;
224
232
  server.on('error', (error) => {
225
- reject(connectionError(`binrpc callback server on port ${String(this.#requestedPort)}: ${error.message}`, error));
233
+ if (!listening) {
234
+ reject(connectionError(`binrpc callback server on port ${String(this.#requestedPort)}: ${error.message}`, error));
235
+ return;
236
+ }
226
237
  this.#onError(error);
227
238
  });
228
239
  server.on('listening', () => {
240
+ listening = true;
229
241
  const address = server.server.address();
230
242
  resolve(typeof address === 'object' && address !== null ? address.port : this.#requestedPort);
231
243
  });
@@ -266,7 +278,9 @@ function asDescriptions(value) {
266
278
  entry !== null &&
267
279
  !Array.isArray(entry) &&
268
280
  typeof entry['ADDRESS'] === 'string') {
269
- descriptions.push(entry);
281
+ // #143: the list fields of a description are made into lists here, once, for every
282
+ // interface - the group process sends `PARAMSETS` as a string on some boxes.
283
+ descriptions.push(normaliseDescription(entry));
270
284
  }
271
285
  }
272
286
  return descriptions;
@@ -282,12 +296,16 @@ export class CallbackServers {
282
296
  #handler;
283
297
  #host;
284
298
  #ports;
299
+ #defaultPorts;
285
300
  #onError;
301
+ #onFallback;
286
302
  constructor(options) {
287
303
  this.#handler = options.handler;
288
304
  this.#host = options.host ?? '0.0.0.0';
289
305
  this.#ports = options.ports;
306
+ this.#defaultPorts = options.defaultPorts ?? { xmlrpc: 0, binrpc: 0 };
290
307
  this.#onError = options.onError ?? (() => undefined);
308
+ this.#onFallback = options.onFallback ?? (() => undefined);
291
309
  }
292
310
  /** Starts the server for a protocol if it is not running yet, and returns its port. */
293
311
  async ensure(protocol) {
@@ -295,10 +313,24 @@ export class CallbackServers {
295
313
  if (running) {
296
314
  return running.port;
297
315
  }
316
+ const configured = protocol === 'binrpc' ? this.#ports.binrpc : this.#ports.xmlrpc;
317
+ const preferred = protocol === 'binrpc' ? this.#defaultPorts.binrpc : this.#defaultPorts.xmlrpc;
318
+ if (configured !== 0 || preferred === 0) {
319
+ return this.#start(protocol, configured);
320
+ }
321
+ try {
322
+ return await this.#start(protocol, preferred);
323
+ }
324
+ catch (error) {
325
+ this.#onFallback(protocol, preferred, error);
326
+ return this.#start(protocol, 0);
327
+ }
328
+ }
329
+ async #start(protocol, port) {
298
330
  const server = new CallbackServer({
299
331
  protocol,
300
332
  host: this.#host,
301
- port: protocol === 'binrpc' ? this.#ports.binrpc : this.#ports.xmlrpc,
333
+ port,
302
334
  handler: this.#handler,
303
335
  onError: this.#onError,
304
336
  });
@@ -7,15 +7,100 @@
7
7
  * 5 s timeout each before the window became usable) and it destroys the socket instead of leaving
8
8
  * it to time out.
9
9
  */
10
+ import dgram from 'node:dgram';
11
+ import dns from 'node:dns';
10
12
  import net from 'node:net';
11
13
  import os from 'node:os';
12
- /** Every non-internal IPv4 address of this machine; candidates for the callback address. */
14
+ import type { CallbackAddressInfo } from '@homematic-manager/core';
15
+ /**
16
+ * Every non-internal IPv4 address of this machine, then `127.0.0.1`; candidates for the callback
17
+ * address. The loopback comes last so nothing that picked "the first candidate" changes - but it
18
+ * has to be offered: on an openccu-lite box the interface processes bind the loopback only
19
+ * (their D-29), so for the Homematic Manager running *on* the box it is the one address they
20
+ * can call back (openccu-lite task 28.10, maintainer 2026-09-08).
21
+ */
13
22
  export declare function localIPv4Addresses(interfaces?: () => NodeJS.Dict<os.NetworkInterfaceInfo[]>): string[];
23
+ /** One IPv4 address of this machine; `netmask` is absent where it is not known (an injected list). */
24
+ export interface LocalIPv4 {
25
+ readonly address: string;
26
+ readonly netmask?: string;
27
+ }
28
+ /**
29
+ * B-53: every non-internal IPv4 address of this machine with its netmask, in the order
30
+ * `os.networkInterfaces()` gives them - the loopback is not in it.
31
+ */
32
+ export declare function localIPv4Interfaces(interfaces?: () => NodeJS.Dict<os.NetworkInterfaceInfo[]>): LocalIPv4[];
33
+ /** A dotted IPv4 address as a number; `undefined` for anything else. */
34
+ export declare function ipv4ToNumber(address: string): number | undefined;
35
+ /** True when `target` is in the network of `address/netmask`. False when any of them is no IPv4 address. */
36
+ export declare function inSubnet(address: string, netmask: string, target: string): boolean;
37
+ /** `169.254.0.0/16`, the address an interface gives itself when no DHCP server answered. */
38
+ export declare function isLinkLocal(address: string): boolean;
39
+ /** `127.0.0.0/8`. */
40
+ export declare function isLoopback(address: string): boolean;
41
+ /**
42
+ * B-53: what the automatic callback address is worked out from. Injected by the tests, so that no
43
+ * unit test depends on the network of the machine it runs on.
44
+ */
45
+ export interface CallbackNetwork {
46
+ /** This machine's non-internal IPv4 addresses, see {@link localIPv4Interfaces}. */
47
+ readonly interfaces: () => LocalIPv4[];
48
+ /** The CCU host's IPv4 address; `undefined` when it does not resolve. Never rejects. */
49
+ readonly resolve: (host: string) => Promise<string | undefined>;
50
+ /** The local address the operating system sends from towards `address`; `undefined` when there is no route. Never rejects. */
51
+ readonly route: (address: string) => Promise<string | undefined>;
52
+ }
53
+ /** How long a name lookup for the callback address may take before the first address is used. */
54
+ export declare const RESOLVE_TIMEOUT_MS = 3000;
55
+ /** The CCU host's IPv4 address, through the system resolver (`/etc/hosts`, mDNS where the OS has it). */
56
+ export declare function resolveIPv4(host: string, lookup?: typeof dns.promises.lookup): Promise<string | undefined>;
57
+ /**
58
+ * The local address a UDP socket gets when it is `connect()`ed to `address`: the source address of
59
+ * the route the operating system would take. `connect` on a datagram socket only sets the default
60
+ * peer - no packet is sent - so this works for a CCU behind a router or a VPN as well as for one in
61
+ * the same network.
62
+ */
63
+ export declare function routeSource(address: string, createSocket?: typeof dgram.createSocket): Promise<string | undefined>;
64
+ /** The machine's own network, as the running host sees it. */
65
+ export declare function systemNetwork(): CallbackNetwork;
66
+ /**
67
+ * A network made of a fixed address list, for a caller that injects `localAddresses` (the tests and
68
+ * the e2e hosts): no netmasks, no name lookup beyond an address literal, no route.
69
+ */
70
+ export declare function staticNetwork(addresses: () => string[]): CallbackNetwork;
71
+ /**
72
+ * B-53 (#162, #165): the automatic callback address, and every address with whether it is in the
73
+ * CCU's network. Synchronous: `hostAddress` and `routed` are what {@link describeCallbackAddresses}
74
+ * found out, and `undefined` when nothing could be.
75
+ *
76
+ * The order: the CCU on the loopback (or `local`) is called back on the loopback; then the
77
+ * address in the CCU's network; then the route's source address; then the first address that is
78
+ * not link-local. A link-local address wins only as the CCU's own network, and the loopback is
79
+ * never chosen for a CCU elsewhere unless this machine has no other address at all.
80
+ */
81
+ export declare function pickCallbackAddress(host: string, hostAddress: string | undefined, interfaces: readonly LocalIPv4[], routed: string | undefined, local?: boolean): CallbackAddressInfo;
82
+ /**
83
+ * B-53: {@link pickCallbackAddress} with the facts looked up - the CCU's name resolved, and the route
84
+ * asked for only when no address shares the CCU's network. Never rejects.
85
+ */
86
+ export declare function describeCallbackAddresses(host: string, network: CallbackNetwork, local?: boolean): Promise<CallbackAddressInfo>;
14
87
  export interface ProbeOptions {
15
88
  readonly timeoutMs?: number;
16
89
  /** Injected for the tests; defaults to `net.connect`. */
17
90
  readonly connect?: typeof net.connect;
18
91
  }
92
+ /**
93
+ * What a port probe found.
94
+ *
95
+ * B-28: `refused` and `unreachable` are different answers. A refused connection means nothing listens
96
+ * there - the interface process is not installed, the normal state of BidCos-Wired on a CCU without a
97
+ * wired gateway. A connection that times out, or a host without a route, says nothing about the
98
+ * process: a slow CCU-Jack, a remote CUxD on a box that is rebooting. Only the first may be shown as
99
+ * "not present".
100
+ */
101
+ export type PortProbe = 'open' | 'refused' | 'unreachable';
102
+ /** Whether a TCP connection to `host:port` is accepted, refused, or not answered in time. Never throws. */
103
+ export declare function probePortState(host: string, port: number, options?: ProbeOptions): Promise<PortProbe>;
19
104
  /** True when a TCP connection to `host:port` is accepted within the timeout. Never throws. */
20
105
  export declare function probePort(host: string, port: number, options?: ProbeOptions): Promise<boolean>;
21
106
  /** Resolves after `ms`; the timer never keeps the process alive. */
@@ -7,9 +7,17 @@
7
7
  * 5 s timeout each before the window became usable) and it destroys the socket instead of leaving
8
8
  * it to time out.
9
9
  */
10
+ import dgram from 'node:dgram';
11
+ import dns from 'node:dns';
10
12
  import net from 'node:net';
11
13
  import os from 'node:os';
12
- /** Every non-internal IPv4 address of this machine; candidates for the callback address. */
14
+ /**
15
+ * Every non-internal IPv4 address of this machine, then `127.0.0.1`; candidates for the callback
16
+ * address. The loopback comes last so nothing that picked "the first candidate" changes - but it
17
+ * has to be offered: on an openccu-lite box the interface processes bind the loopback only
18
+ * (their D-29), so for the Homematic Manager running *on* the box it is the one address they
19
+ * can call back (openccu-lite task 28.10, maintainer 2026-09-08).
20
+ */
13
21
  export function localIPv4Addresses(interfaces = os.networkInterfaces) {
14
22
  const addresses = [];
15
23
  for (const entries of Object.values(interfaces())) {
@@ -19,33 +27,239 @@ export function localIPv4Addresses(interfaces = os.networkInterfaces) {
19
27
  }
20
28
  }
21
29
  }
30
+ addresses.push('127.0.0.1');
22
31
  return addresses;
23
32
  }
24
- /** True when a TCP connection to `host:port` is accepted within the timeout. Never throws. */
25
- export function probePort(host, port, options = {}) {
33
+ /** The address an interface process on this machine calls back on. */
34
+ const LOOPBACK = '127.0.0.1';
35
+ /**
36
+ * B-53: every non-internal IPv4 address of this machine with its netmask, in the order
37
+ * `os.networkInterfaces()` gives them - the loopback is not in it.
38
+ */
39
+ export function localIPv4Interfaces(interfaces = os.networkInterfaces) {
40
+ const found = [];
41
+ for (const entries of Object.values(interfaces())) {
42
+ for (const entry of entries ?? []) {
43
+ if (entry.family === 'IPv4' && !entry.internal && !found.some((seen) => seen.address === entry.address)) {
44
+ found.push({ address: entry.address, netmask: entry.netmask });
45
+ }
46
+ }
47
+ }
48
+ return found;
49
+ }
50
+ /** A dotted IPv4 address as a number; `undefined` for anything else. */
51
+ export function ipv4ToNumber(address) {
52
+ const parts = address.split('.');
53
+ if (parts.length !== 4) {
54
+ return undefined;
55
+ }
56
+ let value = 0;
57
+ for (const part of parts) {
58
+ if (!/^\d{1,3}$/.test(part)) {
59
+ return undefined;
60
+ }
61
+ const byte = Number(part);
62
+ if (byte > 255) {
63
+ return undefined;
64
+ }
65
+ value = value * 256 + byte;
66
+ }
67
+ return value;
68
+ }
69
+ /** True when `target` is in the network of `address/netmask`. False when any of them is no IPv4 address. */
70
+ export function inSubnet(address, netmask, target) {
71
+ const a = ipv4ToNumber(address);
72
+ const m = ipv4ToNumber(netmask);
73
+ const t = ipv4ToNumber(target);
74
+ if (a === undefined || m === undefined || t === undefined) {
75
+ return false;
76
+ }
77
+ // `>>> 0` keeps the results unsigned; `&` alone would make 192.168.x.x negative
78
+ return (a & m) >>> 0 === (t & m) >>> 0;
79
+ }
80
+ /** `169.254.0.0/16`, the address an interface gives itself when no DHCP server answered. */
81
+ export function isLinkLocal(address) {
82
+ return address.startsWith('169.254.');
83
+ }
84
+ /** `127.0.0.0/8`. */
85
+ export function isLoopback(address) {
86
+ return /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(address);
87
+ }
88
+ /** How long a name lookup for the callback address may take before the first address is used. */
89
+ export const RESOLVE_TIMEOUT_MS = 3000;
90
+ /** The CCU host's IPv4 address, through the system resolver (`/etc/hosts`, mDNS where the OS has it). */
91
+ export async function resolveIPv4(host, lookup = dns.promises.lookup) {
92
+ if (ipv4ToNumber(host) !== undefined) {
93
+ return host;
94
+ }
95
+ if (host === '' || net.isIPv6(host)) {
96
+ return undefined;
97
+ }
98
+ try {
99
+ const result = await withTimeout(lookup(host, { family: 4 }), RESOLVE_TIMEOUT_MS, () => new Error('timeout'));
100
+ return result.address;
101
+ }
102
+ catch {
103
+ return undefined;
104
+ }
105
+ }
106
+ /**
107
+ * The local address a UDP socket gets when it is `connect()`ed to `address`: the source address of
108
+ * the route the operating system would take. `connect` on a datagram socket only sets the default
109
+ * peer - no packet is sent - so this works for a CCU behind a router or a VPN as well as for one in
110
+ * the same network.
111
+ */
112
+ export function routeSource(address, createSocket = dgram.createSocket) {
113
+ return new Promise((resolve) => {
114
+ let socket;
115
+ try {
116
+ socket = createSocket('udp4');
117
+ }
118
+ catch {
119
+ resolve(undefined);
120
+ return;
121
+ }
122
+ let settled = false;
123
+ const done = (result) => {
124
+ if (settled) {
125
+ return;
126
+ }
127
+ settled = true;
128
+ try {
129
+ socket.close();
130
+ }
131
+ catch {
132
+ // already closed
133
+ }
134
+ resolve(result);
135
+ };
136
+ socket.on('error', () => {
137
+ done(undefined);
138
+ });
139
+ try {
140
+ // the port does not matter, nothing is sent; 9 is "discard"
141
+ socket.connect(9, address, () => {
142
+ try {
143
+ done(socket.address().address);
144
+ }
145
+ catch {
146
+ done(undefined);
147
+ }
148
+ });
149
+ }
150
+ catch {
151
+ done(undefined);
152
+ }
153
+ });
154
+ }
155
+ /** The machine's own network, as the running host sees it. */
156
+ export function systemNetwork() {
157
+ return {
158
+ interfaces: () => localIPv4Interfaces(),
159
+ resolve: (host) => resolveIPv4(host),
160
+ route: (address) => routeSource(address),
161
+ };
162
+ }
163
+ /**
164
+ * A network made of a fixed address list, for a caller that injects `localAddresses` (the tests and
165
+ * the e2e hosts): no netmasks, no name lookup beyond an address literal, no route.
166
+ */
167
+ export function staticNetwork(addresses) {
168
+ return {
169
+ interfaces: () => addresses()
170
+ .filter((address) => !isLoopback(address))
171
+ .map((address) => ({ address })),
172
+ resolve: (host) => Promise.resolve(ipv4ToNumber(host) === undefined ? undefined : host),
173
+ route: () => Promise.resolve(undefined),
174
+ };
175
+ }
176
+ /**
177
+ * B-53 (#162, #165): the automatic callback address, and every address with whether it is in the
178
+ * CCU's network. Synchronous: `hostAddress` and `routed` are what {@link describeCallbackAddresses}
179
+ * found out, and `undefined` when nothing could be.
180
+ *
181
+ * The order: the CCU on the loopback (or `local`) is called back on the loopback; then the
182
+ * address in the CCU's network; then the route's source address; then the first address that is
183
+ * not link-local. A link-local address wins only as the CCU's own network, and the loopback is
184
+ * never chosen for a CCU elsewhere unless this machine has no other address at all.
185
+ */
186
+ export function pickCallbackAddress(host, hostAddress, interfaces, routed, local = false) {
187
+ const matches = (entry) => hostAddress !== undefined && entry.netmask !== undefined && inSubnet(entry.address, entry.netmask, hostAddress);
188
+ const ccuOnLoopback = local || (hostAddress !== undefined && isLoopback(hostAddress));
189
+ const addresses = interfaces.map((entry) => ({
190
+ address: entry.address,
191
+ inSubnet: matches(entry),
192
+ ...(isLinkLocal(entry.address) ? { linkLocal: true } : {}),
193
+ }));
194
+ addresses.push({ address: LOOPBACK, inSubnet: ccuOnLoopback });
195
+ const choose = () => {
196
+ if (ccuOnLoopback) {
197
+ return { address: LOOPBACK, reason: 'loopback' };
198
+ }
199
+ const subnet = interfaces.find((entry) => matches(entry));
200
+ if (subnet !== undefined) {
201
+ return { address: subnet.address, reason: 'subnet' };
202
+ }
203
+ if (routed !== undefined && !isLinkLocal(routed) && interfaces.some((entry) => entry.address === routed)) {
204
+ return { address: routed, reason: 'route' };
205
+ }
206
+ const first = interfaces.find((entry) => !isLinkLocal(entry.address));
207
+ return { address: first?.address ?? LOOPBACK, reason: 'first' };
208
+ };
209
+ return {
210
+ host,
211
+ ...(hostAddress === undefined ? {} : { hostAddress }),
212
+ auto: choose(),
213
+ addresses,
214
+ };
215
+ }
216
+ /**
217
+ * B-53: {@link pickCallbackAddress} with the facts looked up - the CCU's name resolved, and the route
218
+ * asked for only when no address shares the CCU's network. Never rejects.
219
+ */
220
+ export async function describeCallbackAddresses(host, network, local = false) {
221
+ const interfaces = network.interfaces();
222
+ if (local) {
223
+ return pickCallbackAddress(host, undefined, interfaces, undefined, true);
224
+ }
225
+ const hostAddress = host === '' ? undefined : await network.resolve(host);
226
+ const inNetwork = hostAddress !== undefined &&
227
+ (isLoopback(hostAddress) ||
228
+ interfaces.some((entry) => entry.netmask !== undefined && inSubnet(entry.address, entry.netmask, hostAddress)));
229
+ const routed = hostAddress === undefined || inNetwork ? undefined : await network.route(hostAddress);
230
+ return pickCallbackAddress(host, hostAddress, interfaces, routed);
231
+ }
232
+ /** Whether a TCP connection to `host:port` is accepted, refused, or not answered in time. Never throws. */
233
+ export function probePortState(host, port, options = {}) {
26
234
  const timeoutMs = options.timeoutMs ?? 2000;
27
235
  const connect = options.connect ?? net.connect;
28
236
  return new Promise((resolve) => {
29
237
  let settled = false;
30
- const done = (open) => {
238
+ const done = (result) => {
31
239
  if (settled) {
32
240
  return;
33
241
  }
34
242
  settled = true;
35
243
  socket.destroy();
36
- resolve(open);
244
+ resolve(result);
37
245
  };
38
246
  const socket = connect({ host, port, timeout: timeoutMs }, () => {
39
- done(true);
247
+ done('open');
40
248
  });
41
- socket.on('error', () => {
42
- done(false);
249
+ socket.on('error', (error) => {
250
+ // node's happy-eyeballs connect aggregates the per-address failures in `errors`
251
+ const codes = [error.code, ...(error.errors ?? []).map((entry) => entry.code)];
252
+ done(codes.includes('ECONNREFUSED') ? 'refused' : 'unreachable');
43
253
  });
44
254
  socket.on('timeout', () => {
45
- done(false);
255
+ done('unreachable');
46
256
  });
47
257
  });
48
258
  }
259
+ /** True when a TCP connection to `host:port` is accepted within the timeout. Never throws. */
260
+ export async function probePort(host, port, options = {}) {
261
+ return (await probePortState(host, port, options)) === 'open';
262
+ }
49
263
  /** Resolves after `ms`; the timer never keeps the process alive. */
50
264
  export function delay(ms) {
51
265
  return new Promise((resolve) => {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homematic-manager/backend",
3
- "version": "3.0.0-beta.2",
3
+ "version": "3.0.0-beta.21",
4
4
  "type": "module",
5
5
  "description": "Homematic Manager backend: XML-RPC/BIN-RPC clients and callback servers, caches, optional ReGa",
6
6
  "license": "AGPL-3.0-or-later",