@mp-consulting/homebridge-daikin-cloud 1.5.1 → 1.6.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/README.md +40 -27
- package/config.schema.json +66 -12
- package/dist/src/accessories/air-conditioning-accessory.js +1 -1
- package/dist/src/accessories/air-conditioning-accessory.js.map +1 -1
- package/dist/src/accessories/altherma-accessory.js +1 -1
- package/dist/src/accessories/altherma-accessory.js.map +1 -1
- package/dist/src/accessories/base-accessory.d.ts +5 -4
- package/dist/src/accessories/base-accessory.d.ts.map +1 -1
- package/dist/src/accessories/base-accessory.js +9 -10
- package/dist/src/accessories/base-accessory.js.map +1 -1
- package/dist/src/api/daikin-api.d.ts +22 -6
- package/dist/src/api/daikin-api.d.ts.map +1 -1
- package/dist/src/api/daikin-api.js +49 -23
- package/dist/src/api/daikin-api.js.map +1 -1
- package/dist/src/api/daikin-controller.d.ts +4 -48
- package/dist/src/api/daikin-controller.d.ts.map +1 -1
- package/dist/src/api/daikin-controller.js +14 -84
- package/dist/src/api/daikin-controller.js.map +1 -1
- package/dist/src/api/daikin-mobile-oauth.d.ts +11 -40
- package/dist/src/api/daikin-mobile-oauth.d.ts.map +1 -1
- package/dist/src/api/daikin-mobile-oauth.js +36 -160
- package/dist/src/api/daikin-mobile-oauth.js.map +1 -1
- package/dist/src/api/daikin-oauth.d.ts +10 -37
- package/dist/src/api/daikin-oauth.d.ts.map +1 -1
- package/dist/src/api/daikin-oauth.js +36 -166
- package/dist/src/api/daikin-oauth.js.map +1 -1
- package/dist/src/api/daikin-schemas.d.ts +20 -22
- package/dist/src/api/daikin-schemas.d.ts.map +1 -1
- package/dist/src/api/daikin-schemas.js +17 -49
- package/dist/src/api/daikin-schemas.js.map +1 -1
- package/dist/src/api/daikin-types.d.ts +11 -23
- package/dist/src/api/daikin-types.d.ts.map +1 -1
- package/dist/src/api/daikin-types.js.map +1 -1
- package/dist/src/api/daikin-websocket.d.ts +4 -5
- package/dist/src/api/daikin-websocket.d.ts.map +1 -1
- package/dist/src/api/daikin-websocket.js +62 -34
- package/dist/src/api/daikin-websocket.js.map +1 -1
- package/dist/src/api/http-defaults.d.ts +3 -2
- package/dist/src/api/http-defaults.d.ts.map +1 -1
- package/dist/src/api/http-defaults.js.map +1 -1
- package/dist/src/api/http-transport.d.ts +14 -2
- package/dist/src/api/http-transport.d.ts.map +1 -1
- package/dist/src/api/http-transport.js +32 -9
- package/dist/src/api/http-transport.js.map +1 -1
- package/dist/src/api/token-client.d.ts +82 -0
- package/dist/src/api/token-client.d.ts.map +1 -0
- package/dist/src/api/token-client.js +188 -0
- package/dist/src/api/token-client.js.map +1 -0
- package/dist/src/api/token-storage.d.ts +6 -0
- package/dist/src/api/token-storage.d.ts.map +1 -1
- package/dist/src/api/token-storage.js +27 -1
- package/dist/src/api/token-storage.js.map +1 -1
- package/dist/src/config/config-manager.d.ts +69 -125
- package/dist/src/config/config-manager.d.ts.map +1 -1
- package/dist/src/config/config-manager.js +288 -225
- package/dist/src/config/config-manager.js.map +1 -1
- package/dist/src/constants/api.constants.d.ts +6 -0
- package/dist/src/constants/api.constants.d.ts.map +1 -1
- package/dist/src/constants/api.constants.js +7 -1
- package/dist/src/constants/api.constants.js.map +1 -1
- package/dist/src/constants/auth.constants.d.ts +11 -0
- package/dist/src/constants/auth.constants.d.ts.map +1 -1
- package/dist/src/constants/auth.constants.js +12 -1
- package/dist/src/constants/auth.constants.js.map +1 -1
- package/dist/src/constants/device.constants.d.ts +1 -7
- package/dist/src/constants/device.constants.d.ts.map +1 -1
- package/dist/src/constants/device.constants.js +2 -11
- package/dist/src/constants/device.constants.js.map +1 -1
- package/dist/src/constants/time.constants.d.ts +0 -2
- package/dist/src/constants/time.constants.d.ts.map +1 -1
- package/dist/src/constants/time.constants.js +1 -3
- package/dist/src/constants/time.constants.js.map +1 -1
- package/dist/src/device/accessory-factory.d.ts +0 -5
- package/dist/src/device/accessory-factory.d.ts.map +1 -1
- package/dist/src/device/accessory-factory.js +0 -7
- package/dist/src/device/accessory-factory.js.map +1 -1
- package/dist/src/device/capability-detector.d.ts +9 -1
- package/dist/src/device/capability-detector.d.ts.map +1 -1
- package/dist/src/device/capability-detector.js +32 -28
- package/dist/src/device/capability-detector.js.map +1 -1
- package/dist/src/device/capability-docs.d.ts.map +1 -1
- package/dist/src/device/capability-docs.js +3 -0
- package/dist/src/device/capability-docs.js.map +1 -1
- package/dist/src/device/data-paths.d.ts +18 -0
- package/dist/src/device/data-paths.d.ts.map +1 -0
- package/dist/src/device/data-paths.js +20 -0
- package/dist/src/device/data-paths.js.map +1 -0
- package/dist/src/device/profiles/device-profile.d.ts +0 -5
- package/dist/src/device/profiles/device-profile.d.ts.map +1 -1
- package/dist/src/device/profiles/device-profile.js +0 -21
- package/dist/src/device/profiles/device-profile.js.map +1 -1
- package/dist/src/features/base-feature.d.ts +53 -9
- package/dist/src/features/base-feature.d.ts.map +1 -1
- package/dist/src/features/base-feature.js +93 -40
- package/dist/src/features/base-feature.js.map +1 -1
- package/dist/src/features/feature-manager.d.ts +27 -15
- package/dist/src/features/feature-manager.d.ts.map +1 -1
- package/dist/src/features/feature-manager.js +27 -24
- package/dist/src/features/feature-manager.js.map +1 -1
- package/dist/src/features/index.d.ts +1 -0
- package/dist/src/features/index.d.ts.map +1 -1
- package/dist/src/features/index.js +1 -0
- package/dist/src/features/index.js.map +1 -1
- package/dist/src/features/modes/auto-fan-mode.feature.d.ts +16 -10
- package/dist/src/features/modes/auto-fan-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/auto-fan-mode.feature.js +16 -40
- package/dist/src/features/modes/auto-fan-mode.feature.js.map +1 -1
- package/dist/src/features/modes/dry-operation-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/dry-operation-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/dry-operation-mode.feature.js +11 -30
- package/dist/src/features/modes/dry-operation-mode.feature.js.map +1 -1
- package/dist/src/features/modes/econo-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/econo-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/econo-mode.feature.js +11 -31
- package/dist/src/features/modes/econo-mode.feature.js.map +1 -1
- package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/fan-only-operation-mode.feature.js +11 -30
- package/dist/src/features/modes/fan-only-operation-mode.feature.js.map +1 -1
- package/dist/src/features/modes/firmware-update.feature.d.ts +7 -6
- package/dist/src/features/modes/firmware-update.feature.d.ts.map +1 -1
- package/dist/src/features/modes/firmware-update.feature.js +15 -22
- package/dist/src/features/modes/firmware-update.feature.js.map +1 -1
- package/dist/src/features/modes/holiday-mode.feature.d.ts +2 -1
- package/dist/src/features/modes/holiday-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/holiday-mode.feature.js +5 -15
- package/dist/src/features/modes/holiday-mode.feature.js.map +1 -1
- package/dist/src/features/modes/indoor-silent-mode.feature.d.ts +15 -12
- package/dist/src/features/modes/indoor-silent-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/indoor-silent-mode.feature.js +15 -39
- package/dist/src/features/modes/indoor-silent-mode.feature.js.map +1 -1
- package/dist/src/features/modes/oscillation-mode.feature.d.ts +5 -6
- package/dist/src/features/modes/oscillation-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/oscillation-mode.feature.js +14 -36
- package/dist/src/features/modes/oscillation-mode.feature.js.map +1 -1
- package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/outdoor-silent-mode.feature.js +11 -31
- package/dist/src/features/modes/outdoor-silent-mode.feature.js.map +1 -1
- package/dist/src/features/modes/powerful-mode.feature.d.ts +14 -10
- package/dist/src/features/modes/powerful-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/powerful-mode.feature.js +13 -32
- package/dist/src/features/modes/powerful-mode.feature.js.map +1 -1
- package/dist/src/features/modes/streamer-mode.feature.d.ts +12 -9
- package/dist/src/features/modes/streamer-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/streamer-mode.feature.js +11 -31
- package/dist/src/features/modes/streamer-mode.feature.js.map +1 -1
- package/dist/src/features/on-off-data-point-feature.d.ts +43 -0
- package/dist/src/features/on-off-data-point-feature.d.ts.map +1 -0
- package/dist/src/features/on-off-data-point-feature.js +49 -0
- package/dist/src/features/on-off-data-point-feature.js.map +1 -0
- package/dist/src/platform.d.ts +56 -9
- package/dist/src/platform.d.ts.map +1 -1
- package/dist/src/platform.js +248 -128
- package/dist/src/platform.js.map +1 -1
- package/dist/src/services/climate-control/fan-speed.d.ts +45 -0
- package/dist/src/services/climate-control/fan-speed.d.ts.map +1 -0
- package/dist/src/services/climate-control/fan-speed.js +104 -0
- package/dist/src/services/climate-control/fan-speed.js.map +1 -0
- package/dist/src/services/climate-control/separate-fan.service.d.ts +45 -0
- package/dist/src/services/climate-control/separate-fan.service.d.ts.map +1 -0
- package/dist/src/services/climate-control/separate-fan.service.js +82 -0
- package/dist/src/services/climate-control/separate-fan.service.js.map +1 -0
- package/dist/src/services/climate-control/setpoint-resolver.d.ts +68 -0
- package/dist/src/services/climate-control/setpoint-resolver.d.ts.map +1 -0
- package/dist/src/services/climate-control/setpoint-resolver.js +170 -0
- package/dist/src/services/climate-control/setpoint-resolver.js.map +1 -0
- package/dist/src/services/climate-control/swing-controller.d.ts +28 -0
- package/dist/src/services/climate-control/swing-controller.d.ts.map +1 -0
- package/dist/src/services/climate-control/swing-controller.js +65 -0
- package/dist/src/services/climate-control/swing-controller.js.map +1 -0
- package/dist/src/services/climate-control.service.d.ts +39 -48
- package/dist/src/services/climate-control.service.d.ts.map +1 -1
- package/dist/src/services/climate-control.service.js +223 -554
- package/dist/src/services/climate-control.service.js.map +1 -1
- package/dist/src/services/hot-water-tank.service.d.ts +17 -8
- package/dist/src/services/hot-water-tank.service.d.ts.map +1 -1
- package/dist/src/services/hot-water-tank.service.js +102 -157
- package/dist/src/services/hot-water-tank.service.js.map +1 -1
- package/dist/src/types/daikin-enums.d.ts +0 -5
- package/dist/src/types/daikin-enums.d.ts.map +1 -1
- package/dist/src/types/daikin-enums.js +1 -7
- package/dist/src/types/daikin-enums.js.map +1 -1
- package/dist/src/types/device-capabilities.d.ts +1 -0
- package/dist/src/types/device-capabilities.d.ts.map +1 -1
- package/dist/src/utils/errors.d.ts +9 -0
- package/dist/src/utils/errors.d.ts.map +1 -0
- package/dist/src/utils/errors.js +25 -0
- package/dist/src/utils/errors.js.map +1 -0
- package/dist/src/utils/hap-write.d.ts +22 -0
- package/dist/src/utils/hap-write.d.ts.map +1 -0
- package/dist/src/utils/hap-write.js +33 -0
- package/dist/src/utils/hap-write.js.map +1 -0
- package/dist/src/utils/sleep.d.ts +5 -0
- package/dist/src/utils/sleep.d.ts.map +1 -0
- package/dist/src/utils/sleep.js +10 -0
- package/dist/src/utils/sleep.js.map +1 -0
- package/homebridge-ui/README.md +25 -2
- package/homebridge-ui/public/index.html +19 -17
- package/homebridge-ui/public/lib/kit.css +1 -1
- package/homebridge-ui/public/script.js +95 -32
- package/homebridge-ui/public/styles.css +109 -0
- package/homebridge-ui/server.js +321 -125
- package/package.json +14 -15
- package/dist/src/utils/log-context.d.ts +0 -105
- package/dist/src/utils/log-context.d.ts.map +0 -1
- package/dist/src/utils/log-context.js +0 -206
- package/dist/src/utils/log-context.js.map +0 -1
- package/dist/src/utils/update-mapper.d.ts +0 -59
- package/dist/src/utils/update-mapper.d.ts.map +0 -1
- package/dist/src/utils/update-mapper.js +0 -192
- package/dist/src/utils/update-mapper.js.map +0 -1
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@ A [Homebridge](https://homebridge.io) plugin that integrates Daikin air conditio
|
|
|
27
27
|
- Oscillation switch (`showOscillationSwitch`)
|
|
28
28
|
- Dry mode (`showDryMode`)
|
|
29
29
|
- Fan only mode (`showFanOnlyMode`)
|
|
30
|
+
- Holiday (away) mode (`showHolidayMode`)
|
|
30
31
|
- **Separate Fan Tile** (`showSeparateFanControl`): Expose fan speed and oscillation as a standalone Fan tile, so both stay visible even when the accessory is grouped into a single tile in the Home app
|
|
31
32
|
- **Firmware Updates** (`showFirmwareUpdateSwitch`): Manage gateway firmware updates from HomeKit instead of the Onecta app. The plugin logs when Daikin stages an update for your unit and exposes a "Firmware Update" switch — turn it on to install; it stays on while the update runs and the plugin logs the outcome. Not part of `showExtraFeatures`: it must be enabled explicitly, so an "all switches on" scene can never trigger an install. The unit is unavailable (and rejects commands) while it updates. The current firmware version is also shown in each accessory's HomeKit details.
|
|
32
33
|
|
|
@@ -47,8 +48,8 @@ This plugin supports two authentication methods:
|
|
|
47
48
|
|
|
48
49
|
## Requirements
|
|
49
50
|
|
|
50
|
-
- Node.js
|
|
51
|
-
- Homebridge >= 1.5.0
|
|
51
|
+
- Node.js 20.5+, 22.10+, 24 or 26
|
|
52
|
+
- Homebridge >= 1.5.0 (including 2.x)
|
|
52
53
|
- A Daikin account with devices registered in the Onecta app
|
|
53
54
|
|
|
54
55
|
## Installation
|
|
@@ -137,26 +138,30 @@ Add the platform to your Homebridge `config.json`:
|
|
|
137
138
|
| `daikinPassword` | string | - | Daikin account password (Mobile App mode) |
|
|
138
139
|
| `clientId` | string | - | Daikin Developer App Client ID (Developer Portal mode) |
|
|
139
140
|
| `clientSecret` | string | - | Daikin Developer App Client Secret (Developer Portal mode) |
|
|
140
|
-
| `callbackServerExternalAddress` | string |
|
|
141
|
+
| `callbackServerExternalAddress` | string | - | IP/hostname your browser uses to reach Homebridge for the OAuth callback (Developer Portal mode; the settings UI suggests this host's LAN IP) |
|
|
141
142
|
| `callbackServerPort` | number | `8582` | Port for OAuth callback server (1-65535) |
|
|
142
|
-
| `oidcCallbackServerBindAddr` | string | `0.0.0.0` |
|
|
143
|
-
| `updateIntervalInMinutes` | number | `15` | Polling interval (Developer Portal: 15+ min, Mobile App: 1-5 min) |
|
|
144
|
-
| `forceUpdateDelay` | number | `60000` | Delay (ms) before refreshing after a change |
|
|
143
|
+
| `oidcCallbackServerBindAddr` | string | `0.0.0.0` | Interface the temporary OAuth callback server listens on. Use `0.0.0.0` unless the browser you log in with runs on the Homebridge host itself; only then does a loopback address (`127.0.0.1`) work. The settings UI refuses to start authentication with a loopback bind address and a non-loopback callback address |
|
|
144
|
+
| `updateIntervalInMinutes` | number | `15` | Polling interval, 1-60 (Developer Portal: 15+ min, Mobile App: 1-5 min). Stretched automatically, see [API Rate Limits](#api-rate-limits) |
|
|
145
|
+
| `forceUpdateDelay` | number | `60000` | Delay (ms, 5000-300000) before refreshing after a change from HomeKit. Skipped while the WebSocket is connected |
|
|
145
146
|
| `enableWebSocket` | boolean | `true` | Enable real-time updates (Mobile App mode only) |
|
|
146
147
|
| `httpTransport` | string | `node` | `node` or `curl`. Use `curl` only if authentication times out on your network while curl works — some WAFs drop Node's TLS fingerprint ([#6](https://github.com/mp-consulting/homebridge-daikin-cloud/issues/6)). Requires the curl binary; WebSocket still uses Node TLS. Env override: `DAIKIN_HTTP_TRANSPORT` |
|
|
147
148
|
| `excludedDevicesByDeviceId` | string[] | `[]` | Device IDs to exclude from HomeKit |
|
|
148
|
-
| `
|
|
149
|
-
| `
|
|
150
|
-
| `
|
|
151
|
-
| `
|
|
152
|
-
| `
|
|
153
|
-
| `
|
|
154
|
-
| `
|
|
149
|
+
| `showExtraFeatures` | boolean | `false` | Legacy catch-all: default for every per-feature switch below marked *follows `showExtraFeatures`* |
|
|
150
|
+
| `showPowerfulMode` | boolean | follows `showExtraFeatures` | Show Powerful mode switch |
|
|
151
|
+
| `showEconoMode` | boolean | follows `showExtraFeatures` | Show Econo mode switch |
|
|
152
|
+
| `showStreamerMode` | boolean | follows `showExtraFeatures` | Show Streamer mode switch |
|
|
153
|
+
| `showOutdoorSilentMode` | boolean | follows `showExtraFeatures` | Show Outdoor Silent mode switch |
|
|
154
|
+
| `showIndoorSilentMode` | boolean | follows `showExtraFeatures` | Show Indoor Silent mode switch |
|
|
155
|
+
| `showAutoFanMode` | boolean | follows `showExtraFeatures` | Show Auto fan mode switch (toggles fan speed between auto and manual) |
|
|
156
|
+
| `showOscillationSwitch` | boolean | follows `showExtraFeatures` | Show fan oscillation (swing) as a separate switch (stays visible when the accessory is grouped into a single tile) |
|
|
157
|
+
| `showDryMode` | boolean | follows `showExtraFeatures` | Show Dry mode switch |
|
|
158
|
+
| `showFanOnlyMode` | boolean | follows `showExtraFeatures` | Show Fan Only mode switch |
|
|
159
|
+
| `showHolidayMode` | boolean | follows `showExtraFeatures` | Show Holiday (away) mode switch: on puts the unit into holiday mode, off resumes normal operation |
|
|
155
160
|
| `showSeparateFanControl` | boolean | `false` | Expose fan speed and oscillation as a standalone Fan tile (stays visible when the accessory is grouped into a single tile) |
|
|
156
|
-
| `showDryMode` | boolean | `false` | Show Dry mode switch |
|
|
157
|
-
| `showFanOnlyMode` | boolean | `false` | Show Fan Only mode switch |
|
|
158
161
|
| `showFirmwareUpdateSwitch` | boolean | `false` | Show a Firmware Update switch that installs staged gateway firmware updates (never enabled implicitly by `showExtraFeatures`) |
|
|
159
162
|
|
|
163
|
+
All feature switches only appear if the device supports the feature.
|
|
164
|
+
|
|
160
165
|
## API Rate Limits
|
|
161
166
|
|
|
162
167
|
| Mode | Daily Limit | Recommended Polling |
|
|
@@ -165,10 +170,14 @@ Add the platform to your Homebridge `config.json`:
|
|
|
165
170
|
| Mobile App | 3000 calls/day | 1-5 minutes |
|
|
166
171
|
|
|
167
172
|
The plugin manages rate limits by:
|
|
168
|
-
- Polling at
|
|
169
|
-
-
|
|
170
|
-
-
|
|
171
|
-
-
|
|
173
|
+
- Polling at the configured interval (`updateIntervalInMinutes`)
|
|
174
|
+
- **Stretching polling while the WebSocket is connected**: push updates already deliver changes, so polling drops to a safety-net interval of at least 60 minutes, and the forced refresh after a change from HomeKit is skipped. When the WebSocket disconnects, the configured interval applies again (and a reconnect triggers one catch-up poll)
|
|
175
|
+
- **Backing off on failures**: each consecutive failed poll doubles the interval (up to 4x); polling GETs are not retried on 502/503/504, the next poll is the retry
|
|
176
|
+
- Stretching polling to at least 60 minutes when fewer than 20 calls are left for the day
|
|
177
|
+
- Debouncing refreshes after changes, and coalescing rapid writes to the same setting into one API call
|
|
178
|
+
- Blocking requests when the rate limit is reached (until the `Retry-After` time)
|
|
179
|
+
|
|
180
|
+
The settings UI is careful with the quota too: it caches the device list for 5 minutes, and the rate-limit display reads the status from the last API response the plugin received (saved to a file in the Homebridge storage directory) instead of making an API call.
|
|
172
181
|
|
|
173
182
|
## Fan Speed
|
|
174
183
|
|
|
@@ -200,7 +209,8 @@ rm ~/.homebridge/.daikin-controller-cloud-tokenset
|
|
|
200
209
|
### Authentication Flow Issues
|
|
201
210
|
|
|
202
211
|
- Ensure your redirect URI in the Daikin Developer Portal matches exactly: `https://<callbackServerExternalAddress>:<callbackServerPort>`
|
|
203
|
-
-
|
|
212
|
+
- Set `oidcCallbackServerBindAddr` to `0.0.0.0`; a loopback bind address (`127.0.0.1`) only works when the browser runs on the Homebridge host itself
|
|
213
|
+
- The temporary callback server stops automatically after 10 minutes: if you took longer, start authentication again
|
|
204
214
|
- Check firewall rules for the callback port
|
|
205
215
|
|
|
206
216
|
### Device Not Appearing
|
|
@@ -218,7 +228,8 @@ rm ~/.homebridge/.daikin-controller-cloud-tokenset
|
|
|
218
228
|
### API Gateway Timeout Errors (502, 503, 504)
|
|
219
229
|
|
|
220
230
|
These errors indicate temporary issues with the Daikin Cloud servers:
|
|
221
|
-
-
|
|
231
|
+
- Writes (and one-off reads) are retried up to 3 times with exponential backoff
|
|
232
|
+
- Periodic polls are not retried; instead the poll interval backs off until the API recovers
|
|
222
233
|
- If errors persist, the Daikin API may be experiencing extended downtime
|
|
223
234
|
- Check [Daikin's status page](https://www.daikin.eu/) or try again later
|
|
224
235
|
|
|
@@ -245,9 +256,13 @@ npm run watch
|
|
|
245
256
|
# Run tests
|
|
246
257
|
npm test
|
|
247
258
|
|
|
259
|
+
# Run tests with coverage (thresholds in vitest.config.mts, enforced in CI)
|
|
260
|
+
npm run test:coverage
|
|
261
|
+
|
|
248
262
|
# Check for Daikin API schema drift (fetches live devices, diffs raw vs Zod-parsed,
|
|
249
|
-
# reports any silently-stripped fields).
|
|
250
|
-
#
|
|
263
|
+
# reports any silently-stripped fields). Needs real credentials in
|
|
264
|
+
# test/hbConfig/config.json, so it is a manual check and not run in CI.
|
|
265
|
+
# Add --dump-fixtures to also write per-device fixtures to test/fixtures/live/.
|
|
251
266
|
npm run schema:check
|
|
252
267
|
```
|
|
253
268
|
|
|
@@ -257,16 +272,14 @@ This plugin uses:
|
|
|
257
272
|
- **TypeScript strict mode** for enhanced type safety
|
|
258
273
|
- **Zod validation** for runtime type checking
|
|
259
274
|
- **ESLint** for code quality enforcement
|
|
260
|
-
- **
|
|
275
|
+
- **Vitest** with coverage thresholds enforced in CI (currently ~80% of statements), including the custom UI server
|
|
261
276
|
|
|
262
277
|
### Documentation
|
|
263
278
|
|
|
264
279
|
Comprehensive developer documentation is available in the [`docs/`](docs/) folder:
|
|
265
280
|
|
|
266
281
|
- **[ARCHITECTURE.md](docs/ARCHITECTURE.md)** - System architecture, component design, data flows, and extension guides
|
|
267
|
-
- **[
|
|
268
|
-
- **[IMPROVEMENTS_SUMMARY.md](docs/IMPROVEMENTS_SUMMARY.md)** - Summary of recent improvements and progress
|
|
269
|
-
- **[NEXT_STEPS.md](docs/NEXT_STEPS.md)** - Quick-start guide for contributing
|
|
282
|
+
- **[TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)** - Common problems and fixes
|
|
270
283
|
|
|
271
284
|
For development workflows and coding conventions, see [CLAUDE.md](CLAUDE.md).
|
|
272
285
|
|
package/config.schema.json
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"default": "developer_portal",
|
|
23
23
|
"oneOf": [
|
|
24
24
|
{"title": "Developer Portal (200 API calls/day)", "enum": ["developer_portal"]},
|
|
25
|
-
{"title": "Mobile App (
|
|
25
|
+
{"title": "Mobile App (3000 API calls/day + WebSocket)", "enum": ["mobile_app"]}
|
|
26
26
|
]
|
|
27
27
|
},
|
|
28
28
|
"clientId": {
|
|
@@ -68,15 +68,15 @@
|
|
|
68
68
|
},
|
|
69
69
|
"oidcCallbackServerBindAddr": {
|
|
70
70
|
"title": "Callback Server Bind Address",
|
|
71
|
-
"description": "Network interface
|
|
71
|
+
"description": "Network interface the temporary OAuth callback server listens on during authentication. The browser you log in with must be able to reach it: use 0.0.0.0 unless that browser runs on the Homebridge host itself, in which case 127.0.0.1 keeps the server off the network.",
|
|
72
72
|
"type": "string",
|
|
73
73
|
"required": false,
|
|
74
|
-
"default": "
|
|
75
|
-
"enum": ["
|
|
74
|
+
"default": "0.0.0.0",
|
|
75
|
+
"enum": ["0.0.0.0", "127.0.0.1"],
|
|
76
76
|
"x-schema-form": {
|
|
77
77
|
"titleMap": {
|
|
78
|
-
"
|
|
79
|
-
"
|
|
78
|
+
"0.0.0.0": "0.0.0.0 (all network interfaces)",
|
|
79
|
+
"127.0.0.1": "127.0.0.1 (localhost only - browser on the Homebridge host)"
|
|
80
80
|
},
|
|
81
81
|
"condition": "model.authMode !== 'mobile_app'"
|
|
82
82
|
}
|
|
@@ -107,12 +107,59 @@
|
|
|
107
107
|
"default": false,
|
|
108
108
|
"description": "Expose extra features like Streamer, Econo, and Powerful modes as HomeKit switches (only if supported by your device)"
|
|
109
109
|
},
|
|
110
|
+
"showPowerfulMode": {
|
|
111
|
+
"title": "Powerful Mode Switch",
|
|
112
|
+
"type": "boolean",
|
|
113
|
+
"required": false,
|
|
114
|
+
"description": "Boost heating/cooling performance (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
115
|
+
},
|
|
116
|
+
"showEconoMode": {
|
|
117
|
+
"title": "Econo Mode Switch",
|
|
118
|
+
"type": "boolean",
|
|
119
|
+
"required": false,
|
|
120
|
+
"description": "Energy-saving operation (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
121
|
+
},
|
|
122
|
+
"showStreamerMode": {
|
|
123
|
+
"title": "Streamer Mode Switch",
|
|
124
|
+
"type": "boolean",
|
|
125
|
+
"required": false,
|
|
126
|
+
"description": "Air purification (Streamer) (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
127
|
+
},
|
|
128
|
+
"showOutdoorSilentMode": {
|
|
129
|
+
"title": "Outdoor Silent Mode Switch",
|
|
130
|
+
"type": "boolean",
|
|
131
|
+
"required": false,
|
|
132
|
+
"description": "Reduce outdoor unit noise (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
133
|
+
},
|
|
134
|
+
"showIndoorSilentMode": {
|
|
135
|
+
"title": "Indoor Silent Mode Switch",
|
|
136
|
+
"type": "boolean",
|
|
137
|
+
"required": false,
|
|
138
|
+
"description": "Quiet indoor fan operation (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
139
|
+
},
|
|
140
|
+
"showAutoFanMode": {
|
|
141
|
+
"title": "Auto Fan Mode Switch",
|
|
142
|
+
"type": "boolean",
|
|
143
|
+
"required": false,
|
|
144
|
+
"description": "Automatic fan speed as a switch (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
145
|
+
},
|
|
146
|
+
"showDryMode": {
|
|
147
|
+
"title": "Dry Mode Switch",
|
|
148
|
+
"type": "boolean",
|
|
149
|
+
"required": false,
|
|
150
|
+
"description": "Dehumidification mode as a switch (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
151
|
+
},
|
|
152
|
+
"showFanOnlyMode": {
|
|
153
|
+
"title": "Fan Only Mode Switch",
|
|
154
|
+
"type": "boolean",
|
|
155
|
+
"required": false,
|
|
156
|
+
"description": "Fan without heating/cooling as a switch (only if supported by your device). When not set, follows 'Show Extra Features'."
|
|
157
|
+
},
|
|
110
158
|
"showOscillationSwitch": {
|
|
111
159
|
"title": "Show Oscillation Switch",
|
|
112
160
|
"type": "boolean",
|
|
113
161
|
"required": false,
|
|
114
|
-
"
|
|
115
|
-
"description": "Expose fan oscillation (swing) as a separate HomeKit switch. Useful because the built-in swing control disappears when the accessory is grouped into a single tile in the Home app."
|
|
162
|
+
"description": "Expose fan oscillation (swing) as a separate HomeKit switch. Useful because the built-in swing control disappears when the accessory is grouped into a single tile in the Home app. When not set, follows 'Show Extra Features'."
|
|
116
163
|
},
|
|
117
164
|
"showSeparateFanControl": {
|
|
118
165
|
"title": "Show Separate Fan Tile",
|
|
@@ -125,8 +172,7 @@
|
|
|
125
172
|
"title": "Show Holiday Mode Switch",
|
|
126
173
|
"type": "boolean",
|
|
127
174
|
"required": false,
|
|
128
|
-
"
|
|
129
|
-
"description": "Expose holiday (away) mode as a separate HomeKit switch (only if supported by your device). Turn it on to put the unit into holiday mode and off to resume normal operation."
|
|
175
|
+
"description": "Expose holiday (away) mode as a separate HomeKit switch (only if supported by your device). Turn it on to put the unit into holiday mode and off to resume normal operation. When not set, follows 'Show Extra Features'."
|
|
130
176
|
},
|
|
131
177
|
"showFirmwareUpdateSwitch": {
|
|
132
178
|
"title": "Show Firmware Update Switch",
|
|
@@ -164,7 +210,7 @@
|
|
|
164
210
|
"default": 15,
|
|
165
211
|
"minimum": 1,
|
|
166
212
|
"maximum": 60,
|
|
167
|
-
"description": "How often to poll the Daikin API. Developer Portal: 15+ min recommended (200 calls/day limit). Mobile App: 1-5 min recommended (
|
|
213
|
+
"description": "How often to poll the Daikin API. Developer Portal: 15+ min recommended (200 calls/day limit). Mobile App: 1-5 min recommended (3000 calls/day)."
|
|
168
214
|
},
|
|
169
215
|
"forceUpdateDelay": {
|
|
170
216
|
"title": "Force Update Delay (ms)",
|
|
@@ -196,7 +242,7 @@
|
|
|
196
242
|
{
|
|
197
243
|
"type": "fieldset",
|
|
198
244
|
"title": "Mobile App Authentication",
|
|
199
|
-
"description": "Use your Daikin Onecta account credentials (same as the mobile app). Benefits:
|
|
245
|
+
"description": "Use your Daikin Onecta account credentials (same as the mobile app). Benefits: 3000 API calls/day + real-time WebSocket updates.",
|
|
200
246
|
"expandable": false,
|
|
201
247
|
"condition": "model.authMode === 'mobile_app'",
|
|
202
248
|
"items": [
|
|
@@ -236,6 +282,14 @@
|
|
|
236
282
|
"expanded": false,
|
|
237
283
|
"items": [
|
|
238
284
|
"showExtraFeatures",
|
|
285
|
+
"showPowerfulMode",
|
|
286
|
+
"showEconoMode",
|
|
287
|
+
"showStreamerMode",
|
|
288
|
+
"showOutdoorSilentMode",
|
|
289
|
+
"showIndoorSilentMode",
|
|
290
|
+
"showAutoFanMode",
|
|
291
|
+
"showDryMode",
|
|
292
|
+
"showFanOnlyMode",
|
|
239
293
|
"showOscillationSwitch",
|
|
240
294
|
"showSeparateFanControl",
|
|
241
295
|
"showHolidayMode",
|
|
@@ -12,7 +12,7 @@ class AirConditioningAccessory extends base_accessory_1.BaseAccessory {
|
|
|
12
12
|
throw new Error('No climate control management point found');
|
|
13
13
|
}
|
|
14
14
|
this.service = new services_1.ClimateControlService(this.platform, this.accessory, climateControlEmbeddedId);
|
|
15
|
-
this.logCapabilities(
|
|
15
|
+
this.logCapabilities(this.service.featureManager.capabilities);
|
|
16
16
|
// Push current device state into HomeKit immediately. At startup the device
|
|
17
17
|
// is freshly built from getCloudDevices() which does not emit 'updated', so
|
|
18
18
|
// without this the full refresh only runs on the first poll/WebSocket event -
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"air-conditioning-accessory.js","sourceRoot":"","sources":["../../../src/accessories/air-conditioning-accessory.ts"],"names":[],"mappings":";;;AAEA,qDAAiD;AACjD,0CAAoD;AAEpD,MAAa,wBAAyB,SAAQ,8BAAa;IACzD,OAAO,CAAwB;IAE/B,YACE,QAA6B,EAC7B,SAAyD;QAEzD,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC3B,MAAM,wBAAwB,GAAG,IAAI,CAAC,kCAAkC,CAAC,gBAAgB,CAAC,CAAC;QAE3F,IAAI,wBAAwB,KAAK,IAAI,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,gCAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;QAClG,IAAI,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"air-conditioning-accessory.js","sourceRoot":"","sources":["../../../src/accessories/air-conditioning-accessory.ts"],"names":[],"mappings":";;;AAEA,qDAAiD;AACjD,0CAAoD;AAEpD,MAAa,wBAAyB,SAAQ,8BAAa;IACzD,OAAO,CAAwB;IAE/B,YACE,QAA6B,EAC7B,SAAyD;QAEzD,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAC3B,MAAM,wBAAwB,GAAG,IAAI,CAAC,kCAAkC,CAAC,gBAAgB,CAAC,CAAC;QAE3F,IAAI,wBAAwB,KAAK,IAAI,EAAE,CAAC;YACtC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,IAAI,gCAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;QAClG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QAE/D,4EAA4E;QAC5E,4EAA4E;QAC5E,8EAA8E;QAC9E,wEAAwE;QACxE,2CAA2C;QAC3C,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAEkB,aAAa;QAC9B,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;IAC/B,CAAC;CACF;AA5BD,4DA4BC"}
|
|
@@ -14,7 +14,7 @@ class AlthermaAccessory extends base_accessory_1.BaseAccessory {
|
|
|
14
14
|
const domesticHotWaterTankEmbeddedId = this.getEmbeddedIdByManagementPointType('domesticHotWaterTank');
|
|
15
15
|
if (climateControlEmbeddedId !== null) {
|
|
16
16
|
this.service = new services_1.ClimateControlService(this.platform, this.accessory, climateControlEmbeddedId);
|
|
17
|
-
this.logCapabilities(
|
|
17
|
+
this.logCapabilities(this.service.featureManager.capabilities);
|
|
18
18
|
}
|
|
19
19
|
else {
|
|
20
20
|
this.platform.log.warn(`[${this.name}] No climate control management point found`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"altherma-accessory.js","sourceRoot":"","sources":["../../../src/accessories/altherma-accessory.ts"],"names":[],"mappings":";;;AAEA,qDAAiD;AACjD,0CAAyE;AAEzE,MAAa,iBAAkB,SAAQ,8BAAa;IACjC,IAAI,CAAS;IAC9B,OAAO,CAAyB;IAChC,mBAAmB,CAAuB;IAE1C,YACE,QAA6B,EAC7B,SAAyD;QAEzD,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAE3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;QAEvC,MAAM,wBAAwB,GAAG,IAAI,CAAC,kCAAkC,CAAC,gBAAgB,CAAC,CAAC;QAC3F,MAAM,8BAA8B,GAAG,IAAI,CAAC,kCAAkC,CAAC,sBAAsB,CAAC,CAAC;QAEvG,IAAI,wBAAwB,KAAK,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,GAAG,IAAI,gCAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;YAClG,IAAI,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"altherma-accessory.js","sourceRoot":"","sources":["../../../src/accessories/altherma-accessory.ts"],"names":[],"mappings":";;;AAEA,qDAAiD;AACjD,0CAAyE;AAEzE,MAAa,iBAAkB,SAAQ,8BAAa;IACjC,IAAI,CAAS;IAC9B,OAAO,CAAyB;IAChC,mBAAmB,CAAuB;IAE1C,YACE,QAA6B,EAC7B,SAAyD;QAEzD,KAAK,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QAE3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;QAEvC,MAAM,wBAAwB,GAAG,IAAI,CAAC,kCAAkC,CAAC,gBAAgB,CAAC,CAAC;QAC3F,MAAM,8BAA8B,GAAG,IAAI,CAAC,kCAAkC,CAAC,sBAAsB,CAAC,CAAC;QAEvG,IAAI,wBAAwB,KAAK,IAAI,EAAE,CAAC;YACtC,IAAI,CAAC,OAAO,GAAG,IAAI,gCAAqB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;YAClG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC;QACjE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,6CAA6C,CAAC,CAAC;QACrF,CAAC;QAED,IAAI,8BAA8B,KAAK,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,mBAAmB,GAAG,IAAI,8BAAmB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,8BAA8B,CAAC,CAAC;QACpH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,qDAAqD,CAAC,CAAC;QAC7F,CAAC;QAED,4EAA4E;QAC5E,4EAA4E;QAC5E,8EAA8E;QAC9E,yEAAyE;QACzE,oCAAoC;QACpC,IAAI,CAAC,aAAa,EAAE,CAAC;IACvB,CAAC;IAEkB,aAAa;QAC9B,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,CAAC;QAC9B,IAAI,CAAC,mBAAmB,EAAE,aAAa,EAAE,CAAC;IAC5C,CAAC;CACF;AAzCD,8CAyCC"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PlatformAccessory } from 'homebridge';
|
|
2
2
|
import type { DaikinCloudAccessoryContext, DaikinCloudPlatform } from '../platform';
|
|
3
|
+
import type { DeviceCapabilities } from '../types';
|
|
3
4
|
export declare class BaseAccessory {
|
|
4
5
|
readonly platform: DaikinCloudPlatform;
|
|
5
6
|
readonly accessory: PlatformAccessory<DaikinCloudAccessoryContext>;
|
|
@@ -13,10 +14,10 @@ export declare class BaseAccessory {
|
|
|
13
14
|
protected refreshValues(): void;
|
|
14
15
|
private printDeviceInfo;
|
|
15
16
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
protected logCapabilities(
|
|
17
|
+
* Log the capabilities detected for a management point (the same detection
|
|
18
|
+
* result its FeatureManager uses to decide which feature switches to expose).
|
|
19
|
+
*/
|
|
20
|
+
protected logCapabilities(capabilities: DeviceCapabilities): void;
|
|
20
21
|
getEmbeddedIdByManagementPointType(managementPointType: string): string | null;
|
|
21
22
|
}
|
|
22
23
|
//# sourceMappingURL=base-accessory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-accessory.d.ts","sourceRoot":"","sources":["../../../src/accessories/base-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"base-accessory.d.ts","sourceRoot":"","sources":["../../../src/accessories/base-accessory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,KAAK,EAAE,2BAA2B,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACpF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAGnD,qBAAa,aAAa;IACxB,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC,2BAA2B,CAAC,CAAC;IACnE,SAAgB,wBAAwB,EAAE,MAAM,GAAG,IAAI,CAAC;gBAEtD,QAAQ,EAAE,mBAAmB,EAC7B,SAAS,EAAE,iBAAiB,CAAC,2BAA2B,CAAC;IA2C3D;;;;OAIG;IACH,SAAS,CAAC,aAAa,IAAI,IAAI;IAI/B,OAAO,CAAC,eAAe;IAcvB;;;OAGG;IACH,SAAS,CAAC,eAAe,CAAC,YAAY,EAAE,kBAAkB,GAAG,IAAI;IAKjE,kCAAkC,CAAC,mBAAmB,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAgB/E"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.BaseAccessory = void 0;
|
|
4
|
-
const
|
|
4
|
+
const capability_docs_1 = require("../device/capability-docs");
|
|
5
5
|
class BaseAccessory {
|
|
6
6
|
platform;
|
|
7
7
|
accessory;
|
|
@@ -23,7 +23,9 @@ class BaseAccessory {
|
|
|
23
23
|
: null;
|
|
24
24
|
// Daikin reports versions like '4_0_3'; HomeKit expects dotted revisions
|
|
25
25
|
const firmwareVersion = firmwareData?.value?.replace(/_/g, '.');
|
|
26
|
-
this.accessory.getService(this.platform.Service.AccessoryInformation)
|
|
26
|
+
const informationService = this.accessory.getService(this.platform.Service.AccessoryInformation)
|
|
27
|
+
?? this.accessory.addService(this.platform.Service.AccessoryInformation);
|
|
28
|
+
informationService
|
|
27
29
|
.setCharacteristic(this.platform.Characteristic.Manufacturer, 'Daikin')
|
|
28
30
|
.setCharacteristic(this.platform.Characteristic.Model, modelInfo)
|
|
29
31
|
.setCharacteristic(this.platform.Characteristic.SerialNumber, serialNumber)
|
|
@@ -60,14 +62,11 @@ class BaseAccessory {
|
|
|
60
62
|
this.platform.log.debug('[Platform] HAP UUID: ' + this.accessory.UUID);
|
|
61
63
|
}
|
|
62
64
|
/**
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
logCapabilities(
|
|
67
|
-
|
|
68
|
-
const capabilities = detector.getCapabilities();
|
|
69
|
-
const summary = (0, device_1.getCapabilitySummary)(capabilities);
|
|
70
|
-
this.platform.log.info(`[Platform] capabilities: ${summary}`);
|
|
65
|
+
* Log the capabilities detected for a management point (the same detection
|
|
66
|
+
* result its FeatureManager uses to decide which feature switches to expose).
|
|
67
|
+
*/
|
|
68
|
+
logCapabilities(capabilities) {
|
|
69
|
+
this.platform.log.info(`[Platform] capabilities: ${(0, capability_docs_1.getCapabilitySummary)(capabilities)}`);
|
|
71
70
|
this.platform.log.debug(`[Platform] operation modes: ${capabilities.supportedOperationModes.join(', ')}`);
|
|
72
71
|
}
|
|
73
72
|
getEmbeddedIdByManagementPointType(managementPointType) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base-accessory.js","sourceRoot":"","sources":["../../../src/accessories/base-accessory.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"base-accessory.js","sourceRoot":"","sources":["../../../src/accessories/base-accessory.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
* Handles REST API calls to the Daikin Cloud.
|
|
5
5
|
*/
|
|
6
6
|
import type { RateLimitStatus, GatewayDevice, OAuthProvider } from './daikin-types';
|
|
7
|
+
/** Options for a single API request */
|
|
8
|
+
interface RequestOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Retry on 502/503/504 with exponential backoff. Defaults to true for
|
|
11
|
+
* writes (a dropped write would otherwise be lost) and false for GETs
|
|
12
|
+
* (the next poll is the retry, so retrying only burns the daily quota).
|
|
13
|
+
*/
|
|
14
|
+
retryGatewayErrors?: boolean;
|
|
15
|
+
}
|
|
7
16
|
export declare class RateLimitedError extends Error {
|
|
8
17
|
readonly retryAfter: number;
|
|
9
18
|
constructor(message: string, retryAfter: number);
|
|
@@ -19,6 +28,7 @@ export declare class DaikinApi {
|
|
|
19
28
|
private blockedUntil;
|
|
20
29
|
private refreshPromise;
|
|
21
30
|
private writeQueues;
|
|
31
|
+
private pendingWrites;
|
|
22
32
|
constructor(oauth: OAuthProvider, onRateLimitStatus?: ((status: RateLimitStatus) => void) | undefined);
|
|
23
33
|
/**
|
|
24
34
|
* Make a static GET request with access token (for UI)
|
|
@@ -31,9 +41,13 @@ export declare class DaikinApi {
|
|
|
31
41
|
private static parseHeaderStatic;
|
|
32
42
|
private static makeStaticRequest;
|
|
33
43
|
/**
|
|
34
|
-
* Get all gateway devices with runtime validation
|
|
44
|
+
* Get all gateway devices with runtime validation.
|
|
45
|
+
*
|
|
46
|
+
* Gateway errors (5xx) are not retried by default: for periodic polling the
|
|
47
|
+
* next poll is the retry. Pass `retryGatewayErrors: true` for one-off reads
|
|
48
|
+
* (e.g. initial discovery) where a transient failure would be costly.
|
|
35
49
|
*/
|
|
36
|
-
getDevices(): Promise<GatewayDevice[]>;
|
|
50
|
+
getDevices(options?: RequestOptions): Promise<GatewayDevice[]>;
|
|
37
51
|
/**
|
|
38
52
|
* Update device data (PATCH request)
|
|
39
53
|
*
|
|
@@ -74,6 +88,11 @@ export declare class DaikinApi {
|
|
|
74
88
|
* @param firmwareId - The staged update's id from firmwareUpdate.value.id
|
|
75
89
|
*/
|
|
76
90
|
triggerFirmwareUpdate(deviceId: string, embeddedId: string, firmwareId: string): Promise<void>;
|
|
91
|
+
/**
|
|
92
|
+
* Base path of a management point. IDs come from cloud responses and are
|
|
93
|
+
* encoded so a '/' or '?' in them cannot change which endpoint is hit.
|
|
94
|
+
*/
|
|
95
|
+
private managementPointPath;
|
|
77
96
|
/**
|
|
78
97
|
* Serializes write requests per device through a queue with a fixed inter-request delay.
|
|
79
98
|
* Each device has its own queue so writes for different devices run in parallel,
|
|
@@ -92,10 +111,6 @@ export declare class DaikinApi {
|
|
|
92
111
|
* Calculate delay for exponential backoff with jitter
|
|
93
112
|
*/
|
|
94
113
|
private getRetryDelay;
|
|
95
|
-
/**
|
|
96
|
-
* Sleep for a specified duration
|
|
97
|
-
*/
|
|
98
|
-
private sleep;
|
|
99
114
|
/**
|
|
100
115
|
* Get human-readable name for gateway error status codes
|
|
101
116
|
*/
|
|
@@ -112,4 +127,5 @@ export declare class DaikinApi {
|
|
|
112
127
|
private parseHeader;
|
|
113
128
|
private makeRequest;
|
|
114
129
|
}
|
|
130
|
+
export {};
|
|
115
131
|
//# sourceMappingURL=daikin-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daikin-api.d.ts","sourceRoot":"","sources":["../../../src/api/daikin-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"daikin-api.d.ts","sourceRoot":"","sources":["../../../src/api/daikin-api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAgBpF,uCAAuC;AACvC,UAAU,cAAc;IACtB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAQD,qBAAa,gBAAiB,SAAQ,KAAK;aAGnB,UAAU,EAAE,MAAM;gBADtC,OAAO,EAAE,MAAM,EACK,UAAU,EAAE,MAAM;CAKzC;AAED,qBAAa,eAAgB,SAAQ,KAAK;aAGlB,UAAU,EAAE,MAAM;aAClB,YAAY,EAAE,MAAM;gBAFxC,OAAO,EAAE,MAAM,EACK,UAAU,EAAE,MAAM,EAClB,YAAY,EAAE,MAAM;CAK3C;AAED,qBAAa,SAAS;IAWd,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC;IAXzC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,cAAc,CAA8B;IAGpD,OAAO,CAAC,WAAW,CAA4C;IAG/D,OAAO,CAAC,aAAa,CAAwC;gBAGtC,KAAK,EAAE,aAAa,EACpB,iBAAiB,CAAC,GAAE,CAAC,MAAM,EAAE,eAAe,KAAK,IAAI,aAAA;IAO5E;;SAEK;WACQ,aAAa,CACxB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,CAAC;QAAC,SAAS,EAAE,eAAe,CAAA;KAAE,CAAC;IA6BjH,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAShC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAiBhC;;;;;;SAMK;IACC,UAAU,CAAC,OAAO,GAAE,cAAmB,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;IAKxE;;;;;;;;SAQK;IACC,YAAY,CAChB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,OAAO,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAuBhB;;;;;;;;;;;SAWK;IACC,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC/D,OAAO,CAAC,IAAI,CAAC;IAKhB;;;;;;;;;;;SAWK;IACC,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpG;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;;;OAIG;IACH,OAAO,CAAC,qBAAqB;IAmB7B;;SAEK;IACL,aAAa,IAAI,OAAO;IAIxB;;SAEK;IACL,sBAAsB,IAAI,MAAM;IAIhC;;SAEK;IACL,OAAO,CAAC,aAAa;IAMrB;;SAEK;IACL,OAAO,CAAC,mBAAmB;IAa3B;;SAEK;IACL,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,mBAAmB;IAQ3B;;SAEK;YACS,OAAO;IAiHrB,OAAO,CAAC,WAAW;YASL,WAAW;CAgB1B"}
|