@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,683 +1,74 @@
|
|
|
1
|
+
import * as plugins from '../../plugins.js';
|
|
2
|
+
import { NativeHomeAdmission } from '../../core/classes.nativehomeadmission.js';
|
|
3
|
+
import type { INativeIntegrationSetupContext } from '../../core/types.js';
|
|
1
4
|
import { DaikinMapper } from './daikin.mapper.js';
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
IDaikinConfig,
|
|
5
|
-
IDaikinControlSettings,
|
|
6
|
-
IDaikinRawData,
|
|
7
|
-
IDaikinRefreshResult,
|
|
8
|
-
IDaikinSnapshot,
|
|
9
|
-
IDaikinValueMap,
|
|
10
|
-
TDaikinApiVariant,
|
|
11
|
-
} from './daikin.types.js';
|
|
12
|
-
import { daikinDefaultHttpPort, daikinDefaultHttpsPort, daikinDefaultTimeoutMs, daikinSkyFiPort } from './daikin.types.js';
|
|
13
|
-
|
|
14
|
-
export class DaikinApiError extends Error {}
|
|
15
|
-
export class DaikinApiConnectionError extends DaikinApiError {}
|
|
16
|
-
export class DaikinApiAuthorizationError extends DaikinApiError {}
|
|
17
|
-
export class DaikinUnsupportedCommandError extends DaikinApiError {}
|
|
18
|
-
|
|
19
|
-
const legacyResources = [
|
|
20
|
-
'common/basic_info',
|
|
21
|
-
'aircon/get_sensor_info',
|
|
22
|
-
'aircon/get_model_info',
|
|
23
|
-
'aircon/get_control_info',
|
|
24
|
-
'aircon/get_target',
|
|
25
|
-
'common/get_holiday',
|
|
26
|
-
'common/get_notify',
|
|
27
|
-
'aircon/get_day_power_ex',
|
|
28
|
-
'aircon/get_week_power',
|
|
29
|
-
'aircon/get_year_power',
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
const airbaseResources = [
|
|
33
|
-
'skyfi/common/basic_info',
|
|
34
|
-
'skyfi/aircon/get_control_info',
|
|
35
|
-
'skyfi/aircon/get_model_info',
|
|
36
|
-
'skyfi/aircon/get_sensor_info',
|
|
37
|
-
'skyfi/aircon/get_zone_setting',
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
const resourceKeyMap: Record<string, keyof IDaikinRawData> = {
|
|
41
|
-
'common/basic_info': 'basicInfo',
|
|
42
|
-
'skyfi/common/basic_info': 'basicInfo',
|
|
43
|
-
'aircon/get_control_info': 'controlInfo',
|
|
44
|
-
'skyfi/aircon/get_control_info': 'controlInfo',
|
|
45
|
-
'aircon/get_sensor_info': 'sensorInfo',
|
|
46
|
-
'skyfi/aircon/get_sensor_info': 'sensorInfo',
|
|
47
|
-
'aircon/get_model_info': 'modelInfo',
|
|
48
|
-
'skyfi/aircon/get_model_info': 'modelInfo',
|
|
49
|
-
'common/get_holiday': 'holiday',
|
|
50
|
-
'common/get_notify': 'notify',
|
|
51
|
-
'aircon/get_day_power_ex': 'dayPowerEx',
|
|
52
|
-
'aircon/get_week_power': 'weekPower',
|
|
53
|
-
'aircon/get_year_power': 'yearPower',
|
|
54
|
-
'skyfi/aircon/get_zone_setting': 'zoneSetting',
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
const brp084ModeMap: Record<string, string> = {
|
|
58
|
-
'0300': 'auto',
|
|
59
|
-
'0200': 'cool',
|
|
60
|
-
'0100': 'heat',
|
|
61
|
-
'0000': 'fan',
|
|
62
|
-
'0500': 'dry',
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const brp084FanModeMap: Record<string, string> = {
|
|
66
|
-
'0A00': 'auto',
|
|
67
|
-
'0B00': 'quiet',
|
|
68
|
-
'0300': '1',
|
|
69
|
-
'0400': '2',
|
|
70
|
-
'0500': '3',
|
|
71
|
-
'0600': '4',
|
|
72
|
-
'0700': '5',
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
const brp084Paths = {
|
|
76
|
-
power: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_A002', 'p_01'],
|
|
77
|
-
mode: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_01'],
|
|
78
|
-
indoorTemp: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_A00B', 'p_01'],
|
|
79
|
-
indoorHumidity: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_A00B', 'p_02'],
|
|
80
|
-
outdoorTemp: ['/dsiot/edge/adr_0200.dgc_status', 'dgc_status', 'e_1003', 'e_A00D', 'p_01'],
|
|
81
|
-
mac: ['/dsiot/edge.adp_i', 'adp_i', 'mac'],
|
|
82
|
-
coolTemp: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_02'],
|
|
83
|
-
heatTemp: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_03'],
|
|
84
|
-
autoTemp: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_1D'],
|
|
85
|
-
coolFan: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_09'],
|
|
86
|
-
heatFan: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_0A'],
|
|
87
|
-
autoFan: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_26'],
|
|
88
|
-
fanFan: ['/dsiot/edge/adr_0100.dgc_status', 'dgc_status', 'e_1002', 'e_3001', 'p_28'],
|
|
89
|
-
todayRuntime: ['/dsiot/edge/adr_0100.i_power.week_power', 'week_power', 'today_runtime'],
|
|
90
|
-
weeklyData: ['/dsiot/edge/adr_0100.i_power.week_power', 'week_power', 'datas'],
|
|
91
|
-
};
|
|
5
|
+
import type { IDaikinNativeConfig, IDaikinSnapshot } from './daikin.types.js';
|
|
6
|
+
import { normalizeDaikinConfig } from './daikin.validation.js';
|
|
92
7
|
|
|
8
|
+
/** Selected BRP069 facade. The public protocol owns validation, preflight, HTTP, queueing and drain. */
|
|
93
9
|
export class DaikinClient {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.currentSnapshot = await this.snapshotFromClient();
|
|
111
|
-
} catch (errorArg) {
|
|
112
|
-
this.currentSnapshot = this.offlineSnapshot(this.errorMessage(errorArg));
|
|
113
|
-
}
|
|
114
|
-
return this.cloneSnapshot(this.currentSnapshot);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (!forceRefreshArg && this.hasManualData()) {
|
|
118
|
-
this.currentSnapshot = DaikinMapper.toSnapshot({ config: this.config, online: this.config.online ?? true, source: 'manual' });
|
|
119
|
-
return this.cloneSnapshot(this.currentSnapshot);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (this.config.host || this.config.url) {
|
|
123
|
-
try {
|
|
124
|
-
this.currentSnapshot = await this.fetchSnapshot();
|
|
125
|
-
} catch (errorArg) {
|
|
126
|
-
this.currentSnapshot = this.offlineSnapshot(this.errorMessage(errorArg));
|
|
127
|
-
}
|
|
128
|
-
return this.cloneSnapshot(this.currentSnapshot);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
this.currentSnapshot = this.offlineSnapshot('No Daikin local HTTP endpoint, client, snapshot, or manual data is configured.');
|
|
132
|
-
return this.cloneSnapshot(this.currentSnapshot);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
public async refresh(): Promise<IDaikinRefreshResult> {
|
|
136
|
-
try {
|
|
137
|
-
this.currentSnapshot = undefined;
|
|
138
|
-
const snapshot = await this.getSnapshot(Boolean(this.config.host || this.config.url || this.config.client));
|
|
139
|
-
const success = snapshot.online && !snapshot.error;
|
|
140
|
-
return { success, snapshot, error: success ? undefined : snapshot.error, data: { source: snapshot.source } };
|
|
141
|
-
} catch (errorArg) {
|
|
142
|
-
const error = this.errorMessage(errorArg);
|
|
143
|
-
const snapshot = this.offlineSnapshot(error);
|
|
144
|
-
this.currentSnapshot = snapshot;
|
|
145
|
-
return { success: false, snapshot: this.cloneSnapshot(snapshot), error };
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
public async fetchSnapshot(): Promise<IDaikinSnapshot> {
|
|
150
|
-
const variant = this.config.apiVariant || 'auto';
|
|
151
|
-
if (variant === 'skyfi' || this.config.password) {
|
|
152
|
-
return this.snapshotFromRawData(await this.fetchSkyFiRawData(), 'http');
|
|
153
|
-
}
|
|
154
|
-
if (variant === 'airbase') {
|
|
155
|
-
return this.snapshotFromRawData(await this.fetchLegacyRawData('airbase'), 'http');
|
|
156
|
-
}
|
|
157
|
-
if (variant === 'brp084') {
|
|
158
|
-
return this.snapshotFromRawData(await this.fetchBrp084RawData(), 'http');
|
|
159
|
-
}
|
|
160
|
-
if (variant === 'brp072c' || this.config.apiKey) {
|
|
161
|
-
return this.snapshotFromRawData(await this.fetchLegacyRawData('brp072c'), 'http');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const legacy = await this.fetchLegacyRawData('brp069');
|
|
165
|
-
const legacyValues = DaikinMapper.valuesFromRawData(legacy);
|
|
166
|
-
if (legacyValues.mode || legacyValues.pow || legacyValues.htemp || legacyValues.mac) {
|
|
167
|
-
return this.snapshotFromRawData(legacy, 'http');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
return this.snapshotFromRawData(await this.fetchLegacyRawData('airbase'), 'http');
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
public async execute(commandArg: IDaikinCommandRequest): Promise<unknown> {
|
|
174
|
-
if (this.config.commandExecutor) {
|
|
175
|
-
return this.config.commandExecutor.execute(commandArg);
|
|
176
|
-
}
|
|
177
|
-
if (this.config.client?.execute) {
|
|
178
|
-
return this.config.client.execute(commandArg);
|
|
179
|
-
}
|
|
180
|
-
if (commandArg.action === 'refresh') {
|
|
181
|
-
return (await this.refresh()).snapshot;
|
|
182
|
-
}
|
|
183
|
-
if (!this.config.host && !this.config.url) {
|
|
184
|
-
throw new DaikinApiConnectionError('Daikin commands require config.host/config.url, an injected client.execute, or commandExecutor. Static snapshots/manual data are read-only.');
|
|
185
|
-
}
|
|
186
|
-
if (commandArg.path && commandArg.method) {
|
|
187
|
-
return this.requestKeyValue(commandArg.path, commandArg.query, this.requestVariant(commandArg.protocol), true);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
switch (commandArg.action) {
|
|
191
|
-
case 'set_control':
|
|
192
|
-
return this.setControl(commandArg.settings || {}, this.requestVariant(commandArg.protocol));
|
|
193
|
-
case 'set_holiday':
|
|
194
|
-
return this.setHoliday(Boolean(commandArg.enabled), this.requestVariant(commandArg.protocol));
|
|
195
|
-
case 'set_advanced_mode':
|
|
196
|
-
return this.setAdvancedMode(commandArg.mode || 'powerful', Boolean(commandArg.enabled), this.requestVariant(commandArg.protocol));
|
|
197
|
-
case 'set_streamer':
|
|
198
|
-
return this.setStreamer(Boolean(commandArg.enabled), this.requestVariant(commandArg.protocol));
|
|
199
|
-
case 'set_zone':
|
|
200
|
-
return this.setZone(commandArg.zoneId, commandArg.zoneKey || 'zone_onoff', commandArg.zoneValue ?? (commandArg.enabled ? '1' : '0'), this.requestVariant(commandArg.protocol));
|
|
201
|
-
default:
|
|
202
|
-
throw new DaikinUnsupportedCommandError(`Unsupported Daikin command: ${commandArg.action}`);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
public async destroy(): Promise<void> {
|
|
207
|
-
await this.config.client?.destroy?.();
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
private async snapshotFromClient(): Promise<IDaikinSnapshot> {
|
|
211
|
-
const client = this.config.client;
|
|
212
|
-
if (!client) {
|
|
213
|
-
throw new DaikinApiConnectionError('No Daikin client configured.');
|
|
214
|
-
}
|
|
215
|
-
if (client.getSnapshot) {
|
|
216
|
-
const result = await client.getSnapshot();
|
|
217
|
-
if (this.isSnapshot(result)) {
|
|
218
|
-
return DaikinMapper.toSnapshot({ config: { ...this.config, snapshot: result }, source: 'client', online: result.online });
|
|
219
|
-
}
|
|
220
|
-
return DaikinMapper.toSnapshot({ config: this.config, rawData: result, online: true, source: 'client' });
|
|
221
|
-
}
|
|
222
|
-
if (client.getRawData) {
|
|
223
|
-
return DaikinMapper.toSnapshot({ config: this.config, rawData: await client.getRawData(), online: true, source: 'client' });
|
|
224
|
-
}
|
|
225
|
-
throw new DaikinApiConnectionError('Daikin client must expose getSnapshot() or getRawData().');
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private snapshotFromRawData(rawDataArg: Partial<IDaikinRawData>, sourceArg: 'http' | 'manual' | 'client'): IDaikinSnapshot {
|
|
229
|
-
return DaikinMapper.toSnapshot({ config: this.config, rawData: rawDataArg, online: true, source: sourceArg });
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
private async fetchLegacyRawData(variantArg: TDaikinApiVariant): Promise<Partial<IDaikinRawData>> {
|
|
233
|
-
const resources = variantArg === 'airbase' ? airbaseResources : legacyResources;
|
|
234
|
-
if (variantArg === 'brp072c' && this.config.apiKey) {
|
|
235
|
-
await this.requestKeyValue('common/register_terminal', { key: this.config.apiKey }, variantArg, true);
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const rawData: Partial<IDaikinRawData> = { variant: variantArg, resources: {}, fetchedAt: new Date().toISOString() };
|
|
239
|
-
for (const resource of resources) {
|
|
240
|
-
const data = await this.requestKeyValue(resource, undefined, variantArg, true).catch((errorArg) => {
|
|
241
|
-
if (resource === resources[0]) {
|
|
242
|
-
throw errorArg;
|
|
243
|
-
}
|
|
244
|
-
return {};
|
|
245
|
-
});
|
|
246
|
-
rawData.resources![resource] = data;
|
|
247
|
-
const key = resourceKeyMap[resource];
|
|
248
|
-
if (key) {
|
|
249
|
-
(rawData as Record<string, unknown>)[key] = data;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
return rawData;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
private async fetchSkyFiRawData(): Promise<Partial<IDaikinRawData>> {
|
|
256
|
-
const ac = await this.requestSkyFi('ac.cgi');
|
|
257
|
-
const zones = await this.requestSkyFi('zones.cgi').catch(() => ({}));
|
|
258
|
-
return {
|
|
259
|
-
variant: 'skyfi',
|
|
260
|
-
skyfiAc: ac,
|
|
261
|
-
skyfiZones: zones,
|
|
262
|
-
values: { ...ac, ...zones },
|
|
263
|
-
fetchedAt: new Date().toISOString(),
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
private async fetchBrp084RawData(): Promise<Partial<IDaikinRawData>> {
|
|
268
|
-
const payload = {
|
|
269
|
-
requests: [
|
|
270
|
-
{ op: 2, to: '/dsiot/edge/adr_0100.dgc_status?filter=pv,pt,md' },
|
|
271
|
-
{ op: 2, to: '/dsiot/edge/adr_0200.dgc_status?filter=pv,pt,md' },
|
|
272
|
-
{ op: 2, to: '/dsiot/edge/adr_0100.i_power.week_power?filter=pv,pt,md' },
|
|
273
|
-
{ op: 2, to: '/dsiot/edge.adp_i' },
|
|
274
|
-
],
|
|
275
|
-
};
|
|
276
|
-
const response = await this.requestJson<Record<string, unknown>>('/dsiot/multireq', payload, 'brp084');
|
|
277
|
-
const modeValue = this.findBrp084Value(response, brp084Paths.mode);
|
|
278
|
-
const mode = brp084ModeMap[modeValue] || modeValue;
|
|
279
|
-
const isOff = this.findBrp084Value(response, brp084Paths.power) === '00';
|
|
280
|
-
const tempPath = mode === 'cool' ? brp084Paths.coolTemp : mode === 'heat' ? brp084Paths.heatTemp : brp084Paths.autoTemp;
|
|
281
|
-
const fanPath = mode === 'cool' ? brp084Paths.coolFan : mode === 'heat' ? brp084Paths.heatFan : mode === 'fan' ? brp084Paths.fanFan : brp084Paths.autoFan;
|
|
282
|
-
const values: IDaikinValueMap = {
|
|
283
|
-
mac: this.findBrp084Value(response, brp084Paths.mac),
|
|
284
|
-
pow: isOff ? '0' : '1',
|
|
285
|
-
mode: isOff ? 'off' : mode,
|
|
286
|
-
otemp: this.hexTemp(this.findBrp084Value(response, brp084Paths.outdoorTemp)),
|
|
287
|
-
htemp: this.hexTemp(this.findBrp084Value(response, brp084Paths.indoorTemp), 1),
|
|
288
|
-
hhum: this.hexInt(this.findBrp084Value(response, brp084Paths.indoorHumidity)),
|
|
289
|
-
stemp: this.hexTemp(this.findBrp084Value(response, tempPath)),
|
|
290
|
-
f_rate: brp084FanModeMap[this.findBrp084Value(response, fanPath)] || 'auto',
|
|
291
|
-
datas: this.brp084WeeklyData(response),
|
|
292
|
-
};
|
|
293
|
-
return { variant: 'brp084', brp084: response, values, fetchedAt: new Date().toISOString() };
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
private async setControl(settingsArg: Partial<IDaikinControlSettings>, variantArg: TDaikinApiVariant): Promise<unknown> {
|
|
297
|
-
if (variantArg === 'skyfi') {
|
|
298
|
-
return this.setSkyFiControl(settingsArg);
|
|
299
|
-
}
|
|
300
|
-
if (variantArg === 'brp084') {
|
|
301
|
-
throw new DaikinUnsupportedCommandError('Daikin BRP084 dsiot control writes are not implemented by this native port. Provide commandExecutor for BRP084 controls.');
|
|
302
|
-
}
|
|
303
|
-
return this.setLegacyControl(settingsArg, variantArg === 'airbase' ? 'airbase' : 'brp069');
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
private async setLegacyControl(settingsArg: Partial<IDaikinControlSettings>, variantArg: 'brp069' | 'airbase'): Promise<unknown> {
|
|
307
|
-
const prefix = variantArg === 'airbase' ? 'skyfi/' : '';
|
|
308
|
-
const current = await this.requestKeyValue(`${prefix}aircon/get_control_info`, undefined, variantArg, true);
|
|
309
|
-
const values: IDaikinValueMap = { ...current };
|
|
310
|
-
this.applyControlSettings(values, settingsArg, variantArg);
|
|
311
|
-
|
|
312
|
-
if (settingsArg.mode === 'off') {
|
|
313
|
-
values.pow = '0';
|
|
314
|
-
values.mode = current.mode || values.mode;
|
|
315
|
-
} else if ('mode' in settingsArg || Object.keys(settingsArg).length === 0) {
|
|
316
|
-
values.pow = '1';
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
this.fillModeDefaults(values, current);
|
|
320
|
-
const query = variantArg === 'airbase'
|
|
321
|
-
? {
|
|
322
|
-
f_airside: values.f_airside || 0,
|
|
323
|
-
f_auto: values.f_auto || '0',
|
|
324
|
-
f_dir: values.f_dir || '0',
|
|
325
|
-
f_rate: (values.f_rate || 'A')[0],
|
|
326
|
-
lpw: '',
|
|
327
|
-
mode: values.mode || current.mode || '0',
|
|
328
|
-
pow: values.pow || current.pow || '1',
|
|
329
|
-
shum: values.shum || current.shum || '--',
|
|
330
|
-
stemp: values.stemp || current.stemp || '--',
|
|
331
|
-
}
|
|
332
|
-
: this.cleanQuery({
|
|
333
|
-
mode: values.mode || current.mode || '0',
|
|
334
|
-
pow: values.pow || current.pow || '1',
|
|
335
|
-
shum: values.shum || current.shum || '--',
|
|
336
|
-
stemp: values.stemp || current.stemp || '--',
|
|
337
|
-
f_rate: values.f_rate !== undefined || current.f_rate !== undefined ? values.f_rate || current.f_rate : undefined,
|
|
338
|
-
f_dir: values.f_dir !== undefined || current.f_dir !== undefined ? values.f_dir || current.f_dir : undefined,
|
|
339
|
-
f_dir_ud: current.f_dir_ud !== undefined ? this.swingAxis(values.f_dir, 'ud') : undefined,
|
|
340
|
-
f_dir_lr: current.f_dir_lr !== undefined ? this.swingAxis(values.f_dir, 'lr') : undefined,
|
|
341
|
-
});
|
|
342
|
-
return this.requestKeyValue(`${prefix}aircon/set_control_info`, query, variantArg, true);
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
private async setSkyFiControl(settingsArg: Partial<IDaikinControlSettings>): Promise<unknown> {
|
|
346
|
-
const current = await this.requestSkyFi('ac.cgi');
|
|
347
|
-
const values: IDaikinValueMap = { ...current };
|
|
348
|
-
this.applyControlSettings(values, settingsArg, 'skyfi');
|
|
349
|
-
if (settingsArg.mode === 'off') {
|
|
350
|
-
return this.requestSkyFi('set.cgi', { p: '0' });
|
|
351
|
-
}
|
|
352
|
-
if ('mode' in settingsArg || Object.keys(settingsArg).length === 0) {
|
|
353
|
-
values.opmode = '1';
|
|
354
|
-
values.pow = '1';
|
|
355
|
-
}
|
|
356
|
-
return this.requestSkyFi('set.cgi', {
|
|
357
|
-
p: values.opmode || values.pow || '1',
|
|
358
|
-
t: values.settemp || values.stemp || current.settemp || current.stemp,
|
|
359
|
-
f: values.fanspeed || values.f_rate || current.fanspeed || current.f_rate,
|
|
360
|
-
m: values.acmode || values.mode || current.acmode || current.mode,
|
|
10
|
+
readonly #config: Readonly<IDaikinNativeConfig>;
|
|
11
|
+
readonly #protocol: plugins.ecobridgeDeviceManager.DaikinProtocol;
|
|
12
|
+
readonly #lifetime = new AbortController();
|
|
13
|
+
#healthy = false;
|
|
14
|
+
#destroy?: Promise<void>;
|
|
15
|
+
#removeAbort: () => void = () => undefined;
|
|
16
|
+
|
|
17
|
+
constructor(configArg: IDaikinNativeConfig, contextArg: INativeIntegrationSetupContext) {
|
|
18
|
+
const config = normalizeDaikinConfig(configArg);
|
|
19
|
+
const context = new NativeHomeAdmission('daikin').admit(contextArg, config.homeId);
|
|
20
|
+
const signalArg = context.abortSignal;
|
|
21
|
+
this.#config = Object.freeze({ ...config, homeId: context.homeId });
|
|
22
|
+
this.#protocol = new plugins.ecobridgeDeviceManager.DaikinProtocol({
|
|
23
|
+
address: this.#config.host, expectedMac: this.#config.expectedMac, port: this.#config.port,
|
|
24
|
+
timeoutMs: this.#config.timeoutMs, maxResponseBytes: this.#config.maxResponseBytes,
|
|
25
|
+
maxPendingOperations: this.#config.maxPendingOperations,
|
|
361
26
|
});
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
return this.requestKeyValue('common/set_holiday', { en_hol: enabledArg ? '1' : '0' }, variantArg, true);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
private async setAdvancedMode(modeArg: string, enabledArg: boolean, variantArg: TDaikinApiVariant): Promise<unknown> {
|
|
372
|
-
if (variantArg === 'skyfi' || variantArg === 'brp084') {
|
|
373
|
-
throw new DaikinUnsupportedCommandError(`Daikin ${variantArg} advanced modes are not represented by a supported local request in this port.`);
|
|
27
|
+
if (signalArg) {
|
|
28
|
+
// Preserve cleanup failure in destroy() while an event listener has no promise consumer.
|
|
29
|
+
const aborted = (): void => { void this.destroy().catch(() => undefined); };
|
|
30
|
+
signalArg.addEventListener('abort', aborted, { once: true });
|
|
31
|
+
this.#removeAbort = () => signalArg.removeEventListener('abort', aborted);
|
|
32
|
+
if (signalArg.aborted) aborted();
|
|
374
33
|
}
|
|
375
|
-
const mode = DaikinMapper.humanToDaikin('spmode_kind', modeArg, variantArg) || modeArg;
|
|
376
|
-
return this.requestKeyValue(`${variantArg === 'airbase' ? 'skyfi/' : ''}aircon/set_special_mode`, { spmode_kind: mode, set_spmode: enabledArg ? '1' : '0' }, variantArg, true);
|
|
377
34
|
}
|
|
378
35
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
throw new DaikinUnsupportedCommandError(`Daikin ${variantArg} streamer mode is not represented by a supported local request in this port.`);
|
|
382
|
-
}
|
|
383
|
-
return this.requestKeyValue(`${variantArg === 'airbase' ? 'skyfi/' : ''}aircon/set_special_mode`, { en_streamer: enabledArg ? '1' : '0' }, variantArg, true);
|
|
384
|
-
}
|
|
36
|
+
public get config(): Readonly<IDaikinNativeConfig> { return this.#config; }
|
|
37
|
+
public isHealthy(): boolean { return this.#healthy && !this.#lifetime.signal.aborted; }
|
|
385
38
|
|
|
386
|
-
|
|
387
|
-
if (zoneIdArg === undefined || !Number.isInteger(zoneIdArg) || zoneIdArg < 0) {
|
|
388
|
-
throw new DaikinUnsupportedCommandError('Daikin zone commands require a non-negative zoneId.');
|
|
389
|
-
}
|
|
390
|
-
if (variantArg === 'skyfi') {
|
|
391
|
-
if (keyArg !== 'zone_onoff') {
|
|
392
|
-
throw new DaikinUnsupportedCommandError('Daikin SkyFi only supports zone_onoff through setzone.cgi.');
|
|
393
|
-
}
|
|
394
|
-
return this.requestSkyFi('setzone.cgi', { z: zoneIdArg + 1, s: valueArg });
|
|
395
|
-
}
|
|
396
|
-
if (variantArg !== 'airbase') {
|
|
397
|
-
throw new DaikinUnsupportedCommandError(`Daikin ${variantArg} zone commands are not represented by a supported local request in this port.`);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const current = await this.requestKeyValue('skyfi/aircon/get_zone_setting', undefined, variantArg, true);
|
|
401
|
-
if (!current[keyArg]) {
|
|
402
|
-
throw new DaikinUnsupportedCommandError(`Daikin AirBase zone setting ${keyArg} is not available on this device.`);
|
|
403
|
-
}
|
|
404
|
-
const group = this.listValue(current[keyArg]);
|
|
405
|
-
if (zoneIdArg >= group.length) {
|
|
406
|
-
throw new DaikinUnsupportedCommandError(`Daikin AirBase zone ${zoneIdArg} is outside the available range 0-${Math.max(0, group.length - 1)}.`);
|
|
407
|
-
}
|
|
408
|
-
group[zoneIdArg] = valueArg;
|
|
409
|
-
const values = { ...current, [keyArg]: encodeURIComponent(group.join(';')).toLowerCase() };
|
|
410
|
-
const query = [`zone_name=${values.zone_name || ''}`, `zone_onoff=${values.zone_onoff || ''}`];
|
|
411
|
-
if (values.lztemp_c !== undefined && values.lztemp_h !== undefined) {
|
|
412
|
-
query.push(`lztemp_c=${values.lztemp_c}`, `lztemp_h=${values.lztemp_h}`);
|
|
413
|
-
}
|
|
414
|
-
return this.requestKeyValue(`skyfi/aircon/set_zone_setting?${query.join('&')}`, undefined, variantArg, true);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
private applyControlSettings(valuesArg: IDaikinValueMap, settingsArg: Partial<IDaikinControlSettings>, variantArg: TDaikinApiVariant): void {
|
|
418
|
-
for (const [key, value] of Object.entries(settingsArg)) {
|
|
419
|
-
if (value === undefined) {
|
|
420
|
-
continue;
|
|
421
|
-
}
|
|
422
|
-
if (key === 'stemp') {
|
|
423
|
-
valuesArg.stemp = DaikinMapper.formatTargetTemperature(Number(value));
|
|
424
|
-
valuesArg.settemp = valuesArg.stemp;
|
|
425
|
-
} else if (key === 'shum') {
|
|
426
|
-
valuesArg.shum = String(value);
|
|
427
|
-
} else if (key === 'mode') {
|
|
428
|
-
const daikinMode = DaikinMapper.humanToDaikin('mode', String(value), variantArg);
|
|
429
|
-
valuesArg.mode = daikinMode;
|
|
430
|
-
valuesArg.acmode = daikinMode;
|
|
431
|
-
} else if (key === 'f_rate') {
|
|
432
|
-
const fanRate = DaikinMapper.humanToDaikin('f_rate', String(value), variantArg);
|
|
433
|
-
valuesArg.f_rate = fanRate;
|
|
434
|
-
valuesArg.fanspeed = fanRate;
|
|
435
|
-
} else if (key === 'f_dir') {
|
|
436
|
-
valuesArg.f_dir = DaikinMapper.humanToDaikin('f_dir', String(value), variantArg);
|
|
437
|
-
} else {
|
|
438
|
-
valuesArg[key] = String(value);
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
private fillModeDefaults(valuesArg: IDaikinValueMap, currentArg: IDaikinValueMap): void {
|
|
444
|
-
const mode = valuesArg.mode || currentArg.mode;
|
|
445
|
-
if (!mode) {
|
|
446
|
-
return;
|
|
447
|
-
}
|
|
448
|
-
const defaults: Record<string, string> = { stemp: `dt${mode}`, shum: `dh${mode}`, f_rate: `dfr${mode}` };
|
|
449
|
-
for (const [target, source] of Object.entries(defaults)) {
|
|
450
|
-
if (valuesArg[target] === undefined && currentArg[source] !== undefined) {
|
|
451
|
-
valuesArg[target] = currentArg[source];
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
private async requestSkyFi(pathArg: string, queryArg: Record<string, string | number | boolean | undefined> = {}): Promise<IDaikinValueMap> {
|
|
457
|
-
const query = { pass: this.config.password || '', ...queryArg };
|
|
458
|
-
const response = await this.fetchText(pathArg, query, 'skyfi', true);
|
|
459
|
-
return DaikinMapper.parseSkyFiResponse(response);
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
private async requestKeyValue(pathArg: string, queryArg: Record<string, string | number | boolean | undefined> | undefined, variantArg: TDaikinApiVariant, allowEmptyArg = false): Promise<IDaikinValueMap> {
|
|
463
|
-
if (this.config.client?.getResource && !this.config.host && !this.config.url) {
|
|
464
|
-
return this.config.client.getResource(pathArg, queryArg);
|
|
465
|
-
}
|
|
466
|
-
const text = await this.fetchText(pathArg, queryArg, variantArg, allowEmptyArg);
|
|
467
|
-
if (!text.trim()) {
|
|
468
|
-
return {};
|
|
469
|
-
}
|
|
39
|
+
public async getSnapshot(signalArg?: AbortSignal): Promise<IDaikinSnapshot> {
|
|
470
40
|
try {
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
}
|
|
476
|
-
throw errorArg;
|
|
477
|
-
}
|
|
41
|
+
const state = await this.#protocol.readState({ signal: this.#signal(signalArg) });
|
|
42
|
+
this.#healthy = true;
|
|
43
|
+
return DaikinMapper.fromState(this.#config, state);
|
|
44
|
+
} catch (errorArg) { this.#healthy = false; throw errorArg; }
|
|
478
45
|
}
|
|
479
46
|
|
|
480
|
-
|
|
481
|
-
const url = this.url(pathArg, undefined, variantArg);
|
|
482
|
-
let response: Response;
|
|
47
|
+
public async setControl(controlArg: plugins.ecobridgeDeviceManager.IDaikinControl, signalArg?: AbortSignal): Promise<plugins.ecobridgeDeviceManager.IDaikinControlResult> {
|
|
483
48
|
try {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
body: JSON.stringify(bodyArg),
|
|
488
|
-
signal: AbortSignal.timeout(this.config.timeoutMs || daikinDefaultTimeoutMs),
|
|
489
|
-
});
|
|
49
|
+
const result = await this.#protocol.setControl(controlArg, { signal: this.#signal(signalArg) });
|
|
50
|
+
this.#healthy = true;
|
|
51
|
+
return result;
|
|
490
52
|
} catch (errorArg) {
|
|
491
|
-
|
|
53
|
+
if (!(errorArg instanceof plugins.ecobridgeDeviceManager.DaikinProtocolError) || !['unsupported', 'invalid-options', 'device-error', 'capacity'].includes(errorArg.code)) this.#healthy = false;
|
|
54
|
+
throw errorArg;
|
|
492
55
|
}
|
|
493
|
-
await this.assertOk(response, url, false);
|
|
494
|
-
return await response.json() as TValue;
|
|
495
56
|
}
|
|
496
57
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
signal: AbortSignal.timeout(this.config.timeoutMs || daikinDefaultTimeoutMs),
|
|
58
|
+
public destroy(): Promise<void> {
|
|
59
|
+
if (!this.#destroy) {
|
|
60
|
+
this.#healthy = false;
|
|
61
|
+
this.#destroy = Promise.resolve().then(async () => {
|
|
62
|
+
this.#removeAbort();
|
|
63
|
+
this.#lifetime.abort(new Error('Daikin client is destroyed.'));
|
|
64
|
+
await this.#protocol.close();
|
|
505
65
|
});
|
|
506
|
-
} catch (errorArg) {
|
|
507
|
-
throw new DaikinApiConnectionError(`Connection to ${url} failed: ${this.errorMessage(errorArg)}`);
|
|
508
|
-
}
|
|
509
|
-
if (response.status === 404 && allowEmptyArg) {
|
|
510
|
-
await response.arrayBuffer().catch(() => undefined);
|
|
511
|
-
return '';
|
|
512
|
-
}
|
|
513
|
-
await this.assertOk(response, url, allowEmptyArg);
|
|
514
|
-
return await response.text();
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
private async assertOk(responseArg: Response, urlArg: string, allowEmptyArg: boolean): Promise<void> {
|
|
518
|
-
if (responseArg.status === 403 || responseArg.status === 401) {
|
|
519
|
-
throw new DaikinApiAuthorizationError('Daikin authentication failed. Check API key, UUID, or SkyFi password.');
|
|
520
|
-
}
|
|
521
|
-
if (!responseArg.ok) {
|
|
522
|
-
const text = await responseArg.text().catch(() => '');
|
|
523
|
-
if (allowEmptyArg && responseArg.status === 404) {
|
|
524
|
-
return;
|
|
525
|
-
}
|
|
526
|
-
throw new DaikinApiConnectionError(`Daikin endpoint ${urlArg} failed with HTTP ${responseArg.status}${text ? `: ${text}` : ''}`);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
private url(pathArg: string, queryArg: Record<string, string | number | boolean | undefined> | undefined, variantArg: TDaikinApiVariant): string {
|
|
531
|
-
if (/^https?:\/\//i.test(pathArg)) {
|
|
532
|
-
return pathArg;
|
|
533
|
-
}
|
|
534
|
-
const base = this.baseUrl(variantArg);
|
|
535
|
-
const url = new URL(pathArg.startsWith('/') ? pathArg : `/${pathArg}`, base.endsWith('/') ? base : `${base}/`);
|
|
536
|
-
for (const [key, value] of Object.entries(queryArg || {})) {
|
|
537
|
-
if (value !== undefined) {
|
|
538
|
-
url.searchParams.set(key, String(value));
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
return url.toString();
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
private baseUrl(variantArg: TDaikinApiVariant): string {
|
|
545
|
-
const configured = this.config.url || this.config.host || 'localhost';
|
|
546
|
-
if (/^https?:\/\//i.test(configured)) {
|
|
547
|
-
const url = new URL(configured);
|
|
548
|
-
return `${url.protocol}//${url.host}`;
|
|
549
|
-
}
|
|
550
|
-
const ssl = this.config.ssl ?? this.config.tls ?? variantArg === 'brp072c';
|
|
551
|
-
const protocol = ssl ? 'https' : 'http';
|
|
552
|
-
const defaultPort = variantArg === 'skyfi' ? daikinSkyFiPort : ssl ? daikinDefaultHttpsPort : daikinDefaultHttpPort;
|
|
553
|
-
const port = this.config.port && this.config.port !== defaultPort ? `:${this.config.port}` : '';
|
|
554
|
-
return `${protocol}://${this.hostForUrl(configured)}${port}`;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
private headers(variantArg: TDaikinApiVariant, extraArg: Record<string, string> = {}): Record<string, string> {
|
|
558
|
-
const headers = { ...extraArg };
|
|
559
|
-
if (variantArg === 'brp072c' && this.config.uuid) {
|
|
560
|
-
headers['x-daikin-uuid'] = this.config.uuid.replace(/-/g, '');
|
|
561
66
|
}
|
|
562
|
-
return
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
private requestVariant(valueArg: IDaikinCommandRequest['protocol']): TDaikinApiVariant {
|
|
566
|
-
if (valueArg && valueArg !== 'legacy' && valueArg !== 'auto') {
|
|
567
|
-
return valueArg;
|
|
568
|
-
}
|
|
569
|
-
if (this.config.apiVariant && this.config.apiVariant !== 'auto') {
|
|
570
|
-
return this.config.apiVariant;
|
|
571
|
-
}
|
|
572
|
-
if (this.config.password) {
|
|
573
|
-
return 'skyfi';
|
|
574
|
-
}
|
|
575
|
-
if (this.config.apiKey) {
|
|
576
|
-
return 'brp072c';
|
|
577
|
-
}
|
|
578
|
-
return 'brp069';
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
private findBrp084Value(dataArg: Record<string, unknown>, pathArg: string[]): string {
|
|
582
|
-
const responses = Array.isArray(dataArg.responses) ? dataArg.responses as Array<Record<string, unknown>> : [];
|
|
583
|
-
const from = pathArg[0];
|
|
584
|
-
let nodes = responses.filter((responseArg) => responseArg.fr === from || responseArg.to === from).map((responseArg) => responseArg.pc as Record<string, unknown>).filter(Boolean);
|
|
585
|
-
for (const key of pathArg.slice(1)) {
|
|
586
|
-
let found: Record<string, unknown> | undefined;
|
|
587
|
-
for (const node of nodes) {
|
|
588
|
-
if (node.pn === key) {
|
|
589
|
-
found = node;
|
|
590
|
-
break;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
if (!found) {
|
|
594
|
-
throw new DaikinApiConnectionError(`Daikin BRP084 response missing key ${key}.`);
|
|
595
|
-
}
|
|
596
|
-
if (pathArg[pathArg.length - 1] === key) {
|
|
597
|
-
return String(found.pv ?? '');
|
|
598
|
-
}
|
|
599
|
-
nodes = Array.isArray(found.pch) ? found.pch as Array<Record<string, unknown>> : [];
|
|
600
|
-
}
|
|
601
|
-
return '';
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
private brp084WeeklyData(dataArg: Record<string, unknown>): string | undefined {
|
|
605
|
-
try {
|
|
606
|
-
const value = this.findBrp084Value(dataArg, brp084Paths.weeklyData);
|
|
607
|
-
return Array.isArray(value) ? value.join('/') : String(value);
|
|
608
|
-
} catch {
|
|
609
|
-
return undefined;
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
private hexTemp(valueArg: string, divisorArg = 2): string | undefined {
|
|
614
|
-
if (!valueArg) {
|
|
615
|
-
return undefined;
|
|
616
|
-
}
|
|
617
|
-
const parsed = Number.parseInt(valueArg.slice(0, 2), 16);
|
|
618
|
-
return Number.isFinite(parsed) ? String(parsed / divisorArg) : undefined;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
private hexInt(valueArg: string): string | undefined {
|
|
622
|
-
if (!valueArg) {
|
|
623
|
-
return undefined;
|
|
624
|
-
}
|
|
625
|
-
const parsed = Number.parseInt(valueArg, 16);
|
|
626
|
-
return Number.isFinite(parsed) ? String(parsed) : undefined;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
private swingAxis(valueArg: string | undefined, axisArg: 'ud' | 'lr'): string {
|
|
630
|
-
const value = valueArg || '0';
|
|
631
|
-
if (axisArg === 'ud') {
|
|
632
|
-
return value === '1' || value === '3' ? 'S' : '0';
|
|
633
|
-
}
|
|
634
|
-
return value === '2' || value === '3' ? 'S' : '0';
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
private listValue(valueArg?: string): string[] {
|
|
638
|
-
if (!valueArg) {
|
|
639
|
-
return [];
|
|
640
|
-
}
|
|
641
|
-
let decoded = valueArg;
|
|
642
|
-
try {
|
|
643
|
-
decoded = decodeURIComponent(valueArg.replace(/\+/g, '%20'));
|
|
644
|
-
} catch {
|
|
645
|
-
decoded = valueArg;
|
|
646
|
-
}
|
|
647
|
-
return decoded.includes(';') ? decoded.split(';') : decoded.split('');
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
private cleanQuery(queryArg: Record<string, string | number | boolean | undefined>): Record<string, string | number | boolean | undefined> {
|
|
651
|
-
const cleaned: Record<string, string | number | boolean | undefined> = {};
|
|
652
|
-
for (const [key, value] of Object.entries(queryArg)) {
|
|
653
|
-
if (value !== undefined) {
|
|
654
|
-
cleaned[key] = value;
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
return cleaned;
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
private offlineSnapshot(errorArg: string): IDaikinSnapshot {
|
|
661
|
-
return DaikinMapper.toSnapshot({ config: this.config, online: false, source: 'runtime', error: errorArg });
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
private hasManualData(): boolean {
|
|
665
|
-
return Boolean(this.config.snapshot || this.config.rawData || this.config.values);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
private isSnapshot(valueArg: unknown): valueArg is IDaikinSnapshot {
|
|
669
|
-
return Boolean(valueArg && typeof valueArg === 'object' && 'device' in valueArg && 'climate' in valueArg);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
private hostForUrl(hostArg: string): string {
|
|
673
|
-
return hostArg.includes(':') && !hostArg.startsWith('[') ? `[${hostArg}]` : hostArg;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
private errorMessage(errorArg: unknown): string {
|
|
677
|
-
return errorArg instanceof Error ? errorArg.message : String(errorArg);
|
|
67
|
+
return this.#destroy;
|
|
678
68
|
}
|
|
679
69
|
|
|
680
|
-
|
|
681
|
-
|
|
70
|
+
#signal(signalArg?: AbortSignal): AbortSignal {
|
|
71
|
+
if (this.#destroy) throw new plugins.ecobridgeDeviceManager.DaikinProtocolError('Daikin client is destroyed.', 'closed');
|
|
72
|
+
return signalArg ? AbortSignal.any([signalArg, this.#lifetime.signal]) : this.#lifetime.signal;
|
|
682
73
|
}
|
|
683
74
|
}
|