@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.
Files changed (234) hide show
  1. package/LICENSE +39 -1
  2. package/README.md +5 -3
  3. package/dist/src/accessories/air-conditioning-accessory.d.ts +2 -2
  4. package/dist/src/accessories/air-conditioning-accessory.d.ts.map +1 -1
  5. package/dist/src/accessories/air-conditioning-accessory.js.map +1 -1
  6. package/dist/src/accessories/altherma-accessory.d.ts +2 -2
  7. package/dist/src/accessories/altherma-accessory.d.ts.map +1 -1
  8. package/dist/src/accessories/altherma-accessory.js.map +1 -1
  9. package/dist/src/accessories/base-accessory.d.ts +6 -6
  10. package/dist/src/accessories/base-accessory.d.ts.map +1 -1
  11. package/dist/src/accessories/base-accessory.js +15 -15
  12. package/dist/src/accessories/base-accessory.js.map +1 -1
  13. package/dist/src/api/daikin-api.d.ts +26 -26
  14. package/dist/src/api/daikin-api.d.ts.map +1 -1
  15. package/dist/src/api/daikin-api.js +68 -42
  16. package/dist/src/api/daikin-api.js.map +1 -1
  17. package/dist/src/api/daikin-cloud.repository.d.ts.map +1 -1
  18. package/dist/src/api/daikin-cloud.repository.js +22 -14
  19. package/dist/src/api/daikin-cloud.repository.js.map +1 -1
  20. package/dist/src/api/daikin-controller.d.ts +41 -47
  21. package/dist/src/api/daikin-controller.d.ts.map +1 -1
  22. package/dist/src/api/daikin-controller.js +40 -64
  23. package/dist/src/api/daikin-controller.js.map +1 -1
  24. package/dist/src/api/daikin-device.d.ts +36 -31
  25. package/dist/src/api/daikin-device.d.ts.map +1 -1
  26. package/dist/src/api/daikin-device.js +45 -31
  27. package/dist/src/api/daikin-device.js.map +1 -1
  28. package/dist/src/api/daikin-mobile-oauth.d.ts +20 -20
  29. package/dist/src/api/daikin-mobile-oauth.d.ts.map +1 -1
  30. package/dist/src/api/daikin-mobile-oauth.js +49 -44
  31. package/dist/src/api/daikin-mobile-oauth.js.map +1 -1
  32. package/dist/src/api/daikin-oauth.d.ts +32 -32
  33. package/dist/src/api/daikin-oauth.d.ts.map +1 -1
  34. package/dist/src/api/daikin-oauth.js +64 -56
  35. package/dist/src/api/daikin-oauth.js.map +1 -1
  36. package/dist/src/api/daikin-schemas.d.ts +476 -351
  37. package/dist/src/api/daikin-schemas.d.ts.map +1 -1
  38. package/dist/src/api/daikin-schemas.js +11 -42
  39. package/dist/src/api/daikin-schemas.js.map +1 -1
  40. package/dist/src/api/daikin-types.d.ts +5 -1
  41. package/dist/src/api/daikin-types.d.ts.map +1 -1
  42. package/dist/src/api/daikin-types.js.map +1 -1
  43. package/dist/src/api/daikin-websocket.d.ts +31 -32
  44. package/dist/src/api/daikin-websocket.d.ts.map +1 -1
  45. package/dist/src/api/daikin-websocket.js +55 -35
  46. package/dist/src/api/daikin-websocket.js.map +1 -1
  47. package/dist/src/api/index.d.ts +2 -1
  48. package/dist/src/api/index.d.ts.map +1 -1
  49. package/dist/src/api/index.js +3 -1
  50. package/dist/src/api/index.js.map +1 -1
  51. package/dist/src/api/token-storage.d.ts +21 -0
  52. package/dist/src/api/token-storage.d.ts.map +1 -0
  53. package/dist/src/api/token-storage.js +90 -0
  54. package/dist/src/api/token-storage.js.map +1 -0
  55. package/dist/src/config/config-manager.d.ts +33 -33
  56. package/dist/src/config/config-manager.d.ts.map +1 -1
  57. package/dist/src/config/config-manager.js +33 -33
  58. package/dist/src/config/config-manager.js.map +1 -1
  59. package/dist/src/constants/api.constants.d.ts +4 -0
  60. package/dist/src/constants/api.constants.d.ts.map +1 -1
  61. package/dist/src/constants/api.constants.js +5 -1
  62. package/dist/src/constants/api.constants.js.map +1 -1
  63. package/dist/src/constants/device.constants.d.ts +4 -0
  64. package/dist/src/constants/device.constants.d.ts.map +1 -1
  65. package/dist/src/constants/device.constants.js +5 -1
  66. package/dist/src/constants/device.constants.js.map +1 -1
  67. package/dist/src/device/accessory-factory.d.ts +10 -10
  68. package/dist/src/device/accessory-factory.d.ts.map +1 -1
  69. package/dist/src/device/accessory-factory.js +7 -7
  70. package/dist/src/device/accessory-factory.js.map +1 -1
  71. package/dist/src/device/capability-detector.d.ts +8 -8
  72. package/dist/src/device/capability-detector.d.ts.map +1 -1
  73. package/dist/src/device/capability-detector.js +6 -6
  74. package/dist/src/device/capability-detector.js.map +1 -1
  75. package/dist/src/device/capability-docs.d.ts +1 -9
  76. package/dist/src/device/capability-docs.d.ts.map +1 -1
  77. package/dist/src/device/capability-docs.js +19 -73
  78. package/dist/src/device/capability-docs.js.map +1 -1
  79. package/dist/src/device/profiles/device-profile.d.ts +1 -1
  80. package/dist/src/device/profiles/device-profile.d.ts.map +1 -1
  81. package/dist/src/device/profiles/device-profile.js +4 -4
  82. package/dist/src/device/profiles/device-profile.js.map +1 -1
  83. package/dist/src/features/base-feature.d.ts +2 -2
  84. package/dist/src/features/base-feature.d.ts.map +1 -1
  85. package/dist/src/features/base-feature.js +2 -3
  86. package/dist/src/features/base-feature.js.map +1 -1
  87. package/dist/src/features/feature-manager.d.ts +8 -16
  88. package/dist/src/features/feature-manager.d.ts.map +1 -1
  89. package/dist/src/features/feature-manager.js +5 -17
  90. package/dist/src/features/feature-manager.js.map +1 -1
  91. package/dist/src/features/modes/dry-operation-mode.feature.d.ts +1 -1
  92. package/dist/src/features/modes/dry-operation-mode.feature.d.ts.map +1 -1
  93. package/dist/src/features/modes/dry-operation-mode.feature.js.map +1 -1
  94. package/dist/src/features/modes/econo-mode.feature.d.ts +1 -1
  95. package/dist/src/features/modes/econo-mode.feature.d.ts.map +1 -1
  96. package/dist/src/features/modes/econo-mode.feature.js.map +1 -1
  97. package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts +1 -1
  98. package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts.map +1 -1
  99. package/dist/src/features/modes/fan-only-operation-mode.feature.js.map +1 -1
  100. package/dist/src/features/modes/indoor-silent-mode.feature.d.ts +1 -1
  101. package/dist/src/features/modes/indoor-silent-mode.feature.d.ts.map +1 -1
  102. package/dist/src/features/modes/indoor-silent-mode.feature.js.map +1 -1
  103. package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts +1 -1
  104. package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts.map +1 -1
  105. package/dist/src/features/modes/outdoor-silent-mode.feature.js.map +1 -1
  106. package/dist/src/features/modes/powerful-mode.feature.d.ts +1 -1
  107. package/dist/src/features/modes/powerful-mode.feature.d.ts.map +1 -1
  108. package/dist/src/features/modes/powerful-mode.feature.js.map +1 -1
  109. package/dist/src/features/modes/streamer-mode.feature.d.ts +1 -1
  110. package/dist/src/features/modes/streamer-mode.feature.d.ts.map +1 -1
  111. package/dist/src/features/modes/streamer-mode.feature.js.map +1 -1
  112. package/dist/src/index.d.ts +1 -1
  113. package/dist/src/index.d.ts.map +1 -1
  114. package/dist/src/index.js.map +1 -1
  115. package/dist/src/platform.d.ts +11 -8
  116. package/dist/src/platform.d.ts.map +1 -1
  117. package/dist/src/platform.js +64 -15
  118. package/dist/src/platform.js.map +1 -1
  119. package/dist/src/services/climate-control.service.d.ts +8 -2
  120. package/dist/src/services/climate-control.service.d.ts.map +1 -1
  121. package/dist/src/services/climate-control.service.js +59 -58
  122. package/dist/src/services/climate-control.service.js.map +1 -1
  123. package/dist/src/services/hot-water-tank.service.d.ts +6 -2
  124. package/dist/src/services/hot-water-tank.service.d.ts.map +1 -1
  125. package/dist/src/services/hot-water-tank.service.js +33 -31
  126. package/dist/src/services/hot-water-tank.service.js.map +1 -1
  127. package/dist/src/types/daikin-enums.js +12 -12
  128. package/dist/src/types/daikin-enums.js.map +1 -1
  129. package/dist/src/types/device-capabilities.d.ts +1 -1
  130. package/dist/src/types/device-capabilities.d.ts.map +1 -1
  131. package/dist/src/utils/log-context.d.ts +23 -23
  132. package/dist/src/utils/log-context.d.ts.map +1 -1
  133. package/dist/src/utils/log-context.js +28 -28
  134. package/dist/src/utils/log-context.js.map +1 -1
  135. package/dist/src/utils/strings.d.ts.map +1 -1
  136. package/dist/src/utils/strings.js.map +1 -1
  137. package/dist/src/utils/update-mapper.d.ts +16 -16
  138. package/dist/src/utils/update-mapper.d.ts.map +1 -1
  139. package/dist/src/utils/update-mapper.js +14 -14
  140. package/dist/src/utils/update-mapper.js.map +1 -1
  141. package/homebridge-ui/public/index.html +2 -2
  142. package/homebridge-ui/public/script.js +957 -898
  143. package/homebridge-ui/server.js +746 -678
  144. package/package.json +29 -27
  145. package/.claude/settings.json +0 -3
  146. package/.claude/settings.local.json +0 -29
  147. package/CHANGELOG.md +0 -103
  148. package/CLAUDE.md +0 -269
  149. package/config.md +0 -2
  150. package/dist/src/api/daikin-device-tracker.d.ts +0 -97
  151. package/dist/src/api/daikin-device-tracker.d.ts.map +0 -1
  152. package/dist/src/api/daikin-device-tracker.js +0 -136
  153. package/dist/src/api/daikin-device-tracker.js.map +0 -1
  154. package/dist/src/api/http-interceptor.d.ts +0 -99
  155. package/dist/src/api/http-interceptor.d.ts.map +0 -1
  156. package/dist/src/api/http-interceptor.js +0 -177
  157. package/dist/src/api/http-interceptor.js.map +0 -1
  158. package/dist/src/di/service-container.d.ts +0 -92
  159. package/dist/src/di/service-container.d.ts.map +0 -1
  160. package/dist/src/di/service-container.js +0 -156
  161. package/dist/src/di/service-container.js.map +0 -1
  162. package/dist/src/features/feature-registry.d.ts +0 -100
  163. package/dist/src/features/feature-registry.d.ts.map +0 -1
  164. package/dist/src/features/feature-registry.js +0 -142
  165. package/dist/src/features/feature-registry.js.map +0 -1
  166. package/dist/src/services/service-factory.d.ts +0 -46
  167. package/dist/src/services/service-factory.d.ts.map +0 -1
  168. package/dist/src/services/service-factory.js +0 -72
  169. package/dist/src/services/service-factory.js.map +0 -1
  170. package/dist/src/utils/error-handler.d.ts +0 -101
  171. package/dist/src/utils/error-handler.d.ts.map +0 -1
  172. package/dist/src/utils/error-handler.js +0 -251
  173. package/dist/src/utils/error-handler.js.map +0 -1
  174. package/dist/src/utils/retry.d.ts +0 -42
  175. package/dist/src/utils/retry.d.ts.map +0 -1
  176. package/dist/src/utils/retry.js +0 -70
  177. package/dist/src/utils/retry.js.map +0 -1
  178. package/docs/ARCHITECTURE.md +0 -645
  179. package/docs/IMPLEMENTATION_GUIDE.md +0 -899
  180. package/docs/IMPROVEMENTS_SUMMARY.md +0 -415
  181. package/docs/NEXT_STEPS.md +0 -368
  182. package/docs/Screenshot 2024-07-04 at 18.41.28.png +0 -0
  183. package/docs/TROUBLESHOOTING.md +0 -475
  184. package/docs/api-response-for-BRP069A8x.json +0 -520
  185. package/docs/api-response-for-BRP069C4x-2.json +0 -881
  186. package/docs/api-response-for-BRP069C4x.json +0 -916
  187. package/docs/api-response-for-altherma.json +0 -759
  188. package/docs/api-response-for-altherma2.json +0 -2735
  189. package/docs/api-response-with-multiple-devices-incl-heatpump.json +0 -2544
  190. package/docs/cr-insance-altherma-id-0.json +0 -834
  191. package/docs/mock-air-to-air-dx23.json +0 -759
  192. package/docs/mock-air-to-air-dx4.json +0 -1134
  193. package/docs/mock-airpurifier-with-humidifier.json +0 -732
  194. package/docs/mock-airpurifier.json +0 -450
  195. package/docs/mock-altherma-air-to-water-lan.json +0 -845
  196. package/docs/mock-altherma-air-to-water-wlan.json +0 -845
  197. package/docs/mock-d2cnd-gas-boiler.json +0 -649
  198. package/docs/setpointmode-vs-controlmode-vs-setpoints-vs-sensorydata.txt +0 -6
  199. package/images/fan-speed.jpeg +0 -0
  200. package/images/homekit-controls.jpeg +0 -0
  201. package/images/homekit-settings.jpeg +0 -0
  202. package/images/swing-mode.png +0 -0
  203. package/jest.config.ts +0 -13
  204. package/test/fixtures/altherma-crSense-2.ts +0 -834
  205. package/test/fixtures/altherma-fraction.ts +0 -718
  206. package/test/fixtures/altherma-heat-pump-2.ts +0 -479
  207. package/test/fixtures/altherma-heat-pump.ts +0 -757
  208. package/test/fixtures/altherma-miladcerkic-off.ts +0 -524
  209. package/test/fixtures/altherma-miladcerkic.ts +0 -524
  210. package/test/fixtures/altherma-v1ckoeln.ts +0 -644
  211. package/test/fixtures/altherma-with-embedded-id-zero.ts +0 -834
  212. package/test/fixtures/dx23-airco-2.ts +0 -343
  213. package/test/fixtures/dx23-airco.ts +0 -518
  214. package/test/fixtures/dx4-airco.ts +0 -914
  215. package/test/fixtures/unknown-jan.ts +0 -488
  216. package/test/fixtures/unknown-kitchen-guests.ts +0 -488
  217. package/test/helpers/test-isolation.ts +0 -228
  218. package/test/integration/air-conditioning.test.ts +0 -410
  219. package/test/integration/altherma.test.ts +0 -289
  220. package/test/integration/platform.test.ts +0 -118
  221. package/test/mocks/index.ts +0 -27
  222. package/test/test-gigya-auth.js +0 -443
  223. package/test/test-mobile-oauth.js +0 -175
  224. package/test/test-websocket-mobile.js +0 -123
  225. package/test/test-websocket.js +0 -116
  226. package/test/unit/api/__snapshots__/daikinCloud.test.ts.snap +0 -1320
  227. package/test/unit/api/daikin-api.test.ts +0 -384
  228. package/test/unit/api/daikin-oauth.test.ts +0 -214
  229. package/test/unit/api/daikinCloud.test.ts +0 -12
  230. package/test/unit/config/config-manager.test.ts +0 -271
  231. package/test/unit/device/daikin-device.test.ts +0 -79
  232. package/test/unit/services/hot-water-tank.service.test.ts +0 -123
  233. package/test/unit/utils/error-handler.test.ts +0 -274
  234. package/test/unit/utils/log-context.test.ts +0 -271
@@ -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)