@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,271 +0,0 @@
1
- /**
2
- * ConfigManager Tests
3
- */
4
-
5
- import {ConfigManager, PluginConfig} from '../../../src/config/config-manager';
6
-
7
- describe('ConfigManager', () => {
8
- describe('getAuthMode', () => {
9
- it('should return mobile_app when configured', () => {
10
- const config: PluginConfig = {
11
- platform: 'DaikinCloud',
12
- authMode: 'mobile_app',
13
- };
14
- const manager = new ConfigManager(config);
15
- expect(manager.getAuthMode()).toBe('mobile_app');
16
- });
17
-
18
- it('should default to developer_portal when not specified', () => {
19
- const config: PluginConfig = {
20
- platform: 'DaikinCloud',
21
- };
22
- const manager = new ConfigManager(config);
23
- expect(manager.getAuthMode()).toBe('developer_portal');
24
- });
25
- });
26
-
27
- describe('getDeveloperCredentials', () => {
28
- it('should return credentials when all fields present', () => {
29
- const config: PluginConfig = {
30
- platform: 'DaikinCloud',
31
- clientId: 'test-id',
32
- clientSecret: 'test-secret',
33
- callbackServerExternalAddress: 'example.com',
34
- callbackServerPort: 8582,
35
- };
36
- const manager = new ConfigManager(config);
37
- const creds = manager.getDeveloperCredentials();
38
-
39
- expect(creds).not.toBeNull();
40
- expect(creds?.clientId).toBe('test-id');
41
- expect(creds?.clientSecret).toBe('test-secret');
42
- expect(creds?.callbackServerExternalAddress).toBe('example.com');
43
- expect(creds?.callbackServerPort).toBe(8582);
44
- });
45
-
46
- it('should return null when fields missing', () => {
47
- const config: PluginConfig = {
48
- platform: 'DaikinCloud',
49
- clientId: 'test-id',
50
- };
51
- const manager = new ConfigManager(config);
52
- expect(manager.getDeveloperCredentials()).toBeNull();
53
- });
54
- });
55
-
56
- describe('getMobileCredentials', () => {
57
- it('should return credentials when present', () => {
58
- const config: PluginConfig = {
59
- platform: 'DaikinCloud',
60
- daikinEmail: 'test@example.com',
61
- daikinPassword: 'password123',
62
- };
63
- const manager = new ConfigManager(config);
64
- const creds = manager.getMobileCredentials();
65
-
66
- expect(creds).not.toBeNull();
67
- expect(creds?.email).toBe('test@example.com');
68
- expect(creds?.password).toBe('password123');
69
- });
70
-
71
- it('should return null when fields missing', () => {
72
- const config: PluginConfig = {
73
- platform: 'DaikinCloud',
74
- daikinEmail: 'test@example.com',
75
- };
76
- const manager = new ConfigManager(config);
77
- expect(manager.getMobileCredentials()).toBeNull();
78
- });
79
- });
80
-
81
- describe('validate', () => {
82
- it('should pass validation for valid developer portal config', () => {
83
- const config: PluginConfig = {
84
- platform: 'DaikinCloud',
85
- authMode: 'developer_portal',
86
- clientId: 'test-id',
87
- clientSecret: 'test-secret',
88
- callbackServerExternalAddress: '192.168.1.100',
89
- callbackServerPort: 8582,
90
- };
91
- const manager = new ConfigManager(config);
92
- const result = manager.validate();
93
-
94
- expect(result.valid).toBe(true);
95
- expect(result.errors).toHaveLength(0);
96
- });
97
-
98
- it('should fail validation for developer portal without clientId', () => {
99
- const config: PluginConfig = {
100
- platform: 'DaikinCloud',
101
- authMode: 'developer_portal',
102
- clientSecret: 'test-secret',
103
- callbackServerExternalAddress: '192.168.1.100',
104
- };
105
- const manager = new ConfigManager(config);
106
- const result = manager.validate();
107
-
108
- expect(result.valid).toBe(false);
109
- expect(result.errors).toContain('Client ID is required for Developer Portal mode');
110
- });
111
-
112
- it('should fail validation for localhost callback address', () => {
113
- const config: PluginConfig = {
114
- platform: 'DaikinCloud',
115
- authMode: 'developer_portal',
116
- clientId: 'test-id',
117
- clientSecret: 'test-secret',
118
- callbackServerExternalAddress: 'localhost',
119
- };
120
- const manager = new ConfigManager(config);
121
- const result = manager.validate();
122
-
123
- expect(result.valid).toBe(false);
124
- expect(result.errors).toContain('Callback address cannot be localhost. Use your external IP or domain.');
125
- });
126
-
127
- it('should fail validation for invalid port', () => {
128
- const config: PluginConfig = {
129
- platform: 'DaikinCloud',
130
- authMode: 'developer_portal',
131
- clientId: 'test-id',
132
- clientSecret: 'test-secret',
133
- callbackServerExternalAddress: '192.168.1.100',
134
- callbackServerPort: 99999,
135
- };
136
- const manager = new ConfigManager(config);
137
- const result = manager.validate();
138
-
139
- expect(result.valid).toBe(false);
140
- expect(result.errors.length).toBeGreaterThan(0);
141
- expect(result.errors.some(e => e.includes('port'))).toBe(true);
142
- });
143
-
144
- it('should warn about privileged port', () => {
145
- const config: PluginConfig = {
146
- platform: 'DaikinCloud',
147
- authMode: 'developer_portal',
148
- clientId: 'test-id',
149
- clientSecret: 'test-secret',
150
- callbackServerExternalAddress: '192.168.1.100',
151
- callbackServerPort: 443,
152
- };
153
- const manager = new ConfigManager(config);
154
- const result = manager.validate();
155
-
156
- expect(result.valid).toBe(true);
157
- expect(result.warnings).toContain('Port 443 is privileged (< 1024) and may require root permissions.');
158
- });
159
-
160
- it('should pass validation for valid mobile app config', () => {
161
- const config: PluginConfig = {
162
- platform: 'DaikinCloud',
163
- authMode: 'mobile_app',
164
- daikinEmail: 'test@example.com',
165
- daikinPassword: 'password123',
166
- };
167
- const manager = new ConfigManager(config);
168
- const result = manager.validate();
169
-
170
- expect(result.valid).toBe(true);
171
- expect(result.errors).toHaveLength(0);
172
- });
173
-
174
- it('should fail validation for mobile app without email', () => {
175
- const config: PluginConfig = {
176
- platform: 'DaikinCloud',
177
- authMode: 'mobile_app',
178
- daikinPassword: 'password123',
179
- };
180
- const manager = new ConfigManager(config);
181
- const result = manager.validate();
182
-
183
- expect(result.valid).toBe(false);
184
- expect(result.errors).toContain('Email is required for Mobile App mode');
185
- });
186
-
187
- it('should warn about low update interval for developer portal', () => {
188
- const config: PluginConfig = {
189
- platform: 'DaikinCloud',
190
- authMode: 'developer_portal',
191
- clientId: 'test-id',
192
- clientSecret: 'test-secret',
193
- callbackServerExternalAddress: '192.168.1.100',
194
- updateIntervalInMinutes: 5,
195
- };
196
- const manager = new ConfigManager(config);
197
- const result = manager.validate();
198
-
199
- expect(result.valid).toBe(true);
200
- expect(result.warnings.some(w => w.includes('rate limit'))).toBe(true);
201
- });
202
- });
203
-
204
- describe('getUpdateIntervalMs', () => {
205
- it('should return configured interval in milliseconds', () => {
206
- const config: PluginConfig = {
207
- platform: 'DaikinCloud',
208
- updateIntervalInMinutes: 30,
209
- };
210
- const manager = new ConfigManager(config);
211
- expect(manager.getUpdateIntervalMs()).toBe(30 * 60 * 1000);
212
- });
213
-
214
- it('should return default interval when not configured', () => {
215
- const config: PluginConfig = {
216
- platform: 'DaikinCloud',
217
- };
218
- const manager = new ConfigManager(config);
219
- expect(manager.getUpdateIntervalMs()).toBe(15 * 60 * 1000);
220
- });
221
- });
222
-
223
- describe('isDeviceExcluded', () => {
224
- it('should return true for excluded device', () => {
225
- const config: PluginConfig = {
226
- platform: 'DaikinCloud',
227
- excludedDevicesByDeviceId: ['device1', 'device2'],
228
- };
229
- const manager = new ConfigManager(config);
230
- expect(manager.isDeviceExcluded('device1')).toBe(true);
231
- });
232
-
233
- it('should return false for non-excluded device', () => {
234
- const config: PluginConfig = {
235
- platform: 'DaikinCloud',
236
- excludedDevicesByDeviceId: ['device1', 'device2'],
237
- };
238
- const manager = new ConfigManager(config);
239
- expect(manager.isDeviceExcluded('device3')).toBe(false);
240
- });
241
- });
242
-
243
- describe('getFeatures', () => {
244
- it('should return feature configuration', () => {
245
- const config: PluginConfig = {
246
- platform: 'DaikinCloud',
247
- showPowerfulMode: true,
248
- showEconoMode: false,
249
- };
250
- const manager = new ConfigManager(config);
251
- const features = manager.getFeatures();
252
-
253
- expect(features.powerfulMode).toBe(true);
254
- expect(features.econoMode).toBe(false);
255
- });
256
-
257
- it('should use legacy showExtraFeatures when present', () => {
258
- const config: PluginConfig = {
259
- platform: 'DaikinCloud',
260
- showExtraFeatures: true,
261
- };
262
- const manager = new ConfigManager(config);
263
- const features = manager.getFeatures();
264
-
265
- // All features should be true when legacy flag is set
266
- expect(features.powerfulMode).toBe(true);
267
- expect(features.econoMode).toBe(true);
268
- expect(features.streamerMode).toBe(true);
269
- });
270
- });
271
- });
@@ -1,79 +0,0 @@
1
- import {PlatformAccessory} from 'homebridge/lib/platformAccessory';
2
- import {DaikinCloudDevice, DaikinApi} from '../../../src/api';
3
- import {dx4Airco} from '../../fixtures/dx4-airco';
4
- import {althermaHeatPump} from '../../fixtures/altherma-heat-pump';
5
-
6
- const mockApi = { updateDevice: jest.fn().mockResolvedValue(undefined) } as unknown as DaikinApi;
7
-
8
- it('Get deviceModel from device %s', async () => {
9
- const accessory = new PlatformAccessory('NAME', 'efd08509-2edb-41d0-a9ab-ce913323d811');
10
- accessory.context.device = new DaikinCloudDevice(dx4Airco as any, mockApi);
11
- expect(accessory.context.device.getDescription().deviceModel).toEqual('dx4');
12
- });
13
-
14
- it('Get name from device %s', async () => {
15
- const accessory = new PlatformAccessory('NAME', 'efd08509-2edb-41d0-a9ab-ce913323d811');
16
- accessory.context.device = new DaikinCloudDevice(dx4Airco as any, mockApi);
17
- expect(accessory.context.device.getData('climateControl', 'name', undefined).value).toEqual('Zolder');
18
- });
19
-
20
- it('Get name from device %s', async () => {
21
- const accessory = new PlatformAccessory('NAME', 'efd08509-2edb-41d0-a9ab-ce913323d811');
22
- accessory.context.device = new DaikinCloudDevice(althermaHeatPump as any, mockApi);
23
- expect(accessory.context.device.getData('climateControlMainZone', 'name', undefined).value).toEqual('Altherma');
24
- });
25
-
26
- it('Get tankTemperature from device domesticHotWaterTank', async () => {
27
- const accessory = new PlatformAccessory('NAME', 'efd08509-2edb-41d0-a9ab-ce913323d811');
28
- accessory.context.device = new DaikinCloudDevice(althermaHeatPump as any, mockApi);
29
- expect(accessory.context.device.getData('domesticHotWaterTank', 'sensoryData', '/tankTemperature').value).toEqual(48);
30
- });
31
-
32
- it('Get roomTemperature from climateControl sensoryData', async () => {
33
- const device = new DaikinCloudDevice(dx4Airco as any, mockApi);
34
- const result = device.getData('climateControl', 'sensoryData', '/roomTemperature');
35
- expect(result.value).toEqual(25);
36
- });
37
-
38
- it('Debug: trace getData path for roomTemperature', () => {
39
- const device = new DaikinCloudDevice(dx4Airco as any, mockApi);
40
-
41
- // Check that management point is found
42
- const desc = device.desc;
43
- const mp = desc.managementPoints?.find((m: any) => m.embeddedId === 'climateControl');
44
- expect(mp).toBeDefined();
45
- expect(mp?.sensoryData).toBeDefined();
46
-
47
- // Check sensoryData structure
48
- const sensoryData = mp?.sensoryData;
49
- expect(sensoryData?.value?.roomTemperature?.value).toEqual(25);
50
-
51
- // Now test through getData
52
- const result = device.getData('climateControl', 'sensoryData', '/roomTemperature');
53
- console.log('getData result:', JSON.stringify(result, null, 2));
54
- expect(result.value).toEqual(25);
55
- });
56
-
57
- it('Integration: simulate full AC accessory temperature get', () => {
58
- const device = new DaikinCloudDevice(dx4Airco as any, mockApi);
59
-
60
- // Test the path that ClimateControlService uses
61
- const managementPointId = 'climateControl';
62
-
63
- // 1. getCurrentControlMode() checks controlMode first
64
- const controlModeResult = device.getData(managementPointId, 'controlMode', undefined);
65
- console.log('controlMode result:', JSON.stringify(controlModeResult, null, 2));
66
-
67
- // For AC devices, controlMode should not exist, so it defaults to 'roomTemperature'
68
- const controlMode = controlModeResult.value ? controlModeResult.value : 'roomTemperature';
69
- console.log('controlMode:', controlMode);
70
-
71
- // 2. handleCurrentTemperatureGet uses this path
72
- const path = '/' + controlMode;
73
- console.log('path:', path);
74
-
75
- const temperature = device.getData(managementPointId, 'sensoryData', path);
76
- console.log('temperature result:', JSON.stringify(temperature, null, 2));
77
-
78
- expect(temperature.value).toEqual(25);
79
- });
@@ -1,123 +0,0 @@
1
- import {HotWaterTankService} from '../../../src/services';
2
- import {DaikinCloudDevice, DaikinApi} from '../../../src/api';
3
- import {MockPlatformConfig} from '../../mocks';
4
- import {DaikinCloudAccessoryContext, DaikinCloudPlatform} from '../../../src/platform';
5
- import {PlatformAccessory} from 'homebridge/lib/platformAccessory';
6
- import {Characteristic, uuid} from 'hap-nodejs';
7
- import {althermaHeatPump} from '../../fixtures/altherma-heat-pump';
8
-
9
- import {HomebridgeAPI} from 'homebridge/lib/api.js';
10
- import {Logger} from 'homebridge/lib/logger.js';
11
-
12
- // Helper to get management point data from the device
13
- const getManagementPoint = (device: DaikinCloudDevice, embeddedId: string): any => {
14
- return (device as any).rawData.managementPoints.find((mp: any) => mp.embeddedId === embeddedId);
15
- };
16
-
17
- // Use fake timers to prevent tests from hanging due to setInterval/setTimeout in platform
18
- beforeEach(() => {
19
- jest.useFakeTimers();
20
- });
21
-
22
- afterEach(() => {
23
- jest.clearAllTimers();
24
- jest.useRealTimers();
25
- });
26
-
27
- describe('HotWaterTankService', () => {
28
- let accessory: PlatformAccessory<DaikinCloudAccessoryContext>;
29
- let service: HotWaterTankService;
30
-
31
- const EMBEDDED_ID = 'domesticHotWaterTank';
32
-
33
- beforeEach(() => {
34
- const mockApi = {} as DaikinApi;
35
- accessory = new PlatformAccessory<DaikinCloudAccessoryContext>('ACCESSORY_NAME', uuid.generate('ACCESSORY_UUID'));
36
- // Use a deep copy of the fixture to isolate test mutations
37
- accessory.context['device'] = new DaikinCloudDevice(JSON.parse(JSON.stringify(althermaHeatPump)) as any, mockApi);
38
- accessory.context.device.getLastUpdated = jest.fn().mockReturnValue(new Date(1987, 0, 19, 0, 0, 0, 0));
39
-
40
- const platform = new DaikinCloudPlatform(new Logger(), new MockPlatformConfig(true), new HomebridgeAPI());
41
-
42
- service = new HotWaterTankService(platform, accessory, EMBEDDED_ID);
43
- });
44
-
45
- it('should get the current heating cooling state', async () => {
46
- expect(await service.handleHotWaterTankCurrentHeatingCoolingStateGet()).toBe(Characteristic.CurrentHeatingCoolingState.HEAT);
47
-
48
- getManagementPoint(accessory.context.device, EMBEDDED_ID)['onOffMode'] = { value: 'off' };
49
-
50
- expect(await service.handleHotWaterTankTargetHeatingCoolingStateGet()).toBe(Characteristic.CurrentHeatingCoolingState.OFF);
51
- });
52
-
53
- it('should get the current temperature', async () => {
54
- expect(await service.handleHotWaterTankCurrentTemperatureGet()).toBe(48);
55
- });
56
-
57
- it('should get the target heating cooling temperature', async () => {
58
- expect(await service.handleHotWaterTankHeatingTargetTemperatureGet()).toBe(48);
59
- });
60
-
61
- it('should get the target heating cooling state', async () => {
62
- expect(await service.handleHotWaterTankTargetHeatingCoolingStateGet()).toBe(Characteristic.TargetHeatingCoolingState.HEAT);
63
-
64
- getManagementPoint(accessory.context.device, EMBEDDED_ID)['operationMode'] = {
65
- 'settable': true,
66
- 'values': [
67
- 'auto',
68
- 'dry',
69
- 'cooling',
70
- 'heating',
71
- 'fanOnly',
72
- ],
73
- 'value': 'cooling',
74
- };
75
- expect(await service.handleHotWaterTankTargetHeatingCoolingStateGet()).toBe(Characteristic.TargetHeatingCoolingState.COOL);
76
-
77
- getManagementPoint(accessory.context.device, EMBEDDED_ID)['operationMode'] = {
78
- 'settable': true,
79
- 'values': [
80
- 'auto',
81
- 'dry',
82
- 'cooling',
83
- 'heating',
84
- 'fanOnly',
85
- ],
86
- 'value': 'auto',
87
- };
88
- expect(await service.handleHotWaterTankTargetHeatingCoolingStateGet()).toBe(Characteristic.TargetHeatingCoolingState.AUTO);
89
-
90
- getManagementPoint(accessory.context.device, EMBEDDED_ID)['operationMode'] = {
91
- 'settable': true,
92
- 'values': [
93
- 'auto',
94
- 'dry',
95
- 'cooling',
96
- 'heating',
97
- 'fanOnly',
98
- ],
99
- 'value': 'fanOnly',
100
- };
101
- expect(await service.handleHotWaterTankTargetHeatingCoolingStateGet()).toBe(Characteristic.TargetHeatingCoolingState.AUTO);
102
-
103
- getManagementPoint(accessory.context.device, EMBEDDED_ID)['operationMode'] = {
104
- 'settable': true,
105
- 'values': [
106
- 'auto',
107
- 'dry',
108
- 'cooling',
109
- 'heating',
110
- 'fanOnly',
111
- ],
112
- 'value': 'dry',
113
- };
114
- expect(await service.handleHotWaterTankTargetHeatingCoolingStateGet()).toBe(Characteristic.TargetHeatingCoolingState.AUTO);
115
-
116
- getManagementPoint(accessory.context.device, EMBEDDED_ID)['onOffMode'] = { value: 'off' };
117
- expect(await service.handleHotWaterTankTargetHeatingCoolingStateGet()).toBe(Characteristic.TargetHeatingCoolingState.OFF);
118
- });
119
-
120
- it('should get the powerful mode', async () => {
121
- expect(await service.handlePowerfulModeGet()).toBe(false);
122
- });
123
- });