@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,147 +1,44 @@
|
|
|
1
|
-
import * as plugins from '../../plugins.js';
|
|
1
|
+
import type * as plugins from '../../plugins.js';
|
|
2
2
|
import type { IIntegrationEntity } from '../../core/types.js';
|
|
3
|
-
import type { IBraviatvSnapshot,
|
|
3
|
+
import type { IBraviatvSnapshot, TBraviatvControl } from './braviatv.types.js';
|
|
4
4
|
|
|
5
5
|
export class BraviatvMapper {
|
|
6
|
-
public static
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{ id: '
|
|
22
|
-
|
|
23
|
-
{
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
{
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
public static toEntities(snapshotArg: IBraviatvSnapshot): IIntegrationEntity[] {
|
|
44
|
-
const state = this.state(snapshotArg);
|
|
45
|
-
return [{
|
|
46
|
-
id: `media_player.${this.slug(this.deviceName(snapshotArg))}`,
|
|
47
|
-
uniqueId: `braviatv_${this.slug(this.identity(snapshotArg))}`,
|
|
48
|
-
integrationDomain: 'braviatv',
|
|
49
|
-
deviceId: this.deviceId(snapshotArg),
|
|
50
|
-
platform: 'media_player',
|
|
51
|
-
name: this.deviceName(snapshotArg),
|
|
52
|
-
state: this.mediaState(state),
|
|
53
|
-
attributes: {
|
|
54
|
-
source: this.source(snapshotArg),
|
|
55
|
-
sourceUri: state.sourceUri,
|
|
56
|
-
sourceList: this.sourceList(snapshotArg),
|
|
57
|
-
volumeLevel: state.volumeLevel,
|
|
58
|
-
isVolumeMuted: state.muted,
|
|
59
|
-
mediaTitle: state.mediaTitle,
|
|
60
|
-
mediaChannel: state.mediaChannel,
|
|
61
|
-
mediaContentId: state.mediaContentId,
|
|
62
|
-
mediaContentType: state.mediaContentType,
|
|
63
|
-
mediaDuration: state.mediaDuration,
|
|
64
|
-
mediaPosition: state.mediaPosition,
|
|
65
|
-
mediaPositionUpdatedAt: state.mediaPositionUpdatedAt,
|
|
66
|
-
model: snapshotArg.systemInfo.model,
|
|
67
|
-
powerStatus: state.powerStatus,
|
|
68
|
-
},
|
|
69
|
-
available: state.available !== false,
|
|
70
|
-
}];
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
public static deviceId(snapshotArg: IBraviatvSnapshot): string {
|
|
74
|
-
return `braviatv.device.${this.slug(this.identity(snapshotArg))}`;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
private static state(snapshotArg: IBraviatvSnapshot): IBraviatvState & Required<Pick<IBraviatvState, 'power' | 'playback'>> {
|
|
78
|
-
const state = snapshotArg.state || {};
|
|
79
|
-
const power = state.power || this.powerFromStatus(state.powerStatus);
|
|
80
|
-
return {
|
|
81
|
-
...state,
|
|
82
|
-
power,
|
|
83
|
-
playback: state.playback || (power === 'off' ? 'off' : 'idle'),
|
|
84
|
-
volumePercent: typeof state.volumePercent === 'number' ? state.volumePercent : typeof state.volumeLevel === 'number' ? Math.round(state.volumeLevel * 100) : undefined,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
private static mediaState(stateArg: IBraviatvState): string {
|
|
89
|
-
if (stateArg.available === false) {
|
|
90
|
-
return 'unavailable';
|
|
91
|
-
}
|
|
92
|
-
if (stateArg.power === 'off') {
|
|
93
|
-
return 'off';
|
|
94
|
-
}
|
|
95
|
-
if (stateArg.playback === 'playing') {
|
|
96
|
-
return 'playing';
|
|
97
|
-
}
|
|
98
|
-
if (stateArg.playback === 'paused') {
|
|
99
|
-
return 'paused';
|
|
100
|
-
}
|
|
101
|
-
if (stateArg.power === 'unknown') {
|
|
102
|
-
return 'unknown';
|
|
103
|
-
}
|
|
104
|
-
return stateArg.source || stateArg.mediaTitle ? 'on' : 'idle';
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private static source(snapshotArg: IBraviatvSnapshot): string | undefined {
|
|
108
|
-
return snapshotArg.state.source || this.sourceTitle(snapshotArg, snapshotArg.state.sourceUri) || snapshotArg.state.appTitle;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
private static sourceList(snapshotArg: IBraviatvSnapshot): string[] {
|
|
112
|
-
const values = [...snapshotArg.sources, ...snapshotArg.apps, ...(snapshotArg.channels || [])]
|
|
113
|
-
.map((sourceArg) => sourceArg.title)
|
|
114
|
-
.filter(Boolean);
|
|
115
|
-
return [...new Set(values)];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
private static sourceTitle(snapshotArg: IBraviatvSnapshot, uriArg: string | undefined): string | undefined {
|
|
119
|
-
if (!uriArg) {
|
|
120
|
-
return undefined;
|
|
121
|
-
}
|
|
122
|
-
return [...snapshotArg.sources, ...snapshotArg.apps, ...(snapshotArg.channels || [])].find((sourceArg) => sourceArg.uri === uriArg)?.title;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private static powerFromStatus(statusArg: string | undefined): 'on' | 'off' | 'unknown' {
|
|
126
|
-
const status = (statusArg || '').toLowerCase();
|
|
127
|
-
if (status === 'active') {
|
|
128
|
-
return 'on';
|
|
129
|
-
}
|
|
130
|
-
if (status === 'standby' || status === 'off') {
|
|
131
|
-
return 'off';
|
|
132
|
-
}
|
|
133
|
-
return 'unknown';
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
private static deviceName(snapshotArg: IBraviatvSnapshot): string {
|
|
137
|
-
return snapshotArg.systemInfo.name || snapshotArg.systemInfo.model || 'Sony Bravia TV';
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
private static identity(snapshotArg: IBraviatvSnapshot): string {
|
|
141
|
-
return snapshotArg.systemInfo.cid || snapshotArg.systemInfo.macAddr || snapshotArg.systemInfo.serial || this.deviceName(snapshotArg);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
private static slug(valueArg: string): string {
|
|
145
|
-
return valueArg.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '') || 'braviatv';
|
|
6
|
+
public static deviceId(homeId: string, macAddress: string): string {
|
|
7
|
+
return `braviatv.display.${encodeURIComponent(homeId)}.${macAddress.replace(/:/g, '').toLowerCase()}`;
|
|
8
|
+
}
|
|
9
|
+
public static entityId(homeId: string, macAddress: string, feature: TBraviatvControl['feature']): string {
|
|
10
|
+
return `${feature === 'speaker_volume_raw' ? 'number' : 'switch'}.braviatv.${encodeURIComponent(homeId)}.${macAddress.replace(/:/g, '').toLowerCase()}.${feature}`;
|
|
11
|
+
}
|
|
12
|
+
public static toDevices(snapshot: IBraviatvSnapshot): plugins.shxInterfaces.data.IDeviceDefinition[] {
|
|
13
|
+
const features: plugins.shxInterfaces.data.IDeviceFeature[] = [];
|
|
14
|
+
const state: plugins.shxInterfaces.data.IDeviceState[] = [];
|
|
15
|
+
if (snapshot.power !== undefined) {
|
|
16
|
+
features.push({ id: 'power', capability: 'switch', name: 'Reported display power', readable: true, writable: snapshot.capabilities.power });
|
|
17
|
+
state.push({ featureId: 'power', value: snapshot.power, updatedAt: snapshot.observedAt });
|
|
18
|
+
}
|
|
19
|
+
if (snapshot.speaker) {
|
|
20
|
+
features.push({ id: 'device_mute', capability: 'switch', name: 'Device mute (speaker observation)', readable: true, writable: snapshot.capabilities.deviceMute },
|
|
21
|
+
{ id: 'speaker_volume_raw', capability: 'sensor', name: 'Reported speaker volume', unit: 'raw level', readable: true, writable: snapshot.capabilities.speakerVolume });
|
|
22
|
+
state.push({ featureId: 'device_mute', value: snapshot.speaker.muted, updatedAt: snapshot.observedAt },
|
|
23
|
+
{ featureId: 'speaker_volume_raw', value: snapshot.speaker.volumeRaw, updatedAt: snapshot.observedAt });
|
|
24
|
+
}
|
|
25
|
+
return [{ id: this.deviceId(snapshot.homeId, snapshot.identity.macAddress), integrationDomain: 'braviatv',
|
|
26
|
+
name: snapshot.name, protocol: 'http', manufacturer: 'Sony', model: snapshot.identity.model, online: true, features, state,
|
|
27
|
+
metadata: { homeId: snapshot.homeId, host: snapshot.host, port: snapshot.port, macAddress: snapshot.identity.macAddress,
|
|
28
|
+
serialNumber: snapshot.identity.serial, stateSource: 'independent-display-report', identityAuthentication: 'psk-does-not-prove-peer-identity',
|
|
29
|
+
unencryptedLan: true, volumeLimitRaw: snapshot.capabilities.volumeLimitRaw,
|
|
30
|
+
...(snapshot.speaker ? { minimumVolumeRaw: snapshot.speaker.minimumVolumeRaw, maximumVolumeRaw: snapshot.speaker.maximumVolumeRaw } : {}) } }];
|
|
31
|
+
}
|
|
32
|
+
public static toEntities(snapshot: IBraviatvSnapshot): IIntegrationEntity[] {
|
|
33
|
+
const device = this.toDevices(snapshot)[0];
|
|
34
|
+
return device.features.map((feature) => ({
|
|
35
|
+
id: this.entityId(snapshot.homeId, snapshot.identity.macAddress, feature.id as TBraviatvControl['feature']),
|
|
36
|
+
uniqueId: `${device.id}.${feature.id}`, integrationDomain: 'braviatv', deviceId: device.id,
|
|
37
|
+
platform: feature.id === 'speaker_volume_raw' ? 'number' : 'switch', name: `${snapshot.name} ${feature.name}`,
|
|
38
|
+
state: device.state.find((entry) => entry.featureId === feature.id)!.value, available: true,
|
|
39
|
+
attributes: { ...device.metadata, observedAt: snapshot.observedAt, writable: feature.writable,
|
|
40
|
+
...(feature.id === 'speaker_volume_raw' ? { step: 1, minimum: snapshot.speaker!.minimumVolumeRaw,
|
|
41
|
+
maximum: snapshot.speaker!.maximumVolumeRaw,
|
|
42
|
+
...(snapshot.capabilities.speakerVolume ? { maximumWritableRaw: Math.min(snapshot.speaker!.maximumVolumeRaw, snapshot.capabilities.volumeLimitRaw) } : {}) } : {}) } }));
|
|
146
43
|
}
|
|
147
44
|
}
|
|
@@ -1,194 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export type TBraviatvPowerState = 'on' | 'off' | 'unknown';
|
|
4
|
-
|
|
5
|
-
export type TBraviatvPlaybackState = 'playing' | 'paused' | 'idle' | 'off' | 'unknown';
|
|
6
|
-
|
|
7
|
-
export type TBraviatvSourceType = 'input' | 'app' | 'channel';
|
|
8
|
-
|
|
9
|
-
export type TBraviatvRestService = 'accessControl' | 'appControl' | 'audio' | 'avContent' | 'guide' | 'system' | 'video' | 'videoScreen';
|
|
1
|
+
import type * as plugins from '../../plugins.js';
|
|
2
|
+
import type { IIntegrationSetupContext } from '../../core/types.js';
|
|
10
3
|
|
|
4
|
+
/** Selected BRAVIA Professional v1.0 endpoint; this object contains no credential. */
|
|
11
5
|
export interface IBraviatvConfig {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
6
|
+
homeId: string;
|
|
7
|
+
host: string;
|
|
8
|
+
expectedModel: string;
|
|
9
|
+
expectedMacAddress: string;
|
|
10
|
+
expectedSerial?: string;
|
|
11
|
+
credentialRef: string;
|
|
12
|
+
allowUnencryptedLan: true;
|
|
13
|
+
volumeLimitRaw: number;
|
|
20
14
|
name?: string;
|
|
21
|
-
|
|
22
|
-
manufacturer?: string;
|
|
23
|
-
macAddress?: string;
|
|
24
|
-
serialNumber?: string;
|
|
25
|
-
cid?: string;
|
|
15
|
+
port?: number;
|
|
26
16
|
timeoutMs?: number;
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
systemInfo?: IBraviatvSystemInfo;
|
|
30
|
-
state?: IBraviatvState;
|
|
31
|
-
sources?: IBraviatvSource[];
|
|
32
|
-
apps?: IBraviatvApp[];
|
|
33
|
-
channels?: IBraviatvChannel[];
|
|
34
|
-
commands?: Record<string, string>;
|
|
35
|
-
snapshot?: IBraviatvSnapshot;
|
|
36
|
-
scalarWebApiBaseUrl?: string;
|
|
17
|
+
maxPendingOperations?: number;
|
|
18
|
+
maxResponseBytes?: number;
|
|
37
19
|
}
|
|
38
|
-
|
|
39
20
|
export interface IHomeAssistantBraviatvConfig extends IBraviatvConfig {}
|
|
40
21
|
|
|
41
|
-
export interface
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
export interface IBraviatvSource {
|
|
77
|
-
title: string;
|
|
78
|
-
uri: string;
|
|
79
|
-
type?: TBraviatvSourceType;
|
|
80
|
-
icon?: string;
|
|
81
|
-
label?: string;
|
|
82
|
-
connection?: string;
|
|
83
|
-
status?: string;
|
|
84
|
-
dispNum?: string;
|
|
85
|
-
[key: string]: unknown;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
export interface IBraviatvApp extends IBraviatvSource {
|
|
89
|
-
type?: 'app';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface IBraviatvChannel extends IBraviatvSource {
|
|
93
|
-
type?: 'channel';
|
|
94
|
-
dispNum?: string;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export interface IBraviatvState {
|
|
98
|
-
powerStatus?: TBraviatvPowerStatus;
|
|
99
|
-
power?: TBraviatvPowerState;
|
|
100
|
-
playback?: TBraviatvPlaybackState;
|
|
101
|
-
available?: boolean;
|
|
102
|
-
source?: string;
|
|
103
|
-
sourceUri?: string;
|
|
104
|
-
appTitle?: string;
|
|
105
|
-
volumeLevel?: number;
|
|
106
|
-
volumePercent?: number;
|
|
107
|
-
muted?: boolean;
|
|
108
|
-
mediaTitle?: string;
|
|
109
|
-
mediaChannel?: string;
|
|
110
|
-
mediaContentId?: string;
|
|
111
|
-
mediaContentType?: string;
|
|
112
|
-
mediaDuration?: number;
|
|
113
|
-
mediaPosition?: number;
|
|
114
|
-
mediaPositionUpdatedAt?: string;
|
|
115
|
-
lastError?: string;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export interface IBraviatvSnapshot {
|
|
119
|
-
systemInfo: IBraviatvSystemInfo;
|
|
120
|
-
state: IBraviatvState;
|
|
121
|
-
sources: IBraviatvSource[];
|
|
122
|
-
apps: IBraviatvApp[];
|
|
123
|
-
channels?: IBraviatvChannel[];
|
|
124
|
-
commands?: Record<string, string>;
|
|
125
|
-
updatedAt?: string;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export interface IBraviatvRestCommand {
|
|
129
|
-
type: 'rest';
|
|
130
|
-
service: TBraviatvRestService;
|
|
131
|
-
method: string;
|
|
132
|
-
params?: unknown[];
|
|
133
|
-
version?: string;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface IBraviatvIrccCommand {
|
|
137
|
-
type: 'ircc';
|
|
138
|
-
command?: string;
|
|
139
|
-
code?: string;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export interface IBraviatvSourceCommand {
|
|
143
|
-
type: 'source';
|
|
144
|
-
source: string;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export type TBraviatvCommand = IBraviatvRestCommand | IBraviatvIrccCommand | IBraviatvSourceCommand;
|
|
148
|
-
|
|
149
|
-
export interface IBraviatvEvent {
|
|
150
|
-
type: 'snapshot' | 'command' | 'error';
|
|
151
|
-
command?: TBraviatvCommand;
|
|
152
|
-
snapshot?: IBraviatvSnapshot;
|
|
153
|
-
message?: string;
|
|
154
|
-
timestamp: number;
|
|
155
|
-
}
|
|
156
|
-
|
|
22
|
+
export interface IBraviatvCredentialRequest {
|
|
23
|
+
readonly homeId: string;
|
|
24
|
+
readonly credentialRef: string;
|
|
25
|
+
readonly signal: AbortSignal;
|
|
26
|
+
readonly deadline: number;
|
|
27
|
+
}
|
|
28
|
+
/** Caller owns credential retrieval, storage and its cancellation implementation. */
|
|
29
|
+
export type TBraviatvPskResolver = (request: IBraviatvCredentialRequest) => Promise<string>;
|
|
30
|
+
export interface IBraviatvIntegrationOptions {
|
|
31
|
+
readonly homeId?: string;
|
|
32
|
+
readonly capacity?: number;
|
|
33
|
+
readonly resolvePsk: TBraviatvPskResolver;
|
|
34
|
+
}
|
|
35
|
+
export interface IBraviatvSetupContext extends IIntegrationSetupContext { homeId: string; }
|
|
36
|
+
|
|
37
|
+
export interface IBraviatvSnapshot extends plugins.ecobridgeDeviceManager.ISonyBraviaState {
|
|
38
|
+
readonly homeId: string;
|
|
39
|
+
readonly host: string;
|
|
40
|
+
readonly port: number;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
}
|
|
43
|
+
export interface IBraviatvEffectResult {
|
|
44
|
+
readonly control: plugins.ecobridgeDeviceManager.ISonyBraviaControlObservation['control'];
|
|
45
|
+
readonly requested: boolean | number;
|
|
46
|
+
readonly commandAcknowledged: true;
|
|
47
|
+
readonly causalityConfirmed: false;
|
|
48
|
+
readonly observation: plugins.ecobridgeDeviceManager.ISonyBraviaControlObservation['observation'];
|
|
49
|
+
readonly snapshot: IBraviatvSnapshot;
|
|
50
|
+
}
|
|
51
|
+
export type TBraviatvControl = { feature: 'power'; value: boolean }
|
|
52
|
+
| { feature: 'device_mute'; value: boolean }
|
|
53
|
+
| { feature: 'speaker_volume_raw'; value: number };
|
|
54
|
+
|
|
55
|
+
/** Unverified discovery hints do not establish identity or authorize control. */
|
|
157
56
|
export interface IBraviatvSsdpRecord {
|
|
158
|
-
st?: string;
|
|
159
|
-
usn?: string;
|
|
160
|
-
location?: string;
|
|
57
|
+
st?: string; usn?: string; location?: string;
|
|
161
58
|
headers?: Record<string, string | undefined>;
|
|
162
59
|
upnp?: Record<string, unknown>;
|
|
163
|
-
ssdp_st?: string;
|
|
164
|
-
ssdp_usn?: string;
|
|
165
|
-
ssdp_location?: string;
|
|
60
|
+
ssdp_st?: string; ssdp_usn?: string; ssdp_location?: string;
|
|
166
61
|
[key: string]: unknown;
|
|
167
62
|
}
|
|
168
|
-
|
|
169
63
|
export interface IBraviatvMdnsRecord {
|
|
170
|
-
type?: string;
|
|
171
|
-
name?: string;
|
|
172
|
-
host?: string;
|
|
173
|
-
port?: number;
|
|
64
|
+
type?: string; name?: string; host?: string; port?: number;
|
|
174
65
|
txt?: Record<string, string | undefined>;
|
|
175
66
|
properties?: Record<string, string | undefined>;
|
|
176
67
|
metadata?: Record<string, unknown>;
|
|
177
68
|
}
|
|
178
|
-
|
|
179
69
|
export interface IBraviatvManualEntry {
|
|
180
|
-
host?: string;
|
|
181
|
-
|
|
182
|
-
id?: string;
|
|
183
|
-
name?: string;
|
|
184
|
-
model?: string;
|
|
185
|
-
manufacturer?: string;
|
|
186
|
-
macAddress?: string;
|
|
187
|
-
serialNumber?: string;
|
|
188
|
-
cid?: string;
|
|
189
|
-
psk?: string;
|
|
190
|
-
useSsl?: boolean;
|
|
70
|
+
host?: string; port?: number; id?: string; name?: string; model?: string;
|
|
71
|
+
manufacturer?: string; macAddress?: string; serialNumber?: string; cid?: string;
|
|
191
72
|
metadata?: Record<string, unknown>;
|
|
192
73
|
}
|
|
193
|
-
|
|
194
74
|
export type TBraviatvDiscoveryRecord = IBraviatvSsdpRecord | IBraviatvMdnsRecord | IBraviatvManualEntry;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import type { IBraviatvConfig, IBraviatvIntegrationOptions, TBraviatvControl } from './braviatv.types.js';
|
|
3
|
+
|
|
4
|
+
export function braviatvRecord(value: unknown, allowed?: readonly string[]): Record<string, unknown> {
|
|
5
|
+
if (!value || typeof value !== 'object' || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) {
|
|
6
|
+
throw new TypeError('BRAVIA input must be a plain data object.');
|
|
7
|
+
}
|
|
8
|
+
const result: Record<string, unknown> = {};
|
|
9
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
10
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
11
|
+
if (typeof key !== 'string' || allowed && !allowed.includes(key) || !descriptor || !('value' in descriptor) || !descriptor.enumerable) {
|
|
12
|
+
throw new TypeError('BRAVIA input contains an unsupported field or accessor.');
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(result, key, { value: descriptor.value, enumerable: true });
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
18
|
+
export function braviatvText(value: unknown, label: string, maximum = 128): string {
|
|
19
|
+
if (typeof value !== 'string' || !value || value !== value.trim() || value.length > maximum || /[\p{Cc}\p{Cs}]/u.test(value)) {
|
|
20
|
+
throw new TypeError(`BRAVIA ${label} must be bounded text without control characters.`);
|
|
21
|
+
}
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
export function braviatvInteger(value: unknown, minimum: number, maximum: number): number {
|
|
25
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < minimum || value > maximum) {
|
|
26
|
+
throw new TypeError('BRAVIA integer is outside its supported bounds.');
|
|
27
|
+
}
|
|
28
|
+
return value;
|
|
29
|
+
}
|
|
30
|
+
export function normalizeBraviatvConfig(value: unknown): Readonly<Required<Omit<IBraviatvConfig, 'expectedSerial' | 'name'>> & Pick<IBraviatvConfig, 'expectedSerial' | 'name'>> {
|
|
31
|
+
const config = braviatvRecord(value, ['homeId', 'host', 'expectedModel', 'expectedMacAddress', 'expectedSerial',
|
|
32
|
+
'credentialRef', 'allowUnencryptedLan', 'volumeLimitRaw', 'name', 'port', 'timeoutMs', 'maxPendingOperations', 'maxResponseBytes']);
|
|
33
|
+
const host = braviatvText(config.host, 'selected IPv4', 15);
|
|
34
|
+
const [first, second, , last] = host.split('.').map(Number);
|
|
35
|
+
if (plugins.net.isIP(host) !== 4 || !(first === 10 || first === 127 || first === 172 && second >= 16 && second <= 31 || first === 192 && second === 168) || last === 0 || last === 255) {
|
|
36
|
+
throw new TypeError('BRAVIA requires a selected private or loopback host IPv4 address.');
|
|
37
|
+
}
|
|
38
|
+
const mac = braviatvText(config.expectedMacAddress, 'selected active-network MAC', 17);
|
|
39
|
+
if (!/^(?:[0-9a-f]{2}:){5}[0-9a-f]{2}$/i.test(mac) || /^(?:00:){5}00$|^(?:ff:){5}ff$/i.test(mac) || (Number.parseInt(mac.slice(0, 2), 16) & 1) !== 0) {
|
|
40
|
+
throw new TypeError('BRAVIA requires an exact usable active-network MAC.');
|
|
41
|
+
}
|
|
42
|
+
if (config.allowUnencryptedLan !== true) throw new TypeError('BRAVIA requires explicit unencrypted LAN consent.');
|
|
43
|
+
return Object.freeze({ homeId: braviatvText(config.homeId, 'home ID', 256), host,
|
|
44
|
+
expectedModel: braviatvText(config.expectedModel, 'selected model'), expectedMacAddress: mac.toUpperCase(),
|
|
45
|
+
...(config.expectedSerial === undefined ? {} : { expectedSerial: braviatvText(config.expectedSerial, 'selected serial') }),
|
|
46
|
+
credentialRef: braviatvText(config.credentialRef, 'credential reference', 256), allowUnencryptedLan: true,
|
|
47
|
+
volumeLimitRaw: braviatvInteger(config.volumeLimitRaw, 0, 100),
|
|
48
|
+
...(config.name === undefined ? {} : { name: braviatvText(config.name, 'display name') }),
|
|
49
|
+
port: braviatvInteger(config.port ?? 80, 1, 65535), timeoutMs: braviatvInteger(config.timeoutMs ?? 5000, 1, 30000),
|
|
50
|
+
maxPendingOperations: braviatvInteger(config.maxPendingOperations ?? 16, 1, 128),
|
|
51
|
+
maxResponseBytes: braviatvInteger(config.maxResponseBytes ?? 32768, 1024, 65536) });
|
|
52
|
+
}
|
|
53
|
+
export function normalizeBraviatvOptions(value: unknown): Readonly<IBraviatvIntegrationOptions> {
|
|
54
|
+
const options = braviatvRecord(value, ['homeId', 'capacity', 'resolvePsk']);
|
|
55
|
+
if (typeof options.resolvePsk !== 'function') throw new TypeError('BRAVIA requires a caller-owned PSK resolver.');
|
|
56
|
+
return Object.freeze({
|
|
57
|
+
...(options.homeId === undefined ? {} : { homeId: braviatvText(options.homeId, 'caller home ID', 256) }),
|
|
58
|
+
...(options.capacity === undefined ? {} : { capacity: braviatvInteger(options.capacity, 1, Number.MAX_SAFE_INTEGER) }),
|
|
59
|
+
resolvePsk: options.resolvePsk as IBraviatvIntegrationOptions['resolvePsk'],
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export function validateBraviatvControl(value: unknown): TBraviatvControl {
|
|
63
|
+
const control = braviatvRecord(value, ['feature', 'value']);
|
|
64
|
+
if (control.feature === 'power' && typeof control.value === 'boolean') return { feature: 'power', value: control.value };
|
|
65
|
+
if (control.feature === 'device_mute' && typeof control.value === 'boolean') return { feature: 'device_mute', value: control.value };
|
|
66
|
+
if (control.feature === 'speaker_volume_raw') return { feature: 'speaker_volume_raw', value: braviatvInteger(control.value, 0, 100) };
|
|
67
|
+
throw new TypeError('BRAVIA supports absolute power, device mute and integer speaker volume only.');
|
|
68
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { broadlinkRecord, broadlinkName } from './broadlink.validation.js';
|
|
3
|
+
import type { IBroadlinkIrAction } from './broadlink.types.js';
|
|
4
|
+
|
|
5
|
+
export const readBroadlinkActions = (valueArg: unknown): ReadonlyArray<Readonly<IBroadlinkIrAction>> => {
|
|
6
|
+
if (!Array.isArray(valueArg) || Object.getPrototypeOf(valueArg) !== Array.prototype
|
|
7
|
+
|| valueArg.length < 1 || valueArg.length > 32 || Reflect.ownKeys(valueArg).length !== valueArg.length + 1) {
|
|
8
|
+
throw new TypeError('Broadlink requires 1 through 32 owner-configured IR actions in a dense array.');
|
|
9
|
+
}
|
|
10
|
+
const ids = new Set<string>();
|
|
11
|
+
const actions: Readonly<IBroadlinkIrAction>[] = [];
|
|
12
|
+
for (let index = 0; index < valueArg.length; index++) {
|
|
13
|
+
const descriptor = Object.getOwnPropertyDescriptor(valueArg, String(index));
|
|
14
|
+
if (!descriptor?.enumerable || !('value' in descriptor)) throw new TypeError('Broadlink actions may not contain accessors or holes.');
|
|
15
|
+
const action = broadlinkRecord(descriptor.value, ['id', 'name', 'packetBase64']);
|
|
16
|
+
if (typeof action.id !== 'string' || !/^[a-z][a-z0-9_-]{0,63}$/.test(action.id) || ids.has(action.id)) {
|
|
17
|
+
throw new TypeError('Broadlink action IDs must be unique lowercase identifiers, at most 64 characters.');
|
|
18
|
+
}
|
|
19
|
+
const name = broadlinkName(action.name, 'action name', 128);
|
|
20
|
+
if (typeof action.packetBase64 !== 'string' || action.packetBase64.length > 1368) throw new TypeError('Broadlink IR action requires bounded canonical base64.');
|
|
21
|
+
const packet = Buffer.from(action.packetBase64, 'base64');
|
|
22
|
+
try {
|
|
23
|
+
if (packet.toString('base64') !== action.packetBase64) throw new TypeError('Broadlink IR action requires canonical base64.');
|
|
24
|
+
const validated = plugins.ecobridgeDeviceManager.copyBroadlinkIrPacket(packet);
|
|
25
|
+
validated.fill(0);
|
|
26
|
+
} finally { packet.fill(0); }
|
|
27
|
+
ids.add(action.id);
|
|
28
|
+
actions.push(Object.freeze({ id: action.id, name, packetBase64: action.packetBase64 }));
|
|
29
|
+
}
|
|
30
|
+
return Object.freeze(actions);
|
|
31
|
+
};
|