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.
- package/README.md +2 -1
- package/data/easymode-time-selectors.json +285 -0
- package/data/icons/106_hm-lc-sw1-dr.webp +0 -0
- package/data/icons/108_hm-rc-dis-h-x-eu.webp +0 -0
- package/data/icons/109_hm-lc-sw1-pl-ct.webp +0 -0
- package/data/icons/110_hm-es-pmsw1-dr.webp +0 -0
- package/data/icons/112_hmip-wrc2.webp +0 -0
- package/data/icons/113_hmip-psm-ch.webp +0 -0
- package/data/icons/113_hmip-psm-it.webp +0 -0
- package/data/icons/113_hmip-psm-pe.webp +0 -0
- package/data/icons/113_hmip-psm-uk.webp +0 -0
- package/data/icons/113_hmip-psm.webp +0 -0
- package/data/icons/114_hm-lc-dim1t-fm-lf_3.webp +0 -0
- package/data/icons/116_hm-rc-4-3_brc-h3.webp +0 -0
- package/data/icons/118_hmip-swdo.webp +0 -0
- package/data/icons/119_hmip-rc8.webp +0 -0
- package/data/icons/120_hmip-etrv.webp +0 -0
- package/data/icons/121_hmip-wth.webp +0 -0
- package/data/icons/123_oligo.smart.ip.hm.webp +0 -0
- package/data/icons/125_hmip-smi.webp +0 -0
- package/data/icons/130_hmip-srh.webp +0 -0
- package/data/icons/131_hmip-wrc6.webp +0 -0
- package/data/icons/132_hmip-smo.webp +0 -0
- package/data/icons/133_hmip-asir.webp +0 -0
- package/data/icons/134_hmip-fsm.webp +0 -0
- package/data/icons/135_hmip-fsm16.webp +0 -0
- package/data/icons/136_hmip-miob.webp +0 -0
- package/data/icons/137_hmip-fal-c6.webp +0 -0
- package/data/icons/138_hmip-fal-c10.webp +0 -0
- package/data/icons/140_alpha-ip-rgb.webp +0 -0
- package/data/icons/141_alpha-ip-rgba.webp +0 -0
- package/data/icons/144_hmip-wgc.webp +0 -0
- package/data/icons/145_hmip-froll_hmip-fbl.webp +0 -0
- package/data/icons/146_hmip-sth.webp +0 -0
- package/data/icons/147_hmip-sthd.webp +0 -0
- package/data/icons/148_hmip-stho.webp +0 -0
- package/data/icons/149_hmip-sam.webp +0 -0
- package/data/icons/151_hmip-pcbs-bat.webp +0 -0
- package/data/icons/152_hmip-swdo-i.webp +0 -0
- package/data/icons/153_hmip-spi.webp +0 -0
- package/data/icons/154_hmip-spdr.webp +0 -0
- package/data/icons/155_hmip-whs2.webp +0 -0
- package/data/icons/156_hmip-mod-oc8.webp +0 -0
- package/data/icons/158_hmip-etrv-uk.webp +0 -0
- package/data/icons/159_hmip-mod-rc8.webp +0 -0
- package/data/icons/160_hmipw-drs4.webp +0 -0
- package/data/icons/161_hmipw-drs8.webp +0 -0
- package/data/icons/162_hmipw-drap.webp +0 -0
- package/data/icons/163_hmipw-drbl4.webp +0 -0
- package/data/icons/164_hmipw-dri16.webp +0 -0
- package/data/icons/165_hmipw-fio6.webp +0 -0
- package/data/icons/166_hmipw-drd3.webp +0 -0
- package/data/icons/167_hmipw-dri32.webp +0 -0
- package/data/icons/168_hmip-smi55.webp +0 -0
- package/data/icons/169_hmip-swo-pr.webp +0 -0
- package/data/icons/170_hmip-swo-pl.webp +0 -0
- package/data/icons/171_hmip-swo-b.webp +0 -0
- package/data/icons/172_hmip-swd.webp +0 -0
- package/data/icons/173_hmip-bsl.webp +0 -0
- package/data/icons/174_hmip-slo.webp +0 -0
- package/data/icons/175_hmip-group-heating.webp +0 -0
- package/data/icons/177_hmip-dbb.webp +0 -0
- package/data/icons/178_hmip-etrv-b1.webp +0 -0
- package/data/icons/179_hmip-swdm-b2.webp +0 -0
- package/data/icons/180_hmip-etrv-b.webp +0 -0
- package/data/icons/181_hmip-swdm.webp +0 -0
- package/data/icons/182_hmip-fci1.webp +0 -0
- package/data/icons/183_hmip-mod-tm.webp +0 -0
- package/data/icons/184_hmip-pcbs2.webp +0 -0
- package/data/icons/185_hmip-FCI6.webp +0 -0
- package/data/icons/186_hmip-mp3p.webp +0 -0
- package/data/icons/187_hmip-rcb1.webp +0 -0
- package/data/icons/188_hmip-etrv-c.webp +0 -0
- package/data/icons/190_hmip-sci.webp +0 -0
- package/data/icons/191_hmip-mod-ho.webp +0 -0
- package/data/icons/192_hmip-asir-o.webp +0 -0
- package/data/icons/193_hmip-wt.webp +0 -0
- package/data/icons/194_hmip-wrcd.webp +0 -0
- package/data/icons/195_hmipw-smi55.webp +0 -0
- package/data/icons/196_hmip-ASIR-2.webp +0 -0
- package/data/icons/197_hmip-swdo-pl.webp +0 -0
- package/data/icons/198_hmip-falmot-c12.webp +0 -0
- package/data/icons/199_hmip-mio16-pcb.webp +0 -0
- package/data/icons/200_hmip-wth-b.webp +0 -0
- package/data/icons/201_hmip-stv.webp +0 -0
- package/data/icons/202_hmip-wrcr.webp +0 -0
- package/data/icons/203_hmip-fsi16.webp +0 -0
- package/data/icons/204_hmip-drdi3.webp +0 -0
- package/data/icons/205_hmip-drsi4.webp +0 -0
- package/data/icons/206_hmip-drbli4.webp +0 -0
- package/data/icons/207_hmip-srdo.webp +0 -0
- package/data/icons/208_hmip-dsd-pcb.webp +0 -0
- package/data/icons/209_hmip-etrv-b-uk.webp +0 -0
- package/data/icons/210_hmip-ste2-pcb.webp +0 -0
- package/data/icons/211_hmip-drg-dali.webp +0 -0
- package/data/icons/211_hmip-drsi1.webp +0 -0
- package/data/icons/212_hmip-sfd.webp +0 -0
- package/data/icons/212_hmipw-scthd.webp +0 -0
- package/data/icons/213_hmip-smo230.webp +0 -0
- package/data/icons/213_hmip-wua.webp +0 -0
- package/data/icons/214_hmip-dld.webp +0 -0
- package/data/icons/215_hmip-psm-pe-2.webp +0 -0
- package/data/icons/215_hmip-scth230.webp +0 -0
- package/data/icons/216_hmip-etrv-e.webp +0 -0
- package/data/icons/216_hmip-psm-ch-2.webp +0 -0
- package/data/icons/217_hmip-usbsm.webp +0 -0
- package/data/icons/218_hmip-dls.webp +0 -0
- package/data/icons/219_hmip-fwi.webp +0 -0
- package/data/icons/220_hmip-wsc.webp +0 -0
- package/data/icons/221_hmip-sti.webp +0 -0
- package/data/icons/221_hmip-wkp.webp +0 -0
- package/data/icons/222_hmipw-wgd.webp +0 -0
- package/data/icons/223_hmip-mod-wd-vk.webp +0 -0
- package/data/icons/224_hmip-etrv-cl.webp +0 -0
- package/data/icons/225_hmip-rgbw.webp +0 -0
- package/data/icons/226_hmip-esi.webp +0 -0
- package/data/icons/227_hmip-lsc.webp +0 -0
- package/data/icons/228_elv-sh-sw1-bat.webp +0 -0
- package/data/icons/229_elv-sh-bm-s.webp +0 -0
- package/data/icons/230_hmip-etrv-f.webp +0 -0
- package/data/icons/231_elv-sh-cth.webp +0 -0
- package/data/icons/232_elv-sh-taco.webp +0 -0
- package/data/icons/233_hmip-flc.webp +0 -0
- package/data/icons/234_hmip-etrv-3.webp +0 -0
- package/data/icons/235_hmip-psmco.webp +0 -0
- package/data/icons/236_elv-sh-sb8.webp +0 -0
- package/data/icons/237_elv-sh-ctv.webp +0 -0
- package/data/icons/238_elv-sh-cap.webp +0 -0
- package/data/icons/239_hmip-wgs-f.webp +0 -0
- package/data/icons/240_hmip-wgtc-f.webp +0 -0
- package/data/icons/241_hmip-wgt-f.webp +0 -0
- package/data/icons/242_elv-sh-smsi.webp +0 -0
- package/data/icons/243_elv-sh-crc.webp +0 -0
- package/data/icons/244_elv-sh-krco.webp +0 -0
- package/data/icons/245_hmip-falmot-c8.webp +0 -0
- package/data/icons/246_elv-sh-wsm.webp +0 -0
- package/data/icons/247_hmip-hap-2.webp +0 -0
- package/data/icons/248_hmip-dlp.webp +0 -0
- package/data/icons/249_elv-sh-psmci.webp +0 -0
- package/data/icons/250_elv-sh-sps25.webp +0 -0
- package/data/icons/252_elv-sh-pti2.webp +0 -0
- package/data/icons/253_hmip-udi-smi55.webp +0 -0
- package/data/icons/254_hmip-udi-pb2.webp +0 -0
- package/data/icons/256_ELV-SH-SMS2.webp +0 -0
- package/data/icons/257_ELV-SH-FSI.webp +0 -0
- package/data/icons/258_hmip-m-td15.webp +0 -0
- package/data/icons/259_elv-sh-dusi.webp +0 -0
- package/data/icons/260_hmip-wss.webp +0 -0
- package/data/icons/54a_lc-ddc1-pcb.webp +0 -0
- package/data/icons/72_hm-rc-brc-h.webp +0 -0
- package/data/icons/73_hm-atent.webp +0 -0
- package/data/icons/79_hm-lc-dim1pwm-cv.webp +0 -0
- package/data/icons/84_hm-rc-4-3.webp +0 -0
- package/data/icons/85_hm-rc-sec4-3.webp +0 -0
- package/data/icons/86_hm-rc-key4-3.webp +0 -0
- package/data/icons/CCU3-1-50.webp +0 -0
- package/data/icons/CCU3.webp +0 -0
- package/data/icons/hm-coupling-dim.webp +0 -0
- package/data/icons/hm-coupling-group.webp +0 -0
- package/data/icons/hm-coupling-onoff.webp +0 -0
- package/data/icons/hm-coupling-rgb-dim.webp +0 -0
- package/data/icons/hm-coupling-rgb.webp +0 -0
- package/data/icons/hm-coupling-rgbw-dim.webp +0 -0
- package/data/icons/hm-coupling-rgbw.webp +0 -0
- package/data/icons/hm-coupling-white-dim.webp +0 -0
- package/data/icons/hm-coupling-white.webp +0 -0
- package/data/icons/hm-hue_gateway.webp +0 -0
- package/data/icons/hm-lightify_gateway.webp +0 -0
- package/data/icons/hm_resc-win-pcb-sc.webp +0 -0
- package/data/icons/unknown_device.webp +0 -0
- package/data/manifest.json +7 -1
- package/data/master-metadata.json +1997 -33
- package/data/profiles/ACCESS_RECEIVER.json +26 -13
- package/data/profiles/ACOUSTIC_SIGNAL_VIRTUAL_RECEIVER.json +3270 -76
- package/data/profiles/ACTOR_SECURITY.json +90 -10
- package/data/profiles/ACTOR_WINDOW.json +580 -43
- package/data/profiles/ALARMACTUATOR.json +564 -37
- package/data/profiles/ALARM_COND_SWITCH_RECEIVER.json +36 -4
- package/data/profiles/ALARM_SWITCH_VIRTUAL_RECEIVER.json +735 -33
- package/data/profiles/ARMING.json +115 -5
- package/data/profiles/BLIND.json +1038 -49
- package/data/profiles/BLIND_VIRTUAL_RECEIVER.json +4624 -124
- package/data/profiles/CLIMATECONTROL_FLOOR_PUMP_TRANSCEIVER.json +27 -1
- package/data/profiles/DIMMER.json +2233 -71
- package/data/profiles/DIMMER_VIRTUAL_RECEIVER.json +5773 -102
- package/data/profiles/DIMMER_woLongKeyPress.json +117 -4
- package/data/profiles/DOOR_RECEIVER.json +138 -10
- package/data/profiles/DUAL_WHITE_BRIGHTNESS.json +305 -11
- package/data/profiles/DUAL_WHITE_COLOR.json +730 -23
- package/data/profiles/HEATING_KEY_RECEIVER.json +127 -10
- package/data/profiles/HMW_BLIND.json +555 -20
- package/data/profiles/HMW_DIMMER.json +1337 -47
- package/data/profiles/HMW_INPUT_OUTPUT.json +375 -20
- package/data/profiles/HMW_SWITCH.json +375 -20
- package/data/profiles/JALOUSIE.json +1320 -52
- package/data/profiles/KEYMATIC.json +120 -12
- package/data/profiles/REMOTECONTROL_RECEIVER.json +10 -2
- package/data/profiles/RGBW_AUTOMATIC.json +46 -6
- package/data/profiles/RGBW_COLOR.json +14 -4
- package/data/profiles/SERVO_VIRTUAL_RECEIVER.json +117 -3
- package/data/profiles/SHUTTER_VIRTUAL_RECEIVER.json +4263 -128
- package/data/profiles/SIGNAL_CHIME.json +195 -14
- package/data/profiles/SIGNAL_CHIMEM.json +195 -14
- package/data/profiles/SIGNAL_LED.json +195 -14
- package/data/profiles/SIGNAL_LEDM.json +195 -14
- package/data/profiles/SIMPLE_SWITCH_RECEIVER.json +113 -9
- package/data/profiles/STATUS_INDICATOR.json +1073 -45
- package/data/profiles/SWITCH.json +1412 -60
- package/data/profiles/SWITCH_PANIC.json +315 -13
- package/data/profiles/SWITCH_SENSOR.json +243 -11
- package/data/profiles/SWITCH_VIRTUAL_RECEIVER.json +3963 -131
- package/data/profiles/UNIVERSAL_ACTOR.json +4319 -90
- package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_LSC.json +6094 -196
- package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_PWM.json +4920 -101
- package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_RGB(W).json +2353 -80
- package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_RGBW_DALI.json +6116 -176
- package/data/profiles/UNIVERSAL_LIGHT_RECEIVER_TW.json +3844 -104
- package/data/profiles/VIRTUAL_DIMMER.json +305 -11
- package/data/profiles/VIRTUAL_DUAL_WHITE_COLOR.json +730 -23
- package/data/profiles/WATER_SWITCH_VIRTUAL_RECEIVER.json +3903 -128
- package/data/profiles/WINDOW_DRIVE_RECEIVER.json +220 -8
- package/data/profiles/WINMATIC.json +505 -23
- package/dist/cli.js +24 -0
- package/dist/occulite.d.ts +86 -0
- package/dist/occulite.js +140 -0
- package/dist/options.d.ts +37 -6
- package/dist/options.js +49 -6
- package/dist/server.d.ts +47 -4
- package/dist/server.js +237 -27
- package/dist/sessions.d.ts +9 -1
- package/dist/sessions.js +8 -2
- package/dist/testSupport.js +9 -2
- package/node_modules/@homematic-manager/backend/dist/api/backend.d.ts +33 -0
- package/node_modules/@homematic-manager/backend/dist/api/backend.js +558 -46
- package/node_modules/@homematic-manager/backend/dist/cache/names.d.ts +9 -0
- package/node_modules/@homematic-manager/backend/dist/cache/names.js +21 -0
- package/node_modules/@homematic-manager/backend/dist/config/defaults.js +10 -1
- package/node_modules/@homematic-manager/backend/dist/config/store.d.ts +28 -1
- package/node_modules/@homematic-manager/backend/dist/config/store.js +59 -3
- package/node_modules/@homematic-manager/backend/dist/devices/installMode.js +9 -0
- package/node_modules/@homematic-manager/backend/dist/errors.d.ts +18 -0
- package/node_modules/@homematic-manager/backend/dist/errors.js +51 -2
- package/node_modules/@homematic-manager/backend/dist/images/deviceImages.d.ts +6 -0
- package/node_modules/@homematic-manager/backend/dist/images/deviceImages.js +38 -2
- package/node_modules/@homematic-manager/backend/dist/index.d.ts +3 -1
- package/node_modules/@homematic-manager/backend/dist/index.js +4 -1
- package/node_modules/@homematic-manager/backend/dist/interfaces/manager.d.ts +70 -8
- package/node_modules/@homematic-manager/backend/dist/interfaces/manager.js +333 -44
- package/node_modules/@homematic-manager/backend/dist/meta/client.d.ts +120 -0
- package/node_modules/@homematic-manager/backend/dist/meta/client.js +307 -0
- package/node_modules/@homematic-manager/backend/dist/meta/credentials.d.ts +38 -0
- package/node_modules/@homematic-manager/backend/dist/meta/credentials.js +53 -0
- package/node_modules/@homematic-manager/backend/dist/meta/index.d.ts +12 -0
- package/node_modules/@homematic-manager/backend/dist/meta/index.js +12 -0
- package/node_modules/@homematic-manager/backend/dist/meta/localProvider.d.ts +47 -0
- package/node_modules/@homematic-manager/backend/dist/meta/localProvider.js +119 -0
- package/node_modules/@homematic-manager/backend/dist/meta/occuliteProvider.d.ts +79 -0
- package/node_modules/@homematic-manager/backend/dist/meta/occuliteProvider.js +305 -0
- package/node_modules/@homematic-manager/backend/dist/meta/provider.d.ts +68 -0
- package/node_modules/@homematic-manager/backend/dist/meta/provider.js +19 -0
- package/node_modules/@homematic-manager/backend/dist/meta/regaProvider.d.ts +84 -0
- package/node_modules/@homematic-manager/backend/dist/meta/regaProvider.js +403 -0
- package/node_modules/@homematic-manager/backend/dist/meta/service.d.ts +137 -0
- package/node_modules/@homematic-manager/backend/dist/meta/service.js +412 -0
- package/node_modules/@homematic-manager/backend/dist/rega/client.d.ts +11 -0
- package/node_modules/@homematic-manager/backend/dist/rega/client.js +13 -0
- package/node_modules/@homematic-manager/backend/dist/rega/scripts.d.ts +51 -0
- package/node_modules/@homematic-manager/backend/dist/rega/scripts.js +171 -0
- package/node_modules/@homematic-manager/backend/dist/rpc/client.d.ts +18 -5
- package/node_modules/@homematic-manager/backend/dist/rpc/client.js +11 -5
- package/node_modules/@homematic-manager/backend/dist/rpc/log.d.ts +86 -0
- package/node_modules/@homematic-manager/backend/dist/rpc/log.js +241 -0
- package/node_modules/@homematic-manager/backend/dist/rpc/origin.d.ts +30 -0
- package/node_modules/@homematic-manager/backend/dist/rpc/origin.js +35 -0
- package/node_modules/@homematic-manager/backend/dist/rpc/server.d.ts +12 -0
- package/node_modules/@homematic-manager/backend/dist/rpc/server.js +37 -5
- package/node_modules/@homematic-manager/backend/dist/util/net.d.ts +86 -1
- package/node_modules/@homematic-manager/backend/dist/util/net.js +223 -9
- package/node_modules/@homematic-manager/backend/package.json +1 -1
- package/node_modules/@homematic-manager/core/dist/api/types.d.ts +397 -10
- package/node_modules/@homematic-manager/core/dist/api/types.js +23 -2
- package/node_modules/@homematic-manager/core/dist/data/memory.d.ts +3 -1
- package/node_modules/@homematic-manager/core/dist/data/memory.js +3 -0
- package/node_modules/@homematic-manager/core/dist/data/types.d.ts +60 -0
- package/node_modules/@homematic-manager/core/dist/data/types.js +2 -0
- package/node_modules/@homematic-manager/core/dist/devices/index.d.ts +19 -0
- package/node_modules/@homematic-manager/core/dist/devices/index.js +53 -0
- package/node_modules/@homematic-manager/core/dist/easymodes/engine.d.ts +3 -1
- package/node_modules/@homematic-manager/core/dist/easymodes/engine.js +1 -0
- package/node_modules/@homematic-manager/core/dist/easymodes/form.d.ts +43 -0
- package/node_modules/@homematic-manager/core/dist/easymodes/form.js +84 -0
- package/node_modules/@homematic-manager/core/dist/i18n/messages.js +61 -0
- package/node_modules/@homematic-manager/core/dist/index.d.ts +3 -0
- package/node_modules/@homematic-manager/core/dist/index.js +4 -0
- package/node_modules/@homematic-manager/core/dist/interfaces/table.d.ts +23 -2
- package/node_modules/@homematic-manager/core/dist/interfaces/table.js +18 -1
- package/node_modules/@homematic-manager/core/dist/meta/document.d.ts +71 -0
- package/node_modules/@homematic-manager/core/dist/meta/document.js +260 -0
- package/node_modules/@homematic-manager/core/dist/meta/follow.d.ts +27 -0
- package/node_modules/@homematic-manager/core/dist/meta/follow.js +180 -0
- package/node_modules/@homematic-manager/core/dist/meta/index.d.ts +16 -0
- package/node_modules/@homematic-manager/core/dist/meta/index.js +16 -0
- package/node_modules/@homematic-manager/core/dist/meta/paths.d.ts +96 -0
- package/node_modules/@homematic-manager/core/dist/meta/paths.js +182 -0
- package/node_modules/@homematic-manager/core/dist/meta/slug.d.ts +22 -0
- package/node_modules/@homematic-manager/core/dist/meta/slug.js +59 -0
- package/node_modules/@homematic-manager/core/dist/meta/store.d.ts +147 -0
- package/node_modules/@homematic-manager/core/dist/meta/store.js +537 -0
- package/node_modules/@homematic-manager/core/dist/meta/tree.d.ts +19 -0
- package/node_modules/@homematic-manager/core/dist/meta/tree.js +53 -0
- package/node_modules/@homematic-manager/core/dist/meta/types.d.ts +143 -0
- package/node_modules/@homematic-manager/core/dist/meta/types.js +63 -0
- package/node_modules/@homematic-manager/core/dist/meta/view.d.ts +50 -0
- package/node_modules/@homematic-manager/core/dist/meta/view.js +103 -0
- package/node_modules/@homematic-manager/core/dist/rpc/methods.d.ts +10 -0
- package/node_modules/@homematic-manager/core/dist/rpc/methods.js +51 -1
- package/node_modules/@homematic-manager/core/dist/rpc/text.d.ts +22 -0
- package/node_modules/@homematic-manager/core/dist/rpc/text.js +46 -0
- package/node_modules/@homematic-manager/core/dist/rssi/index.d.ts +125 -13
- package/node_modules/@homematic-manager/core/dist/rssi/index.js +146 -29
- package/node_modules/@homematic-manager/core/dist/serviceMessages/index.d.ts +28 -2
- package/node_modules/@homematic-manager/core/dist/serviceMessages/index.js +44 -6
- package/node_modules/@homematic-manager/core/package.json +1 -1
- package/package.json +3 -3
- package/ui/assets/index-D-NsbBVS.css +1 -0
- package/ui/assets/index-DNUNMBbb.js +16 -0
- package/ui/favicon.ico +0 -0
- package/ui/index.html +3 -2
- package/node_modules/@homematic-manager/backend/dist/write/log.d.ts +0 -51
- package/node_modules/@homematic-manager/backend/dist/write/log.js +0 -151
- package/ui/assets/index-lB-HxsKR.js +0 -13
- package/ui/assets/index-qbhgN2pA.css +0 -1
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `rega` metadata provider (task 27): the CCU's own rooms and functions, through ReGaHSS.
|
|
3
|
+
*
|
|
4
|
+
* On a CCU the rooms and functions the user sees in the WebUI live in ReGa's DOM - enum objects
|
|
5
|
+
* under `ID_ROOMS` and `ID_FUNCTIONS`, each holding channel ids - and a taxonomy kept in this
|
|
6
|
+
* profile beside them would be a second truth. So on a CCU with ReGa this provider *is* the store:
|
|
7
|
+
* the same {@link MetadataProvider} surface the box's provider has, over the same script transport
|
|
8
|
+
* the names already use, so that the editing UI of task 25 does not know which one it talks to.
|
|
9
|
+
*
|
|
10
|
+
* What ReGa's model is, and therefore what this provider is:
|
|
11
|
+
*
|
|
12
|
+
* - **Flat.** A room is a room; there is no room below another and no floor. `state().flat` says
|
|
13
|
+
* so, `createNode` with a parent and a move under a parent are refused.
|
|
14
|
+
* - **Two taxonomies, fixed.** Rooms and functions exist; nothing else can be created or deleted.
|
|
15
|
+
* - **Channels are members, devices are not.** The WebUI assigns channels. A device ref in a
|
|
16
|
+
* membership write is applied to every channel of the device except the `:0` maintenance
|
|
17
|
+
* channel, which is what a user who "puts the device in the kitchen" means.
|
|
18
|
+
* - **Identity is the ReGa id.** A node's id is `r<id>`, stable across renames, so a path never
|
|
19
|
+
* has to be rewritten when a room is renamed.
|
|
20
|
+
* - **No change stream.** ReGa tells nobody when the WebUI edits a room. This provider reads
|
|
21
|
+
* everything on `start()`, after every write of its own, and on `refresh()`, which the UI asks
|
|
22
|
+
* for through `meta.refresh`.
|
|
23
|
+
*
|
|
24
|
+
* Failure is a state, never an exception (D-2): a script that does not run leaves the last
|
|
25
|
+
* document in place, sets `reachable: false` and says so once.
|
|
26
|
+
*/
|
|
27
|
+
import { MetaError, makeRef, normaliseName, parsePath, } from '@homematic-manager/core';
|
|
28
|
+
import { errorMessage } from '../errors.js';
|
|
29
|
+
import { createEnumNodeScript, deleteEnumNodeScript, membershipScript, META_READ_SCRIPT, parseCreatedId, parseMetaSnapshot, renameObjectsScript, } from '../rega/scripts.js';
|
|
30
|
+
const ENUM_NAMES = {
|
|
31
|
+
room: { de: 'Räume', en: 'Rooms' },
|
|
32
|
+
function: { de: 'Gewerke', en: 'Functions' },
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* The rooms and functions a CCU comes with, as the WebUI translates them (`translate.lang.js` of
|
|
36
|
+
* the German and the English WebUI, firmware 3.89.8). ReGa's objects carry the *key* as their
|
|
37
|
+
* `Name()` - `roomKitchen`, not `Küche` - and every WebUI page translates it on display, so a list
|
|
38
|
+
* that shows the keys is not what the user sees on the CCU. Found in the first lab pass of task 27.
|
|
39
|
+
* A name that is not one of these keys is shown as it is; a rename writes the literal name.
|
|
40
|
+
*/
|
|
41
|
+
export const REGA_STOCK_NAMES = {
|
|
42
|
+
roomLivingRoom: { de: 'Wohnzimmer', en: 'Living room' },
|
|
43
|
+
roomKitchen: { de: 'Küche', en: 'Kitchen' },
|
|
44
|
+
roomBedroom: { de: 'Schlafzimmer', en: 'Bed room' },
|
|
45
|
+
roomChildrensRoom1: { de: 'Kinderzimmer 1', en: "Children's room 1" },
|
|
46
|
+
roomChildrensRoom2: { de: 'Kinderzimmer 2', en: "Children's room 2" },
|
|
47
|
+
roomOffice: { de: 'Büro', en: 'Home office' },
|
|
48
|
+
roomBathroom: { de: 'Badezimmer', en: 'Bathroom' },
|
|
49
|
+
roomGarage: { de: 'Garage', en: 'Garage' },
|
|
50
|
+
roomHWR: { de: 'Hauswirtschaftsraum', en: 'Utility room' },
|
|
51
|
+
roomGarden: { de: 'Garten', en: 'Garden' },
|
|
52
|
+
roomTerrace: { de: 'Terrasse', en: 'Terrace' },
|
|
53
|
+
funcLight: { de: 'Licht', en: 'Light' },
|
|
54
|
+
funcHeating: { de: 'Heizung', en: 'Heating' },
|
|
55
|
+
funcClimateControl: { de: 'Klima', en: 'Climatic conditions' },
|
|
56
|
+
funcWeather: { de: 'Wetter', en: 'Weather' },
|
|
57
|
+
funcEnvironment: { de: 'Umwelt', en: 'Environment' },
|
|
58
|
+
funcSecurity: { de: 'Sicherheit', en: 'Security' },
|
|
59
|
+
funcLock: { de: 'Verschluss', en: 'Lock' },
|
|
60
|
+
funcButton: { de: 'Taster', en: 'Button' },
|
|
61
|
+
funcCentral: { de: 'Zentrale', en: 'Central control unit' },
|
|
62
|
+
funcEnergy: { de: 'Energiemanagement', en: 'Energy management' },
|
|
63
|
+
};
|
|
64
|
+
/** `roomKitchen` -> `Küche`; anything that is not a stock key is answered as it is. */
|
|
65
|
+
export function regaStockName(name, language) {
|
|
66
|
+
const stock = REGA_STOCK_NAMES[name];
|
|
67
|
+
if (stock === undefined) {
|
|
68
|
+
return name;
|
|
69
|
+
}
|
|
70
|
+
// the WebUI has German and English; the CCU's own default is German
|
|
71
|
+
return language === 'en' ? stock.en : stock.de;
|
|
72
|
+
}
|
|
73
|
+
/** `r4711` - the node id of a ReGa enum object; stable across renames. */
|
|
74
|
+
export function regaNodeId(id) {
|
|
75
|
+
return `r${String(id)}`;
|
|
76
|
+
}
|
|
77
|
+
/** The ReGa id behind a node id, or `undefined` for anything that is not one. */
|
|
78
|
+
export function parseRegaNodeId(id) {
|
|
79
|
+
const match = /^r(\d+)$/.exec(id);
|
|
80
|
+
return match ? Number(match[1]) : undefined;
|
|
81
|
+
}
|
|
82
|
+
export class RegaMetaProvider {
|
|
83
|
+
kind = 'rega';
|
|
84
|
+
#options;
|
|
85
|
+
/** By ref. */
|
|
86
|
+
#objects = new Map();
|
|
87
|
+
/** By ReGa id, for the membership sets. */
|
|
88
|
+
#byId = new Map();
|
|
89
|
+
#enums = { room: new Map(), function: new Map() };
|
|
90
|
+
#document;
|
|
91
|
+
#revision = 0;
|
|
92
|
+
#reachable = false;
|
|
93
|
+
#error;
|
|
94
|
+
#lastNotice = '';
|
|
95
|
+
constructor(options) {
|
|
96
|
+
this.#options = options;
|
|
97
|
+
}
|
|
98
|
+
state() {
|
|
99
|
+
return {
|
|
100
|
+
provider: 'rega',
|
|
101
|
+
reachable: this.#reachable,
|
|
102
|
+
// ReGa takes every write from whoever may run a script; there is no read-only credential
|
|
103
|
+
writable: this.#reachable,
|
|
104
|
+
revision: this.#revision,
|
|
105
|
+
objects: this.#objects.size,
|
|
106
|
+
flat: true,
|
|
107
|
+
...(this.#error === undefined ? {} : { error: this.#error }),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async start() {
|
|
111
|
+
await this.refresh();
|
|
112
|
+
}
|
|
113
|
+
stop() {
|
|
114
|
+
return Promise.resolve();
|
|
115
|
+
}
|
|
116
|
+
/** Reads everything again. Never throws: a ReGa that does not answer is a state. */
|
|
117
|
+
async refresh() {
|
|
118
|
+
let snapshot;
|
|
119
|
+
try {
|
|
120
|
+
const answer = await this.#options.exec(META_READ_SCRIPT);
|
|
121
|
+
snapshot = parseMetaSnapshot(answer.output);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
this.#fail(error);
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
this.#load(snapshot);
|
|
128
|
+
this.#reachable = true;
|
|
129
|
+
this.#error = undefined;
|
|
130
|
+
this.#lastNotice = '';
|
|
131
|
+
this.#revision += 1;
|
|
132
|
+
this.#announce();
|
|
133
|
+
}
|
|
134
|
+
document() {
|
|
135
|
+
this.#document ??= this.#build();
|
|
136
|
+
return this.#document;
|
|
137
|
+
}
|
|
138
|
+
async setNames(entries) {
|
|
139
|
+
const renames = [];
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
const object = this.#objects.get(entry.ref);
|
|
142
|
+
if (object === undefined) {
|
|
143
|
+
// an address ReGa has never reported can only be named locally, as before (D-2)
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
const name = normaliseName(entry.name);
|
|
147
|
+
if (name !== object.name) {
|
|
148
|
+
renames.push({ object, name });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const script = renameObjectsScript(renames.map((entry) => ({ id: entry.object.id, name: entry.name })));
|
|
152
|
+
if (script === undefined) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
await this.#run(script);
|
|
156
|
+
for (const entry of renames) {
|
|
157
|
+
entry.object.name = entry.name;
|
|
158
|
+
}
|
|
159
|
+
this.#commit();
|
|
160
|
+
}
|
|
161
|
+
async setMembership(entries) {
|
|
162
|
+
const changes = [];
|
|
163
|
+
for (const entry of entries) {
|
|
164
|
+
const wanted = this.#targetsOf(entry.paths);
|
|
165
|
+
for (const object of this.#membersFor(entry.ref)) {
|
|
166
|
+
for (const kind of ['room', 'function']) {
|
|
167
|
+
for (const [id, node] of this.#enums[kind]) {
|
|
168
|
+
const has = node.channels.has(object.id);
|
|
169
|
+
const should = wanted[kind].has(id);
|
|
170
|
+
if (has !== should) {
|
|
171
|
+
changes.push({ enumId: id, channelId: object.id, on: should });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const script = membershipScript(changes);
|
|
178
|
+
if (script === undefined) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
await this.#run(script);
|
|
182
|
+
for (const change of changes) {
|
|
183
|
+
const node = this.#nodeById(change.enumId);
|
|
184
|
+
if (node) {
|
|
185
|
+
if (change.on) {
|
|
186
|
+
node.channels.add(change.channelId);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
node.channels.delete(change.channelId);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
this.#commit();
|
|
194
|
+
}
|
|
195
|
+
createEnum() {
|
|
196
|
+
return Promise.reject(fixedEnums());
|
|
197
|
+
}
|
|
198
|
+
updateEnum() {
|
|
199
|
+
return Promise.reject(fixedEnums());
|
|
200
|
+
}
|
|
201
|
+
deleteEnum() {
|
|
202
|
+
return Promise.reject(fixedEnums());
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* A new room or function. The id the caller derived from the name is not used: ReGa hands out
|
|
206
|
+
* the id, and `r<id>` is what keeps the path stable when the room is renamed later.
|
|
207
|
+
*/
|
|
208
|
+
async createNode(enumId, parent, _id, name) {
|
|
209
|
+
const kind = requireKind(enumId);
|
|
210
|
+
if (parent !== null && parent !== enumId) {
|
|
211
|
+
throw new MetaError('too-deep', 'ReGa rooms and functions are a flat list: no node below another');
|
|
212
|
+
}
|
|
213
|
+
const nodeName = normaliseName(name);
|
|
214
|
+
const answer = await this.#run(createEnumNodeScript(kind, nodeName));
|
|
215
|
+
const id = parseCreatedId(answer.output);
|
|
216
|
+
if (id === undefined) {
|
|
217
|
+
// the object may or may not exist now; the next read says which
|
|
218
|
+
await this.refresh();
|
|
219
|
+
throw new MetaError('unknown-path', `ReGa did not answer with the id of the new ${kind}`);
|
|
220
|
+
}
|
|
221
|
+
this.#enums[kind].set(id, { id, name: nodeName, channels: new Set() });
|
|
222
|
+
this.#commit();
|
|
223
|
+
return `${kind}/${regaNodeId(id)}`;
|
|
224
|
+
}
|
|
225
|
+
async updateNode(path, patch) {
|
|
226
|
+
const { kind, node } = this.#requireNode(path);
|
|
227
|
+
if (patch.parent !== undefined && patch.parent !== null && patch.parent !== kind) {
|
|
228
|
+
throw new MetaError('invalid-move', 'ReGa rooms and functions are a flat list: nothing can be moved below another');
|
|
229
|
+
}
|
|
230
|
+
// `icon` and `position` have no counterpart in ReGa and are accepted without effect
|
|
231
|
+
if (patch.name === undefined) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const name = normaliseName(patch.name);
|
|
235
|
+
if (name === node.name || name === this.#displayName(node)) {
|
|
236
|
+
// the same name again is not a write - nor is the translation of a stock key
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const script = renameObjectsScript([{ id: node.id, name }]);
|
|
240
|
+
if (script === undefined) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
await this.#run(script);
|
|
244
|
+
node.name = name;
|
|
245
|
+
this.#commit();
|
|
246
|
+
}
|
|
247
|
+
async deleteNode(path, detach) {
|
|
248
|
+
const { kind, node } = this.#requireNode(path);
|
|
249
|
+
const refs = [...node.channels]
|
|
250
|
+
.map((id) => this.#byId.get(id)?.ref)
|
|
251
|
+
.filter((ref) => ref !== undefined)
|
|
252
|
+
.sort((a, b) => a.localeCompare(b));
|
|
253
|
+
if (refs.length > 0 && !detach) {
|
|
254
|
+
throw new MetaError('has-members', `${path} still has members`, { refs });
|
|
255
|
+
}
|
|
256
|
+
await this.#run(deleteEnumNodeScript(kind, node.id));
|
|
257
|
+
this.#enums[kind].delete(node.id);
|
|
258
|
+
this.#commit();
|
|
259
|
+
}
|
|
260
|
+
import() {
|
|
261
|
+
return Promise.reject(new MetaError('forbidden', 'a ReGa store cannot be replaced by an import'));
|
|
262
|
+
}
|
|
263
|
+
/*
|
|
264
|
+
* the model
|
|
265
|
+
*/
|
|
266
|
+
#load(snapshot) {
|
|
267
|
+
this.#objects.clear();
|
|
268
|
+
this.#byId.clear();
|
|
269
|
+
for (const entry of snapshot.objects) {
|
|
270
|
+
const interfaceName = entry.interfaceName !== '' ? entry.interfaceName : this.#options.interfaceOf(entry.address);
|
|
271
|
+
if (interfaceName === undefined || interfaceName === '') {
|
|
272
|
+
// no ref without an interface; the name cache still gets it through ReGa's names
|
|
273
|
+
continue;
|
|
274
|
+
}
|
|
275
|
+
const object = {
|
|
276
|
+
id: entry.id,
|
|
277
|
+
address: entry.address,
|
|
278
|
+
ref: makeRef(interfaceName, entry.address),
|
|
279
|
+
name: entry.name,
|
|
280
|
+
};
|
|
281
|
+
this.#objects.set(object.ref, object);
|
|
282
|
+
this.#byId.set(object.id, object);
|
|
283
|
+
}
|
|
284
|
+
for (const kind of ['room', 'function']) {
|
|
285
|
+
const nodes = this.#enums[kind];
|
|
286
|
+
nodes.clear();
|
|
287
|
+
for (const entry of kind === 'room' ? snapshot.rooms : snapshot.functions) {
|
|
288
|
+
nodes.set(entry.id, { id: entry.id, name: entry.name, channels: new Set(entry.channels) });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this.#document = undefined;
|
|
292
|
+
}
|
|
293
|
+
/** The document as the rest of the application reads it, rebuilt lazily after a change. */
|
|
294
|
+
#build() {
|
|
295
|
+
const objects = {};
|
|
296
|
+
for (const object of this.#objects.values()) {
|
|
297
|
+
const paths = [];
|
|
298
|
+
for (const kind of ['room', 'function']) {
|
|
299
|
+
for (const node of this.#enums[kind].values()) {
|
|
300
|
+
if (node.channels.has(object.id)) {
|
|
301
|
+
paths.push(`${kind}/${regaNodeId(node.id)}`);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
objects[object.ref] = { name: object.name, enums: paths, meta: {} };
|
|
306
|
+
}
|
|
307
|
+
const enums = {};
|
|
308
|
+
for (const kind of ['room', 'function']) {
|
|
309
|
+
const tree = [...this.#enums[kind].values()]
|
|
310
|
+
.sort((a, b) => this.#displayName(a).localeCompare(this.#displayName(b), 'de') || a.id - b.id)
|
|
311
|
+
.map((node) => ({ id: regaNodeId(node.id), name: this.#displayName(node) }));
|
|
312
|
+
enums[kind] = { name: { ...ENUM_NAMES[kind] }, tree };
|
|
313
|
+
}
|
|
314
|
+
return { format: 1, revision: this.#revision, objects, enums };
|
|
315
|
+
}
|
|
316
|
+
/** The channels a membership write addresses: the channel itself, or every channel of a device. */
|
|
317
|
+
#membersFor(ref) {
|
|
318
|
+
const object = this.#objects.get(ref);
|
|
319
|
+
if (object === undefined) {
|
|
320
|
+
throw new MetaError('unknown-object', `${ref} is not known to ReGa`);
|
|
321
|
+
}
|
|
322
|
+
if (object.address.includes(':')) {
|
|
323
|
+
return [object];
|
|
324
|
+
}
|
|
325
|
+
const prefix = `${object.address}:`;
|
|
326
|
+
return [...this.#objects.values()].filter((candidate) => candidate.address.startsWith(prefix) && !candidate.address.endsWith(':0'));
|
|
327
|
+
}
|
|
328
|
+
/** The ReGa ids the wanted paths name, per kind; a path that is not a node here is refused. */
|
|
329
|
+
#targetsOf(paths) {
|
|
330
|
+
const targets = { room: new Set(), function: new Set() };
|
|
331
|
+
for (const path of paths) {
|
|
332
|
+
const { kind, node } = this.#requireNode(path);
|
|
333
|
+
targets[kind].add(node.id);
|
|
334
|
+
}
|
|
335
|
+
return targets;
|
|
336
|
+
}
|
|
337
|
+
#requireNode(path) {
|
|
338
|
+
const parsed = parsePath(path);
|
|
339
|
+
const kind = parsed === undefined ? undefined : toKind(parsed.enumId);
|
|
340
|
+
const id = parsed?.ids.length === 1 ? parseRegaNodeId(parsed.ids[0] ?? '') : undefined;
|
|
341
|
+
const node = kind === undefined || id === undefined ? undefined : this.#enums[kind].get(id);
|
|
342
|
+
if (kind === undefined || node === undefined) {
|
|
343
|
+
throw new MetaError('unknown-path', `${path} is not a room or function of this CCU`);
|
|
344
|
+
}
|
|
345
|
+
return { kind, node };
|
|
346
|
+
}
|
|
347
|
+
/** What the WebUI shows for this node: the stock key translated, anything else as it is. */
|
|
348
|
+
#displayName(node) {
|
|
349
|
+
return regaStockName(node.name, this.#options.language);
|
|
350
|
+
}
|
|
351
|
+
#nodeById(id) {
|
|
352
|
+
return this.#enums.room.get(id) ?? this.#enums.function.get(id);
|
|
353
|
+
}
|
|
354
|
+
/** One script, with the outcome reflected in the state; the error goes on to the caller. */
|
|
355
|
+
async #run(script) {
|
|
356
|
+
try {
|
|
357
|
+
const answer = await this.#options.exec(script);
|
|
358
|
+
if (!this.#reachable) {
|
|
359
|
+
this.#reachable = true;
|
|
360
|
+
this.#error = undefined;
|
|
361
|
+
this.#options.onStateChanged(this.state());
|
|
362
|
+
}
|
|
363
|
+
return answer;
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
this.#fail(error);
|
|
367
|
+
throw error;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
#commit() {
|
|
371
|
+
this.#document = undefined;
|
|
372
|
+
this.#revision += 1;
|
|
373
|
+
this.#announce();
|
|
374
|
+
}
|
|
375
|
+
#announce() {
|
|
376
|
+
this.#options.onStateChanged(this.state());
|
|
377
|
+
this.#options.onChanged();
|
|
378
|
+
}
|
|
379
|
+
#fail(error) {
|
|
380
|
+
const message = errorMessage(error);
|
|
381
|
+
this.#reachable = false;
|
|
382
|
+
this.#error = message;
|
|
383
|
+
this.#options.onStateChanged(this.state());
|
|
384
|
+
if (message !== this.#lastNotice) {
|
|
385
|
+
this.#lastNotice = message;
|
|
386
|
+
this.#options.onNotice('warn', `ReGa did not answer the rooms and functions script: ${message}`);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
function toKind(enumId) {
|
|
391
|
+
return enumId === 'room' || enumId === 'function' ? enumId : undefined;
|
|
392
|
+
}
|
|
393
|
+
function requireKind(enumId) {
|
|
394
|
+
const kind = toKind(enumId);
|
|
395
|
+
if (kind === undefined) {
|
|
396
|
+
throw new MetaError('unknown-enum', `${enumId}: ReGa has rooms and functions and nothing else`);
|
|
397
|
+
}
|
|
398
|
+
return kind;
|
|
399
|
+
}
|
|
400
|
+
function fixedEnums() {
|
|
401
|
+
return new MetaError('forbidden', 'ReGa has a fixed set of taxonomies - rooms and functions - that cannot be changed');
|
|
402
|
+
}
|
|
403
|
+
//# sourceMappingURL=regaProvider.js.map
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* D-40: which metadata provider is in charge, and everything the backend calls on it.
|
|
3
|
+
*
|
|
4
|
+
* The selection is openccu-lite's rule and no other: **`GET /api/meta/v1/version` on the configured
|
|
5
|
+
* host**, once per connect. A box answers with `{"api":"meta",…}` and its store is used; a CCU
|
|
6
|
+
* answers 404 or HTML and everything stays as it was. No `/VERSION` sniffing, no host names, no
|
|
7
|
+
* ports - a user who moves a profile between a CCU and a box must not have to edit anything
|
|
8
|
+
* (their invariant 2). `metaProvider: 'local'` skips the probe, `'occulite'` insists on the box.
|
|
9
|
+
* Task 27 adds the third answer: with no box, a ReGa that is on and answered
|
|
10
|
+
* (`options.rega.available`) becomes the store - its rooms and functions are the CCU's own - and
|
|
11
|
+
* `'rega'` insists on that.
|
|
12
|
+
*
|
|
13
|
+
* The service is also where the store's identity meets this application's. The store keys objects
|
|
14
|
+
* by **ref** (`<interface>.<address>`); the grids, the caches and the whole existing API key names
|
|
15
|
+
* by address, because a Homematic address is unique across the interfaces of one CCU in practice.
|
|
16
|
+
* So the ref is resolved here, in one place, from the device caches - and never guessed anywhere
|
|
17
|
+
* else.
|
|
18
|
+
*/
|
|
19
|
+
import { type ConnectionConfig, type MetaDocument, type MetaEnum, type MetaImportMode, type MetaNodePatch, type MetaObjectView, type MetaState, type MetaVersion } from '@homematic-manager/core';
|
|
20
|
+
import type { NameStore } from '../cache/names.js';
|
|
21
|
+
import { type RegaScriptRunner } from './regaProvider.js';
|
|
22
|
+
/** What the service needs to know about ReGa to offer it as a provider (task 27). */
|
|
23
|
+
export interface MetaRegaLink {
|
|
24
|
+
/** ReGa is on and has answered at least once - the `auto` choice takes it only then. */
|
|
25
|
+
readonly available: boolean;
|
|
26
|
+
readonly exec: RegaScriptRunner;
|
|
27
|
+
}
|
|
28
|
+
/** One name to set, as the rest of the backend spells it: by address. */
|
|
29
|
+
export interface MetaNameChange {
|
|
30
|
+
readonly address: string;
|
|
31
|
+
readonly name: string;
|
|
32
|
+
}
|
|
33
|
+
export interface MetaServiceOptions {
|
|
34
|
+
readonly connection: ConnectionConfig;
|
|
35
|
+
/** The profile directory; the `local` store lives in it. */
|
|
36
|
+
readonly dataDir: string;
|
|
37
|
+
/** The per-CCU cache directory; the box's last snapshot lives in it. */
|
|
38
|
+
readonly cacheDir: string;
|
|
39
|
+
/** The name cache the whole application reads; the provider's names are applied to it. */
|
|
40
|
+
readonly names: NameStore;
|
|
41
|
+
/** Which interface a device or channel address belongs to, from the device caches. */
|
|
42
|
+
readonly interfaceOf: (address: string) => string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* The ReGa of this connection, when it is switched on; absent otherwise. `auto` picks it when
|
|
45
|
+
* there is no box and it answered, `rega` insists on it.
|
|
46
|
+
*/
|
|
47
|
+
readonly rega?: MetaRegaLink | undefined;
|
|
48
|
+
/** The document changed: names, enums or objects. */
|
|
49
|
+
readonly onChanged: () => void;
|
|
50
|
+
readonly onStateChanged: (state: MetaState) => void;
|
|
51
|
+
readonly onNotice: (level: 'info' | 'warn' | 'error', message: string) => void;
|
|
52
|
+
/** Injected by the tests. */
|
|
53
|
+
readonly localTokenFile?: string | undefined;
|
|
54
|
+
readonly fetch?: typeof globalThis.fetch;
|
|
55
|
+
readonly detectTimeoutMs?: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The base URL of the box.
|
|
59
|
+
*
|
|
60
|
+
* `local` means "we are the addon on the box itself", where everything is behind the loopback
|
|
61
|
+
* lighttpd; otherwise it is the configured host with the scheme the profile uses for the CCU.
|
|
62
|
+
* `metaUrl` overrides both, for a reverse proxy on a strange port and for the integration tests.
|
|
63
|
+
*/
|
|
64
|
+
export declare function metaBaseUrl(connection: ConnectionConfig): string;
|
|
65
|
+
/** Everything the metadata store is, for one connection. */
|
|
66
|
+
export declare class MetaService {
|
|
67
|
+
#private;
|
|
68
|
+
private constructor();
|
|
69
|
+
/**
|
|
70
|
+
* Probes the box and builds the provider that fits.
|
|
71
|
+
*
|
|
72
|
+
* Never throws: a probe that fails means "no box", which is what every CCU, every Homegear and
|
|
73
|
+
* every desktop answers, and the `local` provider is a complete answer to it.
|
|
74
|
+
*/
|
|
75
|
+
static create(options: MetaServiceOptions): Promise<MetaService>;
|
|
76
|
+
get kind(): 'local' | 'occulite' | 'rega';
|
|
77
|
+
/** True when this connection talks to an openccu-lite box. */
|
|
78
|
+
get onBox(): boolean;
|
|
79
|
+
state(): MetaState;
|
|
80
|
+
document(): MetaDocument;
|
|
81
|
+
enums(): Readonly<Record<string, MetaEnum>>;
|
|
82
|
+
/** Every object as the UI shows it: the name, the paths, and the paths as names. */
|
|
83
|
+
objects(): Record<string, MetaObjectView>;
|
|
84
|
+
start(): Promise<void>;
|
|
85
|
+
stop(): Promise<void>;
|
|
86
|
+
/** Reads the store again - what `meta.refresh` is, and what a ReGa without a change stream needs. */
|
|
87
|
+
refresh(): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* The session the addon should write as (openccu-lite's embedding contract: `?sid=@…@`).
|
|
90
|
+
*
|
|
91
|
+
* Reads keep using the box's local token, which is read-only by design; a write is attributed
|
|
92
|
+
* to the person who opened the page. Without a session the writes go out with whatever the
|
|
93
|
+
* reads use, which on the box means the box answers 403 and the UI says so.
|
|
94
|
+
*/
|
|
95
|
+
setSessionCredential(sid: string | undefined): void;
|
|
96
|
+
/** Copies the store's names into the name cache. Returns true when anything changed. */
|
|
97
|
+
applyNames(): boolean;
|
|
98
|
+
/** The rename: what `names.set` writes into the store after the local cache has it. */
|
|
99
|
+
setNames(entries: readonly MetaNameChange[]): Promise<void>;
|
|
100
|
+
setMembership(entries: readonly {
|
|
101
|
+
ref: string;
|
|
102
|
+
paths: readonly string[];
|
|
103
|
+
}[]): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* The interaction of the whole feature: select rows, assign them to a room.
|
|
106
|
+
*
|
|
107
|
+
* One revision for the whole selection - the store is asked once with the complete membership
|
|
108
|
+
* of every object, not once per object, so a consumer of the change stream sees one change and
|
|
109
|
+
* the box writes its file once.
|
|
110
|
+
*/
|
|
111
|
+
assign(refs: readonly string[], nodePath: string, on: boolean): Promise<void>;
|
|
112
|
+
createEnum(id: string, name: Readonly<Record<string, string>>): Promise<void>;
|
|
113
|
+
updateEnum(id: string, name: Readonly<Record<string, string>>): Promise<void>;
|
|
114
|
+
deleteEnum(id: string, detach: boolean): Promise<void>;
|
|
115
|
+
/**
|
|
116
|
+
* A node under a parent. The id is derived from the name and never changes afterwards, which is
|
|
117
|
+
* what keeps every membership pointing at the same node when the room is renamed.
|
|
118
|
+
*/
|
|
119
|
+
createNode(enumId: string, parent: string | null | undefined, name: string, options?: {
|
|
120
|
+
readonly icon?: string;
|
|
121
|
+
readonly position?: number;
|
|
122
|
+
}): Promise<string>;
|
|
123
|
+
updateNode(nodePath: string, patch: MetaNodePatch): Promise<void>;
|
|
124
|
+
deleteNode(nodePath: string, detach: boolean): Promise<void>;
|
|
125
|
+
import(document: unknown, mode: MetaImportMode): Promise<void>;
|
|
126
|
+
/**
|
|
127
|
+
* The ref of an address: the interface that reports it, or the one the store already uses.
|
|
128
|
+
*
|
|
129
|
+
* The second half matters after a restart with the box unreachable, and for a channel of a
|
|
130
|
+
* device that has just been deleted: the store still has the entry, and a rename of it should
|
|
131
|
+
* go to the same ref rather than to a new one.
|
|
132
|
+
*/
|
|
133
|
+
refFor(address: string): string | undefined;
|
|
134
|
+
/** The version the box answered with, for the settings dialog and the log. */
|
|
135
|
+
get version(): MetaVersion | undefined;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=service.d.ts.map
|