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
@@ -7,13 +7,10 @@
7
7
  * as events and sit in every device's `<device>:0` VALUES paramset - the same thing 2.x does in
8
8
  * main.js (:404-432 for the events, :800-822 for the paramset read).
9
9
  */
10
+ import type { BidcosInterfaceInfo } from '../api/types.js';
10
11
  import type { Paramset, ParamsetValue } from '../rpc/values.js';
11
12
  /** What an interface process sends instead of a value it does not have. */
12
13
  export declare const RSSI_UNKNOWN = 65536;
13
- /** The thresholds of the 2.x `rssiColor()` (homematic-manager.js:4649). */
14
- export declare const RSSI_BAD = -120;
15
- export declare const RSSI_MEDIUM = -100;
16
- export declare const RSSI_GOOD = -20;
17
14
  /** What one partner measures of another. `undefined` where the interface reported 65536. */
18
15
  export interface RssiPair {
19
16
  /** What this device receives from the peer, in dBm. */
@@ -25,22 +22,84 @@ export interface RssiPair {
25
22
  export type RawRssiInfo = Readonly<Record<string, Readonly<Record<string, readonly unknown[]>>>>;
26
23
  /** device or interface address -> peer address -> the pair. */
27
24
  export type RssiMatrix = Record<string, Record<string, RssiPair>>;
28
- /** How good a signal is, for the colour of the grid cell. */
29
- export type RssiClass = 'unknown' | 'bad' | 'medium' | 'good';
30
- /** One value from an `rssiInfo` answer: a number, unless it is the "unknown" placeholder. */
25
+ /** A step of the RSSI scale, 1 the strongest signal, 8 the weakest. */
26
+ export type RssiStep = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
27
+ /** How many of the pill's four signal bars a step lights. */
28
+ export type RssiBars = 0 | 1 | 2 | 3 | 4;
29
+ /** One band of the RSSI scale. */
30
+ export interface RssiBand {
31
+ readonly step: RssiStep;
32
+ /** The lowest reading that still belongs to the band, in dBm; `-Infinity` for the last one. */
33
+ readonly min: number;
34
+ readonly bars: RssiBars;
35
+ /** What the band means, in English - the key the UI translates it by. */
36
+ readonly label: string;
37
+ }
38
+ /**
39
+ * The RSSI scale of the Funk tab (#161): eight bands, 10 dB apart from -30 to -90 dBm.
40
+ *
41
+ * Until 3.0.0-beta.17 there were three classes from the 2.x colour gradient - good from -20 dBm,
42
+ * bad below -100 - and nearly every real link, which lies between -40 and -90, was the same yellow
43
+ * "medium". Issue #161 (@Baxxy13) asked for a finer scale closer to the OpenCCU WebUI, which colours
44
+ * green above -70, yellow down to -90 and red below; both of its edges are edges here. The maintainer
45
+ * posted three eight-step palettes, and on 2026-09-15 he, @Baxxy13 and @Herbert-Testmann settled on
46
+ * "Variante 3" with signal bars in the pill (arrangement B), so that the step reads without its
47
+ * colour too. The fills are theme tokens (`--hmm-rssi-<step>`); this table is the part that is not
48
+ * a colour.
49
+ *
50
+ * A reading belongs to the first band whose lower edge it reaches: -30 is step 1, -40 is step 2.
51
+ */
52
+ export declare const RSSI_BANDS: readonly RssiBand[];
53
+ /**
54
+ * One RSSI value as the CCU hands it out, as dBm - or `undefined` where it is not a measurement.
55
+ *
56
+ * Issue #154: a receive level in dBm is always negative, and yet `rssiInfo` and the `RSSI_*`
57
+ * datapoints produce positive numbers (`37`), numbers far below the noise floor (`-208`) and
58
+ * placeholders (`65536`, `128`). Three things are mixed in there:
59
+ *
60
+ * - **`65536`** is eQ-3's documented "no information" (the WebUI's `rssiinfo.tcl`: *"Der Wert 65536
61
+ * bedeutet, dass keine Informationen vorliegen"*), and `-65536`, `±256`, `0` and `±1` are used
62
+ * the same way by one component or another - `0`/`1` meaning nothing was received in that
63
+ * direction since the last start.
64
+ * - **`128` / `-128`** (`0x80`) is the radio chip's "no RSSI available", not a level.
65
+ * - The rest is a **sign that was lost on the way**: ReGaHss creates the maintenance datapoints as
66
+ * an unsigned byte (`ivtByte`) although the paramset says `INTEGER`, so values arrive with an
67
+ * offset of 256 or with the sign dropped. `130…255` is `value - 256`, `-255…-130` is
68
+ * `-value - 256` (which is what turns the maintainer's `-208` into a perfectly ordinary
69
+ * -48 dBm), and a bare positive `2…126` is the same level without its minus.
70
+ *
71
+ * The mapping is the one Home Assistant's `aiohomematic` applies (`model/generic/sensor.py`,
72
+ * `_fix_rssi`); OpenCCU's WebUI does the `- 256` half in
73
+ * `0144-WebUI-ControlForMaintenanceChannel` and hm2mqtt.js does it for the ReGa cache. The
74
+ * inversion of a small positive value is the one step no eQ-3 source confirms - it is
75
+ * `aiohomematic`'s reading, and it is what makes a `37` in the grid the -37 dBm it plainly is.
76
+ */
31
77
  export declare function normaliseRssiValue(value: unknown): number | undefined;
32
78
  /** Turns an `rssiInfo` answer into the matrix, dropping the 65536 placeholders. */
33
79
  export declare function normaliseRssiInfo(raw: RawRssiInfo): RssiMatrix;
34
80
  /**
35
- * How good a signal is. -20 dBm and better is good, -100 and worse is bad, in between is medium;
36
- * an absent value is unknown. The bounds come from the 2.x colour gradient.
81
+ * The band of {@link RSSI_BANDS} a reading falls into, or `undefined` where it is not a measurement
82
+ * at all (65536 and the other placeholders of #154) - the grid shows a faint dash for those.
37
83
  */
38
- export declare function rssiClass(dbm: number | undefined): RssiClass;
84
+ export declare function rssiBand(dbm: number | undefined): RssiBand | undefined;
85
+ /** The two fields of a `listBidcosInterfaces` entry that name it. */
86
+ export type BidcosInterfaceName = Pick<BidcosInterfaceInfo, 'ADDRESS' | 'DESCRIPTION'>;
39
87
  /**
40
- * The red/green gradient of the 2.x grid, kept so the radio tab looks the same (D-3).
41
- * `undefined` for a value there is none for - the cell stays empty, as it did.
88
+ * How a BidCos interface is named for a person: the `DESCRIPTION` the CCU carries for it - the
89
+ * name a LAN gateway was given in the WebUI, `CCU2-Coprocessor` for the built-in module - and the
90
+ * serial when there is none. The 2.x Funk grid put the serial over the interface's columns with
91
+ * the description in small print under it; a gateway without a description shows its serial alone.
42
92
  */
43
- export declare function rssiColor(dbm: number | undefined): string | undefined;
93
+ export declare function bidcosInterfaceLabel(gateway: BidcosInterfaceName): string;
94
+ /**
95
+ * The receiver a BidCos-RF device is routed through, for the device grid (BUGS.md B-2): the
96
+ * label of the gateway whose serial the description's `INTERFACE` names, the serial itself when
97
+ * `listBidcosInterfaces` does not know it or has not been read yet, and nothing for a device
98
+ * without one - HmIP and Wired have no receivers.
99
+ */
100
+ export declare function receiverLabel(device: {
101
+ readonly INTERFACE?: string | undefined;
102
+ }, gateways: readonly BidcosInterfaceName[]): string;
44
103
  /** The HmIP datapoints the matrix is built from. */
45
104
  export declare const RSSI_DATAPOINTS: readonly string[];
46
105
  export interface RssiStoreOptions {
@@ -88,4 +147,57 @@ export declare class RssiStore {
88
147
  readonly tx?: number;
89
148
  } | undefined;
90
149
  }
150
+ /**
151
+ * Why a device is, or is not, proposed for another receiver (#69).
152
+ *
153
+ * - `switch`: another interface receives the device better than the configured one by at least
154
+ * the margin.
155
+ * - `marginal`: another interface receives it better, but by less than the margin - one sample
156
+ * apart, which `rssiInfo` values are between two reads.
157
+ * - `unheard`: the configured receiver has no measurement of the device at all while another
158
+ * interface has one; that can mean the device never reaches its receiver, or that rfd has not
159
+ * heard it since a restart.
160
+ * - `keep`: the configured receiver hears it best, or at least as well as any other.
161
+ * - `unmeasured`: no interface has a measurement.
162
+ * - `roaming`: the device roams, so the CCU picks its receiver itself; nothing to assign.
163
+ */
164
+ export type ReceiverVerdict = 'switch' | 'marginal' | 'unheard' | 'keep' | 'unmeasured' | 'roaming';
165
+ /** One row of the "assign the best receiver" proposal (#69). */
166
+ export interface ReceiverProposal {
167
+ readonly address: string;
168
+ /** The serial of the receiver the device is configured for. */
169
+ readonly configured: string;
170
+ /** What the configured receiver receives from the device, in dBm. */
171
+ readonly configuredTx: number | undefined;
172
+ /** The interface that receives the device best; `undefined` without a measurement. */
173
+ readonly best: string | undefined;
174
+ readonly bestTx: number | undefined;
175
+ /** `bestTx - configuredTx` where both are known. */
176
+ readonly gain: number | undefined;
177
+ readonly verdict: ReceiverVerdict;
178
+ }
179
+ /**
180
+ * The margin a better interface has to clear before a switch is proposed, in dB. The values of
181
+ * `rssiInfo` are the last measurement rfd holds, and two reads of the same link differ by a few dB
182
+ * without anything having moved; 6 dB is roughly a quartering of the received power and clears
183
+ * that noise.
184
+ */
185
+ export declare const DEFAULT_RECEIVER_MARGIN_DB = 6;
186
+ /** The fields of a device description the proposal reads. */
187
+ export interface ReceiverCandidate {
188
+ readonly ADDRESS: string;
189
+ readonly PARENT?: string | undefined;
190
+ readonly INTERFACE?: string | undefined;
191
+ readonly ROAMING?: boolean | number | undefined;
192
+ }
193
+ /**
194
+ * The dry run behind issue #69: for every BidCos-RF device with a receiver, which interface hears
195
+ * it best and whether that is worth a `setBidcosInterface`. Nothing is written here - the list
196
+ * is what the user confirms, device by device, before anything is. Channels and devices without
197
+ * an `INTERFACE` (HmIP, Wired, groups) are not in the answer at all. Sorted by verdict in the
198
+ * order of {@link ReceiverVerdict}, then by gain, then by address.
199
+ */
200
+ export declare function proposeReceivers(devices: readonly ReceiverCandidate[], interfaceAddresses: readonly string[], store: Pick<RssiStore, 'get' | 'bestInterfaceFor'>, options?: {
201
+ readonly marginDb?: number | undefined;
202
+ }): ReceiverProposal[];
91
203
  //# sourceMappingURL=index.d.ts.map
@@ -9,16 +9,72 @@
9
9
  */
10
10
  /** What an interface process sends instead of a value it does not have. */
11
11
  export const RSSI_UNKNOWN = 65536;
12
- /** The thresholds of the 2.x `rssiColor()` (homematic-manager.js:4649). */
13
- export const RSSI_BAD = -120;
14
- export const RSSI_MEDIUM = -100;
15
- export const RSSI_GOOD = -20;
16
- /** One value from an `rssiInfo` answer: a number, unless it is the "unknown" placeholder. */
12
+ /**
13
+ * The RSSI scale of the Funk tab (#161): eight bands, 10 dB apart from -30 to -90 dBm.
14
+ *
15
+ * Until 3.0.0-beta.17 there were three classes from the 2.x colour gradient - good from -20 dBm,
16
+ * bad below -100 - and nearly every real link, which lies between -40 and -90, was the same yellow
17
+ * "medium". Issue #161 (@Baxxy13) asked for a finer scale closer to the OpenCCU WebUI, which colours
18
+ * green above -70, yellow down to -90 and red below; both of its edges are edges here. The maintainer
19
+ * posted three eight-step palettes, and on 2026-09-15 he, @Baxxy13 and @Herbert-Testmann settled on
20
+ * "Variante 3" with signal bars in the pill (arrangement B), so that the step reads without its
21
+ * colour too. The fills are theme tokens (`--hmm-rssi-<step>`); this table is the part that is not
22
+ * a colour.
23
+ *
24
+ * A reading belongs to the first band whose lower edge it reaches: -30 is step 1, -40 is step 2.
25
+ */
26
+ export const RSSI_BANDS = [
27
+ { step: 1, min: -30, bars: 4, label: 'Very good (maximum)' },
28
+ { step: 2, min: -40, bars: 4, label: 'Very good' },
29
+ { step: 3, min: -50, bars: 4, label: 'Good' },
30
+ { step: 4, min: -60, bars: 3, label: 'Good (normal operation)' },
31
+ { step: 5, min: -70, bars: 3, label: 'Sufficient' },
32
+ { step: 6, min: -80, bars: 2, label: 'Sufficient to weak' },
33
+ { step: 7, min: -90, bars: 1, label: 'Poor' },
34
+ { step: 8, min: Number.NEGATIVE_INFINITY, bars: 0, label: 'Critical' },
35
+ ];
36
+ /**
37
+ * One RSSI value as the CCU hands it out, as dBm - or `undefined` where it is not a measurement.
38
+ *
39
+ * Issue #154: a receive level in dBm is always negative, and yet `rssiInfo` and the `RSSI_*`
40
+ * datapoints produce positive numbers (`37`), numbers far below the noise floor (`-208`) and
41
+ * placeholders (`65536`, `128`). Three things are mixed in there:
42
+ *
43
+ * - **`65536`** is eQ-3's documented "no information" (the WebUI's `rssiinfo.tcl`: *"Der Wert 65536
44
+ * bedeutet, dass keine Informationen vorliegen"*), and `-65536`, `±256`, `0` and `±1` are used
45
+ * the same way by one component or another - `0`/`1` meaning nothing was received in that
46
+ * direction since the last start.
47
+ * - **`128` / `-128`** (`0x80`) is the radio chip's "no RSSI available", not a level.
48
+ * - The rest is a **sign that was lost on the way**: ReGaHss creates the maintenance datapoints as
49
+ * an unsigned byte (`ivtByte`) although the paramset says `INTEGER`, so values arrive with an
50
+ * offset of 256 or with the sign dropped. `130…255` is `value - 256`, `-255…-130` is
51
+ * `-value - 256` (which is what turns the maintainer's `-208` into a perfectly ordinary
52
+ * -48 dBm), and a bare positive `2…126` is the same level without its minus.
53
+ *
54
+ * The mapping is the one Home Assistant's `aiohomematic` applies (`model/generic/sensor.py`,
55
+ * `_fix_rssi`); OpenCCU's WebUI does the `- 256` half in
56
+ * `0144-WebUI-ControlForMaintenanceChannel` and hm2mqtt.js does it for the ReGa cache. The
57
+ * inversion of a small positive value is the one step no eQ-3 source confirms - it is
58
+ * `aiohomematic`'s reading, and it is what makes a `37` in the grid the -37 dBm it plainly is.
59
+ */
17
60
  export function normaliseRssiValue(value) {
18
- if (typeof value !== 'number' || !Number.isFinite(value) || value === RSSI_UNKNOWN) {
61
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
19
62
  return undefined;
20
63
  }
21
- return value;
64
+ if (value > -127 && value < 0) {
65
+ return value; // already a dBm value
66
+ }
67
+ if (value > 1 && value < 127) {
68
+ return -value; // the minus was lost
69
+ }
70
+ if (value > -256 && value < -129) {
71
+ return -value - 256; // -208 -> -48
72
+ }
73
+ if (value > 129 && value < 256) {
74
+ return value - 256; // 218 -> -38
75
+ }
76
+ // 0, ±1, ±128, ±129, ±256, ±65536 and anything outside: not a measurement
77
+ return undefined;
22
78
  }
23
79
  /** Turns an `rssiInfo` answer into the matrix, dropping the 65536 placeholders. */
24
80
  export function normaliseRssiInfo(raw) {
@@ -33,31 +89,39 @@ export function normaliseRssiInfo(raw) {
33
89
  return matrix;
34
90
  }
35
91
  /**
36
- * How good a signal is. -20 dBm and better is good, -100 and worse is bad, in between is medium;
37
- * an absent value is unknown. The bounds come from the 2.x colour gradient.
92
+ * The band of {@link RSSI_BANDS} a reading falls into, or `undefined` where it is not a measurement
93
+ * at all (65536 and the other placeholders of #154) - the grid shows a faint dash for those.
38
94
  */
39
- export function rssiClass(dbm) {
95
+ export function rssiBand(dbm) {
40
96
  const value = normaliseRssiValue(dbm);
41
97
  if (value === undefined) {
42
- return 'unknown';
43
- }
44
- if (value >= RSSI_GOOD) {
45
- return 'good';
98
+ return undefined;
46
99
  }
47
- return value >= RSSI_MEDIUM ? 'medium' : 'bad';
100
+ return RSSI_BANDS.find((band) => value >= band.min);
48
101
  }
49
102
  /**
50
- * The red/green gradient of the 2.x grid, kept so the radio tab looks the same (D-3).
51
- * `undefined` for a value there is none for - the cell stays empty, as it did.
103
+ * How a BidCos interface is named for a person: the `DESCRIPTION` the CCU carries for it - the
104
+ * name a LAN gateway was given in the WebUI, `CCU2-Coprocessor` for the built-in module - and the
105
+ * serial when there is none. The 2.x Funk grid put the serial over the interface's columns with
106
+ * the description in small print under it; a gateway without a description shows its serial alone.
52
107
  */
53
- export function rssiColor(dbm) {
54
- const value = normaliseRssiValue(dbm);
55
- if (value === undefined) {
56
- return undefined;
108
+ export function bidcosInterfaceLabel(gateway) {
109
+ const description = gateway.DESCRIPTION?.trim() ?? '';
110
+ return description === '' ? gateway.ADDRESS : description;
111
+ }
112
+ /**
113
+ * The receiver a BidCos-RF device is routed through, for the device grid (BUGS.md B-2): the
114
+ * label of the gateway whose serial the description's `INTERFACE` names, the serial itself when
115
+ * `listBidcosInterfaces` does not know it or has not been read yet, and nothing for a device
116
+ * without one - HmIP and Wired have no receivers.
117
+ */
118
+ export function receiverLabel(device, gateways) {
119
+ const serial = device.INTERFACE ?? '';
120
+ if (serial === '') {
121
+ return '';
57
122
  }
58
- const red = channel((256 * (value - RSSI_GOOD)) / (RSSI_MEDIUM - RSSI_GOOD));
59
- const green = channel((256 * (value - RSSI_BAD)) / (RSSI_MEDIUM - RSSI_BAD));
60
- return `#${hex(red)}${hex(green)}00`;
123
+ const gateway = gateways.find((candidate) => candidate.ADDRESS === serial);
124
+ return gateway ? bidcosInterfaceLabel(gateway) : serial;
61
125
  }
62
126
  /** The HmIP datapoints the matrix is built from. */
63
127
  export const RSSI_DATAPOINTS = ['RSSI_DEVICE', 'RSSI_PEER'];
@@ -166,10 +230,63 @@ function pair(rx, tx) {
166
230
  }
167
231
  return result;
168
232
  }
169
- function channel(value) {
170
- return Math.min(255, Math.max(0, Math.round(value)));
171
- }
172
- function hex(value) {
173
- return `0${value.toString(16)}`.slice(-2);
233
+ /**
234
+ * The margin a better interface has to clear before a switch is proposed, in dB. The values of
235
+ * `rssiInfo` are the last measurement rfd holds, and two reads of the same link differ by a few dB
236
+ * without anything having moved; 6 dB is roughly a quartering of the received power and clears
237
+ * that noise.
238
+ */
239
+ export const DEFAULT_RECEIVER_MARGIN_DB = 6;
240
+ const VERDICT_ORDER = ['switch', 'marginal', 'unheard', 'keep', 'unmeasured', 'roaming'];
241
+ /**
242
+ * The dry run behind issue #69: for every BidCos-RF device with a receiver, which interface hears
243
+ * it best and whether that is worth a `setBidcosInterface`. Nothing is written here - the list
244
+ * is what the user confirms, device by device, before anything is. Channels and devices without
245
+ * an `INTERFACE` (HmIP, Wired, groups) are not in the answer at all. Sorted by verdict in the
246
+ * order of {@link ReceiverVerdict}, then by gain, then by address.
247
+ */
248
+ export function proposeReceivers(devices, interfaceAddresses, store, options = {}) {
249
+ const margin = Math.max(0, options.marginDb ?? DEFAULT_RECEIVER_MARGIN_DB);
250
+ const proposals = [];
251
+ for (const device of devices) {
252
+ const configured = device.INTERFACE ?? '';
253
+ if (configured === '' || (device.PARENT ?? '') !== '') {
254
+ continue;
255
+ }
256
+ const configuredTx = store.get(device.ADDRESS, configured)?.tx;
257
+ const best = store.bestInterfaceFor(device.ADDRESS, interfaceAddresses);
258
+ const gain = best?.tx !== undefined && configuredTx !== undefined ? best.tx - configuredTx : undefined;
259
+ let verdict;
260
+ if (device.ROAMING === true || device.ROAMING === 1) {
261
+ verdict = 'roaming';
262
+ }
263
+ else if (best === undefined) {
264
+ verdict = 'unmeasured';
265
+ }
266
+ else if (best.address === configured) {
267
+ verdict = 'keep';
268
+ }
269
+ else if (gain === undefined) {
270
+ verdict = 'unheard';
271
+ }
272
+ else if (gain <= 0) {
273
+ verdict = 'keep';
274
+ }
275
+ else {
276
+ verdict = gain >= margin ? 'switch' : 'marginal';
277
+ }
278
+ proposals.push({
279
+ address: device.ADDRESS,
280
+ configured,
281
+ configuredTx,
282
+ best: best?.address,
283
+ bestTx: best?.tx,
284
+ gain,
285
+ verdict,
286
+ });
287
+ }
288
+ return proposals.sort((a, b) => VERDICT_ORDER.indexOf(a.verdict) - VERDICT_ORDER.indexOf(b.verdict) ||
289
+ (b.gain ?? Number.NEGATIVE_INFINITY) - (a.gain ?? Number.NEGATIVE_INFINITY) ||
290
+ a.address.localeCompare(b.address));
174
291
  }
175
292
  //# sourceMappingURL=index.js.map
@@ -10,11 +10,23 @@
10
10
  * The store below is that logic without the globals: a value that is truthy sets the message, a
11
11
  * falsy one clears it, and clearing the last message of a channel drops the channel.
12
12
  */
13
+ import type { ParameterDescription } from '../paramset/description.js';
13
14
  import type { Paramset, ParamsetValue } from '../rpc/values.js';
14
15
  /**
15
16
  * The datapoints that are service messages. `ERROR*` is a prefix rule: devices carry `ERROR`,
16
17
  * `ERROR_CODE`, `ERROR_OVERHEAT`, `ERROR_JAMMED` and a dozen more, all of them meaning the same
17
18
  * thing for the list.
19
+ *
20
+ * `FAULT_REPORTING` (BUGS.md B-24, #150) is the ENUM of the HM-CC-RT-DN's
21
+ * `CLIMATECONTROL_RT_TRANSCEIVER` channel - not on `:0` and not named `ERROR*`, so it was dropped
22
+ * and the WebUI's "Kommunikationsstörung" never reached the list. Its index `0` is `NO_FAULT`,
23
+ * which is falsy, so the store's "falsy clears" rule needs no exception for it. It is not
24
+ * acknowledgeable: its `OPERATIONS` are 5 (read, event), and the WebUI's service-message page
25
+ * enables its confirm button only for a datapoint with the write bit.
26
+ *
27
+ * Only the datapoints named here count, not every one with the description's SERVICE flag: that
28
+ * would take the next device-specific one automatically, but it needs a description per channel
29
+ * before a message can be listed, and it is a broader change than this bug.
18
30
  */
19
31
  export declare const SERVICE_MESSAGE_DATAPOINTS: readonly string[];
20
32
  /** Prefix of the device-specific error datapoints. */
@@ -38,6 +50,14 @@ export declare function isAcknowledgeable(datapoint: string): boolean;
38
50
  * measurement, not a message (main.js:406 - "Not a Service Message!").
39
51
  */
40
52
  export declare function countsAsServiceMessage(datapoint: string, value: ParamsetValue): boolean;
53
+ /**
54
+ * The `VALUE_LIST` name of an ENUM service message's value: `COMMUNICATION_ERROR` for a
55
+ * `FAULT_REPORTING` of `4` (B-24). BidCos sends the index, HmIP may send the name itself; either
56
+ * way the answer is the name, which is what the translations are keyed by
57
+ * (`CLIMATECONTROL_RT_TRANSCEIVER|FAULT_REPORTING|COMMUNICATION_ERROR`). `undefined` when the
58
+ * parameter is not an ENUM, has no such entry, or the entry is one of the empty gaps of a list.
59
+ */
60
+ export declare function serviceMessageValueName(parameter: ParameterDescription | undefined, value: unknown): string | undefined;
41
61
  /**
42
62
  * One stored service message. The shape that crosses the transport is `ServiceMessage` in
43
63
  * `api/types.ts`; this is what the store keeps, with the device and the acknowledgeable flag
@@ -77,7 +97,7 @@ export declare class ServiceMessageStore {
77
97
  * Applies one datapoint. Returns true when something changed, so a caller can decide whether
78
98
  * to notify the UI. A datapoint that is not a service message is ignored.
79
99
  */
80
- apply(interfaceName: string, address: string, datapoint: string, value: ParamsetValue): boolean;
100
+ apply(interfaceName: string, address: string, datapoint: string, value: ParamsetValue, timestamp?: number): boolean;
81
101
  /** Applies an `event` callback; the same thing, named for the call site. */
82
102
  applyEvent(interfaceName: string, address: string, datapoint: string, value: ParamsetValue): boolean;
83
103
  /**
@@ -85,7 +105,13 @@ export declare class ServiceMessageStore {
85
105
  * start-up: every service-message datapoint in it is applied, everything else ignored.
86
106
  */
87
107
  applyParamset(interfaceName: string, address: string, values: Paramset): boolean;
88
- /** Replaces everything an interface has with a fresh `getServiceMessages` answer. */
108
+ /**
109
+ * Replaces everything an interface has with a fresh `getServiceMessages` answer.
110
+ *
111
+ * Issue #150: a message that is still there with the same value keeps the time it was first
112
+ * seen. Rebuilding the map from scratch stamped every row with "now", so pressing Refresh
113
+ * moved the "Since" column of six-day-old messages to this minute.
114
+ */
89
115
  replaceInterface(interfaceName: string, tuples: readonly ServiceMessageTuple[]): void;
90
116
  /** Removes one message. Returns true when there was one. */
91
117
  clear(interfaceName: string, address: string, datapoint: string): boolean;
@@ -15,10 +15,22 @@ import { deviceAddress } from '../address/address.js';
15
15
  * The datapoints that are service messages. `ERROR*` is a prefix rule: devices carry `ERROR`,
16
16
  * `ERROR_CODE`, `ERROR_OVERHEAT`, `ERROR_JAMMED` and a dozen more, all of them meaning the same
17
17
  * thing for the list.
18
+ *
19
+ * `FAULT_REPORTING` (BUGS.md B-24, #150) is the ENUM of the HM-CC-RT-DN's
20
+ * `CLIMATECONTROL_RT_TRANSCEIVER` channel - not on `:0` and not named `ERROR*`, so it was dropped
21
+ * and the WebUI's "Kommunikationsstörung" never reached the list. Its index `0` is `NO_FAULT`,
22
+ * which is falsy, so the store's "falsy clears" rule needs no exception for it. It is not
23
+ * acknowledgeable: its `OPERATIONS` are 5 (read, event), and the WebUI's service-message page
24
+ * enables its confirm button only for a datapoint with the write bit.
25
+ *
26
+ * Only the datapoints named here count, not every one with the description's SERVICE flag: that
27
+ * would take the next device-specific one automatically, but it needs a description per channel
28
+ * before a message can be listed, and it is a broader change than this bug.
18
29
  */
19
30
  export const SERVICE_MESSAGE_DATAPOINTS = [
20
31
  'CONFIG_PENDING',
21
32
  'DUTY_CYCLE',
33
+ 'FAULT_REPORTING',
22
34
  'LOWBAT',
23
35
  'LOW_BAT',
24
36
  'SABOTAGE',
@@ -56,6 +68,21 @@ export function countsAsServiceMessage(datapoint, value) {
56
68
  }
57
69
  return datapoint !== 'DUTY_CYCLE' || typeof value === 'boolean';
58
70
  }
71
+ /**
72
+ * The `VALUE_LIST` name of an ENUM service message's value: `COMMUNICATION_ERROR` for a
73
+ * `FAULT_REPORTING` of `4` (B-24). BidCos sends the index, HmIP may send the name itself; either
74
+ * way the answer is the name, which is what the translations are keyed by
75
+ * (`CLIMATECONTROL_RT_TRANSCEIVER|FAULT_REPORTING|COMMUNICATION_ERROR`). `undefined` when the
76
+ * parameter is not an ENUM, has no such entry, or the entry is one of the empty gaps of a list.
77
+ */
78
+ export function serviceMessageValueName(parameter, value) {
79
+ const list = parameter?.TYPE === 'ENUM' ? parameter.VALUE_LIST : undefined;
80
+ if (list === undefined) {
81
+ return undefined;
82
+ }
83
+ const name = typeof value === 'number' ? list[value] : typeof value === 'string' && list.includes(value) ? value : '';
84
+ return name === undefined || name === '' ? undefined : name;
85
+ }
59
86
  /**
60
87
  * The current service messages of every interface.
61
88
  *
@@ -83,12 +110,12 @@ export class ServiceMessageStore {
83
110
  * Applies one datapoint. Returns true when something changed, so a caller can decide whether
84
111
  * to notify the UI. A datapoint that is not a service message is ignored.
85
112
  */
86
- apply(interfaceName, address, datapoint, value) {
113
+ apply(interfaceName, address, datapoint, value, timestamp) {
87
114
  if (!countsAsServiceMessage(datapoint, value)) {
88
115
  return false;
89
116
  }
90
117
  return value
91
- ? this.#set(interfaceName, address, datapoint, value)
118
+ ? this.#set(interfaceName, address, datapoint, value, timestamp)
92
119
  : this.clear(interfaceName, address, datapoint);
93
120
  }
94
121
  /** Applies an `event` callback; the same thing, named for the call site. */
@@ -106,11 +133,22 @@ export class ServiceMessageStore {
106
133
  }
107
134
  return changed;
108
135
  }
109
- /** Replaces everything an interface has with a fresh `getServiceMessages` answer. */
136
+ /**
137
+ * Replaces everything an interface has with a fresh `getServiceMessages` answer.
138
+ *
139
+ * Issue #150: a message that is still there with the same value keeps the time it was first
140
+ * seen. Rebuilding the map from scratch stamped every row with "now", so pressing Refresh
141
+ * moved the "Since" column of six-day-old messages to this minute.
142
+ */
110
143
  replaceInterface(interfaceName, tuples) {
144
+ const previous = new Map();
145
+ for (const record of this.forInterface(interfaceName)) {
146
+ previous.set(`${record.address}|${record.datapoint}`, record);
147
+ }
111
148
  this.#byInterface.delete(interfaceName);
112
149
  for (const [address, datapoint, value] of tuples) {
113
- this.apply(interfaceName, address, datapoint, value);
150
+ const kept = previous.get(`${address}|${datapoint}`);
151
+ this.apply(interfaceName, address, datapoint, value, kept?.value === value ? kept.timestamp : undefined);
114
152
  }
115
153
  }
116
154
  /** Removes one message. Returns true when there was one. */
@@ -155,7 +193,7 @@ export class ServiceMessageStore {
155
193
  toTuples(interfaceName) {
156
194
  return this.forInterface(interfaceName).map((message) => [message.address, message.datapoint, message.value]);
157
195
  }
158
- #set(interfaceName, address, datapoint, value) {
196
+ #set(interfaceName, address, datapoint, value, timestamp) {
159
197
  let channels = this.#byInterface.get(interfaceName);
160
198
  if (!channels) {
161
199
  channels = new Map();
@@ -177,7 +215,7 @@ export class ServiceMessageStore {
177
215
  datapoint,
178
216
  value,
179
217
  acknowledgeable: isAcknowledgeable(datapoint),
180
- timestamp: this.#now(),
218
+ timestamp: timestamp ?? this.#now(),
181
219
  });
182
220
  return true;
183
221
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@homematic-manager/core",
3
- "version": "3.0.0-beta.2",
3
+ "version": "3.0.0-beta.21",
4
4
  "type": "module",
5
5
  "description": "Pure domain logic of the Homematic Manager: no I/O, no DOM",
6
6
  "license": "AGPL-3.0-or-later",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "homematic-manager",
3
- "version": "3.0.0-beta.2",
3
+ "version": "3.0.0-beta.21",
4
4
  "type": "module",
5
5
  "description": "Configure and administer Homematic and HomematicIP devices - devices and channels, direct links, paramsets, RSSI, service messages, events and an RPC console - from a local HTTP/WebSocket server that also serves the web UI",
6
6
  "keywords": [
@@ -67,8 +67,8 @@
67
67
  "hm-simulator": "^1.0.0"
68
68
  },
69
69
  "dependencies": {
70
- "@homematic-manager/backend": "3.0.0-beta.2",
71
- "@homematic-manager/core": "3.0.0-beta.2",
70
+ "@homematic-manager/backend": "3.0.0-beta.21",
71
+ "@homematic-manager/core": "3.0.0-beta.21",
72
72
  "binrpc": "^4.2.0",
73
73
  "homematic-rega": "^2.0.0",
74
74
  "homematic-xmlrpc": "^2.0.0",