@smarthome.exchange/integrations 1.0.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +84 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/core/classes.configstore.d.ts +2 -0
- package/dist_ts/core/classes.configstore.js +84 -27
- package/dist_ts/core/classes.nativehomeadmission.d.ts +19 -0
- package/dist_ts/core/classes.nativehomeadmission.js +84 -0
- package/dist_ts/core/classes.nativeintegrationowner.d.ts +81 -0
- package/dist_ts/core/classes.nativeintegrationowner.js +273 -0
- package/dist_ts/core/classes.runtimemanager.d.ts +2 -0
- package/dist_ts/core/classes.runtimemanager.js +11 -3
- package/dist_ts/core/index.d.ts +2 -0
- package/dist_ts/core/index.js +3 -1
- package/dist_ts/core/types.d.ts +16 -0
- package/dist_ts/integrations/braviatv/braviatv.classes.client.d.ts +23 -72
- package/dist_ts/integrations/braviatv/braviatv.classes.client.js +265 -625
- package/dist_ts/integrations/braviatv/braviatv.classes.configflow.d.ts +7 -7
- package/dist_ts/integrations/braviatv/braviatv.classes.configflow.js +51 -68
- package/dist_ts/integrations/braviatv/braviatv.classes.integration.d.ts +8 -11
- package/dist_ts/integrations/braviatv/braviatv.classes.integration.js +186 -135
- package/dist_ts/integrations/braviatv/braviatv.discovery.js +12 -11
- package/dist_ts/integrations/braviatv/braviatv.mapper.d.ts +6 -14
- package/dist_ts/integrations/braviatv/braviatv.mapper.js +37 -131
- package/dist_ts/integrations/braviatv/braviatv.types.d.ts +55 -133
- package/dist_ts/integrations/braviatv/braviatv.validation.d.ts +7 -0
- package/dist_ts/integrations/braviatv/braviatv.validation.js +72 -0
- package/dist_ts/integrations/broadlink/broadlink.actions.d.ts +2 -0
- package/dist_ts/integrations/broadlink/broadlink.actions.js +36 -0
- package/dist_ts/integrations/broadlink/broadlink.classes.client.d.ts +21 -19
- package/dist_ts/integrations/broadlink/broadlink.classes.client.js +185 -124
- package/dist_ts/integrations/broadlink/broadlink.classes.configflow.d.ts +5 -4
- package/dist_ts/integrations/broadlink/broadlink.classes.configflow.js +64 -83
- package/dist_ts/integrations/broadlink/broadlink.classes.integration.d.ts +16 -19
- package/dist_ts/integrations/broadlink/broadlink.classes.integration.js +114 -59
- package/dist_ts/integrations/broadlink/broadlink.mapper.d.ts +3 -2
- package/dist_ts/integrations/broadlink/broadlink.mapper.js +2 -1
- package/dist_ts/integrations/broadlink/broadlink.selected.mapper.d.ts +10 -0
- package/dist_ts/integrations/broadlink/broadlink.selected.mapper.js +41 -0
- package/dist_ts/integrations/broadlink/broadlink.types.d.ts +43 -7
- package/dist_ts/integrations/broadlink/broadlink.validation.d.ts +7 -0
- package/dist_ts/integrations/broadlink/broadlink.validation.js +63 -0
- package/dist_ts/integrations/daikin/daikin.classes.client.d.ts +10 -52
- package/dist_ts/integrations/daikin/daikin.classes.client.js +55 -614
- package/dist_ts/integrations/daikin/daikin.classes.configflow.d.ts +8 -12
- package/dist_ts/integrations/daikin/daikin.classes.configflow.js +77 -138
- package/dist_ts/integrations/daikin/daikin.classes.integration.d.ts +7 -24
- package/dist_ts/integrations/daikin/daikin.classes.integration.js +175 -67
- package/dist_ts/integrations/daikin/daikin.discovery.d.ts +11 -24
- package/dist_ts/integrations/daikin/daikin.discovery.js +98 -305
- package/dist_ts/integrations/daikin/daikin.mapper.d.ts +6 -7
- package/dist_ts/integrations/daikin/daikin.mapper.js +95 -155
- package/dist_ts/integrations/daikin/daikin.types.d.ts +24 -44
- package/dist_ts/integrations/daikin/daikin.types.js +1 -1
- package/dist_ts/integrations/daikin/daikin.validation.d.ts +5 -0
- package/dist_ts/integrations/daikin/daikin.validation.js +53 -0
- package/dist_ts/integrations/deconz/deconz.classes.client.d.ts +37 -29
- package/dist_ts/integrations/deconz/deconz.classes.client.js +521 -294
- package/dist_ts/integrations/deconz/deconz.classes.configflow.d.ts +6 -1
- package/dist_ts/integrations/deconz/deconz.classes.configflow.js +63 -33
- package/dist_ts/integrations/deconz/deconz.classes.integration.d.ts +4 -3
- package/dist_ts/integrations/deconz/deconz.classes.integration.js +85 -40
- package/dist_ts/integrations/deconz/deconz.mapper.d.ts +1 -0
- package/dist_ts/integrations/deconz/deconz.mapper.js +24 -6
- package/dist_ts/integrations/deconz/deconz.types.d.ts +43 -6
- package/dist_ts/integrations/deconz/deconz.validation.d.ts +7 -1
- package/dist_ts/integrations/deconz/deconz.validation.js +215 -4
- package/dist_ts/integrations/denonavr/denonavr.classes.client.d.ts +31 -40
- package/dist_ts/integrations/denonavr/denonavr.classes.client.js +149 -404
- package/dist_ts/integrations/denonavr/denonavr.classes.configflow.d.ts +7 -2
- package/dist_ts/integrations/denonavr/denonavr.classes.configflow.js +44 -36
- package/dist_ts/integrations/denonavr/denonavr.classes.integration.d.ts +6 -11
- package/dist_ts/integrations/denonavr/denonavr.classes.integration.js +192 -113
- package/dist_ts/integrations/denonavr/denonavr.discovery.d.ts +10 -18
- package/dist_ts/integrations/denonavr/denonavr.discovery.js +71 -193
- package/dist_ts/integrations/denonavr/denonavr.mapper.d.ts +5 -13
- package/dist_ts/integrations/denonavr/denonavr.mapper.js +35 -159
- package/dist_ts/integrations/denonavr/denonavr.types.d.ts +55 -90
- package/dist_ts/integrations/denonavr/denonavr.validation.d.ts +10 -0
- package/dist_ts/integrations/denonavr/denonavr.validation.js +86 -0
- package/dist_ts/integrations/esphome/esphome.classes.client.d.ts +19 -7
- package/dist_ts/integrations/esphome/esphome.classes.client.js +183 -89
- package/dist_ts/integrations/esphome/esphome.classes.configflow.d.ts +5 -2
- package/dist_ts/integrations/esphome/esphome.classes.configflow.js +43 -33
- package/dist_ts/integrations/esphome/esphome.classes.integration.d.ts +8 -6
- package/dist_ts/integrations/esphome/esphome.classes.integration.js +71 -43
- package/dist_ts/integrations/esphome/esphome.discovery.js +4 -12
- package/dist_ts/integrations/esphome/esphome.mapper.d.ts +2 -2
- package/dist_ts/integrations/esphome/esphome.mapper.js +6 -4
- package/dist_ts/integrations/esphome/esphome.types.d.ts +31 -6
- package/dist_ts/integrations/esphome/esphome.types.js +1 -1
- package/dist_ts/integrations/esphome/esphome.validation.d.ts +7 -0
- package/dist_ts/integrations/esphome/esphome.validation.js +66 -0
- package/dist_ts/integrations/homeassistant/homeassistant.classes.client.d.ts +32 -4
- package/dist_ts/integrations/homeassistant/homeassistant.classes.client.js +345 -116
- package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.d.ts +8 -5
- package/dist_ts/integrations/homeassistant/homeassistant.classes.integration.js +34 -8
- package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.d.ts +7 -4
- package/dist_ts/integrations/homeassistant/homeassistant.classes.runtime.js +44 -56
- package/dist_ts/integrations/homeassistant/homeassistant.types.d.ts +12 -1
- package/dist_ts/integrations/hue/hue.classes.client.d.ts +6 -1
- package/dist_ts/integrations/hue/hue.classes.client.js +120 -45
- package/dist_ts/integrations/hue/hue.classes.configflow.js +16 -7
- package/dist_ts/integrations/hue/hue.classes.integration.d.ts +2 -0
- package/dist_ts/integrations/hue/hue.classes.integration.js +103 -30
- package/dist_ts/integrations/hue/hue.validation.d.ts +1 -0
- package/dist_ts/integrations/hue/hue.validation.js +14 -4
- package/dist_ts/integrations/kodi/kodi.classes.client.d.ts +11 -45
- package/dist_ts/integrations/kodi/kodi.classes.client.js +84 -310
- package/dist_ts/integrations/kodi/kodi.classes.configflow.d.ts +9 -8
- package/dist_ts/integrations/kodi/kodi.classes.configflow.js +53 -48
- package/dist_ts/integrations/kodi/kodi.classes.integration.d.ts +11 -11
- package/dist_ts/integrations/kodi/kodi.classes.integration.js +114 -171
- package/dist_ts/integrations/kodi/kodi.discovery.js +53 -29
- package/dist_ts/integrations/kodi/kodi.mapper.d.ts +7 -2
- package/dist_ts/integrations/kodi/kodi.mapper.js +48 -10
- package/dist_ts/integrations/kodi/kodi.types.d.ts +32 -28
- package/dist_ts/integrations/kodi/kodi.validation.d.ts +9 -0
- package/dist_ts/integrations/kodi/kodi.validation.js +62 -0
- package/dist_ts/integrations/modbus/modbus.classes.client.d.ts +15 -61
- package/dist_ts/integrations/modbus/modbus.classes.client.js +117 -776
- package/dist_ts/integrations/modbus/modbus.classes.configflow.d.ts +9 -5
- package/dist_ts/integrations/modbus/modbus.classes.configflow.js +70 -38
- package/dist_ts/integrations/modbus/modbus.classes.integration.d.ts +6 -17
- package/dist_ts/integrations/modbus/modbus.classes.integration.js +133 -57
- package/dist_ts/integrations/modbus/modbus.discovery.d.ts +5 -8
- package/dist_ts/integrations/modbus/modbus.discovery.js +38 -93
- package/dist_ts/integrations/modbus/modbus.mapper.d.ts +8 -32
- package/dist_ts/integrations/modbus/modbus.mapper.js +71 -431
- package/dist_ts/integrations/modbus/modbus.types.d.ts +82 -332
- package/dist_ts/integrations/modbus/modbus.validation.d.ts +10 -0
- package/dist_ts/integrations/modbus/modbus.validation.js +128 -0
- package/dist_ts/integrations/mqtt/mqtt.classes.client.d.ts +15 -2
- package/dist_ts/integrations/mqtt/mqtt.classes.client.js +173 -23
- package/dist_ts/integrations/mqtt/mqtt.classes.configflow.d.ts +5 -1
- package/dist_ts/integrations/mqtt/mqtt.classes.configflow.js +53 -33
- package/dist_ts/integrations/mqtt/mqtt.classes.integration.d.ts +4 -1
- package/dist_ts/integrations/mqtt/mqtt.classes.integration.js +127 -56
- package/dist_ts/integrations/mqtt/mqtt.classes.session.d.ts +13 -0
- package/dist_ts/integrations/mqtt/mqtt.classes.session.js +130 -0
- package/dist_ts/integrations/mqtt/mqtt.mapper.d.ts +3 -0
- package/dist_ts/integrations/mqtt/mqtt.mapper.js +44 -1
- package/dist_ts/integrations/mqtt/mqtt.types.d.ts +46 -0
- package/dist_ts/integrations/mqtt/mqtt.validation.d.ts +7 -0
- package/dist_ts/integrations/mqtt/mqtt.validation.js +180 -0
- package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.d.ts +12 -34
- package/dist_ts/integrations/nanoleaf/nanoleaf.classes.client.js +143 -231
- package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.d.ts +6 -1
- package/dist_ts/integrations/nanoleaf/nanoleaf.classes.configflow.js +105 -18
- package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.d.ts +8 -8
- package/dist_ts/integrations/nanoleaf/nanoleaf.classes.integration.js +141 -155
- package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.d.ts +9 -0
- package/dist_ts/integrations/nanoleaf/nanoleaf.credentials.js +35 -0
- package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.d.ts +6 -18
- package/dist_ts/integrations/nanoleaf/nanoleaf.mapper.js +45 -220
- package/dist_ts/integrations/nanoleaf/nanoleaf.types.d.ts +33 -147
- package/dist_ts/integrations/nanoleaf/nanoleaf.validation.d.ts +6 -0
- package/dist_ts/integrations/nanoleaf/nanoleaf.validation.js +82 -0
- package/dist_ts/integrations/onkyo/onkyo.classes.client.d.ts +15 -20
- package/dist_ts/integrations/onkyo/onkyo.classes.client.js +161 -404
- package/dist_ts/integrations/onkyo/onkyo.classes.configflow.d.ts +9 -4
- package/dist_ts/integrations/onkyo/onkyo.classes.configflow.js +51 -6
- package/dist_ts/integrations/onkyo/onkyo.classes.integration.d.ts +22 -6
- package/dist_ts/integrations/onkyo/onkyo.classes.integration.js +144 -11
- package/dist_ts/integrations/onkyo/onkyo.discovery.d.ts +6 -1
- package/dist_ts/integrations/onkyo/onkyo.discovery.js +40 -4
- package/dist_ts/integrations/onkyo/onkyo.mapper.d.ts +7 -8
- package/dist_ts/integrations/onkyo/onkyo.mapper.js +45 -12
- package/dist_ts/integrations/onkyo/onkyo.types.d.ts +58 -8
- package/dist_ts/integrations/onkyo/onkyo.types.js +13 -102
- package/dist_ts/integrations/onkyo/onkyo.validation.d.ts +16 -0
- package/dist_ts/integrations/onkyo/onkyo.validation.js +77 -0
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.d.ts +25 -25
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.client.js +116 -360
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.d.ts +11 -3
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.js +76 -6
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.d.ts +26 -4
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.classes.integration.js +142 -9
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.d.ts +2 -1
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.discovery.js +31 -4
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.d.ts +9 -9
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.mapper.js +31 -149
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.d.ts +51 -11
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.types.js +22 -87
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.d.ts +6 -0
- package/dist_ts/integrations/panasonic_viera/panasonic_viera.validation.js +56 -0
- package/dist_ts/integrations/pioneer/pioneer.classes.client.d.ts +31 -16
- package/dist_ts/integrations/pioneer/pioneer.classes.client.js +167 -409
- package/dist_ts/integrations/pioneer/pioneer.classes.configflow.d.ts +10 -3
- package/dist_ts/integrations/pioneer/pioneer.classes.configflow.js +66 -6
- package/dist_ts/integrations/pioneer/pioneer.classes.integration.d.ts +13 -5
- package/dist_ts/integrations/pioneer/pioneer.classes.integration.js +239 -11
- package/dist_ts/integrations/pioneer/pioneer.discovery.d.ts +14 -1
- package/dist_ts/integrations/pioneer/pioneer.discovery.js +51 -4
- package/dist_ts/integrations/pioneer/pioneer.mapper.d.ts +14 -8
- package/dist_ts/integrations/pioneer/pioneer.mapper.js +54 -12
- package/dist_ts/integrations/pioneer/pioneer.types.d.ts +79 -12
- package/dist_ts/integrations/pioneer/pioneer.types.js +12 -76
- package/dist_ts/integrations/pioneer/pioneer.validation.d.ts +10 -0
- package/dist_ts/integrations/pioneer/pioneer.validation.js +85 -0
- package/dist_ts/integrations/samsungtv/samsungtv.classes.client.d.ts +4 -2
- package/dist_ts/integrations/samsungtv/samsungtv.classes.client.js +41 -16
- package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.d.ts +5 -0
- package/dist_ts/integrations/samsungtv/samsungtv.classes.configflow.js +20 -7
- package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.d.ts +1 -0
- package/dist_ts/integrations/samsungtv/samsungtv.classes.integration.js +53 -50
- package/dist_ts/integrations/samsungtv/samsungtv.types.d.ts +4 -1
- package/dist_ts/integrations/shelly/shelly.classes.client.d.ts +26 -30
- package/dist_ts/integrations/shelly/shelly.classes.client.js +504 -276
- package/dist_ts/integrations/shelly/shelly.classes.configflow.d.ts +8 -3
- package/dist_ts/integrations/shelly/shelly.classes.configflow.js +43 -38
- package/dist_ts/integrations/shelly/shelly.classes.integration.d.ts +6 -6
- package/dist_ts/integrations/shelly/shelly.classes.integration.js +103 -101
- package/dist_ts/integrations/shelly/shelly.classes.subscription.d.ts +4 -0
- package/dist_ts/integrations/shelly/shelly.classes.subscription.js +24 -2
- package/dist_ts/integrations/shelly/shelly.mapper.d.ts +1 -2
- package/dist_ts/integrations/shelly/shelly.mapper.js +21 -20
- package/dist_ts/integrations/shelly/shelly.rpc.js +4 -1
- package/dist_ts/integrations/shelly/shelly.types.d.ts +42 -2
- package/dist_ts/integrations/shelly/shelly.types.js +11 -2
- package/dist_ts/integrations/shelly/shelly.validation.d.ts +7 -0
- package/dist_ts/integrations/shelly/shelly.validation.js +79 -0
- package/dist_ts/integrations/sonos/sonos.classes.client.d.ts +79 -22
- package/dist_ts/integrations/sonos/sonos.classes.client.js +427 -139
- package/dist_ts/integrations/sonos/sonos.classes.configflow.d.ts +9 -2
- package/dist_ts/integrations/sonos/sonos.classes.configflow.js +26 -28
- package/dist_ts/integrations/sonos/sonos.classes.integration.d.ts +7 -6
- package/dist_ts/integrations/sonos/sonos.classes.integration.js +289 -224
- package/dist_ts/integrations/sonos/sonos.config.d.ts +6 -1
- package/dist_ts/integrations/sonos/sonos.config.js +23 -2
- package/dist_ts/integrations/sonos/sonos.mapper.d.ts +1 -1
- package/dist_ts/integrations/sonos/sonos.mapper.js +14 -9
- package/dist_ts/integrations/sonos/sonos.matchers.js +3 -3
- package/dist_ts/integrations/sonos/sonos.types.d.ts +26 -1
- package/dist_ts/integrations/soundtouch/soundtouch.classes.client.d.ts +13 -36
- package/dist_ts/integrations/soundtouch/soundtouch.classes.client.js +179 -502
- package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.d.ts +6 -1
- package/dist_ts/integrations/soundtouch/soundtouch.classes.configflow.js +50 -40
- package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.d.ts +14 -15
- package/dist_ts/integrations/soundtouch/soundtouch.classes.integration.js +108 -128
- package/dist_ts/integrations/soundtouch/soundtouch.discovery.d.ts +2 -20
- package/dist_ts/integrations/soundtouch/soundtouch.discovery.js +23 -113
- package/dist_ts/integrations/soundtouch/soundtouch.mapper.d.ts +3 -12
- package/dist_ts/integrations/soundtouch/soundtouch.mapper.js +35 -189
- package/dist_ts/integrations/soundtouch/soundtouch.types.d.ts +57 -142
- package/dist_ts/integrations/soundtouch/soundtouch.types.js +18 -3
- package/dist_ts/integrations/soundtouch/soundtouch.validation.d.ts +22 -0
- package/dist_ts/integrations/soundtouch/soundtouch.validation.js +65 -0
- package/dist_ts/integrations/tasmota/tasmota.classes.integration.d.ts +5 -0
- package/dist_ts/integrations/tasmota/tasmota.classes.integration.js +23 -7
- package/dist_ts/integrations/tasmota/tasmota.classes.runtime.d.ts +19 -5
- package/dist_ts/integrations/tasmota/tasmota.classes.runtime.js +115 -41
- package/dist_ts/integrations/tasmota/tasmota.config.js +23 -1
- package/dist_ts/integrations/tasmota/tasmota.credentials.d.ts +11 -0
- package/dist_ts/integrations/tasmota/tasmota.credentials.js +97 -0
- package/dist_ts/integrations/tasmota/tasmota.discovery.d.ts +7 -1
- package/dist_ts/integrations/tasmota/tasmota.discovery.js +108 -30
- package/dist_ts/integrations/tasmota/tasmota.mapper.d.ts +2 -2
- package/dist_ts/integrations/tasmota/tasmota.mapper.js +7 -7
- package/dist_ts/integrations/tasmota/tasmota.types.d.ts +41 -2
- package/dist_ts/integrations/tuya/tuya.classes.integration.d.ts +4 -1
- package/dist_ts/integrations/tuya/tuya.classes.integration.js +79 -110
- package/dist_ts/integrations/tuya/tuya.classes.runtime.d.ts +5 -2
- package/dist_ts/integrations/tuya/tuya.classes.runtime.js +73 -26
- package/dist_ts/integrations/tuya/tuya.mapper.js +2 -2
- package/dist_ts/integrations/tuya/tuya.types.d.ts +3 -0
- package/dist_ts/integrations/tuya/tuya.validation.d.ts +2 -2
- package/dist_ts/integrations/tuya/tuya.validation.js +6 -11
- package/dist_ts/integrations/webostv/webostv.classes.client.d.ts +6 -5
- package/dist_ts/integrations/webostv/webostv.classes.client.js +147 -76
- package/dist_ts/integrations/webostv/webostv.classes.configflow.d.ts +7 -2
- package/dist_ts/integrations/webostv/webostv.classes.configflow.js +36 -20
- package/dist_ts/integrations/webostv/webostv.classes.integration.d.ts +4 -4
- package/dist_ts/integrations/webostv/webostv.classes.integration.js +46 -54
- package/dist_ts/integrations/webostv/webostv.mapper.js +5 -5
- package/dist_ts/integrations/webostv/webostv.types.d.ts +16 -3
- package/dist_ts/integrations/webostv/webostv.types.js +1 -1
- package/dist_ts/integrations/webostv/webostv.validation.d.ts +3 -1
- package/dist_ts/integrations/webostv/webostv.validation.js +23 -1
- package/dist_ts/integrations/wiz/index.d.ts +1 -0
- package/dist_ts/integrations/wiz/index.js +2 -1
- package/dist_ts/integrations/wiz/wiz.classes.client.d.ts +14 -28
- package/dist_ts/integrations/wiz/wiz.classes.client.js +93 -229
- package/dist_ts/integrations/wiz/wiz.classes.configflow.d.ts +6 -4
- package/dist_ts/integrations/wiz/wiz.classes.configflow.js +38 -67
- package/dist_ts/integrations/wiz/wiz.classes.integration.d.ts +10 -21
- package/dist_ts/integrations/wiz/wiz.classes.integration.js +204 -44
- package/dist_ts/integrations/wiz/wiz.discovery.d.ts +10 -31
- package/dist_ts/integrations/wiz/wiz.discovery.js +48 -249
- package/dist_ts/integrations/wiz/wiz.mapper.d.ts +7 -51
- package/dist_ts/integrations/wiz/wiz.mapper.js +82 -668
- package/dist_ts/integrations/wiz/wiz.types.d.ts +34 -208
- package/dist_ts/integrations/wiz/wiz.validation.d.ts +8 -0
- package/dist_ts/integrations/wiz/wiz.validation.js +72 -0
- package/dist_ts/integrations/yamaha/index.d.ts +1 -0
- package/dist_ts/integrations/yamaha/index.js +2 -1
- package/dist_ts/integrations/yamaha/yamaha.classes.client.d.ts +30 -4
- package/dist_ts/integrations/yamaha/yamaha.classes.client.js +162 -6
- package/dist_ts/integrations/yamaha/yamaha.classes.configflow.d.ts +10 -3
- package/dist_ts/integrations/yamaha/yamaha.classes.configflow.js +106 -6
- package/dist_ts/integrations/yamaha/yamaha.classes.integration.d.ts +22 -4
- package/dist_ts/integrations/yamaha/yamaha.classes.integration.js +243 -8
- package/dist_ts/integrations/yamaha/yamaha.discovery.d.ts +13 -1
- package/dist_ts/integrations/yamaha/yamaha.discovery.js +57 -4
- package/dist_ts/integrations/yamaha/yamaha.mapper.d.ts +16 -8
- package/dist_ts/integrations/yamaha/yamaha.mapper.js +58 -12
- package/dist_ts/integrations/yamaha/yamaha.types.d.ts +73 -6
- package/dist_ts/integrations/yamaha/yamaha.types.js +8 -94
- package/dist_ts/integrations/yamaha/yamaha.validation.d.ts +12 -0
- package/dist_ts/integrations/yamaha/yamaha.validation.js +89 -0
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.d.ts +6 -1
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.js +18 -8
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.d.ts +4 -1
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.js +54 -6
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.d.ts +12 -6
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.js +73 -59
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.d.ts +3 -2
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.js +17 -12
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.types.d.ts +31 -2
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.d.ts +9 -1
- package/dist_ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.js +57 -7
- package/dist_ts/integrations/zwave_js/zwave_js.classes.client.d.ts +10 -4
- package/dist_ts/integrations/zwave_js/zwave_js.classes.client.js +167 -31
- package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.d.ts +6 -1
- package/dist_ts/integrations/zwave_js/zwave_js.classes.configflow.js +57 -35
- package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.d.ts +3 -1
- package/dist_ts/integrations/zwave_js/zwave_js.classes.integration.js +59 -37
- package/dist_ts/integrations/zwave_js/zwave_js.discovery.js +3 -3
- package/dist_ts/integrations/zwave_js/zwave_js.mapper.js +41 -24
- package/dist_ts/integrations/zwave_js/zwave_js.types.d.ts +25 -3
- package/dist_ts/integrations/zwave_js/zwave_js.validation.d.ts +6 -2
- package/dist_ts/integrations/zwave_js/zwave_js.validation.js +52 -17
- package/dist_ts/plugins.d.ts +2 -1
- package/dist_ts/plugins.js +3 -2
- package/package.json +9 -9
- package/readme.md +539 -8
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/core/classes.configstore.ts +84 -27
- package/ts/core/classes.nativehomeadmission.ts +96 -0
- package/ts/core/classes.nativeintegrationowner.ts +302 -0
- package/ts/core/classes.runtimemanager.ts +11 -2
- package/ts/core/index.ts +2 -0
- package/ts/core/types.ts +18 -0
- package/ts/integrations/braviatv/braviatv.classes.client.ts +245 -709
- package/ts/integrations/braviatv/braviatv.classes.configflow.ts +47 -76
- package/ts/integrations/braviatv/braviatv.classes.integration.ts +167 -147
- package/ts/integrations/braviatv/braviatv.discovery.ts +11 -10
- package/ts/integrations/braviatv/braviatv.mapper.ts +39 -142
- package/ts/integrations/braviatv/braviatv.types.ts +53 -173
- package/ts/integrations/braviatv/braviatv.validation.ts +68 -0
- package/ts/integrations/broadlink/broadlink.actions.ts +31 -0
- package/ts/integrations/broadlink/broadlink.classes.client.ts +170 -144
- package/ts/integrations/broadlink/broadlink.classes.configflow.ts +59 -89
- package/ts/integrations/broadlink/broadlink.classes.integration.ts +110 -64
- package/ts/integrations/broadlink/broadlink.mapper.ts +5 -4
- package/ts/integrations/broadlink/broadlink.selected.mapper.ts +46 -0
- package/ts/integrations/broadlink/broadlink.types.ts +48 -8
- package/ts/integrations/broadlink/broadlink.validation.ts +66 -0
- package/ts/integrations/daikin/daikin.classes.client.ts +52 -661
- package/ts/integrations/daikin/daikin.classes.configflow.ts +72 -152
- package/ts/integrations/daikin/daikin.classes.integration.ts +166 -71
- package/ts/integrations/daikin/daikin.discovery.ts +94 -346
- package/ts/integrations/daikin/daikin.mapper.ts +83 -166
- package/ts/integrations/daikin/daikin.types.ts +27 -48
- package/ts/integrations/daikin/daikin.validation.ts +51 -0
- package/ts/integrations/daikin/readme.md +83 -0
- package/ts/integrations/deconz/deconz.classes.client.ts +348 -252
- package/ts/integrations/deconz/deconz.classes.configflow.ts +57 -29
- package/ts/integrations/deconz/deconz.classes.integration.ts +69 -37
- package/ts/integrations/deconz/deconz.mapper.ts +22 -5
- package/ts/integrations/deconz/deconz.types.ts +49 -6
- package/ts/integrations/deconz/deconz.validation.ts +177 -4
- package/ts/integrations/deconz/readme.md +15 -1
- package/ts/integrations/denonavr/denonavr.classes.client.ts +132 -421
- package/ts/integrations/denonavr/denonavr.classes.configflow.ts +44 -37
- package/ts/integrations/denonavr/denonavr.classes.integration.ts +171 -117
- package/ts/integrations/denonavr/denonavr.discovery.ts +67 -220
- package/ts/integrations/denonavr/denonavr.mapper.ts +36 -182
- package/ts/integrations/denonavr/denonavr.types.ts +48 -111
- package/ts/integrations/denonavr/denonavr.validation.ts +87 -0
- package/ts/integrations/esphome/esphome.classes.client.ts +179 -94
- package/ts/integrations/esphome/esphome.classes.configflow.ts +40 -33
- package/ts/integrations/esphome/esphome.classes.integration.ts +63 -36
- package/ts/integrations/esphome/esphome.discovery.ts +3 -12
- package/ts/integrations/esphome/esphome.mapper.ts +9 -7
- package/ts/integrations/esphome/esphome.types.ts +35 -6
- package/ts/integrations/esphome/esphome.validation.ts +66 -0
- package/ts/integrations/esphome/readme.md +20 -6
- package/ts/integrations/homeassistant/homeassistant.classes.client.ts +353 -125
- package/ts/integrations/homeassistant/homeassistant.classes.integration.ts +35 -18
- package/ts/integrations/homeassistant/homeassistant.classes.runtime.ts +50 -63
- package/ts/integrations/homeassistant/homeassistant.types.ts +17 -1
- package/ts/integrations/homeassistant/readme.md +22 -6
- package/ts/integrations/hue/hue.classes.client.ts +110 -41
- package/ts/integrations/hue/hue.classes.configflow.ts +12 -6
- package/ts/integrations/hue/hue.classes.integration.ts +92 -26
- package/ts/integrations/hue/hue.validation.ts +13 -3
- package/ts/integrations/hue/readme.md +3 -3
- package/ts/integrations/kodi/kodi.classes.client.ts +72 -352
- package/ts/integrations/kodi/kodi.classes.configflow.ts +52 -55
- package/ts/integrations/kodi/kodi.classes.integration.ts +97 -178
- package/ts/integrations/kodi/kodi.discovery.ts +49 -28
- package/ts/integrations/kodi/kodi.mapper.ts +52 -10
- package/ts/integrations/kodi/kodi.types.ts +33 -58
- package/ts/integrations/kodi/kodi.validation.ts +60 -0
- package/ts/integrations/modbus/modbus.classes.client.ts +100 -842
- package/ts/integrations/modbus/modbus.classes.configflow.ts +70 -41
- package/ts/integrations/modbus/modbus.classes.integration.ts +115 -60
- package/ts/integrations/modbus/modbus.discovery.ts +38 -106
- package/ts/integrations/modbus/modbus.mapper.ts +64 -467
- package/ts/integrations/modbus/modbus.types.ts +64 -381
- package/ts/integrations/modbus/modbus.validation.ts +119 -0
- package/ts/integrations/mqtt/mqtt.classes.client.ts +136 -19
- package/ts/integrations/mqtt/mqtt.classes.configflow.ts +45 -32
- package/ts/integrations/mqtt/mqtt.classes.integration.ts +99 -38
- package/ts/integrations/mqtt/mqtt.classes.session.ts +118 -0
- package/ts/integrations/mqtt/mqtt.mapper.ts +43 -1
- package/ts/integrations/mqtt/mqtt.types.ts +52 -0
- package/ts/integrations/mqtt/mqtt.validation.ts +157 -0
- package/ts/integrations/mqtt/readme.md +12 -3
- package/ts/integrations/nanoleaf/nanoleaf.classes.client.ts +115 -249
- package/ts/integrations/nanoleaf/nanoleaf.classes.configflow.ts +90 -19
- package/ts/integrations/nanoleaf/nanoleaf.classes.integration.ts +130 -181
- package/ts/integrations/nanoleaf/nanoleaf.credentials.ts +39 -0
- package/ts/integrations/nanoleaf/nanoleaf.mapper.ts +47 -260
- package/ts/integrations/nanoleaf/nanoleaf.types.ts +29 -147
- package/ts/integrations/nanoleaf/nanoleaf.validation.ts +77 -0
- package/ts/integrations/onkyo/onkyo.classes.client.ts +148 -457
- package/ts/integrations/onkyo/onkyo.classes.configflow.ts +52 -6
- package/ts/integrations/onkyo/onkyo.classes.integration.ts +121 -12
- package/ts/integrations/onkyo/onkyo.discovery.ts +41 -3
- package/ts/integrations/onkyo/onkyo.mapper.ts +46 -19
- package/ts/integrations/onkyo/onkyo.types.ts +55 -110
- package/ts/integrations/onkyo/onkyo.validation.ts +85 -0
- package/ts/integrations/onkyo/readme.md +126 -0
- package/ts/integrations/panasonic_viera/panasonic_viera.classes.client.ts +101 -398
- package/ts/integrations/panasonic_viera/panasonic_viera.classes.configflow.ts +69 -5
- package/ts/integrations/panasonic_viera/panasonic_viera.classes.integration.ts +141 -9
- package/ts/integrations/panasonic_viera/panasonic_viera.discovery.ts +32 -3
- package/ts/integrations/panasonic_viera/panasonic_viera.mapper.ts +34 -161
- package/ts/integrations/panasonic_viera/panasonic_viera.types.ts +52 -96
- package/ts/integrations/panasonic_viera/panasonic_viera.validation.ts +56 -0
- package/ts/integrations/pioneer/pioneer.classes.client.ts +132 -428
- package/ts/integrations/pioneer/pioneer.classes.configflow.ts +67 -5
- package/ts/integrations/pioneer/pioneer.classes.integration.ts +225 -11
- package/ts/integrations/pioneer/pioneer.discovery.ts +45 -3
- package/ts/integrations/pioneer/pioneer.mapper.ts +57 -13
- package/ts/integrations/pioneer/pioneer.types.ts +87 -85
- package/ts/integrations/pioneer/pioneer.validation.ts +84 -0
- package/ts/integrations/samsungtv/readme.md +11 -5
- package/ts/integrations/samsungtv/samsungtv.classes.client.ts +40 -15
- package/ts/integrations/samsungtv/samsungtv.classes.configflow.ts +21 -6
- package/ts/integrations/samsungtv/samsungtv.classes.integration.ts +53 -38
- package/ts/integrations/samsungtv/samsungtv.types.ts +4 -1
- package/ts/integrations/shelly/readme.md +22 -7
- package/ts/integrations/shelly/shelly.classes.client.ts +386 -269
- package/ts/integrations/shelly/shelly.classes.configflow.ts +43 -38
- package/ts/integrations/shelly/shelly.classes.integration.ts +92 -111
- package/ts/integrations/shelly/shelly.classes.subscription.ts +24 -1
- package/ts/integrations/shelly/shelly.mapper.ts +19 -20
- package/ts/integrations/shelly/shelly.rpc.ts +2 -0
- package/ts/integrations/shelly/shelly.types.ts +50 -2
- package/ts/integrations/shelly/shelly.validation.ts +76 -0
- package/ts/integrations/sonos/readme.md +117 -38
- package/ts/integrations/sonos/sonos.classes.client.ts +392 -123
- package/ts/integrations/sonos/sonos.classes.configflow.ts +25 -28
- package/ts/integrations/sonos/sonos.classes.integration.ts +211 -186
- package/ts/integrations/sonos/sonos.config.ts +24 -2
- package/ts/integrations/sonos/sonos.mapper.ts +13 -8
- package/ts/integrations/sonos/sonos.matchers.ts +2 -2
- package/ts/integrations/sonos/sonos.types.ts +30 -1
- package/ts/integrations/soundtouch/soundtouch.classes.client.ts +152 -571
- package/ts/integrations/soundtouch/soundtouch.classes.configflow.ts +47 -42
- package/ts/integrations/soundtouch/soundtouch.classes.integration.ts +95 -150
- package/ts/integrations/soundtouch/soundtouch.discovery.ts +21 -133
- package/ts/integrations/soundtouch/soundtouch.mapper.ts +36 -207
- package/ts/integrations/soundtouch/soundtouch.types.ts +50 -195
- package/ts/integrations/soundtouch/soundtouch.validation.ts +60 -0
- package/ts/integrations/tasmota/readme.md +16 -5
- package/ts/integrations/tasmota/tasmota.classes.integration.ts +24 -6
- package/ts/integrations/tasmota/tasmota.classes.runtime.ts +112 -43
- package/ts/integrations/tasmota/tasmota.config.ts +17 -0
- package/ts/integrations/tasmota/tasmota.credentials.ts +92 -0
- package/ts/integrations/tasmota/tasmota.discovery.ts +87 -24
- package/ts/integrations/tasmota/tasmota.mapper.ts +6 -6
- package/ts/integrations/tasmota/tasmota.types.ts +43 -2
- package/ts/integrations/tuya/readme.md +52 -10
- package/ts/integrations/tuya/tuya.classes.integration.ts +69 -98
- package/ts/integrations/tuya/tuya.classes.runtime.ts +70 -24
- package/ts/integrations/tuya/tuya.mapper.ts +1 -1
- package/ts/integrations/tuya/tuya.types.ts +4 -0
- package/ts/integrations/tuya/tuya.validation.ts +5 -8
- package/ts/integrations/webostv/readme.md +115 -22
- package/ts/integrations/webostv/webostv.classes.client.ts +123 -50
- package/ts/integrations/webostv/webostv.classes.configflow.ts +35 -15
- package/ts/integrations/webostv/webostv.classes.integration.ts +44 -37
- package/ts/integrations/webostv/webostv.mapper.ts +4 -4
- package/ts/integrations/webostv/webostv.types.ts +18 -3
- package/ts/integrations/webostv/webostv.validation.ts +22 -1
- package/ts/integrations/wiz/index.ts +1 -0
- package/ts/integrations/wiz/wiz.classes.client.ts +84 -254
- package/ts/integrations/wiz/wiz.classes.configflow.ts +39 -70
- package/ts/integrations/wiz/wiz.classes.integration.ts +189 -45
- package/ts/integrations/wiz/wiz.discovery.ts +48 -291
- package/ts/integrations/wiz/wiz.mapper.ts +81 -754
- package/ts/integrations/wiz/wiz.types.ts +24 -224
- package/ts/integrations/wiz/wiz.validation.ts +73 -0
- package/ts/integrations/yamaha/index.ts +1 -0
- package/ts/integrations/yamaha/yamaha.classes.client.ts +150 -6
- package/ts/integrations/yamaha/yamaha.classes.configflow.ts +100 -5
- package/ts/integrations/yamaha/yamaha.classes.integration.ts +236 -8
- package/ts/integrations/yamaha/yamaha.discovery.ts +52 -3
- package/ts/integrations/yamaha/yamaha.mapper.ts +65 -13
- package/ts/integrations/yamaha/yamaha.types.ts +77 -97
- package/ts/integrations/yamaha/yamaha.validation.ts +86 -0
- package/ts/integrations/zigbee2mqtt/readme.md +22 -27
- package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.configflow.ts +16 -7
- package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.integration.ts +53 -6
- package/ts/integrations/zigbee2mqtt/zigbee2mqtt.classes.runtime.ts +62 -49
- package/ts/integrations/zigbee2mqtt/zigbee2mqtt.mapper.ts +17 -11
- package/ts/integrations/zigbee2mqtt/zigbee2mqtt.types.ts +35 -2
- package/ts/integrations/zigbee2mqtt/zigbee2mqtt.validation.ts +53 -7
- package/ts/integrations/zwave_js/readme.md +42 -9
- package/ts/integrations/zwave_js/zwave_js.classes.client.ts +155 -31
- package/ts/integrations/zwave_js/zwave_js.classes.configflow.ts +55 -31
- package/ts/integrations/zwave_js/zwave_js.classes.integration.ts +57 -35
- package/ts/integrations/zwave_js/zwave_js.discovery.ts +2 -2
- package/ts/integrations/zwave_js/zwave_js.mapper.ts +37 -23
- package/ts/integrations/zwave_js/zwave_js.types.ts +26 -3
- package/ts/integrations/zwave_js/zwave_js.validation.ts +52 -18
- package/ts/plugins.ts +2 -1
|
@@ -1,35 +1,69 @@
|
|
|
1
|
-
#
|
|
1
|
+
# LG webOS TV
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The native runtime pairs with a verified TV through its SSAP WebSocket endpoint,
|
|
4
|
+
stores pairing keys encrypted in the host's database, and observes power, volume,
|
|
5
|
+
mute, foreground application and external inputs through authoritative subscriptions.
|
|
6
|
+
It uses the installed `ws` transport and requires no Home Assistant server.
|
|
7
|
+
`HomeAssistantWebostvIntegration` remains an exported constructor alias.
|
|
4
8
|
|
|
5
9
|
```typescript
|
|
6
|
-
const integration = new WebostvIntegration({
|
|
10
|
+
const integration = new WebostvIntegration({
|
|
11
|
+
db,
|
|
12
|
+
keyProvider,
|
|
13
|
+
allowedCommands: ['volume_set', 'volume_mute'],
|
|
14
|
+
});
|
|
7
15
|
const runtime = await integration.setup({
|
|
8
|
-
homeId: 'home
|
|
9
|
-
endpoint: 'wss://
|
|
16
|
+
homeId: 'home:example',
|
|
17
|
+
endpoint: 'wss://tv.example:3001/',
|
|
10
18
|
expectedDeviceUUID: verifiedDeviceUUID,
|
|
11
19
|
pairingMode: 'prompt',
|
|
12
|
-
certificateAuthority:
|
|
13
|
-
}, {});
|
|
14
|
-
|
|
15
|
-
await runtime.
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
certificateAuthority: ownerCertificateChain,
|
|
21
|
+
}, { homeId: 'home:example', abortSignal });
|
|
22
|
+
|
|
23
|
+
const [device] = await runtime.devices();
|
|
24
|
+
const result = await runtime.callService!({
|
|
25
|
+
domain: 'webostv',
|
|
26
|
+
service: 'volume_set',
|
|
27
|
+
target: { deviceId: device.id },
|
|
28
|
+
data: { volume: 25 },
|
|
18
29
|
});
|
|
19
30
|
await integration.destroy();
|
|
20
31
|
```
|
|
21
32
|
|
|
22
|
-
The
|
|
33
|
+
The host independently selects `context.homeId`. The integration binds that home
|
|
34
|
+
once, including through config flow and failed setup. An optional constructor
|
|
35
|
+
`homeId` constrains the selected context. Configuration, discovery, form values
|
|
36
|
+
and database scope cannot select a home or grant control. Config flow captures
|
|
37
|
+
the selected home and rejects submitted home fields. Its forms stop accepting
|
|
38
|
+
submissions after flow close or integration destruction.
|
|
23
39
|
|
|
24
|
-
The
|
|
40
|
+
The exported client has the same host boundary:
|
|
41
|
+
`new WebostvClient(config, { homeId, abortSignal }, options)`. Construction performs
|
|
42
|
+
no pairing, provider calls or transport I/O. Setup requires either constructor
|
|
43
|
+
`db` and `keyProvider` together, or an actual `NoSqlConfigStore` in the context
|
|
44
|
+
with the exact selected home and `webostv` domain. Scope checks call the genuine
|
|
45
|
+
store implementation; overriding `getScope` cannot grant ownership. Context
|
|
46
|
+
stores, databases and key providers remain caller-owned.
|
|
47
|
+
The provider supplies 32-byte keys through `currentKey(signal)` and
|
|
48
|
+
`keyForId(id, signal)`. A correctly scoped context store takes precedence over
|
|
49
|
+
constructor persistence; an invalid supplied store fails without falling back.
|
|
25
50
|
|
|
26
|
-
|
|
51
|
+
Every effect defaults to denied. The host supplies a copied, immutable
|
|
52
|
+
`allowedCommands` list in constructor options. The supported exact values are
|
|
53
|
+
`turn_on`, `turn_off`, `volume_set`, `volume_up`, `volume_down`, `volume_mute`,
|
|
54
|
+
`select_source`, `media_play`, `media_pause` and `media_stop`. Unknown, duplicate,
|
|
55
|
+
sparse or accessor-bearing lists are rejected. Saved configuration and form
|
|
56
|
+
values cannot set permissions. Volume and mute features are writable only while
|
|
57
|
+
connected and explicitly authorized. Service targets and feature writes must
|
|
58
|
+
refer to this runtime's home-prefixed device and media-player entity; input
|
|
59
|
+
selection requires an advertised input ID. Deep-standby wake-on-LAN and
|
|
60
|
+
next/previous track controls are unsupported.
|
|
27
61
|
|
|
28
|
-
|
|
62
|
+
Services accept the `webostv` or `media_player` domain with these exact arguments:
|
|
29
63
|
|
|
30
|
-
| Service |
|
|
64
|
+
| Service | Data | SSAP endpoint |
|
|
31
65
|
| --- | --- | --- |
|
|
32
|
-
| `status`, `snapshot` | none | Last authoritative subscribed state
|
|
66
|
+
| `status`, `snapshot` | none | Last authoritative subscribed state and current availability |
|
|
33
67
|
| `volume_set` | `{ volume: integer 0..100 }` | `audio/setVolume` |
|
|
34
68
|
| `volume_up`, `volume_down` | none | `audio/volumeUp`, `audio/volumeDown` |
|
|
35
69
|
| `volume_mute` | `{ mute: boolean }` | `audio/setMute` |
|
|
@@ -37,12 +71,71 @@ Supported exact-target services in `webostv` or `media_player`:
|
|
|
37
71
|
| `media_play`, `media_pause`, `media_stop` | none | `media.controls/play`, `/pause`, `/stop` |
|
|
38
72
|
| `turn_on`, `turn_off` | none | `system/turnOn`, `system/turnOff` |
|
|
39
73
|
|
|
40
|
-
|
|
74
|
+
The TV must report the expected UUID before an existing pairing key is sent.
|
|
75
|
+
Stored keys are bound to both UUID and endpoint. `prompt` explicitly permits
|
|
76
|
+
pairing confirmation on the TV; `existing` refuses absent or rejected durable
|
|
77
|
+
pairing. TLS certificate validation stays enabled, and an owner-supplied PEM
|
|
78
|
+
chain can establish trust. Cleartext `ws` requires explicit
|
|
79
|
+
`allowUnencryptedConnection: true`. Credentials in endpoints, arbitrary URL
|
|
80
|
+
paths and fixture/injected-client production configs are rejected.
|
|
81
|
+
Discovery admits only explicit manual candidates with the domain and metadata
|
|
82
|
+
`{ endpoint, expectedDeviceUUID }`; it does not probe or verify a TV. Cleartext
|
|
83
|
+
UUID selection provides no cryptographic authentication. There is no automatic
|
|
84
|
+
WS downgrade, endpoint guessing, filesystem persistence or credential fallback.
|
|
85
|
+
The accepted key is stored before subscriptions start. Existing mode never
|
|
86
|
+
accepts fresh pairing, though the TV may display a prompt before disconnection.
|
|
87
|
+
|
|
88
|
+
A successful command receipt reports `acknowledgement: 'tv-response'` and
|
|
89
|
+
`physicalCompletion: 'unverified'`. Independent one-shot reads of the documented
|
|
90
|
+
state endpoints produce `observationStatus: 'observed'` and an observation when
|
|
91
|
+
available. Failure to read back an already accepted command produces
|
|
92
|
+
`observationStatus: 'unavailable'`; it never replays the command or substitutes
|
|
93
|
+
cached state as a fresh observation. Readback does not optimistically overwrite
|
|
94
|
+
subscription state. Model metadata comes from `system/getSystemInfo.modelName`
|
|
95
|
+
and stays absent when unreported. Owner permissions are not advertised as a
|
|
96
|
+
TV-reported per-command capability list.
|
|
97
|
+
Power-off timeout remains indeterminate even if the TV physically turned off.
|
|
98
|
+
`turn_on` requires an already connected TV supporting that method. Media controls
|
|
99
|
+
depend on the foreground application. All five state subscriptions and the
|
|
100
|
+
pre-registration system-info request are required; unsupported firmware fails
|
|
101
|
+
setup explicitly. Remote pointer sockets, app launching, channels and calibration
|
|
102
|
+
remain outside the runtime.
|
|
103
|
+
|
|
104
|
+
The owner defaults to a combined capacity of 16 pending operations, runtimes and
|
|
105
|
+
retained cleanup resources. Runtime destruction releases its setup lease.
|
|
106
|
+
Integration destruction is terminal and shares one close promise. The client
|
|
107
|
+
publishes its close promise before cancellation and availability callbacks, then
|
|
108
|
+
drains startup, commands, accepted async subscribers and owned store cleanup.
|
|
109
|
+
Unsubscribe removes admission and joins callbacks already accepted for that
|
|
110
|
+
subscription. Throwing or rejecting subscribers are isolated and removed.
|
|
111
|
+
Callbacks can request teardown; directly returning the client, runtime or owner's close promise
|
|
112
|
+
does not create a self-wait. A callback must not await teardown that is itself
|
|
113
|
+
waiting for that callback to finish.
|
|
114
|
+
|
|
115
|
+
Late encryption-provider cleanup failures reject close and remain retained.
|
|
116
|
+
After the provider settles, explicit `retryCleanup()` acknowledges cleanup
|
|
117
|
+
without replaying provider calls, pairing or commands, and without reopening
|
|
118
|
+
admission. A client closes only stores it created; borrowed stores remain usable.
|
|
119
|
+
Frames, pending requests, subscribers and inputs remain bounded. Heartbeat or
|
|
120
|
+
malformed authoritative state closes the instance. Disconnected snapshots retain
|
|
121
|
+
their observation timestamp and report unavailable. Reconnection requires a new
|
|
122
|
+
setup; there is no surviving command queue.
|
|
41
123
|
|
|
42
|
-
|
|
124
|
+
Migration requires an independently selected home in setup, flow and client
|
|
125
|
+
contexts, and explicit constructor command permissions for effects. The former
|
|
126
|
+
client `(config, persistenceOptions, signal)` signature becomes
|
|
127
|
+
`(config, { homeId, configStore?, abortSignal? }, options)`. Production `rawData`,
|
|
128
|
+
`snapshot`, `snapshotProvider`, injected clients/command executors and fixture
|
|
129
|
+
mapping remain unsupported; fixture data belongs only in tests.
|
|
43
130
|
|
|
44
|
-
|
|
131
|
+
Protocol and transport references:
|
|
45
132
|
|
|
46
|
-
|
|
133
|
+
- [SSAP endpoints in aiowebostv](https://github.com/home-assistant-libs/aiowebostv/blob/main/aiowebostv/endpoints.py)
|
|
134
|
+
- [ConnectSDK webOS service](https://github.com/ConnectSDK/Connect-SDK-Android-Core/blob/master/src/com/connectsdk/service/WebOSTVService.java)
|
|
135
|
+
- [ws transport documentation](https://github.com/websockets/ws/blob/master/doc/ws.md)
|
|
136
|
+
- [ws on npm](https://www.npmjs.com/package/ws)
|
|
47
137
|
|
|
48
|
-
|
|
138
|
+
Verification uses local WebSocket/TLS and disposable in-memory database fixtures.
|
|
139
|
+
Real pairing, firmware acceptance and owner-device control require separate owner
|
|
140
|
+
authorization. No TV-reported per-command service-list contract was confirmed;
|
|
141
|
+
the adapter does not invent one.
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import { NoSqlConfigStore } from '../../core/classes.configstore.js';
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
3
|
+
import { NativeHomeAdmission, type INativeAdmissionContext } from '../../core/classes.nativehomeadmission.js';
|
|
4
|
+
import type { INativeIntegrationSetupContext } from '../../core/types.js';
|
|
5
|
+
import type { IWebostvCommandResult, IWebostvConfig, IWebostvInput, IWebostvIntegrationOptions, IWebostvSnapshot, TWebostvClientEvent, TWebostvClientHandler, TWebostvCommand } from './webostv.types.js';
|
|
6
|
+
import { normalizeWebostvConfig, normalizeWebostvOptions, webostvInteger, webostvObject, webostvString } from './webostv.validation.js';
|
|
5
7
|
|
|
6
8
|
interface IPendingRequest {
|
|
7
9
|
resolve(valueArg: Record<string, unknown>): void;
|
|
@@ -26,38 +28,47 @@ export class WebostvClient {
|
|
|
26
28
|
readonly #config: Readonly<IWebostvConfig>;
|
|
27
29
|
readonly #store: NoSqlConfigStore;
|
|
28
30
|
readonly #ownsStore: boolean;
|
|
31
|
+
readonly #context: INativeAdmissionContext;
|
|
32
|
+
readonly #allowedCommands: readonly TWebostvCommand[];
|
|
29
33
|
readonly #lifetime = new AbortController();
|
|
30
34
|
readonly #pending = new Map<string, IPendingRequest>();
|
|
31
35
|
readonly #subscriptions = new Map<string, (payloadArg: Record<string, unknown>) => void>();
|
|
32
|
-
readonly #handlers = new Set<
|
|
36
|
+
readonly #handlers = new Set<TWebostvClientHandler>();
|
|
37
|
+
readonly #operations = new Set<Promise<unknown>>();
|
|
38
|
+
readonly #handlerOperations = new Map<TWebostvClientHandler, Set<Promise<void>>>();
|
|
33
39
|
#socket?: plugins.ws.WebSocket;
|
|
34
40
|
#snapshot?: IWebostvSnapshot;
|
|
35
41
|
#sequence = 0;
|
|
36
42
|
#start?: Promise<IWebostvSnapshot>;
|
|
37
43
|
#destroy?: Promise<void>;
|
|
44
|
+
#retry?: Promise<void>;
|
|
38
45
|
#heartbeat?: ReturnType<typeof setInterval>;
|
|
39
46
|
#awaitingPong = false;
|
|
40
47
|
#ready = false;
|
|
41
48
|
#failure?: Error;
|
|
42
|
-
#
|
|
43
|
-
readonly #handlerCleanups = new Map<(eventArg: TWebostvClientEvent) => void, () => void>();
|
|
49
|
+
readonly #handlerCleanups = new Map<TWebostvClientHandler, () => void>();
|
|
44
50
|
#removeExternalAbort: () => void = () => undefined;
|
|
45
51
|
|
|
46
|
-
constructor(configArg: IWebostvConfig, optionsArg
|
|
52
|
+
constructor(configArg: IWebostvConfig, contextArg: INativeIntegrationSetupContext, optionsArg: IWebostvIntegrationOptions = {}) {
|
|
47
53
|
this.#config = normalizeWebostvConfig(configArg);
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
const options = normalizeWebostvOptions(optionsArg);
|
|
55
|
+
this.#context = new NativeHomeAdmission('webostv', { homeId: options.homeId }).admit(contextArg, this.#config.homeId);
|
|
56
|
+
this.#allowedCommands = options.allowedCommands!;
|
|
57
|
+
if (this.#context.configStore) {
|
|
58
|
+
this.#store = this.#context.configStore;
|
|
52
59
|
this.#ownsStore = false;
|
|
53
60
|
} else {
|
|
54
|
-
if (!
|
|
55
|
-
this.#store = new NoSqlConfigStore({ db:
|
|
61
|
+
if (!options.db || !options.keyProvider) throw new TypeError('webOS requires an owner-supplied database and external encryption key provider.');
|
|
62
|
+
this.#store = new NoSqlConfigStore({ db: options.db, keyProvider: options.keyProvider, homeId: this.#context.homeId, integrationDomain: 'webostv' });
|
|
56
63
|
this.#ownsStore = true;
|
|
57
64
|
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#startAbortListener(): void {
|
|
68
|
+
const signalArg = this.#context.abortSignal;
|
|
58
69
|
if (signalArg) {
|
|
59
|
-
const abort = (): void => { void this.destroy(); };
|
|
60
|
-
if (signalArg.aborted)
|
|
70
|
+
const abort = (): void => { void this.destroy().catch(() => undefined); };
|
|
71
|
+
if (signalArg.aborted) abort();
|
|
61
72
|
else { signalArg.addEventListener('abort', abort, { once: true }); this.#removeExternalAbort = () => signalArg.removeEventListener('abort', abort); }
|
|
62
73
|
}
|
|
63
74
|
}
|
|
@@ -66,55 +77,99 @@ export class WebostvClient {
|
|
|
66
77
|
|
|
67
78
|
public async getSnapshot(signalArg?: AbortSignal): Promise<IWebostvSnapshot> {
|
|
68
79
|
if (signalArg?.aborted) throw new Error('webOS snapshot was aborted.');
|
|
69
|
-
if (!this.#start)
|
|
80
|
+
if (!this.#start) {
|
|
81
|
+
if (this.#destroy) throw new Error('webOS client is closed.');
|
|
82
|
+
// Track raw startup before foreign work; its rejection handler joins close only after settlement.
|
|
83
|
+
this.#start = this.#track(() => this.#initialize()).catch(async (errorArg: unknown) => {
|
|
84
|
+
try { await this.destroy(); }
|
|
85
|
+
catch (cleanupErrorArg) { throw new AggregateError([errorArg, cleanupErrorArg], 'webOS setup and cleanup failed.'); }
|
|
86
|
+
throw errorArg;
|
|
87
|
+
});
|
|
88
|
+
this.#startAbortListener();
|
|
89
|
+
}
|
|
70
90
|
await this.#start;
|
|
71
91
|
if (signalArg?.aborted) throw new Error('webOS snapshot was aborted.');
|
|
72
92
|
if (!this.#snapshot) throw new Error('webOS state is unavailable.');
|
|
73
93
|
return structuredClone({ ...this.#snapshot, connected: this.isHealthy() });
|
|
74
94
|
}
|
|
75
95
|
|
|
76
|
-
public
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
96
|
+
public execute(commandArg: TWebostvCommand, argumentArg?: unknown, signalArg?: AbortSignal): Promise<IWebostvCommandResult> {
|
|
97
|
+
return this.#track(async () => {
|
|
98
|
+
if (!this.#allowedCommands.includes(commandArg)) throw new Error('webOS command is not authorized by its owner.');
|
|
99
|
+
if (!this.isHealthy()) throw new Error('webOS is disconnected; command was not sent.');
|
|
100
|
+
let uri: string;
|
|
101
|
+
let payload: Record<string, unknown> = {};
|
|
102
|
+
if (commandArg === 'volume_set') { uri = 'audio/setVolume'; payload = { volume: webostvInteger(argumentArg, 'volume', 0, 100) }; }
|
|
103
|
+
else if (commandArg === 'volume_mute') {
|
|
104
|
+
if (typeof argumentArg !== 'boolean') throw new TypeError('webOS mute must be boolean.');
|
|
105
|
+
uri = 'audio/setMute'; payload = { mute: argumentArg };
|
|
106
|
+
} else if (commandArg === 'select_source') {
|
|
107
|
+
const inputId = webostvString(argumentArg, 'inputId');
|
|
108
|
+
if (!this.#snapshot?.inputs.some((inputArg) => inputArg.id === inputId)) throw new TypeError('webOS input must match an advertised input id.');
|
|
109
|
+
uri = 'tv/switchInput'; payload = { inputId };
|
|
110
|
+
} else {
|
|
111
|
+
if (!Object.hasOwn(commandEndpoints, commandArg) || argumentArg !== undefined) throw new TypeError('Unsupported webOS command or extra arguments.');
|
|
112
|
+
uri = commandEndpoints[commandArg];
|
|
113
|
+
}
|
|
114
|
+
await this.#request('request', uri, payload, undefined, signalArg);
|
|
115
|
+
// Correlated acceptance is not proof of physical completion. Read state independently.
|
|
116
|
+
try {
|
|
117
|
+
const observed: Partial<IWebostvSnapshot> = {};
|
|
118
|
+
for (const [field, endpoint] of Object.entries(endpoints)) {
|
|
119
|
+
this.#applyState(observed, field as keyof typeof endpoints, await this.#request('request', endpoint, {}, undefined, signalArg));
|
|
120
|
+
}
|
|
121
|
+
if (!this.isHealthy() || !this.#snapshot) throw new Error('webOS observation is unavailable.');
|
|
122
|
+
const observation = { ...this.#snapshot, ...observed, observedAt: new Date().toISOString() };
|
|
123
|
+
return { acknowledgement: 'tv-response', physicalCompletion: 'unverified', observationStatus: 'observed', observation: structuredClone(observation) };
|
|
124
|
+
} catch {
|
|
125
|
+
return { acknowledgement: 'tv-response', physicalCompletion: 'unverified', observationStatus: 'unavailable' };
|
|
126
|
+
}
|
|
127
|
+
});
|
|
93
128
|
}
|
|
94
129
|
|
|
95
|
-
public async subscribe(handlerArg:
|
|
130
|
+
public async subscribe(handlerArg: TWebostvClientHandler, signalArg?: AbortSignal): Promise<() => Promise<void>> {
|
|
96
131
|
await this.getSnapshot(signalArg);
|
|
97
132
|
if (signalArg?.aborted || this.#lifetime.signal.aborted) throw new Error('webOS subscription was aborted.');
|
|
98
133
|
if (this.#handlers.size >= 128) throw new Error('webOS subscriber capacity reached.');
|
|
99
|
-
|
|
134
|
+
if (typeof handlerArg !== 'function') throw new TypeError('webOS subscriber must be a function.');
|
|
135
|
+
const subscriber: TWebostvClientHandler = (eventArg) => handlerArg(eventArg);
|
|
100
136
|
this.#handlers.add(subscriber);
|
|
101
137
|
const remove = (): void => { this.#handlers.delete(subscriber); this.#handlerCleanups.delete(subscriber); signalArg?.removeEventListener('abort', remove); };
|
|
102
138
|
this.#handlerCleanups.set(subscriber, remove);
|
|
103
139
|
signalArg?.addEventListener('abort', remove, { once: true });
|
|
104
|
-
return async () =>
|
|
140
|
+
return async () => {
|
|
141
|
+
remove();
|
|
142
|
+
await Promise.allSettled([...(this.#handlerOperations.get(subscriber) ?? [])]);
|
|
143
|
+
};
|
|
105
144
|
}
|
|
106
145
|
|
|
107
146
|
public destroy(): Promise<void> {
|
|
108
147
|
if (this.#destroy) return this.#destroy;
|
|
109
|
-
this.#destroy = this.#close();
|
|
148
|
+
this.#destroy = Promise.resolve().then(() => this.#close());
|
|
149
|
+
this.#ready = false;
|
|
150
|
+
this.#lifetime.abort(new Error('webOS client was closed.'));
|
|
110
151
|
return this.#destroy;
|
|
111
152
|
}
|
|
112
153
|
|
|
154
|
+
public retryCleanup(): Promise<void> {
|
|
155
|
+
if (!this.#destroy) return Promise.reject(new Error('webOS cleanup retry requires terminal close.'));
|
|
156
|
+
if (!this.#retry) {
|
|
157
|
+
const retry = Promise.resolve().then(async () => {
|
|
158
|
+
await this.#destroy!.catch(() => undefined);
|
|
159
|
+
if (this.#ownsStore) await this.#store.retryCleanup();
|
|
160
|
+
});
|
|
161
|
+
this.#retry = retry;
|
|
162
|
+
const settled = (): void => { this.#retry = undefined; };
|
|
163
|
+
void retry.then(settled, settled);
|
|
164
|
+
}
|
|
165
|
+
return this.#retry;
|
|
166
|
+
}
|
|
167
|
+
|
|
113
168
|
async #close(): Promise<void> {
|
|
114
|
-
this.#ready = false;
|
|
115
|
-
this.#lifetime.abort(new Error('webOS client was closed.'));
|
|
116
169
|
this.#removeExternalAbort();
|
|
117
170
|
const closeStore = this.#ownsStore ? this.#store.close() : Promise.resolve();
|
|
171
|
+
// Install a rejection handler immediately; socket shutdown and callback drainage run concurrently.
|
|
172
|
+
const storeResult = Promise.allSettled([closeStore]);
|
|
118
173
|
clearInterval(this.#heartbeat);
|
|
119
174
|
for (const request of this.#pending.values()) { clearTimeout(request.timer); request.cleanup(); request.reject(new Error('webOS connection closed; effects already sent have an indeterminate outcome.')); }
|
|
120
175
|
this.#pending.clear(); this.#subscriptions.clear();
|
|
@@ -122,23 +177,21 @@ export class WebostvClient {
|
|
|
122
177
|
for (const cleanup of [...this.#handlerCleanups.values()]) cleanup();
|
|
123
178
|
this.#handlers.clear();
|
|
124
179
|
const socket = this.#socket;
|
|
125
|
-
if (
|
|
126
|
-
await new Promise<void>((resolveArg) => {
|
|
180
|
+
if (socket && socket.readyState !== plugins.ws.WebSocket.CLOSED) await new Promise<void>((resolveArg) => {
|
|
127
181
|
const timer = setTimeout(() => { socket.terminate(); }, 1000);
|
|
128
182
|
socket.once('close', () => { clearTimeout(timer); socket.removeAllListeners(); resolveArg(); });
|
|
129
183
|
if (socket.readyState === plugins.ws.WebSocket.CONNECTING) socket.terminate();
|
|
130
184
|
else socket.close(1000);
|
|
131
185
|
});
|
|
132
|
-
await Promise.
|
|
186
|
+
await Promise.allSettled([...this.#operations, ...[...this.#handlerOperations.values()].flatMap((operationsArg) => [...operationsArg])]);
|
|
187
|
+
const [result] = await storeResult;
|
|
188
|
+
if (result.status === 'rejected') throw new Error('webOS encrypted pairing cleanup failed; explicit retryCleanup is required.');
|
|
133
189
|
}
|
|
134
190
|
|
|
135
191
|
async #persist<TResult>(operationArg: () => Promise<TResult>): Promise<TResult> {
|
|
136
192
|
if (this.#lifetime.signal.aborted) throw new Error('webOS persistence was aborted.');
|
|
137
|
-
|
|
138
|
-
this.#storage = operation;
|
|
139
|
-
try { return await operation; }
|
|
193
|
+
try { return await operationArg(); }
|
|
140
194
|
catch { throw new Error(this.#lifetime.signal.aborted ? 'webOS persistence was aborted.' : 'webOS encrypted pairing storage failed.'); }
|
|
141
|
-
finally { if (this.#storage === operation) this.#storage = undefined; }
|
|
142
195
|
}
|
|
143
196
|
|
|
144
197
|
async #initialize(): Promise<IWebostvSnapshot> {
|
|
@@ -157,7 +210,8 @@ export class WebostvClient {
|
|
|
157
210
|
const hello = await this.#request('hello', undefined, { appId: 'exchange.smarthome', appName: 'smarthome.exchange' });
|
|
158
211
|
if (hello.deviceUUID !== this.#config.expectedDeviceUUID) throw new Error('webOS hello device UUID does not match the verified TV.');
|
|
159
212
|
// New webOS requires this request before registration; permission denial fails setup explicitly.
|
|
160
|
-
await this.#request('request', 'system/getSystemInfo', {});
|
|
213
|
+
const systemInfo = await this.#request('request', 'system/getSystemInfo', {});
|
|
214
|
+
const model = systemInfo.modelName === undefined ? undefined : webostvString(systemInfo.modelName, 'reported model');
|
|
161
215
|
const registered = await this.#request('register', undefined, {
|
|
162
216
|
pairingType: 'PROMPT', ...(clientKey ? { 'client-key': clientKey } : {}),
|
|
163
217
|
manifest: { manifestVersion: 1, appVersion: '1.0', permissions },
|
|
@@ -178,7 +232,7 @@ export class WebostvClient {
|
|
|
178
232
|
await this.#request('subscribe', uri, {}, (payloadArg) => update(field as keyof typeof endpoints, payloadArg));
|
|
179
233
|
}
|
|
180
234
|
if (initial.powerState === undefined || initial.volume === undefined || initial.muted === undefined || initial.currentAppId === undefined || initial.inputs === undefined) throw new Error('webOS did not supply a complete initial state.');
|
|
181
|
-
this.#snapshot = { homeId: this.#
|
|
235
|
+
this.#snapshot = { homeId: this.#context.homeId, deviceUUID: this.#config.expectedDeviceUUID, name: this.#config.name!, model, authorizedCommands: this.#allowedCommands, connected: true, powerState: initial.powerState, volume: initial.volume, muted: initial.muted, currentAppId: initial.currentAppId, inputs: initial.inputs, observedAt: new Date().toISOString() };
|
|
182
236
|
if (this.#lifetime.signal.aborted || this.#socket?.readyState !== plugins.ws.WebSocket.OPEN) throw new Error('webOS connection closed during setup.');
|
|
183
237
|
this.#ready = true;
|
|
184
238
|
this.#heartbeat = setInterval(() => {
|
|
@@ -288,13 +342,32 @@ export class WebostvClient {
|
|
|
288
342
|
request.reject(request.type === 'request' ? new Error(`${errorArg.message} Effects already sent have an indeterminate outcome.`) : errorArg);
|
|
289
343
|
}
|
|
290
344
|
this.#pending.clear();
|
|
291
|
-
void this.destroy();
|
|
345
|
+
void this.destroy().catch(() => undefined);
|
|
292
346
|
}
|
|
293
347
|
|
|
294
348
|
#emit(eventArg: TWebostvClientEvent): void {
|
|
295
349
|
for (const handler of [...this.#handlers]) {
|
|
296
|
-
|
|
297
|
-
|
|
350
|
+
const operations = this.#handlerOperations.get(handler) ?? new Set<Promise<void>>();
|
|
351
|
+
this.#handlerOperations.set(handler, operations);
|
|
352
|
+
const event = eventArg.type === 'state' ? { ...eventArg, snapshot: structuredClone(eventArg.snapshot) } : eventArg;
|
|
353
|
+
// Publish callback ownership before invoking user code, including close reentry.
|
|
354
|
+
const operation = Promise.resolve().then(() => {
|
|
355
|
+
const result = handler(event);
|
|
356
|
+
// A terminal callback may return the very close it triggered; never make close await itself.
|
|
357
|
+
return result === this.#destroy ? undefined : result;
|
|
358
|
+
}).catch(() => { this.#handlerCleanups.get(handler)?.(); });
|
|
359
|
+
operations.add(operation);
|
|
360
|
+
void operation.then(() => {
|
|
361
|
+
operations.delete(operation);
|
|
362
|
+
if (!operations.size) this.#handlerOperations.delete(handler);
|
|
363
|
+
});
|
|
298
364
|
}
|
|
299
365
|
}
|
|
366
|
+
|
|
367
|
+
#track<TResult>(operationArg: () => Promise<TResult>): Promise<TResult> {
|
|
368
|
+
const operation = Promise.resolve().then(operationArg);
|
|
369
|
+
this.#operations.add(operation);
|
|
370
|
+
void operation.then(() => this.#operations.delete(operation), () => this.#operations.delete(operation));
|
|
371
|
+
return operation;
|
|
372
|
+
}
|
|
300
373
|
}
|
|
@@ -1,22 +1,42 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { NativeIntegrationOwner, type INativeIntegrationOwnerOptions, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
|
|
2
|
+
import type { IConfigFlow, IConfigFlowStep, IDiscoveryCandidate, INativeConfigFlowContext } from '../../core/types.js';
|
|
2
3
|
import { createWebostvDiscoveryDescriptor } from './webostv.discovery.js';
|
|
3
4
|
import type { IWebostvConfig } from './webostv.types.js';
|
|
4
5
|
import { normalizeWebostvConfig, webostvKeys, webostvObject } from './webostv.validation.js';
|
|
5
6
|
|
|
6
7
|
export class WebostvConfigFlow implements IConfigFlow<IWebostvConfig> {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
8
|
+
readonly #owner: NativeIntegrationOwner;
|
|
9
|
+
readonly #scope: NativeIntegrationScope;
|
|
10
|
+
readonly #ownsOwner: boolean;
|
|
11
|
+
|
|
12
|
+
constructor(optionsArg: INativeIntegrationOwnerOptions = {}, ownerArg?: NativeIntegrationOwner) {
|
|
13
|
+
this.#owner = ownerArg ?? new NativeIntegrationOwner('webostv', optionsArg);
|
|
14
|
+
this.#ownsOwner = ownerArg === undefined;
|
|
15
|
+
this.#scope = this.#owner.createFlowScope();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
public start(candidateArg: IDiscoveryCandidate, contextArg: INativeConfigFlowContext): Promise<IConfigFlowStep<IWebostvConfig>> {
|
|
19
|
+
const context = this.#scope.admit(contextArg);
|
|
20
|
+
return this.#scope.run(context, undefined, async () => {
|
|
21
|
+
const result = await createWebostvDiscoveryDescriptor().getValidators()[0].validate(candidateArg, context);
|
|
22
|
+
if (!result.matched || !result.candidate) return { kind: 'error', error: result.reason };
|
|
23
|
+
const candidate = result.candidate;
|
|
24
|
+
return { kind: 'form', title: 'Pair verified LG webOS TV', description: 'Pairing uses the selected home. Prompt mode requires confirmation on the TV.',
|
|
25
|
+
fields: [{ name: 'pairingMode', label: 'Pairing mode', type: 'select', required: true, options: [{ label: 'Use durable existing pairing', value: 'existing' }, { label: 'Confirm new pairing on TV', value: 'prompt' }] }, { name: 'allowUnencryptedConnection', label: 'Allow explicit cleartext local endpoint', type: 'boolean' }],
|
|
26
|
+
submit: async (valuesArg) => {
|
|
27
|
+
try {
|
|
28
|
+
return await this.#scope.run(context, context.homeId, async () => {
|
|
29
|
+
const values = webostvObject(valuesArg, 'webOS config flow values');
|
|
30
|
+
webostvKeys(values, ['pairingMode', 'allowUnencryptedConnection', 'certificateAuthority']);
|
|
31
|
+
const config = normalizeWebostvConfig({ ...values, homeId: context.homeId, endpoint: candidate.metadata!.endpoint, expectedDeviceUUID: candidate.metadata!.expectedDeviceUUID, name: candidate.name } as IWebostvConfig);
|
|
32
|
+
return { kind: 'done', config };
|
|
33
|
+
});
|
|
34
|
+
} catch (errorArg) { return { kind: 'error', error: errorArg instanceof Error ? errorArg.message : 'Invalid webOS config.' }; }
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
});
|
|
21
38
|
}
|
|
39
|
+
|
|
40
|
+
public close(): Promise<void> { return this.#ownsOwner ? this.#owner.close() : this.#scope.close(); }
|
|
41
|
+
public retryCleanup(): Promise<void> { return this.#ownsOwner ? this.#owner.retryCleanup() : this.#scope.retryCleanup(); }
|
|
22
42
|
}
|