@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,47 +1,54 @@
|
|
|
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 { IDenonavrConfig, IDenonavrIntegrationOptions } from './denonavr.types.js';
|
|
4
|
+
import { DenonavrClient } from './denonavr.classes.client.js';
|
|
5
|
+
import { denonavrRecord, normalizeDenonavrConfig } from './denonavr.validation.js';
|
|
3
6
|
|
|
4
7
|
export class DenonavrConfigFlow implements IConfigFlow<IDenonavrConfig> {
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
private readonly scope: NativeIntegrationScope;
|
|
9
|
+
|
|
10
|
+
public constructor(options: IDenonavrIntegrationOptions = {}, scope?: NativeIntegrationScope) {
|
|
11
|
+
this.scope = scope ?? new NativeIntegrationOwner('denonavr', options).createFlowScope();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
public async start(input: IDiscoveryCandidate, context: IConfigFlowContext): Promise<IConfigFlowStep<IDenonavrConfig>> {
|
|
15
|
+
const candidate = denonavrRecord(input);
|
|
16
|
+
if (candidate.integrationDomain !== 'denonavr') return { kind: 'error', error: 'Candidate does not belong to DenonAVR.' };
|
|
17
|
+
const metadata = candidate.metadata === undefined ? {} : denonavrRecord(candidate.metadata);
|
|
18
|
+
const hints = { host: candidate.host, expectedUdn: candidate.id, model: candidate.model, descriptionUrl: metadata.descriptionUrl };
|
|
19
|
+
const admitted = this.scope.admit(context);
|
|
7
20
|
return {
|
|
8
|
-
kind: 'form',
|
|
9
|
-
|
|
10
|
-
description: 'Configure the local Denon/Marantz AVR HTTP endpoint.',
|
|
21
|
+
kind: 'form', title: 'Connect selected Denon or Marantz receiver',
|
|
22
|
+
description: 'Confirm the exact UPnP identity, selected IPv4 description URL and owner volume ceiling for the host-selected home. LAN identity is unauthenticated. Enable network control in standby when needed.',
|
|
11
23
|
fields: [
|
|
12
|
-
{ name: 'host', label: '
|
|
13
|
-
{ name: '
|
|
14
|
-
{ name: '
|
|
15
|
-
{ name: 'model', label: '
|
|
24
|
+
{ name: 'host', label: 'Selected receiver IPv4', type: 'text', required: true },
|
|
25
|
+
{ name: 'descriptionUrl', label: 'Selected UPnP description URL', type: 'text', required: true },
|
|
26
|
+
{ name: 'expectedUdn', label: 'Expected UPnP UDN', type: 'text', required: true },
|
|
27
|
+
{ name: 'model', label: 'Documented model', type: 'select', required: true, options: ['AVR-1913', 'AVR-2113CI', 'NR1605', 'SR5009'].map((value) => ({ label: value, value })) },
|
|
28
|
+
{ name: 'maximumVolumeDb', label: 'Owner maximum volume (dB)', type: 'number', required: true },
|
|
29
|
+
{ name: 'name', label: 'Display name', type: 'text' },
|
|
16
30
|
],
|
|
17
|
-
submit: async (
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
friendlyName: name,
|
|
34
|
-
manufacturer: candidateArg.manufacturer,
|
|
35
|
-
modelName: model,
|
|
36
|
-
serialNumber: candidateArg.serialNumber,
|
|
37
|
-
} : undefined,
|
|
38
|
-
},
|
|
39
|
-
};
|
|
31
|
+
submit: async (inputValues) => {
|
|
32
|
+
try {
|
|
33
|
+
const values = denonavrRecord(inputValues, ['homeId', 'host', 'descriptionUrl', 'expectedUdn', 'model', 'maximumVolumeDb', 'name', 'port', 'timeoutMs', 'maxPendingOperations', 'maxDescriptionBytes']);
|
|
34
|
+
if (values.homeId !== undefined && values.homeId !== admitted.homeId) throw new Error('DenonAVR submitted home conflicts with the host-selected home.');
|
|
35
|
+
const config = normalizeDenonavrConfig({ ...hints, ...values, homeId: admitted.homeId });
|
|
36
|
+
return await this.scope.run(admitted, config.homeId, async (lease) => {
|
|
37
|
+
const client = new DenonavrClient(config, lease.context);
|
|
38
|
+
lease.own(() => client.retryCleanup());
|
|
39
|
+
await client.start(lease.signal);
|
|
40
|
+
lease.assertOpen();
|
|
41
|
+
return { kind: 'done', title: 'Selected receiver admitted', config };
|
|
42
|
+
});
|
|
43
|
+
} catch (error) {
|
|
44
|
+
if (error instanceof AggregateError) throw error;
|
|
45
|
+
return { kind: 'error', title: 'Receiver admission failed', error: error instanceof Error ? error.message : 'Receiver admission failed.' };
|
|
46
|
+
}
|
|
40
47
|
},
|
|
41
48
|
};
|
|
42
49
|
}
|
|
43
|
-
}
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
51
|
+
public destroy(): Promise<void> { return this.scope.close(); }
|
|
52
|
+
|
|
53
|
+
public retryCleanup(): Promise<void> { return this.scope.retryCleanup(); }
|
|
54
|
+
}
|
|
@@ -1,157 +1,211 @@
|
|
|
1
|
-
import
|
|
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, IIntegrationSetupContext, IServiceCallRequest, IServiceCallResult } from '../../core/types.js';
|
|
4
5
|
import { DenonavrClient } from './denonavr.classes.client.js';
|
|
5
6
|
import { DenonavrConfigFlow } from './denonavr.classes.configflow.js';
|
|
6
7
|
import { createDenonavrDiscoveryDescriptor } from './denonavr.discovery.js';
|
|
7
8
|
import { DenonavrMapper } from './denonavr.mapper.js';
|
|
8
|
-
import
|
|
9
|
+
import { denonavrRecord, normalizeDenonavrConfig, validateDenonavrControl } from './denonavr.validation.js';
|
|
10
|
+
import type { IDenonavrConfig, IDenonavrEffectResult, IDenonavrIntegrationOptions, IDenonavrSnapshot, TDenonavrControl } from './denonavr.types.js';
|
|
9
11
|
|
|
10
12
|
export class DenonavrIntegration extends BaseIntegration<IDenonavrConfig> {
|
|
11
13
|
public readonly domain = 'denonavr';
|
|
12
|
-
public readonly displayName = 'Denon
|
|
14
|
+
public readonly displayName = 'Denon and Marantz selected receivers';
|
|
13
15
|
public readonly status = 'control-runtime' as const;
|
|
14
16
|
public readonly discoveryDescriptor = createDenonavrDiscoveryDescriptor();
|
|
15
|
-
public readonly configFlow
|
|
16
|
-
public readonly metadata = {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
dependencies: [],
|
|
24
|
-
afterDependencies: [],
|
|
25
|
-
codeowners: ['@ol-iver', '@starkillerOG'],
|
|
26
|
-
configFlow: true,
|
|
27
|
-
documentation: 'https://www.home-assistant.io/integrations/denonavr',
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
public async setup(configArg: IDenonavrConfig, contextArg: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
|
|
31
|
-
void contextArg;
|
|
32
|
-
return new DenonavrRuntime(new DenonavrClient(configArg));
|
|
17
|
+
public readonly configFlow: DenonavrConfigFlow;
|
|
18
|
+
public readonly metadata = { source: 'native-typescript', integrationType: 'device', iotClass: 'local_poll' };
|
|
19
|
+
private readonly owner: NativeIntegrationOwner;
|
|
20
|
+
|
|
21
|
+
public constructor(options: IDenonavrIntegrationOptions = {}) {
|
|
22
|
+
super();
|
|
23
|
+
this.owner = new NativeIntegrationOwner('denonavr', options);
|
|
24
|
+
this.configFlow = new DenonavrConfigFlow(options, this.owner.createFlowScope());
|
|
33
25
|
}
|
|
34
26
|
|
|
35
|
-
public
|
|
27
|
+
public setup(config: IDenonavrConfig, context: IIntegrationSetupContext): Promise<IIntegrationRuntime> {
|
|
28
|
+
let selected: ReturnType<typeof normalizeDenonavrConfig>;
|
|
29
|
+
try { selected = normalizeDenonavrConfig(config); } catch (error) { return Promise.reject(error); }
|
|
30
|
+
try {
|
|
31
|
+
return this.owner.runSetup(context, selected.homeId, async (lease) => {
|
|
32
|
+
const client = new DenonavrClient(selected, lease.context);
|
|
33
|
+
let runtime: DenonavrRuntime | undefined;
|
|
34
|
+
lease.own(async () => {
|
|
35
|
+
const ownedRuntime = runtime;
|
|
36
|
+
const results = await Promise.allSettled([
|
|
37
|
+
Promise.resolve().then(() => client.retryCleanup()),
|
|
38
|
+
...(ownedRuntime ? [Promise.resolve().then(() => ownedRuntime.closeSubscriptions())] : []),
|
|
39
|
+
]);
|
|
40
|
+
const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
|
|
41
|
+
if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'DenonAVR owned client or subscriber cleanup failed.');
|
|
42
|
+
});
|
|
43
|
+
const initial = await client.start(lease.signal);
|
|
44
|
+
lease.assertOpen();
|
|
45
|
+
runtime = new DenonavrRuntime(client, initial, lease);
|
|
46
|
+
lease.promoteToRuntime();
|
|
47
|
+
return runtime;
|
|
48
|
+
});
|
|
49
|
+
} catch (error) { return Promise.reject(error); }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public destroy(): Promise<void> {
|
|
53
|
+
return this.owner.close();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
public retryCleanup(): Promise<void> { return this.owner.retryCleanup(); }
|
|
36
57
|
}
|
|
37
58
|
|
|
38
59
|
export class HomeAssistantDenonavrIntegration extends DenonavrIntegration {}
|
|
39
60
|
|
|
61
|
+
interface IDenonavrSubscription {
|
|
62
|
+
handler: (event: IIntegrationEvent) => void;
|
|
63
|
+
active: boolean;
|
|
64
|
+
failed: boolean;
|
|
65
|
+
failure?: unknown;
|
|
66
|
+
detach(): void;
|
|
67
|
+
stop(): Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
|
|
40
70
|
class DenonavrRuntime implements IIntegrationRuntime {
|
|
41
|
-
public domain = 'denonavr';
|
|
71
|
+
public readonly domain = 'denonavr';
|
|
72
|
+
private readonly subscriptions = new Set<IDenonavrSubscription>();
|
|
73
|
+
private readonly parentAbort: () => void;
|
|
74
|
+
private closePromise?: Promise<void>;
|
|
75
|
+
private closed = false;
|
|
76
|
+
|
|
77
|
+
public constructor(private readonly client: DenonavrClient, private snapshot: IDenonavrSnapshot,
|
|
78
|
+
private readonly lease: INativeSetupLease) {
|
|
79
|
+
// The owning integration retains failed runtimes; closePromise exposes asynchronous abort cleanup failures.
|
|
80
|
+
this.parentAbort = () => { void this.destroy().catch(() => {}); };
|
|
81
|
+
lease.signal.addEventListener('abort', this.parentAbort, { once: true });
|
|
82
|
+
if (lease.signal.aborted) this.parentAbort();
|
|
83
|
+
}
|
|
42
84
|
|
|
43
|
-
|
|
85
|
+
public isHealthy(): boolean { return !this.closed && this.client.isHealthy(); }
|
|
44
86
|
|
|
45
|
-
public async devices(): Promise<shxInterfaces.data.IDeviceDefinition[]> {
|
|
46
|
-
|
|
87
|
+
public async devices(signal?: AbortSignal): Promise<plugins.shxInterfaces.data.IDeviceDefinition[]> {
|
|
88
|
+
this.assertOpen();
|
|
89
|
+
const snapshot = await this.client.getSnapshot(signal);
|
|
90
|
+
this.publish(snapshot);
|
|
91
|
+
return DenonavrMapper.toDevices(snapshot);
|
|
47
92
|
}
|
|
48
93
|
|
|
49
94
|
public async entities(): Promise<IIntegrationEntity[]> {
|
|
50
|
-
|
|
95
|
+
this.assertOpen();
|
|
96
|
+
const snapshot = await this.client.getSnapshot();
|
|
97
|
+
this.publish(snapshot);
|
|
98
|
+
return DenonavrMapper.toEntities(snapshot);
|
|
51
99
|
}
|
|
52
100
|
|
|
53
|
-
public async
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
}
|
|
101
|
+
public async writeFeature(input: IDeviceFeatureWriteRequest, signal?: AbortSignal): Promise<IServiceCallResult> {
|
|
102
|
+
this.assertOpen();
|
|
103
|
+
const request = denonavrRecord(input, ['device', 'feature', 'value']);
|
|
104
|
+
const device = denonavrRecord(request.device);
|
|
105
|
+
const feature = denonavrRecord(request.feature);
|
|
106
|
+
const canonical = DenonavrMapper.toDevices(this.snapshot)[0];
|
|
107
|
+
if (device.id !== canonical.id || device.integrationDomain !== this.domain) throw new Error('DenonAVR feature target is outside the selected home and receiver.');
|
|
108
|
+
const admitted = canonical.features.find((entry) => entry.id === feature.id);
|
|
109
|
+
if (!admitted?.writable || feature.capability !== admitted.capability) throw new Error('DenonAVR feature is not writable for the selected receiver.');
|
|
110
|
+
const control = validateDenonavrControl({ feature: admitted.id, value: request.value });
|
|
111
|
+
return this.control(control, signal);
|
|
112
|
+
}
|
|
63
113
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
114
|
+
public async callService(input: IServiceCallRequest): Promise<IServiceCallResult> {
|
|
115
|
+
this.assertOpen();
|
|
116
|
+
const request = denonavrRecord(input, ['domain', 'service', 'target', 'data']);
|
|
117
|
+
const target = denonavrRecord(request.target, ['deviceId', 'entityId']);
|
|
118
|
+
const deviceId = DenonavrMapper.deviceId(this.snapshot.homeId, this.snapshot.identity.udn);
|
|
119
|
+
const entityId = DenonavrMapper.entityId(this.snapshot.homeId, this.snapshot.identity.udn);
|
|
120
|
+
if ((!target.deviceId && !target.entityId) || (target.deviceId !== undefined && target.deviceId !== deviceId)
|
|
121
|
+
|| (target.entityId !== undefined && target.entityId !== entityId)) throw new Error('DenonAVR service target is outside the selected home and receiver.');
|
|
122
|
+
if (request.domain !== 'media_player') throw new Error('DenonAVR services use media_player.');
|
|
123
|
+
let control: TDenonavrControl;
|
|
124
|
+
if (request.service === 'turn_on' || request.service === 'turn_off') {
|
|
125
|
+
denonavrRecord(request.data ?? {}, []);
|
|
126
|
+
control = { feature: 'power', value: request.service === 'turn_on' };
|
|
127
|
+
} else if (request.service === 'volume_set') {
|
|
128
|
+
const data = denonavrRecord(request.data, ['volume_db']);
|
|
129
|
+
control = validateDenonavrControl({ feature: 'volume_db', value: data.volume_db });
|
|
130
|
+
} else if (request.service === 'volume_mute') {
|
|
131
|
+
const data = denonavrRecord(request.data, ['is_volume_muted']);
|
|
132
|
+
control = validateDenonavrControl({ feature: 'muted', value: data.is_volume_muted });
|
|
133
|
+
} else if (request.service === 'select_source') {
|
|
134
|
+
const data = denonavrRecord(request.data, ['source']);
|
|
135
|
+
control = validateDenonavrControl({ feature: 'input', value: data.source });
|
|
136
|
+
} else throw new Error('DenonAVR supports explicit power, mute, absolute dB volume and observed physical inputs only.');
|
|
137
|
+
return this.control(control);
|
|
76
138
|
}
|
|
77
139
|
|
|
78
|
-
|
|
79
|
-
|
|
140
|
+
/** Emits only newly completed adapter observations; it does not create a receiver polling loop. */
|
|
141
|
+
public async subscribe(handler: (event: IIntegrationEvent) => void, signal?: AbortSignal): Promise<() => Promise<void>> {
|
|
142
|
+
this.assertOpen();
|
|
143
|
+
if (typeof handler !== 'function' || (signal !== undefined && !(signal instanceof AbortSignal))) throw new TypeError('DenonAVR subscription requires a callback and optional AbortSignal.');
|
|
144
|
+
signal?.throwIfAborted();
|
|
145
|
+
if (this.subscriptions.size >= 32) throw new Error('DenonAVR subscription capacity reached.');
|
|
146
|
+
const subscription: IDenonavrSubscription = {
|
|
147
|
+
handler, active: true, failed: false,
|
|
148
|
+
detach: () => { subscription.active = false; signal?.removeEventListener('abort', aborted); },
|
|
149
|
+
stop: async () => {
|
|
150
|
+
subscription.detach();
|
|
151
|
+
this.subscriptions.delete(subscription);
|
|
152
|
+
if (subscription.failed) throw subscription.failure;
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
const aborted = () => { subscription.detach(); this.subscriptions.delete(subscription); };
|
|
156
|
+
signal?.addEventListener('abort', aborted, { once: true });
|
|
157
|
+
this.subscriptions.add(subscription);
|
|
158
|
+
if (signal?.aborted) aborted();
|
|
159
|
+
return subscription.stop;
|
|
80
160
|
}
|
|
81
161
|
|
|
82
|
-
|
|
83
|
-
if (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
if (requestArg.service === 'volume_up') {
|
|
90
|
-
return 'volume_up';
|
|
162
|
+
public destroy(): Promise<void> {
|
|
163
|
+
if (!this.closePromise) {
|
|
164
|
+
this.closePromise = Promise.resolve().then(() => this.lease.close());
|
|
165
|
+
this.closed = true;
|
|
166
|
+
this.lease.signal.removeEventListener('abort', this.parentAbort);
|
|
167
|
+
for (const subscription of this.subscriptions) subscription.detach();
|
|
91
168
|
}
|
|
92
|
-
|
|
93
|
-
return 'volume_down';
|
|
94
|
-
}
|
|
95
|
-
if (requestArg.service === 'volume_set') {
|
|
96
|
-
return 'set_volume';
|
|
97
|
-
}
|
|
98
|
-
if (requestArg.service === 'volume_mute') {
|
|
99
|
-
return 'mute';
|
|
100
|
-
}
|
|
101
|
-
if (requestArg.service === 'select_source') {
|
|
102
|
-
return 'select_source';
|
|
103
|
-
}
|
|
104
|
-
if (requestArg.service === 'media_play' || requestArg.service === 'play') {
|
|
105
|
-
return 'play';
|
|
106
|
-
}
|
|
107
|
-
if (requestArg.service === 'media_pause' || requestArg.service === 'pause') {
|
|
108
|
-
return 'pause';
|
|
109
|
-
}
|
|
110
|
-
if (requestArg.service === 'media_stop' || requestArg.service === 'stop') {
|
|
111
|
-
return 'stop';
|
|
112
|
-
}
|
|
113
|
-
if (requestArg.service === 'media_play_pause' || requestArg.service === 'play_pause') {
|
|
114
|
-
return 'play_pause';
|
|
115
|
-
}
|
|
116
|
-
if (requestArg.service === 'media_previous_track' || requestArg.service === 'previous_track') {
|
|
117
|
-
return 'previous_track';
|
|
118
|
-
}
|
|
119
|
-
if (requestArg.service === 'media_next_track' || requestArg.service === 'next_track') {
|
|
120
|
-
return 'next_track';
|
|
121
|
-
}
|
|
122
|
-
return undefined;
|
|
169
|
+
return this.closePromise;
|
|
123
170
|
}
|
|
124
171
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
return 'Zone3';
|
|
132
|
-
}
|
|
133
|
-
const entityId = requestArg.target.entityId?.toLowerCase() || '';
|
|
134
|
-
if (entityId.includes('zone2')) {
|
|
135
|
-
return 'Zone2';
|
|
136
|
-
}
|
|
137
|
-
if (entityId.includes('zone3')) {
|
|
138
|
-
return 'Zone3';
|
|
139
|
-
}
|
|
140
|
-
return 'Main';
|
|
172
|
+
public async closeSubscriptions(): Promise<void> {
|
|
173
|
+
this.closed = true;
|
|
174
|
+
this.lease.signal.removeEventListener('abort', this.parentAbort);
|
|
175
|
+
const results = await Promise.allSettled([...this.subscriptions].map((entry) => entry.stop()));
|
|
176
|
+
const failures = results.filter((entry): entry is PromiseRejectedResult => entry.status === 'rejected');
|
|
177
|
+
if (failures.length) throw new AggregateError(failures.map((entry) => entry.reason), 'DenonAVR subscriber cleanup failed.');
|
|
141
178
|
}
|
|
142
179
|
|
|
143
|
-
private
|
|
144
|
-
|
|
145
|
-
|
|
180
|
+
private async control(control: TDenonavrControl, signal?: AbortSignal): Promise<IServiceCallResult> {
|
|
181
|
+
try {
|
|
182
|
+
const result = await this.client.setControl(control, signal);
|
|
183
|
+
this.publish(result.snapshot);
|
|
184
|
+
return this.result(result);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
return { success: false, error: error instanceof Error ? error.message : 'DenonAVR control failed.',
|
|
187
|
+
data: { effectOutcome: error instanceof plugins.ecobridgeDeviceManager.DenonProtocolError ? error.effectOutcome : 'not-sent' } };
|
|
188
|
+
}
|
|
146
189
|
}
|
|
147
190
|
|
|
148
|
-
private
|
|
149
|
-
|
|
150
|
-
|
|
191
|
+
private result(result: IDenonavrEffectResult): IServiceCallResult {
|
|
192
|
+
return { success: result.outcome === 'observed-target', ...(result.outcome === 'indeterminate' ? { error: 'Requested receiver setting was not observed.' } : {}),
|
|
193
|
+
data: { dispatch: result.dispatch, outcome: result.outcome, devices: DenonavrMapper.toDevices(result.snapshot), entities: DenonavrMapper.toEntities(result.snapshot) } };
|
|
151
194
|
}
|
|
152
195
|
|
|
153
|
-
private
|
|
154
|
-
|
|
155
|
-
|
|
196
|
+
private publish(snapshot: IDenonavrSnapshot): void {
|
|
197
|
+
if (this.closed) return;
|
|
198
|
+
this.snapshot = snapshot;
|
|
199
|
+
for (const subscription of [...this.subscriptions]) {
|
|
200
|
+
if (this.closed) break;
|
|
201
|
+
if (!subscription.active) continue;
|
|
202
|
+
try {
|
|
203
|
+
subscription.handler({ type: 'state_changed', integrationDomain: this.domain,
|
|
204
|
+
deviceId: DenonavrMapper.deviceId(snapshot.homeId, snapshot.identity.udn), entityId: DenonavrMapper.entityId(snapshot.homeId, snapshot.identity.udn),
|
|
205
|
+
data: structuredClone(snapshot), timestamp: Date.now() });
|
|
206
|
+
} catch (error) { subscription.failed = true; subscription.failure = error; subscription.detach(); }
|
|
207
|
+
}
|
|
156
208
|
}
|
|
209
|
+
|
|
210
|
+
private assertOpen(): void { if (this.closed) throw new Error('DenonAVR runtime is closed.'); }
|
|
157
211
|
}
|