@mp-consulting/homebridge-daikin-cloud 1.3.5 → 1.3.7
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/LICENSE +39 -1
- package/README.md +5 -3
- package/dist/src/accessories/air-conditioning-accessory.d.ts +2 -2
- package/dist/src/accessories/air-conditioning-accessory.d.ts.map +1 -1
- package/dist/src/accessories/air-conditioning-accessory.js.map +1 -1
- package/dist/src/accessories/altherma-accessory.d.ts +2 -2
- package/dist/src/accessories/altherma-accessory.d.ts.map +1 -1
- package/dist/src/accessories/altherma-accessory.js.map +1 -1
- package/dist/src/accessories/base-accessory.d.ts +6 -6
- package/dist/src/accessories/base-accessory.d.ts.map +1 -1
- package/dist/src/accessories/base-accessory.js +15 -15
- package/dist/src/accessories/base-accessory.js.map +1 -1
- package/dist/src/api/daikin-api.d.ts +26 -26
- package/dist/src/api/daikin-api.d.ts.map +1 -1
- package/dist/src/api/daikin-api.js +68 -42
- package/dist/src/api/daikin-api.js.map +1 -1
- package/dist/src/api/daikin-cloud.repository.d.ts.map +1 -1
- package/dist/src/api/daikin-cloud.repository.js +22 -14
- package/dist/src/api/daikin-cloud.repository.js.map +1 -1
- package/dist/src/api/daikin-controller.d.ts +41 -47
- package/dist/src/api/daikin-controller.d.ts.map +1 -1
- package/dist/src/api/daikin-controller.js +40 -64
- package/dist/src/api/daikin-controller.js.map +1 -1
- package/dist/src/api/daikin-device.d.ts +36 -31
- package/dist/src/api/daikin-device.d.ts.map +1 -1
- package/dist/src/api/daikin-device.js +45 -31
- package/dist/src/api/daikin-device.js.map +1 -1
- package/dist/src/api/daikin-mobile-oauth.d.ts +20 -20
- package/dist/src/api/daikin-mobile-oauth.d.ts.map +1 -1
- package/dist/src/api/daikin-mobile-oauth.js +49 -44
- package/dist/src/api/daikin-mobile-oauth.js.map +1 -1
- package/dist/src/api/daikin-oauth.d.ts +32 -32
- package/dist/src/api/daikin-oauth.d.ts.map +1 -1
- package/dist/src/api/daikin-oauth.js +64 -56
- package/dist/src/api/daikin-oauth.js.map +1 -1
- package/dist/src/api/daikin-schemas.d.ts +476 -351
- package/dist/src/api/daikin-schemas.d.ts.map +1 -1
- package/dist/src/api/daikin-schemas.js +11 -42
- package/dist/src/api/daikin-schemas.js.map +1 -1
- package/dist/src/api/daikin-types.d.ts +5 -1
- 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 +31 -32
- package/dist/src/api/daikin-websocket.d.ts.map +1 -1
- package/dist/src/api/daikin-websocket.js +55 -35
- package/dist/src/api/daikin-websocket.js.map +1 -1
- package/dist/src/api/index.d.ts +2 -1
- package/dist/src/api/index.d.ts.map +1 -1
- package/dist/src/api/index.js +3 -1
- package/dist/src/api/index.js.map +1 -1
- package/dist/src/api/token-storage.d.ts +21 -0
- package/dist/src/api/token-storage.d.ts.map +1 -0
- package/dist/src/api/token-storage.js +90 -0
- package/dist/src/api/token-storage.js.map +1 -0
- package/dist/src/config/config-manager.d.ts +33 -33
- package/dist/src/config/config-manager.d.ts.map +1 -1
- package/dist/src/config/config-manager.js +33 -33
- package/dist/src/config/config-manager.js.map +1 -1
- package/dist/src/constants/api.constants.d.ts +4 -0
- package/dist/src/constants/api.constants.d.ts.map +1 -1
- package/dist/src/constants/api.constants.js +5 -1
- package/dist/src/constants/api.constants.js.map +1 -1
- package/dist/src/constants/device.constants.d.ts +4 -0
- package/dist/src/constants/device.constants.d.ts.map +1 -1
- package/dist/src/constants/device.constants.js +5 -1
- package/dist/src/constants/device.constants.js.map +1 -1
- package/dist/src/device/accessory-factory.d.ts +10 -10
- package/dist/src/device/accessory-factory.d.ts.map +1 -1
- package/dist/src/device/accessory-factory.js +7 -7
- package/dist/src/device/accessory-factory.js.map +1 -1
- package/dist/src/device/capability-detector.d.ts +8 -8
- package/dist/src/device/capability-detector.d.ts.map +1 -1
- package/dist/src/device/capability-detector.js +6 -6
- package/dist/src/device/capability-detector.js.map +1 -1
- package/dist/src/device/capability-docs.d.ts +1 -9
- package/dist/src/device/capability-docs.d.ts.map +1 -1
- package/dist/src/device/capability-docs.js +19 -73
- package/dist/src/device/capability-docs.js.map +1 -1
- package/dist/src/device/profiles/device-profile.d.ts +1 -1
- package/dist/src/device/profiles/device-profile.d.ts.map +1 -1
- package/dist/src/device/profiles/device-profile.js +4 -4
- package/dist/src/device/profiles/device-profile.js.map +1 -1
- package/dist/src/features/base-feature.d.ts +2 -2
- package/dist/src/features/base-feature.d.ts.map +1 -1
- package/dist/src/features/base-feature.js +2 -3
- package/dist/src/features/base-feature.js.map +1 -1
- package/dist/src/features/feature-manager.d.ts +8 -16
- package/dist/src/features/feature-manager.d.ts.map +1 -1
- package/dist/src/features/feature-manager.js +5 -17
- package/dist/src/features/feature-manager.js.map +1 -1
- package/dist/src/features/modes/dry-operation-mode.feature.d.ts +1 -1
- package/dist/src/features/modes/dry-operation-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/dry-operation-mode.feature.js.map +1 -1
- package/dist/src/features/modes/econo-mode.feature.d.ts +1 -1
- package/dist/src/features/modes/econo-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/econo-mode.feature.js.map +1 -1
- package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts +1 -1
- 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.map +1 -1
- package/dist/src/features/modes/indoor-silent-mode.feature.d.ts +1 -1
- package/dist/src/features/modes/indoor-silent-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/indoor-silent-mode.feature.js.map +1 -1
- package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts +1 -1
- package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/outdoor-silent-mode.feature.js.map +1 -1
- package/dist/src/features/modes/powerful-mode.feature.d.ts +1 -1
- package/dist/src/features/modes/powerful-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/powerful-mode.feature.js.map +1 -1
- package/dist/src/features/modes/streamer-mode.feature.d.ts +1 -1
- package/dist/src/features/modes/streamer-mode.feature.d.ts.map +1 -1
- package/dist/src/features/modes/streamer-mode.feature.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/platform.d.ts +11 -8
- package/dist/src/platform.d.ts.map +1 -1
- package/dist/src/platform.js +64 -15
- package/dist/src/platform.js.map +1 -1
- package/dist/src/services/climate-control.service.d.ts +8 -2
- package/dist/src/services/climate-control.service.d.ts.map +1 -1
- package/dist/src/services/climate-control.service.js +59 -58
- package/dist/src/services/climate-control.service.js.map +1 -1
- package/dist/src/services/hot-water-tank.service.d.ts +6 -2
- package/dist/src/services/hot-water-tank.service.d.ts.map +1 -1
- package/dist/src/services/hot-water-tank.service.js +33 -31
- package/dist/src/services/hot-water-tank.service.js.map +1 -1
- package/dist/src/types/daikin-enums.js +12 -12
- package/dist/src/types/daikin-enums.js.map +1 -1
- package/dist/src/types/device-capabilities.d.ts +1 -1
- package/dist/src/types/device-capabilities.d.ts.map +1 -1
- package/dist/src/utils/log-context.d.ts +23 -23
- package/dist/src/utils/log-context.d.ts.map +1 -1
- package/dist/src/utils/log-context.js +28 -28
- package/dist/src/utils/log-context.js.map +1 -1
- package/dist/src/utils/strings.d.ts.map +1 -1
- package/dist/src/utils/strings.js.map +1 -1
- package/dist/src/utils/update-mapper.d.ts +16 -16
- package/dist/src/utils/update-mapper.d.ts.map +1 -1
- package/dist/src/utils/update-mapper.js +14 -14
- package/dist/src/utils/update-mapper.js.map +1 -1
- package/homebridge-ui/public/index.html +2 -2
- package/homebridge-ui/public/script.js +957 -898
- package/homebridge-ui/server.js +746 -678
- package/package.json +29 -27
- package/.claude/settings.json +0 -3
- package/.claude/settings.local.json +0 -29
- package/CHANGELOG.md +0 -103
- package/CLAUDE.md +0 -269
- package/config.md +0 -2
- package/dist/src/api/daikin-device-tracker.d.ts +0 -97
- package/dist/src/api/daikin-device-tracker.d.ts.map +0 -1
- package/dist/src/api/daikin-device-tracker.js +0 -136
- package/dist/src/api/daikin-device-tracker.js.map +0 -1
- package/dist/src/api/http-interceptor.d.ts +0 -99
- package/dist/src/api/http-interceptor.d.ts.map +0 -1
- package/dist/src/api/http-interceptor.js +0 -177
- package/dist/src/api/http-interceptor.js.map +0 -1
- package/dist/src/di/service-container.d.ts +0 -92
- package/dist/src/di/service-container.d.ts.map +0 -1
- package/dist/src/di/service-container.js +0 -156
- package/dist/src/di/service-container.js.map +0 -1
- package/dist/src/features/feature-registry.d.ts +0 -100
- package/dist/src/features/feature-registry.d.ts.map +0 -1
- package/dist/src/features/feature-registry.js +0 -142
- package/dist/src/features/feature-registry.js.map +0 -1
- package/dist/src/services/service-factory.d.ts +0 -46
- package/dist/src/services/service-factory.d.ts.map +0 -1
- package/dist/src/services/service-factory.js +0 -72
- package/dist/src/services/service-factory.js.map +0 -1
- package/dist/src/utils/error-handler.d.ts +0 -101
- package/dist/src/utils/error-handler.d.ts.map +0 -1
- package/dist/src/utils/error-handler.js +0 -251
- package/dist/src/utils/error-handler.js.map +0 -1
- package/dist/src/utils/retry.d.ts +0 -42
- package/dist/src/utils/retry.d.ts.map +0 -1
- package/dist/src/utils/retry.js +0 -70
- package/dist/src/utils/retry.js.map +0 -1
- package/docs/ARCHITECTURE.md +0 -645
- package/docs/IMPLEMENTATION_GUIDE.md +0 -899
- package/docs/IMPROVEMENTS_SUMMARY.md +0 -415
- package/docs/NEXT_STEPS.md +0 -368
- package/docs/Screenshot 2024-07-04 at 18.41.28.png +0 -0
- package/docs/TROUBLESHOOTING.md +0 -475
- package/docs/api-response-for-BRP069A8x.json +0 -520
- package/docs/api-response-for-BRP069C4x-2.json +0 -881
- package/docs/api-response-for-BRP069C4x.json +0 -916
- package/docs/api-response-for-altherma.json +0 -759
- package/docs/api-response-for-altherma2.json +0 -2735
- package/docs/api-response-with-multiple-devices-incl-heatpump.json +0 -2544
- package/docs/cr-insance-altherma-id-0.json +0 -834
- package/docs/mock-air-to-air-dx23.json +0 -759
- package/docs/mock-air-to-air-dx4.json +0 -1134
- package/docs/mock-airpurifier-with-humidifier.json +0 -732
- package/docs/mock-airpurifier.json +0 -450
- package/docs/mock-altherma-air-to-water-lan.json +0 -845
- package/docs/mock-altherma-air-to-water-wlan.json +0 -845
- package/docs/mock-d2cnd-gas-boiler.json +0 -649
- package/docs/setpointmode-vs-controlmode-vs-setpoints-vs-sensorydata.txt +0 -6
- package/images/fan-speed.jpeg +0 -0
- package/images/homekit-controls.jpeg +0 -0
- package/images/homekit-settings.jpeg +0 -0
- package/images/swing-mode.png +0 -0
- package/jest.config.ts +0 -13
- package/test/fixtures/altherma-crSense-2.ts +0 -834
- package/test/fixtures/altherma-fraction.ts +0 -718
- package/test/fixtures/altherma-heat-pump-2.ts +0 -479
- package/test/fixtures/altherma-heat-pump.ts +0 -757
- package/test/fixtures/altherma-miladcerkic-off.ts +0 -524
- package/test/fixtures/altherma-miladcerkic.ts +0 -524
- package/test/fixtures/altherma-v1ckoeln.ts +0 -644
- package/test/fixtures/altherma-with-embedded-id-zero.ts +0 -834
- package/test/fixtures/dx23-airco-2.ts +0 -343
- package/test/fixtures/dx23-airco.ts +0 -518
- package/test/fixtures/dx4-airco.ts +0 -914
- package/test/fixtures/unknown-jan.ts +0 -488
- package/test/fixtures/unknown-kitchen-guests.ts +0 -488
- package/test/helpers/test-isolation.ts +0 -228
- package/test/integration/air-conditioning.test.ts +0 -410
- package/test/integration/altherma.test.ts +0 -289
- package/test/integration/platform.test.ts +0 -118
- package/test/mocks/index.ts +0 -27
- package/test/test-gigya-auth.js +0 -443
- package/test/test-mobile-oauth.js +0 -175
- package/test/test-websocket-mobile.js +0 -123
- package/test/test-websocket.js +0 -116
- package/test/unit/api/__snapshots__/daikinCloud.test.ts.snap +0 -1320
- package/test/unit/api/daikin-api.test.ts +0 -384
- package/test/unit/api/daikin-oauth.test.ts +0 -214
- package/test/unit/api/daikinCloud.test.ts +0 -12
- package/test/unit/config/config-manager.test.ts +0 -271
- package/test/unit/device/daikin-device.test.ts +0 -79
- package/test/unit/services/hot-water-tank.service.test.ts +0 -123
- package/test/unit/utils/error-handler.test.ts +0 -274
- package/test/unit/utils/log-context.test.ts +0 -271
package/docs/ARCHITECTURE.md
DELETED
|
@@ -1,645 +0,0 @@
|
|
|
1
|
-
# Architecture Documentation
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
This Homebridge plugin integrates Daikin air conditioning units via the Daikin Cloud (Onecta) API with Apple HomeKit. The architecture supports dual authentication modes, real-time WebSocket updates, and extensible feature management.
|
|
6
|
-
|
|
7
|
-
## System Architecture
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
-
│ Apple HomeKit │
|
|
12
|
-
│ (iOS Home App / Siri) │
|
|
13
|
-
└───────────────────────────┬─────────────────────────────────┘
|
|
14
|
-
│ HAP Protocol
|
|
15
|
-
┌───────────────────────────┴─────────────────────────────────┐
|
|
16
|
-
│ Homebridge │
|
|
17
|
-
│ (HAP-nodejs) │
|
|
18
|
-
└───────────────────────────┬─────────────────────────────────┘
|
|
19
|
-
│ Plugin API
|
|
20
|
-
┌───────────────────────────┴─────────────────────────────────┐
|
|
21
|
-
│ Daikin Cloud Platform Plugin │
|
|
22
|
-
│ ┌──────────────────────────────────────────────────────┐ │
|
|
23
|
-
│ │ DaikinCloudPlatform │ │
|
|
24
|
-
│ │ - Manages accessories lifecycle │ │
|
|
25
|
-
│ │ - Coordinates controllers & services │ │
|
|
26
|
-
│ │ - Handles WebSocket events │ │
|
|
27
|
-
│ └──────────────────────────────────────────────────────┘ │
|
|
28
|
-
│ │
|
|
29
|
-
│ ┌─────────────┐ ┌──────────────┐ ┌──────────────────┐ │
|
|
30
|
-
│ │ Accessories │ │ Services │ │ Features │ │
|
|
31
|
-
│ │ - AC Unit │ │ - Climate │ │ - Powerful Mode │ │
|
|
32
|
-
│ │ - Altherma │ │ - Hot Water │ │ - Econo Mode │ │
|
|
33
|
-
│ └─────────────┘ └──────────────┘ └──────────────────┘ │
|
|
34
|
-
│ │
|
|
35
|
-
│ ┌──────────────────────────────────────────────────────┐ │
|
|
36
|
-
│ │ DaikinCloudController │ │
|
|
37
|
-
│ │ - OAuth management │ │
|
|
38
|
-
│ │ - API rate limiting │ │
|
|
39
|
-
│ │ - Device data management │ │
|
|
40
|
-
│ └──────────────────────────────────────────────────────┘ │
|
|
41
|
-
└───────────────────────────┬─────────────────────────────────┘
|
|
42
|
-
┌─────────┴─────────┐
|
|
43
|
-
│ │
|
|
44
|
-
┌──────────┴─────────┐ ┌────┴────────────┐
|
|
45
|
-
│ OAuth Provider │ │ WebSocket │
|
|
46
|
-
│ - Developer Portal │ │ - Real-time │
|
|
47
|
-
│ - Mobile App │ │ - Device Events│
|
|
48
|
-
└──────────┬─────────┘ └────┬────────────┘
|
|
49
|
-
│ │
|
|
50
|
-
┌──────────┴───────────────────┴────────────┐
|
|
51
|
-
│ Daikin Cloud API (Onecta) │
|
|
52
|
-
│ https://api.onecta.daikineurope.com │
|
|
53
|
-
└────────────────────────────────────────────┘
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Core Components
|
|
57
|
-
|
|
58
|
-
### 1. Platform Layer
|
|
59
|
-
|
|
60
|
-
#### DaikinCloudPlatform ([platform.ts](src/platform.ts))
|
|
61
|
-
|
|
62
|
-
The main entry point implementing Homebridge's `DynamicPlatformPlugin` interface.
|
|
63
|
-
|
|
64
|
-
**Responsibilities:**
|
|
65
|
-
- Initialize and configure the plugin
|
|
66
|
-
- Discover and register HAP accessories
|
|
67
|
-
- Manage device polling and WebSocket connections
|
|
68
|
-
- Handle configuration validation
|
|
69
|
-
- Coordinate between controllers, services, and accessories
|
|
70
|
-
|
|
71
|
-
**Key Methods:**
|
|
72
|
-
- `discoverDevices()`: Fetches devices from API and creates/updates accessories
|
|
73
|
-
- `configureAccessory()`: Restores cached accessories on Homebridge restart
|
|
74
|
-
- `updateDevices()`: Periodic polling for device state changes
|
|
75
|
-
- `handleWebSocketDeviceUpdate()`: Processes real-time WebSocket updates
|
|
76
|
-
|
|
77
|
-
**Lifecycle:**
|
|
78
|
-
1. Constructor: Initialize services, validate config
|
|
79
|
-
2. `didFinishLaunching()`: Start authentication and device discovery
|
|
80
|
-
3. Periodic updates or WebSocket events
|
|
81
|
-
4. Cleanup on shutdown
|
|
82
|
-
|
|
83
|
-
### 2. Authentication Layer
|
|
84
|
-
|
|
85
|
-
#### DaikinCloudController ([api/daikin-controller.ts](src/api/daikin-controller.ts))
|
|
86
|
-
|
|
87
|
-
Unified controller managing both authentication modes.
|
|
88
|
-
|
|
89
|
-
**Dual Authentication Support:**
|
|
90
|
-
|
|
91
|
-
##### Developer Portal Mode
|
|
92
|
-
- Uses OAuth 2.0 Authorization Code flow
|
|
93
|
-
- Requires Client ID/Secret from Daikin Developer Portal
|
|
94
|
-
- 200 API calls/day limit
|
|
95
|
-
- No WebSocket support
|
|
96
|
-
- **Flow:**
|
|
97
|
-
1. Generate authorization URL
|
|
98
|
-
2. User authenticates via browser
|
|
99
|
-
3. Exchange code for access/refresh tokens
|
|
100
|
-
4. Store tokens securely (mode 0o600)
|
|
101
|
-
|
|
102
|
-
##### Mobile App Mode
|
|
103
|
-
- Uses Gigya authentication + PKCE
|
|
104
|
-
- Requires email/password (same as Onecta app)
|
|
105
|
-
- 5000 API calls/day limit
|
|
106
|
-
- WebSocket support for real-time updates
|
|
107
|
-
- **Flow:**
|
|
108
|
-
1. Login via Gigya API
|
|
109
|
-
2. Exchange Gigya token for Daikin OIDC token
|
|
110
|
-
3. Use access token for API calls
|
|
111
|
-
4. Establish WebSocket connection
|
|
112
|
-
|
|
113
|
-
#### OAuth Providers
|
|
114
|
-
|
|
115
|
-
- [daikin-oauth.ts](src/api/daikin-oauth.ts): Developer Portal OAuth implementation
|
|
116
|
-
- [daikin-mobile-oauth.ts](src/api/daikin-mobile-oauth.ts): Mobile App Gigya authentication
|
|
117
|
-
|
|
118
|
-
**Token Management:**
|
|
119
|
-
- Automatic token refresh before expiration
|
|
120
|
-
- Exponential backoff for failed refreshes
|
|
121
|
-
- Secure file storage with restricted permissions
|
|
122
|
-
- Event-driven token updates
|
|
123
|
-
|
|
124
|
-
### 3. API Integration Layer
|
|
125
|
-
|
|
126
|
-
#### DaikinApi ([api/daikin-api.ts](src/api/daikin-api.ts))
|
|
127
|
-
|
|
128
|
-
HTTP client for Daikin Cloud API with built-in resilience.
|
|
129
|
-
|
|
130
|
-
**Features:**
|
|
131
|
-
- Rate limit tracking (per-minute and per-day)
|
|
132
|
-
- Automatic retry with exponential backoff
|
|
133
|
-
- Gateway timeout handling (502, 503, 504)
|
|
134
|
-
- Request/response logging
|
|
135
|
-
- Error categorization
|
|
136
|
-
|
|
137
|
-
**Rate Limiting:**
|
|
138
|
-
```typescript
|
|
139
|
-
Headers:
|
|
140
|
-
- x-ratelimit-limit-minute: 10
|
|
141
|
-
- x-ratelimit-remaining-minute: 9
|
|
142
|
-
- x-ratelimit-limit-day: 200 (Developer) / 5000 (Mobile)
|
|
143
|
-
- x-ratelimit-remaining-day: 195
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
**Retry Strategy:**
|
|
147
|
-
- Initial delay: 1s
|
|
148
|
-
- Max delay: 60s
|
|
149
|
-
- Exponential backoff with jitter
|
|
150
|
-
- Max retries: 3
|
|
151
|
-
|
|
152
|
-
#### WebSocket Integration ([api/daikin-websocket.ts](src/api/daikin-websocket.ts))
|
|
153
|
-
|
|
154
|
-
Real-time device state updates (Mobile App mode only).
|
|
155
|
-
|
|
156
|
-
**Connection Management:**
|
|
157
|
-
- Automatic reconnection on disconnect
|
|
158
|
-
- Exponential backoff (1s → 5min)
|
|
159
|
-
- Heartbeat/ping-pong for connection health
|
|
160
|
-
- Event-driven architecture
|
|
161
|
-
|
|
162
|
-
**Message Flow:**
|
|
163
|
-
```
|
|
164
|
-
Device State Change
|
|
165
|
-
↓
|
|
166
|
-
Daikin Cloud
|
|
167
|
-
↓ (WebSocket)
|
|
168
|
-
Plugin WebSocket Client
|
|
169
|
-
↓ (Event)
|
|
170
|
-
Platform.handleWebSocketDeviceUpdate()
|
|
171
|
-
↓
|
|
172
|
-
UpdateMapper.applyUpdate()
|
|
173
|
-
↓
|
|
174
|
-
HAP Service.updateCharacteristic()
|
|
175
|
-
↓
|
|
176
|
-
HomeKit
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### 4. Device Management Layer
|
|
180
|
-
|
|
181
|
-
#### DaikinCloudDevice ([api/daikin-device.ts](src/api/daikin-device.ts))
|
|
182
|
-
|
|
183
|
-
Represents a single Daikin device with management points (embedded units).
|
|
184
|
-
|
|
185
|
-
**Structure:**
|
|
186
|
-
```
|
|
187
|
-
Gateway Device
|
|
188
|
-
└─ Management Point 1 (e.g., Indoor Unit #1)
|
|
189
|
-
├─ onOffMode
|
|
190
|
-
├─ operationMode
|
|
191
|
-
├─ temperatureControl
|
|
192
|
-
├─ sensoryData
|
|
193
|
-
└─ fanControl
|
|
194
|
-
└─ Management Point 2 (e.g., Hot Water Tank)
|
|
195
|
-
├─ onOffMode
|
|
196
|
-
├─ tankTemperature
|
|
197
|
-
└─ targetTemperature
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
**Key Methods:**
|
|
201
|
-
- `getData(embeddedId, characteristicName)`: Retrieve device data
|
|
202
|
-
- `updateData(updates)`: Apply API response updates
|
|
203
|
-
- `getEmbeddedIds()`: List all management points
|
|
204
|
-
|
|
205
|
-
#### Capability Detection ([device/capability-detector.ts](src/device/capability-detector.ts))
|
|
206
|
-
|
|
207
|
-
Analyzes device capabilities to determine supported features.
|
|
208
|
-
|
|
209
|
-
**Detection Logic:**
|
|
210
|
-
```typescript
|
|
211
|
-
detectCapabilities(device: GatewayDevice) {
|
|
212
|
-
// Check device type
|
|
213
|
-
if (device.type === 'climateControl') {
|
|
214
|
-
// Detect operation modes (cooling, heating, auto)
|
|
215
|
-
// Detect fan control
|
|
216
|
-
// Detect swing mode
|
|
217
|
-
} else if (device.type === 'domesticHotWaterTank') {
|
|
218
|
-
// Detect tank temperature
|
|
219
|
-
// Detect target temperature range
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
### 5. Accessory Layer
|
|
225
|
-
|
|
226
|
-
#### Base Accessory ([accessories/base-accessory.ts](src/accessories/base-accessory.ts))
|
|
227
|
-
|
|
228
|
-
Abstract base class for all accessories providing common functionality.
|
|
229
|
-
|
|
230
|
-
**Responsibilities:**
|
|
231
|
-
- Service lifecycle management
|
|
232
|
-
- Characteristic binding
|
|
233
|
-
- Error handling
|
|
234
|
-
- Feature integration
|
|
235
|
-
|
|
236
|
-
#### Air Conditioning Accessory ([accessories/air-conditioning-accessory.ts](src/accessories/air-conditioning-accessory.ts))
|
|
237
|
-
|
|
238
|
-
Maps Daikin AC unit to HAP HeaterCooler or Thermostat service.
|
|
239
|
-
|
|
240
|
-
**Service Selection:**
|
|
241
|
-
- Default: HeaterCooler (iOS 11+)
|
|
242
|
-
- Fallback: Thermostat (older compatibility)
|
|
243
|
-
|
|
244
|
-
**Characteristic Mapping:**
|
|
245
|
-
|
|
246
|
-
| Daikin | HomeKit (HeaterCooler) | HomeKit (Thermostat) |
|
|
247
|
-
|--------|----------------------|---------------------|
|
|
248
|
-
| onOffMode | Active | CurrentHeatingCoolingState |
|
|
249
|
-
| operationMode (cooling) | TargetHeaterCoolerState.COOL | TargetHeatingCoolingState.COOL |
|
|
250
|
-
| operationMode (heating) | TargetHeaterCoolerState.HEAT | TargetHeatingCoolingState.HEAT |
|
|
251
|
-
| operationMode (auto) | TargetHeaterCoolerState.AUTO | TargetHeatingCoolingState.AUTO |
|
|
252
|
-
| temperatureControl | CoolingThresholdTemperature<br>HeatingThresholdTemperature | TargetTemperature |
|
|
253
|
-
| sensoryData.roomTemperature | CurrentTemperature | CurrentTemperature |
|
|
254
|
-
| fanControl | RotationSpeed (%) | - |
|
|
255
|
-
|
|
256
|
-
#### Altherma Accessory ([accessories/altherma-accessory.ts](src/accessories/altherma-accessory.ts))
|
|
257
|
-
|
|
258
|
-
Heat pump and hot water tank management.
|
|
259
|
-
|
|
260
|
-
**Services:**
|
|
261
|
-
- Climate Control: Thermostat service
|
|
262
|
-
- Hot Water: Thermostat service
|
|
263
|
-
|
|
264
|
-
### 6. Service Layer
|
|
265
|
-
|
|
266
|
-
Services encapsulate HAP service logic for climate control and hot water.
|
|
267
|
-
|
|
268
|
-
#### Climate Control Service ([services/climate-control.service.ts](src/services/climate-control.service.ts))
|
|
269
|
-
|
|
270
|
-
**Characteristic Handlers:**
|
|
271
|
-
- `Active` (GET/SET): Turn unit on/off
|
|
272
|
-
- `CurrentHeaterCoolerState` (GET): Current operating state
|
|
273
|
-
- `TargetHeaterCoolerState` (GET/SET): Cooling/heating/auto mode
|
|
274
|
-
- `CurrentTemperature` (GET): Room temperature
|
|
275
|
-
- `CoolingThresholdTemperature` (GET/SET): Target cooling temp
|
|
276
|
-
- `HeatingThresholdTemperature` (GET/SET): Target heating temp
|
|
277
|
-
- `RotationSpeed` (GET/SET): Fan speed (percentage)
|
|
278
|
-
- `SwingMode` (GET/SET): Fan swing (if supported)
|
|
279
|
-
|
|
280
|
-
**Update Flow:**
|
|
281
|
-
```
|
|
282
|
-
User changes target temp in Home app
|
|
283
|
-
↓
|
|
284
|
-
HAP SET handler
|
|
285
|
-
↓
|
|
286
|
-
Service validates value
|
|
287
|
-
↓
|
|
288
|
-
API PATCH request to Daikin
|
|
289
|
-
↓
|
|
290
|
-
Force update after delay (60s)
|
|
291
|
-
↓
|
|
292
|
-
Refresh device state from API
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
### 7. Feature System
|
|
296
|
-
|
|
297
|
-
Extensible feature modules for extra modes (Powerful, Econo, etc.).
|
|
298
|
-
|
|
299
|
-
#### Feature Architecture
|
|
300
|
-
|
|
301
|
-
```
|
|
302
|
-
BaseFeature (abstract)
|
|
303
|
-
├─ PowerfulModeFeature
|
|
304
|
-
├─ EconoModeFeature
|
|
305
|
-
├─ StreamerModeFeature
|
|
306
|
-
├─ OutdoorSilentModeFeature
|
|
307
|
-
├─ IndoorSilentModeFeature
|
|
308
|
-
├─ DryOperationModeFeature
|
|
309
|
-
└─ FanOnlyOperationModeFeature
|
|
310
|
-
```
|
|
311
|
-
|
|
312
|
-
**Feature Lifecycle:**
|
|
313
|
-
1. FeatureRegistry discovers available features
|
|
314
|
-
2. Platform checks device capabilities
|
|
315
|
-
3. FeatureManager creates feature instances
|
|
316
|
-
4. Features register as Switch services
|
|
317
|
-
5. User toggles switch in Home app
|
|
318
|
-
6. Feature sends API request
|
|
319
|
-
7. State synced via polling or WebSocket
|
|
320
|
-
|
|
321
|
-
#### Adding a New Feature
|
|
322
|
-
|
|
323
|
-
```typescript
|
|
324
|
-
// 1. Create feature class
|
|
325
|
-
export class CustomModeFeature extends BaseFeature {
|
|
326
|
-
featureName = 'customMode';
|
|
327
|
-
displayName = 'Custom Mode';
|
|
328
|
-
|
|
329
|
-
async isSupported(): Promise<boolean> {
|
|
330
|
-
return this.device.getData(this.embeddedId, 'customMode') !== undefined;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
async getState(): Promise<boolean> {
|
|
334
|
-
const data = this.device.getData(this.embeddedId, 'customMode', undefined);
|
|
335
|
-
return data.value === 'on';
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
async setState(enabled: boolean): Promise<void> {
|
|
339
|
-
await this.controller.setDeviceData(/* ... */);
|
|
340
|
-
}
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// 2. Register in FeatureRegistry
|
|
344
|
-
import {CustomModeFeature} from './modes/custom-mode.feature';
|
|
345
|
-
export const FEATURE_REGISTRY = {
|
|
346
|
-
customMode: CustomModeFeature,
|
|
347
|
-
// ...
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
// 3. Add config option
|
|
351
|
-
showCustomMode?: boolean;
|
|
352
|
-
|
|
353
|
-
// 4. Update FeatureManager logic
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
### 8. Utility Layer
|
|
357
|
-
|
|
358
|
-
#### UpdateMapper ([utils/update-mapper.ts](src/utils/update-mapper.ts))
|
|
359
|
-
|
|
360
|
-
Centralized WebSocket update mapping logic.
|
|
361
|
-
|
|
362
|
-
**Consolidates:**
|
|
363
|
-
- Characteristic name mapping
|
|
364
|
-
- Service type handling (HeaterCooler vs Thermostat)
|
|
365
|
-
- State conversion logic
|
|
366
|
-
- Logging
|
|
367
|
-
|
|
368
|
-
**Before (duplicated in platform.ts):**
|
|
369
|
-
```typescript
|
|
370
|
-
switch (characteristicName) {
|
|
371
|
-
case 'onOffMode':
|
|
372
|
-
// 50 lines of logic
|
|
373
|
-
case 'operationMode':
|
|
374
|
-
// 50 lines of logic
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
**After (single source of truth):**
|
|
379
|
-
```typescript
|
|
380
|
-
const result = updateMapper.applyUpdate(accessory, update);
|
|
381
|
-
this.log.debug(`Updated ${result.updated.join(', ')}`);
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
#### Error Handler ([utils/error-handler.ts](src/utils/error-handler.ts))
|
|
385
|
-
|
|
386
|
-
Comprehensive error categorization and handling.
|
|
387
|
-
|
|
388
|
-
**Error Categories:**
|
|
389
|
-
- Network errors (timeout, connection refused)
|
|
390
|
-
- Authentication errors (401, 403)
|
|
391
|
-
- Rate limit errors (429)
|
|
392
|
-
- Server errors (500, 502, 503, 504)
|
|
393
|
-
- Validation errors (400)
|
|
394
|
-
|
|
395
|
-
**Severity Levels:**
|
|
396
|
-
- Critical: Authentication failure, controller not initialized
|
|
397
|
-
- Error: API errors, device not found
|
|
398
|
-
- Warning: Rate limit approaching, retry attempts
|
|
399
|
-
- Info: Normal operations
|
|
400
|
-
|
|
401
|
-
#### Config Manager ([config/config-manager.ts](src/config/config-manager.ts))
|
|
402
|
-
|
|
403
|
-
Centralized configuration with validation and defaults.
|
|
404
|
-
|
|
405
|
-
**Features:**
|
|
406
|
-
- Type-safe configuration access
|
|
407
|
-
- Zod schema validation
|
|
408
|
-
- Sensible defaults
|
|
409
|
-
- Validation with warnings/errors
|
|
410
|
-
- Normalized configuration caching
|
|
411
|
-
|
|
412
|
-
## Data Flow
|
|
413
|
-
|
|
414
|
-
### Device Discovery Flow
|
|
415
|
-
|
|
416
|
-
```
|
|
417
|
-
1. Homebridge starts
|
|
418
|
-
↓
|
|
419
|
-
2. Platform.constructor()
|
|
420
|
-
↓
|
|
421
|
-
3. Platform.didFinishLaunching()
|
|
422
|
-
↓
|
|
423
|
-
4. Authenticate (Developer Portal or Mobile App)
|
|
424
|
-
↓
|
|
425
|
-
5. DaikinController.updateAllDeviceData()
|
|
426
|
-
↓
|
|
427
|
-
6. API GET /v1/gateway-devices
|
|
428
|
-
↓
|
|
429
|
-
7. Parse device list
|
|
430
|
-
↓
|
|
431
|
-
8. For each device:
|
|
432
|
-
├─ Create DaikinCloudDevice
|
|
433
|
-
├─ Detect capabilities
|
|
434
|
-
├─ AccessoryFactory.create()
|
|
435
|
-
├─ Register with platform
|
|
436
|
-
└─ Setup services and characteristics
|
|
437
|
-
↓
|
|
438
|
-
9. Start polling interval (Developer Portal)
|
|
439
|
-
OR
|
|
440
|
-
Connect WebSocket (Mobile App)
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
### State Update Flow (Polling)
|
|
444
|
-
|
|
445
|
-
```
|
|
446
|
-
1. setInterval fires (every N minutes)
|
|
447
|
-
↓
|
|
448
|
-
2. Platform.updateDevices()
|
|
449
|
-
↓
|
|
450
|
-
3. Controller.updateAllDeviceData()
|
|
451
|
-
↓
|
|
452
|
-
4. API GET /v1/gateway-devices
|
|
453
|
-
↓
|
|
454
|
-
5. For each device:
|
|
455
|
-
├─ device.updateData(apiResponse)
|
|
456
|
-
├─ Service reads new values
|
|
457
|
-
└─ HAP pushes to HomeKit
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
### State Update Flow (WebSocket)
|
|
461
|
-
|
|
462
|
-
```
|
|
463
|
-
1. User changes setting on physical remote
|
|
464
|
-
↓
|
|
465
|
-
2. Daikin device sends update to cloud
|
|
466
|
-
↓
|
|
467
|
-
3. Cloud pushes WebSocket message
|
|
468
|
-
↓
|
|
469
|
-
4. Plugin WebSocket client receives message
|
|
470
|
-
↓
|
|
471
|
-
5. Parse and validate message
|
|
472
|
-
↓
|
|
473
|
-
6. Emit 'websocket_device_update' event
|
|
474
|
-
↓
|
|
475
|
-
7. Platform.handleWebSocketDeviceUpdate()
|
|
476
|
-
↓
|
|
477
|
-
8. UpdateMapper.applyUpdate()
|
|
478
|
-
↓
|
|
479
|
-
9. Service.updateCharacteristic()
|
|
480
|
-
↓
|
|
481
|
-
10. HomeKit reflects new state instantly
|
|
482
|
-
```
|
|
483
|
-
|
|
484
|
-
### User Control Flow
|
|
485
|
-
|
|
486
|
-
```
|
|
487
|
-
1. User adjusts temp in Home app
|
|
488
|
-
↓
|
|
489
|
-
2. HAP SET request
|
|
490
|
-
↓
|
|
491
|
-
3. Service.handleSet()
|
|
492
|
-
↓
|
|
493
|
-
4. Validate value
|
|
494
|
-
↓
|
|
495
|
-
5. Controller.setDeviceData()
|
|
496
|
-
↓
|
|
497
|
-
6. API PATCH /v1/gateway-devices/{id}
|
|
498
|
-
↓
|
|
499
|
-
7. Daikin Cloud processes request
|
|
500
|
-
↓
|
|
501
|
-
8. Physical device updates
|
|
502
|
-
↓
|
|
503
|
-
9. (After 60s delay)
|
|
504
|
-
├─ Force update
|
|
505
|
-
└─ Refresh state from API
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
## Configuration Schema
|
|
509
|
-
|
|
510
|
-
```json
|
|
511
|
-
{
|
|
512
|
-
"platform": "DaikinCloud",
|
|
513
|
-
"authMode": "mobile_app",
|
|
514
|
-
|
|
515
|
-
// Mobile App credentials
|
|
516
|
-
"daikinEmail": "user@example.com",
|
|
517
|
-
"daikinPassword": "password",
|
|
518
|
-
|
|
519
|
-
// Developer Portal credentials
|
|
520
|
-
"clientId": "abc123",
|
|
521
|
-
"clientSecret": "xyz789",
|
|
522
|
-
"callbackServerExternalAddress": "192.168.1.100",
|
|
523
|
-
"callbackServerPort": 8582,
|
|
524
|
-
"oidcCallbackServerBindAddr": "0.0.0.0",
|
|
525
|
-
|
|
526
|
-
// Update settings
|
|
527
|
-
"updateIntervalInMinutes": 15,
|
|
528
|
-
"forceUpdateDelay": 60000,
|
|
529
|
-
"enableWebSocket": true,
|
|
530
|
-
|
|
531
|
-
// Device exclusions
|
|
532
|
-
"excludedDevicesByDeviceId": ["device-id-1"],
|
|
533
|
-
|
|
534
|
-
// Feature toggles
|
|
535
|
-
"showPowerfulMode": true,
|
|
536
|
-
"showEconoMode": true,
|
|
537
|
-
"showStreamerMode": false,
|
|
538
|
-
"showOutdoorSilentMode": false,
|
|
539
|
-
"showIndoorSilentMode": false,
|
|
540
|
-
"showDryMode": false,
|
|
541
|
-
"showFanOnlyMode": false
|
|
542
|
-
}
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
## Security Considerations
|
|
546
|
-
|
|
547
|
-
1. **Token Storage**: Tokens saved with mode 0o600 (owner read/write only)
|
|
548
|
-
2. **Credential Logging**: Passwords and secrets masked in logs
|
|
549
|
-
3. **HTTPS**: All API communication over TLS
|
|
550
|
-
4. **Rate Limiting**: Proactive rate limit management prevents API lockout
|
|
551
|
-
5. **Input Validation**: Zod schemas validate all configuration input
|
|
552
|
-
|
|
553
|
-
## Performance Optimizations
|
|
554
|
-
|
|
555
|
-
1. **WebSocket vs Polling**: Real-time updates reduce API calls from ~96/day to ~10/day
|
|
556
|
-
2. **Update Mapper**: Centralized logic reduces code duplication and improves maintainability
|
|
557
|
-
3. **Force Update Delay**: 60s delay after user changes prevents rapid polling
|
|
558
|
-
4. **Capability Caching**: Device capabilities detected once at startup
|
|
559
|
-
5. **Exponential Backoff**: Failed requests don't overwhelm API
|
|
560
|
-
|
|
561
|
-
## Testing Strategy
|
|
562
|
-
|
|
563
|
-
### Unit Tests
|
|
564
|
-
- API client mocking
|
|
565
|
-
- Service characteristic handling
|
|
566
|
-
- Feature state management
|
|
567
|
-
- Config validation
|
|
568
|
-
|
|
569
|
-
### Integration Tests
|
|
570
|
-
- OAuth flows (Developer Portal + Mobile App)
|
|
571
|
-
- WebSocket connection/reconnection
|
|
572
|
-
- Device discovery and sync
|
|
573
|
-
- Full platform lifecycle
|
|
574
|
-
|
|
575
|
-
### Test Fixtures
|
|
576
|
-
Located in [test/fixtures/](test/fixtures/):
|
|
577
|
-
- Real device API responses
|
|
578
|
-
- Various device types (AC, Altherma, Heat Pump)
|
|
579
|
-
- Edge cases (unknown devices, missing data)
|
|
580
|
-
|
|
581
|
-
## Extending the Plugin
|
|
582
|
-
|
|
583
|
-
### Adding a New Device Type
|
|
584
|
-
|
|
585
|
-
1. Create device profile in [src/device/profiles/](src/device/profiles/)
|
|
586
|
-
2. Update capability detector for new characteristics
|
|
587
|
-
3. Create accessory class extending BaseAccessory
|
|
588
|
-
4. Register in AccessoryFactory
|
|
589
|
-
5. Add integration tests with fixture data
|
|
590
|
-
|
|
591
|
-
### Adding a New Authentication Method
|
|
592
|
-
|
|
593
|
-
1. Implement OAuthProvider interface
|
|
594
|
-
2. Add token management logic
|
|
595
|
-
3. Update DaikinControllerConfig type
|
|
596
|
-
4. Add configuration validation
|
|
597
|
-
5. Update platform initialization logic
|
|
598
|
-
|
|
599
|
-
### Adding a New API Endpoint
|
|
600
|
-
|
|
601
|
-
1. Add method to DaikinApi class
|
|
602
|
-
2. Define TypeScript types for request/response
|
|
603
|
-
3. Add Zod validation schema
|
|
604
|
-
4. Implement error handling
|
|
605
|
-
5. Add unit tests with mocked responses
|
|
606
|
-
|
|
607
|
-
## Troubleshooting
|
|
608
|
-
|
|
609
|
-
### Common Issues
|
|
610
|
-
|
|
611
|
-
1. **Token Expired**: Delete token file and re-authenticate
|
|
612
|
-
2. **Rate Limit Exceeded**: Increase polling interval or use Mobile App mode
|
|
613
|
-
3. **WebSocket Disconnects**: Check logs for reconnection attempts; firewall may block
|
|
614
|
-
4. **Device Not Found**: Verify device in Onecta app; check exclusion list
|
|
615
|
-
|
|
616
|
-
### Debug Logging
|
|
617
|
-
|
|
618
|
-
Enable debug mode:
|
|
619
|
-
```bash
|
|
620
|
-
homebridge -D
|
|
621
|
-
```
|
|
622
|
-
|
|
623
|
-
Look for log prefixes:
|
|
624
|
-
- `[Platform]`: Platform lifecycle
|
|
625
|
-
- `[OAuth]`: Authentication
|
|
626
|
-
- `[API]`: API requests/responses
|
|
627
|
-
- `[WebSocket]`: WebSocket events
|
|
628
|
-
- `[UpdateMapper]`: State updates
|
|
629
|
-
- `[Service]`: HAP service operations
|
|
630
|
-
|
|
631
|
-
## Future Enhancements
|
|
632
|
-
|
|
633
|
-
1. **Differential Updates**: Only sync changed devices
|
|
634
|
-
2. **Status UI**: Dashboard showing API usage, connection health
|
|
635
|
-
3. **Device-Level Error Tracking**: Per-device error states
|
|
636
|
-
4. **Advanced Scheduling**: HomeKit automation integration
|
|
637
|
-
5. **Multi-Language Support**: Internationalized device names
|
|
638
|
-
6. **Performance Profiling**: Memory leak detection, optimization
|
|
639
|
-
|
|
640
|
-
## References
|
|
641
|
-
|
|
642
|
-
- [Homebridge Plugin Development](https://developers.homebridge.io/)
|
|
643
|
-
- [HAP-nodejs Documentation](https://github.com/homebridge/HAP-NodeJS)
|
|
644
|
-
- [Daikin Developer Portal](https://developer.cloud.daikineurope.com/)
|
|
645
|
-
- [Onecta App Information](https://www.daikin.eu/en_us/product-group/control-systems/onecta.html)
|