@smarthome.exchange/integrations 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +49 -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 +79 -0
- package/dist_ts/core/classes.nativeintegrationowner.js +269 -0
- package/dist_ts/core/index.d.ts +2 -0
- package/dist_ts/core/index.js +3 -1
- package/dist_ts/core/types.d.ts +14 -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/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/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/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/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/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/package.json +3 -3
- package/readme.md +514 -2
- 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 +297 -0
- package/ts/core/index.ts +2 -0
- package/ts/core/types.ts +16 -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/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/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/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/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/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
|
@@ -1,84 +1,55 @@
|
|
|
1
1
|
import type { IConfigFlow, IConfigFlowContext, IConfigFlowStep, IDiscoveryCandidate } from '../../core/types.js';
|
|
2
|
-
import type
|
|
2
|
+
import { NativeIntegrationOwner, type NativeIntegrationScope } from '../../core/classes.nativeintegrationowner.js';
|
|
3
|
+
import type { IBraviatvConfig, IBraviatvIntegrationOptions } from './braviatv.types.js';
|
|
4
|
+
import { BraviatvClient } from './braviatv.classes.client.js';
|
|
5
|
+
import { braviatvRecord, normalizeBraviatvConfig, normalizeBraviatvOptions } from './braviatv.validation.js';
|
|
3
6
|
|
|
4
7
|
export class BraviatvConfigFlow implements IConfigFlow<IBraviatvConfig> {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
readonly #options?: Readonly<IBraviatvIntegrationOptions>;
|
|
9
|
+
readonly #scope: NativeIntegrationScope;
|
|
10
|
+
public constructor(options?: IBraviatvIntegrationOptions, scope?: NativeIntegrationScope) {
|
|
11
|
+
this.#options = options === undefined ? undefined : normalizeBraviatvOptions(options);
|
|
12
|
+
this.#scope = scope ?? new NativeIntegrationOwner('braviatv', { homeId: this.#options?.homeId, capacity: this.#options?.capacity }).createFlowScope();
|
|
13
|
+
}
|
|
14
|
+
public async start(input: IDiscoveryCandidate, context: IConfigFlowContext): Promise<IConfigFlowStep<IBraviatvConfig>> {
|
|
15
|
+
const candidate = braviatvRecord(input);
|
|
16
|
+
if (candidate.integrationDomain !== 'braviatv') return { kind: 'error', error: 'Candidate does not belong to BRAVIA.' };
|
|
17
|
+
if (!this.#options) return { kind: 'error', error: 'BRAVIA admission requires caller-owned PSK resolver options.' };
|
|
18
|
+
const options = this.#options;
|
|
19
|
+
const hints = { host: candidate.host };
|
|
20
|
+
const admitted = this.#scope.admit(context);
|
|
21
|
+
return { kind: 'form', title: 'Select BRAVIA Professional display',
|
|
22
|
+
description: 'Confirm private IPv4, model and active-network MAC for the host-selected home. Caller provides a private-level PSK reference. LAN HTTP is unencrypted and PSK access does not prove peer identity. Speaker volume uses integer raw levels.',
|
|
11
23
|
fields: [
|
|
12
|
-
{ name: 'host', label: '
|
|
13
|
-
{ name: '
|
|
14
|
-
{ name: '
|
|
15
|
-
{ name: '
|
|
16
|
-
{ name: '
|
|
17
|
-
{ name: '
|
|
18
|
-
{ name: '
|
|
24
|
+
{ name: 'host', label: 'Selected display IPv4', type: 'text', required: true },
|
|
25
|
+
{ name: 'expectedModel', label: 'Exact observed model', type: 'text', required: true },
|
|
26
|
+
{ name: 'expectedMacAddress', label: 'Exact active-network MAC', type: 'text', required: true },
|
|
27
|
+
{ name: 'expectedSerial', label: 'Exact serial (optional)', type: 'text' },
|
|
28
|
+
{ name: 'credentialRef', label: 'Caller private-level PSK reference', type: 'text', required: true },
|
|
29
|
+
{ name: 'allowUnencryptedLan', label: 'Allow unencrypted selected LAN HTTP', type: 'boolean', required: true },
|
|
30
|
+
{ name: 'volumeLimitRaw', label: 'Owner speaker ceiling (integer raw level 0..100)', type: 'number', required: true },
|
|
31
|
+
{ name: 'name', label: 'Display name', type: 'text' },
|
|
19
32
|
],
|
|
20
|
-
submit: async (
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
submit: async (inputValues) => {
|
|
34
|
+
try {
|
|
35
|
+
const values = braviatvRecord(inputValues, ['homeId', 'host', 'expectedModel', 'expectedMacAddress', 'expectedSerial',
|
|
36
|
+
'credentialRef', 'allowUnencryptedLan', 'volumeLimitRaw', 'name', 'port', 'timeoutMs', 'maxPendingOperations', 'maxResponseBytes']);
|
|
37
|
+
if (values.homeId !== undefined && values.homeId !== admitted.homeId) throw new Error('BRAVIA submitted home conflicts with the host-selected home.');
|
|
38
|
+
// Discovery supplies only captured endpoint hints; exact model and MAC remain explicit selections.
|
|
39
|
+
const config = normalizeBraviatvConfig({ ...values, homeId: admitted.homeId, host: values.host ?? hints.host });
|
|
40
|
+
return await this.#scope.run(admitted, config.homeId, async (lease) => {
|
|
41
|
+
const client = new BraviatvClient(config, { ...lease.context, abortSignal: lease.signal }, options);
|
|
42
|
+
lease.own(() => client.retryCleanup());
|
|
43
|
+
await client.start(lease.signal);
|
|
44
|
+
lease.assertOpen();
|
|
45
|
+
return { kind: 'done', title: 'Selected display admitted', config };
|
|
46
|
+
});
|
|
47
|
+
} catch (error) {
|
|
48
|
+
if (error instanceof AggregateError) throw error;
|
|
49
|
+
return { kind: 'error', title: 'Display admission failed', error: 'Confirm exact home and display identity, private PSK reference, explicit LAN consent, supported APIs and owner speaker ceiling.' };
|
|
30
50
|
}
|
|
31
|
-
|
|
32
|
-
const useSsl = this.booleanValue(valuesArg.useSsl) ?? this.booleanMetadata(candidateArg, 'useSsl') ?? false;
|
|
33
|
-
return {
|
|
34
|
-
kind: 'done',
|
|
35
|
-
title: 'Sony Bravia TV configured',
|
|
36
|
-
config: {
|
|
37
|
-
host,
|
|
38
|
-
port: this.numberValue(valuesArg.port) || candidateArg.port || (useSsl ? 443 : 80),
|
|
39
|
-
useSsl,
|
|
40
|
-
psk,
|
|
41
|
-
pin,
|
|
42
|
-
usePsk: Boolean(psk),
|
|
43
|
-
name: this.stringValue(valuesArg.name) || candidateArg.name,
|
|
44
|
-
model: this.stringValue(valuesArg.model) || candidateArg.model,
|
|
45
|
-
manufacturer: candidateArg.manufacturer || 'Sony',
|
|
46
|
-
macAddress: candidateArg.macAddress,
|
|
47
|
-
serialNumber: candidateArg.serialNumber,
|
|
48
|
-
cid: candidateArg.id || this.stringMetadata(candidateArg, 'cid'),
|
|
49
|
-
scalarWebApiBaseUrl: this.stringMetadata(candidateArg, 'scalarWebApiBaseUrl'),
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
private stringValue(valueArg: unknown): string | undefined {
|
|
57
|
-
return typeof valueArg === 'string' && valueArg.trim() ? valueArg.trim() : undefined;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
private numberValue(valueArg: unknown): number | undefined {
|
|
61
|
-
if (typeof valueArg === 'number' && Number.isFinite(valueArg)) {
|
|
62
|
-
return valueArg;
|
|
63
|
-
}
|
|
64
|
-
if (typeof valueArg === 'string' && valueArg.trim()) {
|
|
65
|
-
const value = Number(valueArg);
|
|
66
|
-
return Number.isFinite(value) ? value : undefined;
|
|
67
|
-
}
|
|
68
|
-
return undefined;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
private booleanValue(valueArg: unknown): boolean | undefined {
|
|
72
|
-
return typeof valueArg === 'boolean' ? valueArg : undefined;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
private stringMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): string | undefined {
|
|
76
|
-
const value = candidateArg.metadata?.[keyArg];
|
|
77
|
-
return typeof value === 'string' && value ? value : undefined;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private booleanMetadata(candidateArg: IDiscoveryCandidate, keyArg: string): boolean | undefined {
|
|
81
|
-
const value = candidateArg.metadata?.[keyArg];
|
|
82
|
-
return typeof value === 'boolean' ? value : undefined;
|
|
51
|
+
} };
|
|
83
52
|
}
|
|
53
|
+
public destroy(): Promise<void> { return this.#scope.close(); }
|
|
54
|
+
public retryCleanup(): Promise<void> { return this.#scope.retryCleanup(); }
|
|
84
55
|
}
|
|
@@ -1,177 +1,197 @@
|
|
|
1
1
|
import * as plugins from '../../plugins.js';
|
|
2
2
|
import { BaseIntegration } from '../../core/classes.baseintegration.js';
|
|
3
|
-
import
|
|
3
|
+
import { NativeIntegrationOwner, type INativeSetupLease } from '../../core/classes.nativeintegrationowner.js';
|
|
4
|
+
import type { IDeviceFeatureWriteRequest, IIntegrationEntity, IIntegrationEvent, IIntegrationRuntime,
|
|
5
|
+
IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
|
|
4
6
|
import { BraviatvClient } from './braviatv.classes.client.js';
|
|
5
7
|
import { BraviatvConfigFlow } from './braviatv.classes.configflow.js';
|
|
6
8
|
import { createBraviatvDiscoveryDescriptor } from './braviatv.discovery.js';
|
|
7
9
|
import { BraviatvMapper } from './braviatv.mapper.js';
|
|
8
|
-
import
|
|
10
|
+
import { braviatvRecord, normalizeBraviatvConfig, normalizeBraviatvOptions, validateBraviatvControl } from './braviatv.validation.js';
|
|
11
|
+
import type { IBraviatvConfig, IBraviatvEffectResult, IBraviatvIntegrationOptions,
|
|
12
|
+
IBraviatvSetupContext, IBraviatvSnapshot, TBraviatvControl } from './braviatv.types.js';
|
|
9
13
|
|
|
10
14
|
export class BraviatvIntegration extends BaseIntegration<IBraviatvConfig> {
|
|
11
15
|
public readonly domain = 'braviatv';
|
|
12
|
-
public readonly displayName = 'Sony
|
|
16
|
+
public readonly displayName = 'Selected Sony BRAVIA Professional display';
|
|
13
17
|
public readonly status = 'control-runtime' as const;
|
|
14
18
|
public readonly discoveryDescriptor = createBraviatvDiscoveryDescriptor();
|
|
15
|
-
public readonly configFlow
|
|
16
|
-
public readonly metadata = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
integrationType: 'device',
|
|
21
|
-
iotClass: 'local_polling',
|
|
22
|
-
requirements: ['pybravia==0.4.1'],
|
|
23
|
-
dependencies: ['ssdp'],
|
|
24
|
-
afterDependencies: [],
|
|
25
|
-
codeowners: ['@bieniu', '@Drafteed'],
|
|
26
|
-
configFlow: true,
|
|
27
|
-
documentation: 'https://www.home-assistant.io/integrations/braviatv',
|
|
28
|
-
};
|
|
19
|
+
public readonly configFlow: BraviatvConfigFlow;
|
|
20
|
+
public readonly metadata = { source: 'native-typescript', integrationType: 'device', iotClass: 'local_poll',
|
|
21
|
+
documentation: 'https://pro-bravia.sony.net/remote-display-control/rest-api/reference/' };
|
|
22
|
+
readonly #options?: Readonly<IBraviatvIntegrationOptions>;
|
|
23
|
+
readonly #owner: NativeIntegrationOwner;
|
|
29
24
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
/** Unconfigured registry descriptors are inert; setup requires explicit caller home and credentials. */
|
|
26
|
+
public constructor(options?: IBraviatvIntegrationOptions) {
|
|
27
|
+
super();
|
|
28
|
+
this.#options = options === undefined ? undefined : normalizeBraviatvOptions(options);
|
|
29
|
+
this.#owner = new NativeIntegrationOwner('braviatv', { homeId: this.#options?.homeId, capacity: this.#options?.capacity });
|
|
30
|
+
this.configFlow = new BraviatvConfigFlow(this.#options, this.#owner.createFlowScope());
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
public
|
|
36
|
-
|
|
33
|
+
public setup(config: IBraviatvConfig, context: IBraviatvSetupContext): Promise<IIntegrationRuntime> {
|
|
34
|
+
if (!this.#options) return Promise.reject(new Error('BRAVIA setup requires caller-owned PSK resolver options.'));
|
|
35
|
+
const options = this.#options;
|
|
36
|
+
try {
|
|
37
|
+
const selected = normalizeBraviatvConfig(config);
|
|
38
|
+
return this.#owner.runSetup(context, selected.homeId, async (lease) => {
|
|
39
|
+
const client = new BraviatvClient(selected, { ...lease.context, abortSignal: lease.signal }, options);
|
|
40
|
+
let runtime: BraviatvRuntime | undefined;
|
|
41
|
+
lease.own(async () => {
|
|
42
|
+
const ownedRuntime = runtime;
|
|
43
|
+
const results = await Promise.allSettled([
|
|
44
|
+
Promise.resolve().then(() => client.retryCleanup()),
|
|
45
|
+
...(ownedRuntime ? [Promise.resolve().then(() => ownedRuntime.closeSubscriptions())] : []),
|
|
46
|
+
]);
|
|
47
|
+
const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
|
|
48
|
+
if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'BRAVIA owned cleanup failed.');
|
|
49
|
+
});
|
|
50
|
+
const initial = await client.start(lease.signal);
|
|
51
|
+
lease.assertOpen();
|
|
52
|
+
runtime = new BraviatvRuntime(client, initial, lease);
|
|
53
|
+
lease.promoteToRuntime();
|
|
54
|
+
return runtime;
|
|
55
|
+
});
|
|
56
|
+
} catch (error) { return Promise.reject(error); }
|
|
57
|
+
}
|
|
37
58
|
|
|
59
|
+
public destroy(): Promise<void> {
|
|
60
|
+
return this.#owner.close();
|
|
61
|
+
}
|
|
62
|
+
public retryCleanup(): Promise<void> { return this.#owner.retryCleanup(); }
|
|
63
|
+
}
|
|
38
64
|
export class HomeAssistantBraviatvIntegration extends BraviatvIntegration {}
|
|
39
65
|
|
|
40
|
-
|
|
41
|
-
|
|
66
|
+
interface IBraviatvSubscription {
|
|
67
|
+
handler: (event: IIntegrationEvent) => void;
|
|
68
|
+
active: boolean;
|
|
69
|
+
failed: boolean;
|
|
70
|
+
detach(): void;
|
|
71
|
+
stop(): Promise<void>;
|
|
72
|
+
}
|
|
42
73
|
|
|
43
|
-
|
|
74
|
+
class BraviatvRuntime implements IIntegrationRuntime {
|
|
75
|
+
public readonly domain = 'braviatv';
|
|
76
|
+
readonly #subscriptions = new Set<IBraviatvSubscription>();
|
|
77
|
+
readonly #parentAbort: () => void;
|
|
78
|
+
#closePromise?: Promise<void>;
|
|
79
|
+
#closed = false;
|
|
44
80
|
|
|
45
|
-
public
|
|
46
|
-
|
|
81
|
+
public constructor(private readonly client: BraviatvClient, private snapshot: IBraviatvSnapshot,
|
|
82
|
+
private readonly lease: INativeSetupLease) {
|
|
83
|
+
this.#parentAbort = () => { void this.destroy().catch(() => {}); };
|
|
84
|
+
lease.signal.addEventListener('abort', this.#parentAbort, { once: true });
|
|
85
|
+
if (lease.signal.aborted) this.#parentAbort();
|
|
86
|
+
}
|
|
87
|
+
public isHealthy(): boolean { return !this.#closed && this.client.isHealthy(); }
|
|
88
|
+
public async devices(signal?: AbortSignal): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> {
|
|
89
|
+
this.assertOpen();
|
|
90
|
+
const snapshot = await this.client.getSnapshot(signal);
|
|
91
|
+
this.publish(snapshot);
|
|
92
|
+
return BraviatvMapper.toDevices(snapshot);
|
|
47
93
|
}
|
|
48
|
-
|
|
49
94
|
public async entities(): Promise<IIntegrationEntity[]> {
|
|
50
|
-
|
|
95
|
+
this.assertOpen();
|
|
96
|
+
const snapshot = await this.client.getSnapshot();
|
|
97
|
+
this.publish(snapshot);
|
|
98
|
+
return BraviatvMapper.toEntities(snapshot);
|
|
51
99
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return { success: false, error: `Unsupported Sony Bravia TV service domain: ${requestArg.domain}` };
|
|
63
|
-
}
|
|
64
|
-
return await this.callMediaPlayerService(requestArg);
|
|
65
|
-
} catch (errorArg) {
|
|
66
|
-
return { success: false, error: errorArg instanceof Error ? errorArg.message : String(errorArg) };
|
|
67
|
-
}
|
|
100
|
+
public async writeFeature(input: IDeviceFeatureWriteRequest, signal?: AbortSignal): Promise<IServiceCallResult> {
|
|
101
|
+
this.assertOpen();
|
|
102
|
+
const request = braviatvRecord(input, ['device', 'feature', 'value']);
|
|
103
|
+
const device = braviatvRecord(request.device);
|
|
104
|
+
const feature = braviatvRecord(request.feature);
|
|
105
|
+
const deviceId = BraviatvMapper.deviceId(this.snapshot.homeId, this.snapshot.identity.macAddress);
|
|
106
|
+
if (device.id !== deviceId || device.integrationDomain !== this.domain) throw new Error('BRAVIA feature target is outside the selected home and display.');
|
|
107
|
+
const control = validateBraviatvControl({ feature: feature.id, value: request.value });
|
|
108
|
+
if (feature.capability !== (control.feature === 'speaker_volume_raw' ? 'sensor' : 'switch')) throw new Error('BRAVIA feature capability does not match the selected control.');
|
|
109
|
+
return this.control(control, signal);
|
|
68
110
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
111
|
+
public async callService(input: IServiceCallRequest): Promise<IServiceCallResult> {
|
|
112
|
+
this.assertOpen();
|
|
113
|
+
const request = braviatvRecord(input, ['domain', 'service', 'target', 'data']);
|
|
114
|
+
if (request.domain !== 'braviatv') throw new Error('BRAVIA selected-display services use braviatv.');
|
|
115
|
+
let control: TBraviatvControl;
|
|
116
|
+
if (request.service === 'set_power') {
|
|
117
|
+
const data = braviatvRecord(request.data, ['power']);
|
|
118
|
+
control = validateBraviatvControl({ feature: 'power', value: data.power });
|
|
119
|
+
} else if (request.service === 'set_device_mute') {
|
|
120
|
+
const data = braviatvRecord(request.data, ['muted']);
|
|
121
|
+
control = validateBraviatvControl({ feature: 'device_mute', value: data.muted });
|
|
122
|
+
} else if (request.service === 'set_speaker_volume_raw') {
|
|
123
|
+
const data = braviatvRecord(request.data, ['volume_raw']);
|
|
124
|
+
control = validateBraviatvControl({ feature: 'speaker_volume_raw', value: data.volume_raw });
|
|
125
|
+
} else throw new Error('BRAVIA supports separate absolute power, device mute and integer speaker volume services only.');
|
|
126
|
+
const target = braviatvRecord(request.target, ['deviceId', 'entityId']);
|
|
127
|
+
const deviceId = BraviatvMapper.deviceId(this.snapshot.homeId, this.snapshot.identity.macAddress);
|
|
128
|
+
const entityId = BraviatvMapper.entityId(this.snapshot.homeId, this.snapshot.identity.macAddress, control.feature);
|
|
129
|
+
if ((!target.deviceId && !target.entityId) || target.deviceId !== undefined && target.deviceId !== deviceId || target.entityId !== undefined && target.entityId !== entityId) {
|
|
130
|
+
throw new Error('BRAVIA service target is outside the selected home, display and control.');
|
|
131
|
+
}
|
|
132
|
+
return this.control(control);
|
|
72
133
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
134
|
+
/** Completed observations only; subscriptions never start a polling loop. */
|
|
135
|
+
public async subscribe(handler: (event: IIntegrationEvent) => void, signal?: AbortSignal): Promise<() => Promise<void>> {
|
|
136
|
+
this.assertOpen();
|
|
137
|
+
if (typeof handler !== 'function' || signal !== undefined && !(signal instanceof AbortSignal)) throw new TypeError('BRAVIA subscription requires a callback and optional AbortSignal.');
|
|
138
|
+
if (signal?.aborted) throw new Error('BRAVIA subscription was cancelled.');
|
|
139
|
+
if (this.#subscriptions.size >= 32) throw new Error('BRAVIA subscription capacity reached.');
|
|
140
|
+
const aborted = () => { subscription.detach(); this.#subscriptions.delete(subscription); };
|
|
141
|
+
const subscription: IBraviatvSubscription = { handler, active: true, failed: false,
|
|
142
|
+
detach: () => { subscription.active = false; signal?.removeEventListener('abort', aborted); },
|
|
143
|
+
stop: async () => { subscription.detach(); this.#subscriptions.delete(subscription);
|
|
144
|
+
if (subscription.failed) throw new Error('BRAVIA subscriber failed.'); } };
|
|
145
|
+
signal?.addEventListener('abort', aborted, { once: true });
|
|
146
|
+
this.#subscriptions.add(subscription);
|
|
147
|
+
if (signal?.aborted) aborted();
|
|
148
|
+
return subscription.stop;
|
|
87
149
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
return { success: true };
|
|
97
|
-
}
|
|
98
|
-
return { success: false, error: `Unsupported Sony Bravia TV service: ${requestArg.service}` };
|
|
150
|
+
public destroy(): Promise<void> {
|
|
151
|
+
if (!this.#closePromise) {
|
|
152
|
+
this.#closePromise = Promise.resolve().then(() => this.lease.close());
|
|
153
|
+
this.#closed = true;
|
|
154
|
+
this.lease.signal.removeEventListener('abort', this.#parentAbort);
|
|
155
|
+
for (const subscription of this.#subscriptions) subscription.detach();
|
|
156
|
+
}
|
|
157
|
+
return this.#closePromise;
|
|
99
158
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
if (requestArg.service === 'play_pause' || requestArg.service === 'media_play_pause') {
|
|
119
|
-
await this.client.sendCommand('Play');
|
|
120
|
-
return { success: true };
|
|
121
|
-
}
|
|
122
|
-
if (requestArg.service === 'stop' || requestArg.service === 'media_stop') {
|
|
123
|
-
await this.client.mediaStop();
|
|
124
|
-
return { success: true };
|
|
125
|
-
}
|
|
126
|
-
if (requestArg.service === 'next_track' || requestArg.service === 'media_next_track') {
|
|
127
|
-
await this.client.nextTrack();
|
|
128
|
-
return { success: true };
|
|
129
|
-
}
|
|
130
|
-
if (requestArg.service === 'previous_track' || requestArg.service === 'media_previous_track') {
|
|
131
|
-
await this.client.previousTrack();
|
|
132
|
-
return { success: true };
|
|
133
|
-
}
|
|
134
|
-
if (requestArg.service === 'volume_set') {
|
|
135
|
-
const level = requestArg.data?.volume_level;
|
|
136
|
-
if (typeof level !== 'number') {
|
|
137
|
-
return { success: false, error: 'Sony Bravia TV volume_set requires data.volume_level.' };
|
|
138
|
-
}
|
|
139
|
-
await this.client.setVolumeLevel(level);
|
|
140
|
-
return { success: true };
|
|
141
|
-
}
|
|
142
|
-
if (requestArg.service === 'volume_up') {
|
|
143
|
-
await this.client.volumeUp();
|
|
144
|
-
return { success: true };
|
|
145
|
-
}
|
|
146
|
-
if (requestArg.service === 'volume_down') {
|
|
147
|
-
await this.client.volumeDown();
|
|
148
|
-
return { success: true };
|
|
149
|
-
}
|
|
150
|
-
if (requestArg.service === 'volume_mute' || requestArg.service === 'mute') {
|
|
151
|
-
const muted = requestArg.data?.is_volume_muted ?? requestArg.data?.muted;
|
|
152
|
-
if (typeof muted !== 'boolean') {
|
|
153
|
-
return { success: false, error: 'Sony Bravia TV volume_mute requires data.is_volume_muted.' };
|
|
154
|
-
}
|
|
155
|
-
await this.client.muteVolume(muted);
|
|
156
|
-
return { success: true };
|
|
157
|
-
}
|
|
158
|
-
if (requestArg.service === 'select_source') {
|
|
159
|
-
const source = requestArg.data?.source;
|
|
160
|
-
if (typeof source !== 'string' || !source) {
|
|
161
|
-
return { success: false, error: 'Sony Bravia TV select_source requires data.source.' };
|
|
162
|
-
}
|
|
163
|
-
await this.client.selectSource(source);
|
|
164
|
-
return { success: true };
|
|
159
|
+
public async closeSubscriptions(): Promise<void> {
|
|
160
|
+
this.#closed = true;
|
|
161
|
+
this.lease.signal.removeEventListener('abort', this.#parentAbort);
|
|
162
|
+
const results = await Promise.allSettled([...this.#subscriptions].map((entry) => entry.stop()));
|
|
163
|
+
const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
|
|
164
|
+
if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'BRAVIA subscriber cleanup failed.');
|
|
165
|
+
}
|
|
166
|
+
private async control(control: TBraviatvControl, signal?: AbortSignal): Promise<IServiceCallResult> {
|
|
167
|
+
try {
|
|
168
|
+
const result = await this.client.setControl(control, signal);
|
|
169
|
+
this.publish(result.snapshot);
|
|
170
|
+
return this.result(result);
|
|
171
|
+
} catch (error) {
|
|
172
|
+
const failure = error instanceof plugins.ecobridgeDeviceManager.SonyBraviaProtocolError ? error : undefined;
|
|
173
|
+
return { success: false, error: failure?.message ?? 'BRAVIA selected-display control was not admitted.',
|
|
174
|
+
data: { effectOutcome: failure?.effectOutcome ?? 'not-sent', commandAcknowledged: failure?.commandAcknowledged ?? false, causalityConfirmed: false,
|
|
175
|
+
...(failure ? { code: failure.code } : {}) } };
|
|
165
176
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
177
|
+
}
|
|
178
|
+
private result(result: IBraviatvEffectResult): IServiceCallResult {
|
|
179
|
+
return { success: result.observation === 'matching-reported-state',
|
|
180
|
+
...(result.observation === 'different-reported-state' ? { error: 'BRAVIA acknowledged the command, but the independent reported state differs.' } : {}),
|
|
181
|
+
data: { commandAcknowledged: result.commandAcknowledged, causalityConfirmed: result.causalityConfirmed,
|
|
182
|
+
observation: result.observation, control: result.control, requested: result.requested,
|
|
183
|
+
devices: BraviatvMapper.toDevices(result.snapshot), entities: BraviatvMapper.toEntities(result.snapshot) } };
|
|
184
|
+
}
|
|
185
|
+
private publish(snapshot: IBraviatvSnapshot): void {
|
|
186
|
+
if (this.#closed) return;
|
|
187
|
+
this.snapshot = snapshot;
|
|
188
|
+
for (const subscription of [...this.#subscriptions]) {
|
|
189
|
+
if (this.#closed) break;
|
|
190
|
+
if (!subscription.active) continue;
|
|
191
|
+
try { subscription.handler({ type: 'state_changed', integrationDomain: this.domain,
|
|
192
|
+
deviceId: BraviatvMapper.deviceId(snapshot.homeId, snapshot.identity.macAddress), data: structuredClone(snapshot), timestamp: Date.now() }); }
|
|
193
|
+
catch { subscription.failed = true; subscription.detach(); }
|
|
174
194
|
}
|
|
175
|
-
return { success: false, error: `Unsupported Sony Bravia TV media_player service: ${requestArg.service}` };
|
|
176
195
|
}
|
|
196
|
+
private assertOpen(): void { if (this.#closed) throw new Error('BRAVIA runtime is closed.'); }
|
|
177
197
|
}
|
|
@@ -30,8 +30,8 @@ export class BraviatvSsdpMatcher implements IDiscoveryMatcher<IBraviatvSsdpRecor
|
|
|
30
30
|
const id = stripUuid(usn || stringValue(recordArg, 'udn', 'UDN')) || stringValue(recordArg, 'cid', 'macAddr');
|
|
31
31
|
return {
|
|
32
32
|
matched: true,
|
|
33
|
-
confidence:
|
|
34
|
-
reason: 'SSDP
|
|
33
|
+
confidence: 'medium',
|
|
34
|
+
reason: 'Unverified SSDP metadata supplies Sony BRAVIA setup hints only.',
|
|
35
35
|
normalizedDeviceId: id,
|
|
36
36
|
candidate: {
|
|
37
37
|
source: 'ssdp',
|
|
@@ -72,8 +72,8 @@ export class BraviatvMdnsMatcher implements IDiscoveryMatcher<IBraviatvMdnsRecor
|
|
|
72
72
|
const id = valueForKey(properties, 'cid') || valueForKey(properties, 'id') || valueForKey(properties, 'deviceid') || name;
|
|
73
73
|
return {
|
|
74
74
|
matched: true,
|
|
75
|
-
confidence:
|
|
76
|
-
reason: 'mDNS
|
|
75
|
+
confidence: 'medium',
|
|
76
|
+
reason: 'Unverified mDNS metadata supplies Sony BRAVIA setup hints only.',
|
|
77
77
|
normalizedDeviceId: id,
|
|
78
78
|
candidate: {
|
|
79
79
|
source: 'mdns',
|
|
@@ -88,7 +88,6 @@ export class BraviatvMdnsMatcher implements IDiscoveryMatcher<IBraviatvMdnsRecor
|
|
|
88
88
|
metadata: {
|
|
89
89
|
mdnsType: recordArg.type,
|
|
90
90
|
mdnsName: recordArg.name,
|
|
91
|
-
txt: properties,
|
|
92
91
|
},
|
|
93
92
|
},
|
|
94
93
|
};
|
|
@@ -116,17 +115,14 @@ export class BraviatvManualMatcher implements IDiscoveryMatcher<IBraviatvManualE
|
|
|
116
115
|
integrationDomain: 'braviatv',
|
|
117
116
|
id,
|
|
118
117
|
host: inputArg.host,
|
|
119
|
-
port: inputArg.port ||
|
|
118
|
+
port: inputArg.port || 80,
|
|
120
119
|
name: inputArg.name,
|
|
121
120
|
manufacturer: inputArg.manufacturer || 'Sony',
|
|
122
121
|
model: inputArg.model,
|
|
123
122
|
serialNumber: inputArg.serialNumber,
|
|
124
123
|
macAddress: inputArg.macAddress,
|
|
125
124
|
metadata: {
|
|
126
|
-
...(inputArg.metadata || {}),
|
|
127
125
|
cid: inputArg.cid,
|
|
128
|
-
psk: inputArg.psk,
|
|
129
|
-
useSsl: inputArg.useSsl,
|
|
130
126
|
},
|
|
131
127
|
},
|
|
132
128
|
};
|
|
@@ -146,7 +142,12 @@ export class BraviatvCandidateValidator implements IDiscoveryValidator {
|
|
|
146
142
|
matched,
|
|
147
143
|
confidence: matched && candidateArg.host ? 'high' : matched ? 'medium' : 'low',
|
|
148
144
|
reason: matched ? 'Candidate has Sony Bravia metadata.' : 'Candidate is not Sony Bravia TV.',
|
|
149
|
-
candidate: matched ?
|
|
145
|
+
candidate: matched ? {
|
|
146
|
+
source: candidateArg.source, integrationDomain: 'braviatv', id: candidateArg.id,
|
|
147
|
+
host: candidateArg.host, port: candidateArg.port, name: candidateArg.name,
|
|
148
|
+
manufacturer: candidateArg.manufacturer, model: candidateArg.model,
|
|
149
|
+
macAddress: candidateArg.macAddress, serialNumber: candidateArg.serialNumber,
|
|
150
|
+
} : undefined,
|
|
150
151
|
normalizedDeviceId: candidateArg.id || candidateArg.macAddress || candidateArg.serialNumber || candidateArg.host,
|
|
151
152
|
};
|
|
152
153
|
}
|