@mp-consulting/homebridge-daikin-cloud 1.3.6 → 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 (287) hide show
  1. package/LICENSE +39 -1
  2. package/README.md +3 -1
  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 +5 -5
  10. package/dist/src/accessories/base-accessory.d.ts.map +1 -1
  11. package/dist/src/accessories/base-accessory.js +7 -4
  12. package/dist/src/accessories/base-accessory.js.map +1 -1
  13. package/dist/src/api/daikin-api.d.ts +25 -25
  14. package/dist/src/api/daikin-api.d.ts.map +1 -1
  15. package/dist/src/api/daikin-api.js +41 -31
  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.map +1 -1
  19. package/dist/src/api/daikin-controller.d.ts +41 -42
  20. package/dist/src/api/daikin-controller.d.ts.map +1 -1
  21. package/dist/src/api/daikin-controller.js +39 -39
  22. package/dist/src/api/daikin-controller.js.map +1 -1
  23. package/dist/src/api/daikin-device.d.ts +33 -31
  24. package/dist/src/api/daikin-device.d.ts.map +1 -1
  25. package/dist/src/api/daikin-device.js +40 -29
  26. package/dist/src/api/daikin-device.js.map +1 -1
  27. package/dist/src/api/daikin-mobile-oauth.d.ts +16 -16
  28. package/dist/src/api/daikin-mobile-oauth.d.ts.map +1 -1
  29. package/dist/src/api/daikin-mobile-oauth.js +32 -22
  30. package/dist/src/api/daikin-mobile-oauth.js.map +1 -1
  31. package/dist/src/api/daikin-oauth.d.ts +29 -29
  32. package/dist/src/api/daikin-oauth.d.ts.map +1 -1
  33. package/dist/src/api/daikin-oauth.js +45 -35
  34. package/dist/src/api/daikin-oauth.js.map +1 -1
  35. package/dist/src/api/daikin-schemas.d.ts +4 -4
  36. package/dist/src/api/daikin-schemas.js +3 -3
  37. package/dist/src/api/daikin-schemas.js.map +1 -1
  38. package/dist/src/api/daikin-types.js.map +1 -1
  39. package/dist/src/api/daikin-websocket.d.ts +31 -32
  40. package/dist/src/api/daikin-websocket.d.ts.map +1 -1
  41. package/dist/src/api/daikin-websocket.js +30 -30
  42. package/dist/src/api/daikin-websocket.js.map +1 -1
  43. package/dist/src/api/index.d.ts +1 -1
  44. package/dist/src/api/index.d.ts.map +1 -1
  45. package/dist/src/api/index.js +2 -1
  46. package/dist/src/api/index.js.map +1 -1
  47. package/dist/src/api/token-storage.d.ts +1 -1
  48. package/dist/src/api/token-storage.d.ts.map +1 -1
  49. package/dist/src/api/token-storage.js +20 -11
  50. package/dist/src/api/token-storage.js.map +1 -1
  51. package/dist/src/config/config-manager.d.ts +33 -33
  52. package/dist/src/config/config-manager.d.ts.map +1 -1
  53. package/dist/src/config/config-manager.js +33 -33
  54. package/dist/src/config/config-manager.js.map +1 -1
  55. package/dist/src/constants/api.constants.js.map +1 -1
  56. package/dist/src/device/accessory-factory.d.ts +10 -10
  57. package/dist/src/device/accessory-factory.d.ts.map +1 -1
  58. package/dist/src/device/accessory-factory.js +6 -6
  59. package/dist/src/device/accessory-factory.js.map +1 -1
  60. package/dist/src/device/capability-detector.d.ts +8 -8
  61. package/dist/src/device/capability-detector.d.ts.map +1 -1
  62. package/dist/src/device/capability-detector.js +6 -6
  63. package/dist/src/device/capability-detector.js.map +1 -1
  64. package/dist/src/device/capability-docs.d.ts +1 -1
  65. package/dist/src/device/capability-docs.d.ts.map +1 -1
  66. package/dist/src/device/capability-docs.js +1 -2
  67. package/dist/src/device/capability-docs.js.map +1 -1
  68. package/dist/src/device/profiles/device-profile.d.ts +1 -1
  69. package/dist/src/device/profiles/device-profile.d.ts.map +1 -1
  70. package/dist/src/device/profiles/device-profile.js +4 -4
  71. package/dist/src/device/profiles/device-profile.js.map +1 -1
  72. package/dist/src/features/base-feature.d.ts +2 -2
  73. package/dist/src/features/base-feature.d.ts.map +1 -1
  74. package/dist/src/features/base-feature.js +2 -3
  75. package/dist/src/features/base-feature.js.map +1 -1
  76. package/dist/src/features/feature-manager.d.ts +8 -8
  77. package/dist/src/features/feature-manager.d.ts.map +1 -1
  78. package/dist/src/features/feature-manager.js +5 -5
  79. package/dist/src/features/feature-manager.js.map +1 -1
  80. package/dist/src/features/modes/dry-operation-mode.feature.d.ts +1 -1
  81. package/dist/src/features/modes/dry-operation-mode.feature.d.ts.map +1 -1
  82. package/dist/src/features/modes/dry-operation-mode.feature.js.map +1 -1
  83. package/dist/src/features/modes/econo-mode.feature.d.ts +1 -1
  84. package/dist/src/features/modes/econo-mode.feature.d.ts.map +1 -1
  85. package/dist/src/features/modes/econo-mode.feature.js.map +1 -1
  86. package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts +1 -1
  87. package/dist/src/features/modes/fan-only-operation-mode.feature.d.ts.map +1 -1
  88. package/dist/src/features/modes/fan-only-operation-mode.feature.js.map +1 -1
  89. package/dist/src/features/modes/indoor-silent-mode.feature.d.ts +1 -1
  90. package/dist/src/features/modes/indoor-silent-mode.feature.d.ts.map +1 -1
  91. package/dist/src/features/modes/indoor-silent-mode.feature.js.map +1 -1
  92. package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts +1 -1
  93. package/dist/src/features/modes/outdoor-silent-mode.feature.d.ts.map +1 -1
  94. package/dist/src/features/modes/outdoor-silent-mode.feature.js.map +1 -1
  95. package/dist/src/features/modes/powerful-mode.feature.d.ts +1 -1
  96. package/dist/src/features/modes/powerful-mode.feature.d.ts.map +1 -1
  97. package/dist/src/features/modes/powerful-mode.feature.js.map +1 -1
  98. package/dist/src/features/modes/streamer-mode.feature.d.ts +1 -1
  99. package/dist/src/features/modes/streamer-mode.feature.d.ts.map +1 -1
  100. package/dist/src/features/modes/streamer-mode.feature.js.map +1 -1
  101. package/dist/src/index.d.ts +1 -1
  102. package/dist/src/index.d.ts.map +1 -1
  103. package/dist/src/index.js.map +1 -1
  104. package/dist/src/platform.d.ts +6 -5
  105. package/dist/src/platform.d.ts.map +1 -1
  106. package/dist/src/platform.js +2 -2
  107. package/dist/src/platform.js.map +1 -1
  108. package/dist/src/services/climate-control.service.d.ts +8 -2
  109. package/dist/src/services/climate-control.service.d.ts.map +1 -1
  110. package/dist/src/services/climate-control.service.js +53 -59
  111. package/dist/src/services/climate-control.service.js.map +1 -1
  112. package/dist/src/services/hot-water-tank.service.d.ts +6 -2
  113. package/dist/src/services/hot-water-tank.service.d.ts.map +1 -1
  114. package/dist/src/services/hot-water-tank.service.js +31 -34
  115. package/dist/src/services/hot-water-tank.service.js.map +1 -1
  116. package/dist/src/types/daikin-enums.js +12 -12
  117. package/dist/src/types/daikin-enums.js.map +1 -1
  118. package/dist/src/types/device-capabilities.d.ts +1 -1
  119. package/dist/src/types/device-capabilities.d.ts.map +1 -1
  120. package/dist/src/utils/log-context.d.ts +23 -23
  121. package/dist/src/utils/log-context.d.ts.map +1 -1
  122. package/dist/src/utils/log-context.js +28 -28
  123. package/dist/src/utils/log-context.js.map +1 -1
  124. package/dist/src/utils/strings.d.ts.map +1 -1
  125. package/dist/src/utils/strings.js.map +1 -1
  126. package/dist/src/utils/update-mapper.d.ts +16 -16
  127. package/dist/src/utils/update-mapper.d.ts.map +1 -1
  128. package/dist/src/utils/update-mapper.js +14 -14
  129. package/dist/src/utils/update-mapper.js.map +1 -1
  130. package/homebridge-ui/public/script.js +956 -897
  131. package/homebridge-ui/server.js +739 -695
  132. package/package.json +27 -24
  133. package/.claude/settings.json +0 -3
  134. package/.claude/settings.local.json +0 -24
  135. package/CHANGELOG.md +0 -114
  136. package/CLAUDE.md +0 -269
  137. package/config.md +0 -2
  138. package/docs/ARCHITECTURE.md +0 -645
  139. package/docs/IMPLEMENTATION_GUIDE.md +0 -899
  140. package/docs/IMPROVEMENTS_SUMMARY.md +0 -415
  141. package/docs/NEXT_STEPS.md +0 -368
  142. package/docs/Screenshot 2024-07-04 at 18.41.28.png +0 -0
  143. package/docs/TROUBLESHOOTING.md +0 -475
  144. package/docs/api-response-for-BRP069A8x.json +0 -520
  145. package/docs/api-response-for-BRP069C4x-2.json +0 -881
  146. package/docs/api-response-for-BRP069C4x.json +0 -916
  147. package/docs/api-response-for-altherma.json +0 -759
  148. package/docs/api-response-for-altherma2.json +0 -2735
  149. package/docs/api-response-with-multiple-devices-incl-heatpump.json +0 -2544
  150. package/docs/cr-insance-altherma-id-0.json +0 -834
  151. package/docs/mock-air-to-air-dx23.json +0 -759
  152. package/docs/mock-air-to-air-dx4.json +0 -1134
  153. package/docs/mock-airpurifier-with-humidifier.json +0 -732
  154. package/docs/mock-airpurifier.json +0 -450
  155. package/docs/mock-altherma-air-to-water-lan.json +0 -845
  156. package/docs/mock-altherma-air-to-water-wlan.json +0 -845
  157. package/docs/mock-d2cnd-gas-boiler.json +0 -649
  158. package/docs/setpointmode-vs-controlmode-vs-setpoints-vs-sensorydata.txt +0 -6
  159. package/images/fan-speed.jpeg +0 -0
  160. package/images/homekit-controls.jpeg +0 -0
  161. package/images/homekit-settings.jpeg +0 -0
  162. package/images/swing-mode.png +0 -0
  163. package/jest.config.ts +0 -21
  164. package/test/fixtures/altherma-crSense-2.ts +0 -834
  165. package/test/fixtures/altherma-fraction.ts +0 -718
  166. package/test/fixtures/altherma-heat-pump-2.ts +0 -479
  167. package/test/fixtures/altherma-heat-pump.ts +0 -757
  168. package/test/fixtures/altherma-miladcerkic-off.ts +0 -524
  169. package/test/fixtures/altherma-miladcerkic.ts +0 -524
  170. package/test/fixtures/altherma-v1ckoeln.ts +0 -644
  171. package/test/fixtures/altherma-with-embedded-id-zero.ts +0 -834
  172. package/test/fixtures/dx23-airco-2.ts +0 -343
  173. package/test/fixtures/dx23-airco.ts +0 -518
  174. package/test/fixtures/dx4-airco.ts +0 -914
  175. package/test/fixtures/unknown-jan.ts +0 -488
  176. package/test/fixtures/unknown-kitchen-guests.ts +0 -488
  177. package/test/hbConfig/.daikin-mobile-tokenset +0 -8
  178. package/test/hbConfig/.uix-dashboard.json +0 -1
  179. package/test/hbConfig/.uix-secrets +0 -1
  180. package/test/hbConfig/accessories/.cachedAccessories.bak +0 -1
  181. package/test/hbConfig/accessories/cachedAccessories +0 -1
  182. package/test/hbConfig/accessories/uiAccessoriesLayout.json +0 -1
  183. package/test/hbConfig/auth.json +0 -10
  184. package/test/hbConfig/backups/config-backups/config.json.1767953686461 +0 -25
  185. package/test/hbConfig/backups/config-backups/config.json.1767953695236 +0 -29
  186. package/test/hbConfig/backups/config-backups/config.json.1767953814763 +0 -29
  187. package/test/hbConfig/backups/config-backups/config.json.1767953823101 +0 -29
  188. package/test/hbConfig/backups/config-backups/config.json.1767954822835 +0 -29
  189. package/test/hbConfig/backups/config-backups/config.json.1767954859218 +0 -29
  190. package/test/hbConfig/backups/config-backups/config.json.1767960145503 +0 -33
  191. package/test/hbConfig/backups/config-backups/config.json.1767960168068 +0 -44
  192. package/test/hbConfig/backups/config-backups/config.json.1767960170333 +0 -46
  193. package/test/hbConfig/backups/config-backups/config.json.1767960172731 +0 -44
  194. package/test/hbConfig/backups/config-backups/config.json.1767960179323 +0 -44
  195. package/test/hbConfig/backups/config-backups/config.json.1767960182114 +0 -44
  196. package/test/hbConfig/backups/config-backups/config.json.1767960189302 +0 -44
  197. package/test/hbConfig/backups/config-backups/config.json.1767960195194 +0 -44
  198. package/test/hbConfig/backups/config-backups/config.json.1767960197301 +0 -44
  199. package/test/hbConfig/backups/config-backups/config.json.1767960199151 +0 -44
  200. package/test/hbConfig/backups/config-backups/config.json.1767960199667 +0 -44
  201. package/test/hbConfig/backups/config-backups/config.json.1767960329839 +0 -44
  202. package/test/hbConfig/backups/config-backups/config.json.1767960334503 +0 -44
  203. package/test/hbConfig/backups/config-backups/config.json.1767960336208 +0 -44
  204. package/test/hbConfig/backups/config-backups/config.json.1767960338537 +0 -44
  205. package/test/hbConfig/backups/config-backups/config.json.1767963223953 +0 -44
  206. package/test/hbConfig/backups/config-backups/config.json.1767963241753 +0 -44
  207. package/test/hbConfig/backups/config-backups/config.json.1767963252785 +0 -44
  208. package/test/hbConfig/backups/config-backups/config.json.1767963463944 +0 -44
  209. package/test/hbConfig/backups/config-backups/config.json.1767963834475 +0 -44
  210. package/test/hbConfig/backups/config-backups/config.json.1767963838474 +0 -44
  211. package/test/hbConfig/backups/config-backups/config.json.1767963843066 +0 -44
  212. package/test/hbConfig/backups/config-backups/config.json.1767965217715 +0 -44
  213. package/test/hbConfig/backups/config-backups/config.json.1767965419624 +0 -25
  214. package/test/hbConfig/backups/config-backups/config.json.1767965870934 +0 -32
  215. package/test/hbConfig/backups/config-backups/config.json.1767977675045 +0 -32
  216. package/test/hbConfig/backups/config-backups/config.json.1767977677222 +0 -33
  217. package/test/hbConfig/backups/config-backups/config.json.1767977710226 +0 -33
  218. package/test/hbConfig/backups/config-backups/config.json.1767977741397 +0 -33
  219. package/test/hbConfig/backups/config-backups/config.json.1767977977093 +0 -35
  220. package/test/hbConfig/backups/config-backups/config.json.1767977981773 +0 -35
  221. package/test/hbConfig/backups/config-backups/config.json.1767977986514 +0 -35
  222. package/test/hbConfig/backups/config-backups/config.json.1767977991174 +0 -35
  223. package/test/hbConfig/backups/config-backups/config.json.1767979424487 +0 -35
  224. package/test/hbConfig/backups/config-backups/config.json.1767979424987 +0 -35
  225. package/test/hbConfig/backups/config-backups/config.json.1767979432646 +0 -47
  226. package/test/hbConfig/backups/config-backups/config.json.1767979433150 +0 -47
  227. package/test/hbConfig/backups/config-backups/config.json.1767979436933 +0 -47
  228. package/test/hbConfig/backups/config-backups/config.json.1767979437438 +0 -47
  229. package/test/hbConfig/backups/config-backups/config.json.1767979441676 +0 -47
  230. package/test/hbConfig/backups/config-backups/config.json.1767979442180 +0 -47
  231. package/test/hbConfig/backups/config-backups/config.json.1767979466735 +0 -47
  232. package/test/hbConfig/backups/config-backups/config.json.1767979903636 +0 -47
  233. package/test/hbConfig/backups/config-backups/config.json.1767979904135 +0 -47
  234. package/test/hbConfig/backups/config-backups/config.json.1767979906606 +0 -47
  235. package/test/hbConfig/backups/config-backups/config.json.1767979907108 +0 -47
  236. package/test/hbConfig/backups/config-backups/config.json.1767988702341 +0 -47
  237. package/test/hbConfig/backups/config-backups/config.json.1767988702837 +0 -47
  238. package/test/hbConfig/backups/config-backups/config.json.1767988713159 +0 -47
  239. package/test/hbConfig/backups/config-backups/config.json.1767988713664 +0 -47
  240. package/test/hbConfig/backups/config-backups/config.json.1767988918139 +0 -47
  241. package/test/hbConfig/backups/config-backups/config.json.1767988918639 +0 -47
  242. package/test/hbConfig/backups/config-backups/config.json.1767988921120 +0 -47
  243. package/test/hbConfig/backups/config-backups/config.json.1767988921624 +0 -47
  244. package/test/hbConfig/backups/config-backups/config.json.1767988930307 +0 -47
  245. package/test/hbConfig/backups/config-backups/config.json.1767988935070 +0 -47
  246. package/test/hbConfig/backups/config-backups/config.json.1767988935574 +0 -47
  247. package/test/hbConfig/backups/config-backups/config.json.1767989710262 +0 -47
  248. package/test/hbConfig/backups/config-backups/config.json.1767989710760 +0 -47
  249. package/test/hbConfig/backups/config-backups/config.json.1767989729668 +0 -47
  250. package/test/hbConfig/backups/config-backups/config.json.1767990295225 +0 -47
  251. package/test/hbConfig/backups/config-backups/config.json.1767990479921 +0 -47
  252. package/test/hbConfig/backups/config-backups/config.json.1767990481702 +0 -49
  253. package/test/hbConfig/backups/instance-backups/homebridge-backup-1E4A432551BA.1768010187391.tar.gz +0 -0
  254. package/test/hbConfig/backups/instance-backups/homebridge-backup-1E4A432551BA.1768096587387.tar.gz +0 -0
  255. package/test/hbConfig/backups/instance-backups/homebridge-backup-1E4A432551BA.1768182987404.tar.gz +0 -0
  256. package/test/hbConfig/config.json +0 -47
  257. package/test/hbConfig/daikin-cloud-certs/server.crt +0 -22
  258. package/test/hbConfig/daikin-cloud-certs/server.key +0 -28
  259. package/test/hbConfig/persist/AccessoryInfo.1E4A432551BA.json +0 -1
  260. package/test/hbConfig/persist/IdentifierCache.1E4A432551BA.json +0 -1
  261. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14758 +0 -1
  262. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14759 +0 -1
  263. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14760 +0 -1
  264. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14761 +0 -1
  265. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14762 +0 -1
  266. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14764 +0 -1
  267. package/test/helpers/test-isolation.ts +0 -228
  268. package/test/integration/air-conditioning.test.ts +0 -396
  269. package/test/integration/altherma.test.ts +0 -279
  270. package/test/integration/platform.test.ts +0 -118
  271. package/test/mobile-tokens.json +0 -8
  272. package/test/mocks/index.ts +0 -27
  273. package/test/test-gigya-auth.js +0 -443
  274. package/test/test-mobile-oauth.js +0 -175
  275. package/test/test-websocket-mobile.js +0 -123
  276. package/test/test-websocket.js +0 -116
  277. package/test/unit/api/__snapshots__/daikinCloud.test.ts.snap +0 -1320
  278. package/test/unit/api/daikin-api.test.ts +0 -442
  279. package/test/unit/api/daikin-cloud-repository.test.ts +0 -107
  280. package/test/unit/api/daikin-oauth.test.ts +0 -214
  281. package/test/unit/api/daikinCloud.test.ts +0 -12
  282. package/test/unit/api/token-storage.test.ts +0 -90
  283. package/test/unit/config/config-manager.test.ts +0 -271
  284. package/test/unit/device/daikin-device.test.ts +0 -73
  285. package/test/unit/services/hot-water-tank.service.test.ts +0 -123
  286. package/test/unit/utils/log-context.test.ts +0 -271
  287. package/test/unit/utils/update-mapper.test.ts +0 -404
@@ -1,228 +0,0 @@
1
- /**
2
- * Test Isolation Helpers
3
- *
4
- * Provides utilities for better test isolation:
5
- * - Test context management
6
- * - Automatic cleanup
7
- * - Mock factories
8
- * - Fake timers
9
- */
10
-
11
- import {Logger, PlatformAccessory, PlatformConfig} from 'homebridge';
12
- import {DaikinCloudAccessoryContext} from '../../src/platform';
13
-
14
- /**
15
- * Test context for managing test lifecycle
16
- */
17
- export class TestContext {
18
- private readonly cleanupCallbacks: Array<() => void | Promise<void>> = [];
19
- private timersMocked = false;
20
-
21
- /**
22
- * Register a cleanup callback
23
- */
24
- onCleanup(callback: () => void | Promise<void>): void {
25
- this.cleanupCallbacks.push(callback);
26
- }
27
-
28
- /**
29
- * Use fake timers for this test
30
- */
31
- useFakeTimers(): void {
32
- if (!this.timersMocked) {
33
- jest.useFakeTimers();
34
- this.timersMocked = true;
35
- this.onCleanup(() => {
36
- jest.runOnlyPendingTimers();
37
- jest.useRealTimers();
38
- this.timersMocked = false;
39
- });
40
- }
41
- }
42
-
43
- /**
44
- * Advance timers by time
45
- */
46
- async advanceTimersByTime(ms: number): Promise<void> {
47
- if (!this.timersMocked) {
48
- throw new Error('Timers must be mocked first. Call useFakeTimers()');
49
- }
50
- jest.advanceTimersByTime(ms);
51
- await Promise.resolve(); // Flush microtasks
52
- }
53
-
54
- /**
55
- * Run all timers
56
- */
57
- async runAllTimers(): Promise<void> {
58
- if (!this.timersMocked) {
59
- throw new Error('Timers must be mocked first. Call useFakeTimers()');
60
- }
61
- jest.runAllTimers();
62
- await Promise.resolve(); // Flush microtasks
63
- }
64
-
65
- /**
66
- * Clean up all resources
67
- */
68
- async cleanup(): Promise<void> {
69
- for (const callback of this.cleanupCallbacks.reverse()) {
70
- await callback();
71
- }
72
- this.cleanupCallbacks.length = 0;
73
- }
74
- }
75
-
76
- /**
77
- * Create a test context for a test
78
- */
79
- export function createTestContext(): TestContext {
80
- return new TestContext();
81
- }
82
-
83
- /**
84
- * Create a mock logger
85
- */
86
- export function createMockLogger(): Logger {
87
- const logger = {
88
- debug: jest.fn(),
89
- info: jest.fn(),
90
- warn: jest.fn(),
91
- error: jest.fn(),
92
- log: jest.fn(),
93
- success: jest.fn(),
94
- } as unknown as Logger;
95
-
96
- return logger;
97
- }
98
-
99
- /**
100
- * Create a mock platform config
101
- */
102
- export function createMockConfig(overrides: Partial<PlatformConfig> = {}): PlatformConfig {
103
- return {
104
- name: 'Test Platform',
105
- platform: 'DaikinCloud',
106
- clientId: 'test-client-id',
107
- clientSecret: 'test-client-secret',
108
- callbackServerExternalAddress: 'test.example.com',
109
- callbackServerPort: 8582,
110
- oidcCallbackServerBindAddr: '0.0.0.0',
111
- updateIntervalInMinutes: 15,
112
- forceUpdateDelay: 60000,
113
- showExtraFeatures: false,
114
- enableWebSocket: true,
115
- ...overrides,
116
- } as PlatformConfig;
117
- }
118
-
119
- /**
120
- * Create a mock accessory
121
- */
122
- export function createMockAccessory(
123
- displayName: string,
124
- context?: Partial<DaikinCloudAccessoryContext>,
125
- ): PlatformAccessory<DaikinCloudAccessoryContext> {
126
- const mockContext: DaikinCloudAccessoryContext = {
127
- device: {} as any,
128
- useHeaterCooler: false,
129
- ...context,
130
- };
131
-
132
- const accessory = {
133
- UUID: `test-uuid-${displayName}`,
134
- displayName,
135
- context: mockContext,
136
- services: [],
137
- getService: jest.fn(),
138
- addService: jest.fn(),
139
- removeService: jest.fn(),
140
- getServiceById: jest.fn(),
141
- } as unknown as PlatformAccessory<DaikinCloudAccessoryContext>;
142
-
143
- return accessory;
144
- }
145
-
146
- /**
147
- * Spy on console methods and restore after cleanup
148
- */
149
- export function spyOnConsole(context: TestContext): {
150
- log: jest.SpyInstance;
151
- warn: jest.SpyInstance;
152
- error: jest.SpyInstance;
153
- } {
154
- const spies = {
155
- log: jest.spyOn(console, 'log').mockImplementation(),
156
- warn: jest.spyOn(console, 'warn').mockImplementation(),
157
- error: jest.spyOn(console, 'error').mockImplementation(),
158
- };
159
-
160
- context.onCleanup(() => {
161
- spies.log.mockRestore();
162
- spies.warn.mockRestore();
163
- spies.error.mockRestore();
164
- });
165
-
166
- return spies;
167
- }
168
-
169
- /**
170
- * Create isolated test suite with automatic cleanup
171
- */
172
- export function describeIsolated(name: string, fn: (getContext: () => TestContext) => void): void {
173
- describe(name, () => {
174
- let context: TestContext;
175
-
176
- beforeEach(() => {
177
- context = createTestContext();
178
- });
179
-
180
- afterEach(async () => {
181
- await context.cleanup();
182
- });
183
-
184
- fn(() => context);
185
- });
186
- }
187
-
188
- /**
189
- * Wait for a condition to be true
190
- */
191
- export async function waitFor(
192
- condition: () => boolean | Promise<boolean>,
193
- options: { timeout?: number; interval?: number } = {},
194
- ): Promise<void> {
195
- const timeout = options.timeout ?? 5000;
196
- const interval = options.interval ?? 50;
197
- const startTime = Date.now();
198
-
199
- while (!(await condition())) {
200
- if (Date.now() - startTime > timeout) {
201
- throw new Error('waitFor timeout exceeded');
202
- }
203
- await new Promise(resolve => setTimeout(resolve, interval));
204
- }
205
- }
206
-
207
- /**
208
- * Create a deferred promise for testing async flows
209
- */
210
- export function createDeferred<T>(): {
211
- promise: Promise<T>;
212
- resolve: (value: T) => void;
213
- reject: (error: Error) => void;
214
- } {
215
- let resolve: (value: T) => void;
216
- let reject: (error: Error) => void;
217
-
218
- const promise = new Promise<T>((res, rej) => {
219
- resolve = res;
220
- reject = rej;
221
- });
222
-
223
- return {
224
- promise,
225
- resolve: resolve!,
226
- reject: reject!,
227
- };
228
- }
@@ -1,396 +0,0 @@
1
- import {PlatformAccessory} from 'homebridge/lib/platformAccessory';
2
- import {DaikinCloudAccessoryContext, DaikinCloudPlatform} from '../../src/platform';
3
- import {MockPlatformConfig} from '../mocks';
4
- import {AirConditioningAccessory} from '../../src/accessories';
5
- import {DaikinCloudDevice, DaikinCloudController, DaikinApi} from '../../src/api';
6
- import {unknownJan} from '../fixtures/unknown-jan';
7
- import {unknownKitchenGuests} from '../fixtures/unknown-kitchen-guests';
8
- import {dx23Airco} from '../fixtures/dx23-airco';
9
- import {dx4Airco} from '../fixtures/dx4-airco';
10
- import {dx23Airco2} from '../fixtures/dx23-airco-2';
11
-
12
- import {HomebridgeAPI} from 'homebridge/lib/api.js';
13
- import {Logger} from 'homebridge/lib/logger.js';
14
- import {
15
- PowerfulModeFeature,
16
- EconoModeFeature,
17
- StreamerModeFeature,
18
- OutdoorSilentModeFeature,
19
- IndoorSilentModeFeature,
20
- DryOperationModeFeature,
21
- FanOnlyOperationModeFeature,
22
- } from '../../src/features';
23
-
24
- // Use fake timers to prevent tests from hanging due to setInterval/setTimeout in platform
25
- beforeEach(() => {
26
- jest.useFakeTimers();
27
- });
28
-
29
- afterEach(() => {
30
- jest.clearAllTimers();
31
- jest.useRealTimers();
32
- });
33
-
34
- type DeviceState = {
35
- activeState: boolean;
36
- currentTemperature: number;
37
- targetHeaterCoolerState: string;
38
- coolingThresholdTemperature: number;
39
- heatingThresholdTemperature: number;
40
- rotationSpeed: number;
41
- swingMode: number;
42
- powerfulMode: number;
43
- econoMode: number;
44
- streamerMode: number;
45
- outdoorSilentMode: number;
46
- indoorSilentMode: number;
47
- dryOperationMode: number;
48
- fanOnlyOperationMode: number;
49
- };
50
-
51
- test.each<Array<string | string | any | DeviceState>>([
52
- [
53
- 'dx4',
54
- 'climateControl',
55
- dx4Airco,
56
- {
57
- activeState: true,
58
- currentTemperature: 25,
59
- targetHeaterCoolerState: 1,
60
- coolingThresholdTemperature: 25,
61
- heatingThresholdTemperature: 22,
62
- rotationSpeed: 2,
63
- swingMode: 0,
64
- powerfulMode: false,
65
- econoMode: false,
66
- streamerMode: false,
67
- outdoorSilentMode: false,
68
- indoorSilentMode: false,
69
- dryOperationMode: false,
70
- fanOnlyOperationMode: false,
71
- },
72
- ],
73
- [
74
- 'dx23',
75
- 'climateControl',
76
- dx23Airco,
77
- {
78
- activeState: false,
79
- currentTemperature: 27,
80
- targetHeaterCoolerState: 2,
81
- coolingThresholdTemperature: 17,
82
- heatingThresholdTemperature: 17,
83
- rotationSpeed: 3,
84
- swingMode: 1,
85
- powerfulMode: undefined,
86
- econoMode: undefined,
87
- streamerMode: undefined,
88
- outdoorSilentMode: undefined,
89
- indoorSilentMode: undefined,
90
- dryOperationMode: false,
91
- fanOnlyOperationMode: false,
92
- },
93
- ],
94
- [
95
- 'dx23-2',
96
- 'climateControl',
97
- dx23Airco2,
98
- {
99
- activeState: true,
100
- currentTemperature: 19,
101
- targetHeaterCoolerState: 1,
102
- coolingThresholdTemperature: 25,
103
- heatingThresholdTemperature: 13,
104
- rotationSpeed: 4,
105
- swingMode: 0,
106
- powerfulMode: false,
107
- econoMode: undefined,
108
- streamerMode: undefined,
109
- outdoorSilentMode: undefined,
110
- indoorSilentMode: false,
111
- dryOperationMode: false,
112
- fanOnlyOperationMode: false,
113
- },
114
- ],
115
- [
116
- 'unknown',
117
- 'climateControl',
118
- unknownKitchenGuests,
119
- {
120
- activeState: false,
121
- currentTemperature: 30.1,
122
- targetHeaterCoolerState: 2,
123
- coolingThresholdTemperature: 23.5,
124
- heatingThresholdTemperature: undefined,
125
- rotationSpeed: 1,
126
- swingMode: 1,
127
- powerfulMode: undefined,
128
- econoMode: undefined,
129
- streamerMode: undefined,
130
- outdoorSilentMode: undefined,
131
- indoorSilentMode: undefined,
132
- dryOperationMode: false,
133
- fanOnlyOperationMode: false,
134
- },
135
- ],
136
- [
137
- 'unknown2',
138
- 'climateControl',
139
- unknownJan,
140
- {
141
- activeState: false,
142
- currentTemperature: 27,
143
- targetHeaterCoolerState: 2,
144
- coolingThresholdTemperature: 26.1,
145
- heatingThresholdTemperature: undefined,
146
- rotationSpeed: 1,
147
- swingMode: 1,
148
- powerfulMode: undefined,
149
- econoMode: undefined,
150
- streamerMode: undefined,
151
- outdoorSilentMode: undefined,
152
- indoorSilentMode: undefined,
153
- dryOperationMode: false,
154
- fanOnlyOperationMode: false,
155
- },
156
- ],
157
- ])('Create DaikinCloudAirConditioningAccessory with %s device', async (name: string, climateControlEmbeddedId: string, deviceJson, state: DeviceState) => {
158
- const mockApi = {
159
- updateDevice: jest.fn().mockResolvedValue(undefined),
160
- } as unknown as DaikinApi;
161
- const device = new DaikinCloudDevice(deviceJson as any, mockApi);
162
-
163
- jest.spyOn(DaikinCloudController.prototype, 'getCloudDevices').mockImplementation(async () => {
164
- return [device];
165
- });
166
-
167
- const config = new MockPlatformConfig(true);
168
- const api = new HomebridgeAPI();
169
-
170
- const uuid = api.hap.uuid.generate(device.getId());
171
- const accessory = new api.platformAccessory("NAME_FOR_TEST", uuid);
172
- accessory.context['device'] = device;
173
-
174
- expect(() => {
175
- new AirConditioningAccessory(new DaikinCloudPlatform(new Logger(), config, api), accessory as unknown as PlatformAccessory<DaikinCloudAccessoryContext>);
176
- }).not.toThrow();
177
-
178
- const homebridgeAccessory = new AirConditioningAccessory(new DaikinCloudPlatform(new Logger(), config, api), accessory as unknown as PlatformAccessory<DaikinCloudAccessoryContext>);
179
-
180
- if (typeof state.activeState !== 'undefined') {
181
- expect(await homebridgeAccessory.service.handleActiveStateGet()).toBe(state.activeState);
182
- await expect(homebridgeAccessory.service.handleActiveStateSet(1)).resolves.not.toThrow();
183
- await expect(homebridgeAccessory.service.handleActiveStateSet(0)).resolves.not.toThrow();
184
- }
185
-
186
- expect(await homebridgeAccessory.service.handleCurrentTemperatureGet()).toBe(state.currentTemperature);
187
-
188
- if (typeof state.coolingThresholdTemperature !== 'undefined') {
189
- expect(await homebridgeAccessory.service.handleCoolingThresholdTemperatureGet()).toBe(state.coolingThresholdTemperature);
190
- await expect(homebridgeAccessory.service.handleCoolingThresholdTemperatureSet(21)).resolves.not.toThrow();
191
- }
192
-
193
- if (typeof state.heatingThresholdTemperature !== 'undefined') {
194
- expect(await homebridgeAccessory.service.handleHeatingThresholdTemperatureGet()).toBe(state.heatingThresholdTemperature);
195
- await expect(homebridgeAccessory.service.handleHeatingThresholdTemperatureSet(25)).resolves.not.toThrow();
196
- }
197
-
198
- if (typeof state.rotationSpeed !== 'undefined') {
199
- expect(await homebridgeAccessory.service.handleRotationSpeedGet()).toBe(state.rotationSpeed);
200
- await expect(homebridgeAccessory.service.handleRotationSpeedSet(50)).resolves.not.toThrow();
201
- }
202
-
203
- if (typeof state.targetHeaterCoolerState !== 'undefined') {
204
- expect(await homebridgeAccessory.service.handleTargetHeaterCoolerStateGet()).toBe(state.targetHeaterCoolerState);
205
- await expect(homebridgeAccessory.service.handleTargetHeaterCoolerStateSet(1)).resolves.not.toThrow();
206
- }
207
-
208
- if (typeof state.swingMode !== 'undefined') {
209
- expect(await homebridgeAccessory.service.handleSwingModeGet()).toBe(state.swingMode);
210
- await expect(homebridgeAccessory.service.handleSwingModeSet(1)).resolves.not.toThrow();
211
- }
212
-
213
- if (typeof state.powerfulMode !== 'undefined') {
214
- const feature = homebridgeAccessory.service.featureManager.getFeature(PowerfulModeFeature);
215
- expect(feature).toBeDefined();
216
- expect(await feature!.handleGet()).toBe(state.powerfulMode);
217
- }
218
-
219
- if (typeof state.econoMode !== 'undefined') {
220
- const feature = homebridgeAccessory.service.featureManager.getFeature(EconoModeFeature);
221
- expect(feature).toBeDefined();
222
- expect(await feature!.handleGet()).toBe(state.econoMode);
223
- }
224
-
225
- if (typeof state.streamerMode !== 'undefined') {
226
- const feature = homebridgeAccessory.service.featureManager.getFeature(StreamerModeFeature);
227
- expect(feature).toBeDefined();
228
- expect(await feature!.handleGet()).toBe(state.streamerMode);
229
- }
230
-
231
- if (typeof state.outdoorSilentMode !== 'undefined') {
232
- const feature = homebridgeAccessory.service.featureManager.getFeature(OutdoorSilentModeFeature);
233
- expect(feature).toBeDefined();
234
- expect(await feature!.handleGet()).toBe(state.outdoorSilentMode);
235
- }
236
-
237
- if (typeof state.indoorSilentMode !== 'undefined') {
238
- const feature = homebridgeAccessory.service.featureManager.getFeature(IndoorSilentModeFeature);
239
- expect(feature).toBeDefined();
240
- expect(await feature!.handleGet()).toBe(state.indoorSilentMode);
241
- }
242
-
243
- if (typeof state.dryOperationMode !== 'undefined') {
244
- const feature = homebridgeAccessory.service.featureManager.getFeature(DryOperationModeFeature);
245
- expect(feature).toBeDefined();
246
- expect(await feature!.handleGet()).toBe(state.dryOperationMode);
247
- }
248
-
249
- if (typeof state.fanOnlyOperationMode !== 'undefined') {
250
- const feature = homebridgeAccessory.service.featureManager.getFeature(FanOnlyOperationModeFeature);
251
- expect(feature).toBeDefined();
252
- expect(await feature!.handleGet()).toBe(state.fanOnlyOperationMode);
253
- }
254
- });
255
-
256
- test.each<Array<string | string | any>>([
257
- ['dx4', 'climateControl', dx4Airco],
258
- ['dx23', 'climateControl', dx23Airco],
259
- ])('Create DaikinCloudAirConditioningAccessory with %s device, showExtraFeatures disabled', async (name, climateControlEmbeddedId, deviceJson) => {
260
- const mockApi = { updateDevice: jest.fn().mockResolvedValue(undefined) } as unknown as DaikinApi;
261
- const device = new DaikinCloudDevice(deviceJson as any, mockApi);
262
-
263
- jest.spyOn(DaikinCloudController.prototype, 'getCloudDevices').mockImplementation(async () => {
264
- return [device];
265
- });
266
-
267
-
268
- const config = new MockPlatformConfig(false);
269
- const api = new HomebridgeAPI();
270
-
271
- const uuid = api.hap.uuid.generate(device.getId());
272
- const accessory = new api.platformAccessory("NAME_FOR_TEST", uuid);
273
-
274
- accessory.addService(api.hap.Service.Switch, 'Powerful mode', 'Powerful_Mode');
275
- accessory.addService(api.hap.Service.Switch, 'Econo mode', 'Econo_Mode');
276
- accessory.addService(api.hap.Service.Switch, 'Streamer mode', 'Streamer_Mode');
277
- accessory.addService(api.hap.Service.Switch, 'Outdoor silent mode', 'Outdoor_Silent_Mode');
278
- accessory.addService(api.hap.Service.Switch, 'Indoor silent mode', 'Indoor_Silent_Mode');
279
- accessory.context['device'] = device;
280
-
281
- const removeServiceSpy = jest.spyOn(accessory, 'removeService').mockImplementation();
282
-
283
- const homebridgeAccessory = new AirConditioningAccessory(new DaikinCloudPlatform(new Logger(), config, api), accessory as unknown as PlatformAccessory<DaikinCloudAccessoryContext>);
284
-
285
-
286
- expect(removeServiceSpy).toHaveBeenNthCalledWith(1, expect.objectContaining({ displayName: 'Powerful mode', subtype: 'Powerful_Mode' }));
287
- expect(removeServiceSpy).toHaveBeenNthCalledWith(2, expect.objectContaining({ displayName: 'Econo mode', subtype: 'Econo_Mode' }));
288
- expect(removeServiceSpy).toHaveBeenNthCalledWith(3, expect.objectContaining({ displayName: 'Streamer mode', subtype: 'Streamer_Mode' }));
289
- expect(removeServiceSpy).toHaveBeenNthCalledWith(4, expect.objectContaining({ displayName: 'Outdoor silent mode', subtype: 'Outdoor_Silent_Mode' }));
290
- expect(removeServiceSpy).toHaveBeenNthCalledWith(5, expect.objectContaining({ displayName: 'Indoor silent mode', subtype: 'Indoor_Silent_Mode' }));
291
-
292
- });
293
-
294
- test('DaikinCloudAirConditioningAccessory Getters', async () => {
295
- const mockApi = { updateDevice: jest.fn().mockResolvedValue(undefined) } as unknown as DaikinApi;
296
- const device = new DaikinCloudDevice(dx4Airco as any, mockApi);
297
-
298
- jest.spyOn(DaikinCloudController.prototype, 'getCloudDevices').mockImplementation(async () => {
299
- return [device];
300
- });
301
-
302
- const config = new MockPlatformConfig(false);
303
- const api = new HomebridgeAPI();
304
-
305
- const uuid = api.hap.uuid.generate(device.getId());
306
- const accessory = new api.platformAccessory(device.getData('climateControl', 'name', undefined).value as string, uuid);
307
- accessory.context['device'] = device;
308
-
309
- const homebridgeAccessory = new AirConditioningAccessory(new DaikinCloudPlatform(new Logger(), config, api), accessory as unknown as PlatformAccessory<DaikinCloudAccessoryContext>);
310
-
311
- expect(await homebridgeAccessory.service.handleActiveStateGet()).toEqual(true);
312
- expect(await homebridgeAccessory.service.handleCurrentTemperatureGet()).toEqual(25);
313
- expect(await homebridgeAccessory.service.handleCoolingThresholdTemperatureGet()).toEqual(25);
314
- expect(await homebridgeAccessory.service.handleRotationSpeedGet()).toEqual(2);
315
- expect(await homebridgeAccessory.service.handleHeatingThresholdTemperatureGet()).toEqual(22);
316
- expect(await homebridgeAccessory.service.handleTargetHeaterCoolerStateGet()).toEqual(1);
317
- expect(await homebridgeAccessory.service.handleSwingModeGet()).toEqual(0);
318
-
319
- // Feature-based getters via FeatureManager
320
- const powerfulFeature = homebridgeAccessory.service.featureManager.getFeature(PowerfulModeFeature);
321
- expect(await powerfulFeature!.handleGet()).toEqual(false);
322
- const econoFeature = homebridgeAccessory.service.featureManager.getFeature(EconoModeFeature);
323
- expect(await econoFeature!.handleGet()).toEqual(false);
324
- const streamerFeature = homebridgeAccessory.service.featureManager.getFeature(StreamerModeFeature);
325
- expect(await streamerFeature!.handleGet()).toEqual(false);
326
- const outdoorSilentFeature = homebridgeAccessory.service.featureManager.getFeature(OutdoorSilentModeFeature);
327
- expect(await outdoorSilentFeature!.handleGet()).toEqual(false);
328
- const indoorSilentFeature = homebridgeAccessory.service.featureManager.getFeature(IndoorSilentModeFeature);
329
- expect(await indoorSilentFeature!.handleGet()).toEqual(false);
330
- });
331
-
332
- test('DaikinCloudAirConditioningAccessory Setters', async () => {
333
- const mockApi = { updateDevice: jest.fn().mockResolvedValue(undefined) } as unknown as DaikinApi;
334
- const device = new DaikinCloudDevice(dx4Airco as any, mockApi);
335
-
336
- jest.spyOn(DaikinCloudController.prototype, 'getCloudDevices').mockImplementation(async () => {
337
- return [device];
338
- });
339
-
340
- const setDataSpy = jest.spyOn(DaikinCloudDevice.prototype, 'setData').mockImplementation();
341
-
342
- const config = new MockPlatformConfig(false);
343
- const api = new HomebridgeAPI();
344
-
345
- const uuid = api.hap.uuid.generate(device.getId());
346
- const accessory = new api.platformAccessory(device.getData('climateControl', 'name', undefined).value as string, uuid);
347
- // device.updateData = () => jest.fn();
348
- accessory.context['device'] = device;
349
-
350
- const homebridgeAccessory = new AirConditioningAccessory(new DaikinCloudPlatform(new Logger(), config, api), accessory as unknown as PlatformAccessory<DaikinCloudAccessoryContext>);
351
-
352
- await homebridgeAccessory.service.handleActiveStateSet(1);
353
- expect(setDataSpy).toHaveBeenNthCalledWith(1, 'climateControl', 'onOffMode', 'on', undefined);
354
-
355
- await homebridgeAccessory.service.handleActiveStateSet(0);
356
- expect(setDataSpy).toHaveBeenNthCalledWith(2, 'climateControl', 'onOffMode', 'off', undefined);
357
-
358
- await homebridgeAccessory.service.handleCoolingThresholdTemperatureSet(21);
359
- expect(setDataSpy).toHaveBeenNthCalledWith(3, 'climateControl', 'temperatureControl', '/operationModes/cooling/setpoints/roomTemperature', 21);
360
-
361
- await homebridgeAccessory.service.handleRotationSpeedSet(50);
362
- expect(setDataSpy).toHaveBeenNthCalledWith(4, 'climateControl', 'fanControl', '/operationModes/heating/fanSpeed/currentMode', 'fixed');
363
- expect(setDataSpy).toHaveBeenNthCalledWith(5, 'climateControl', 'fanControl', '/operationModes/heating/fanSpeed/modes/fixed', 50);
364
-
365
- await homebridgeAccessory.service.handleHeatingThresholdTemperatureSet(25);
366
- expect(setDataSpy).toHaveBeenNthCalledWith(6, 'climateControl', 'temperatureControl', '/operationModes/heating/setpoints/roomTemperature', 25);
367
-
368
- await homebridgeAccessory.service.handleTargetHeaterCoolerStateSet(1);
369
- expect(setDataSpy).toHaveBeenNthCalledWith(7, 'climateControl', 'operationMode', 'heating', undefined);
370
- expect(setDataSpy).toHaveBeenNthCalledWith(8, 'climateControl', 'onOffMode', 'on', undefined);
371
-
372
- await homebridgeAccessory.service.handleSwingModeSet(1);
373
- expect(setDataSpy).toHaveBeenNthCalledWith(9, 'climateControl', 'fanControl', '/operationModes/heating/fanDirection/horizontal/currentMode', 'swing');
374
- expect(setDataSpy).toHaveBeenNthCalledWith(10, 'climateControl', 'fanControl', '/operationModes/heating/fanDirection/vertical/currentMode', 'swing');
375
-
376
- // Feature-based setters via FeatureManager
377
- const powerfulFeature = homebridgeAccessory.service.featureManager.getFeature(PowerfulModeFeature);
378
- await powerfulFeature!.handleSet(true);
379
- expect(setDataSpy).toHaveBeenNthCalledWith(11, 'climateControl', 'powerfulMode', 'on', undefined);
380
-
381
- const econoFeature = homebridgeAccessory.service.featureManager.getFeature(EconoModeFeature);
382
- await econoFeature!.handleSet(true);
383
- expect(setDataSpy).toHaveBeenNthCalledWith(12, 'climateControl', 'econoMode', 'on', undefined);
384
-
385
- const streamerFeature = homebridgeAccessory.service.featureManager.getFeature(StreamerModeFeature);
386
- await streamerFeature!.handleSet(true);
387
- expect(setDataSpy).toHaveBeenNthCalledWith(13, 'climateControl', 'streamerMode', 'on', undefined);
388
-
389
- const outdoorSilentFeature = homebridgeAccessory.service.featureManager.getFeature(OutdoorSilentModeFeature);
390
- await outdoorSilentFeature!.handleSet(true);
391
- expect(setDataSpy).toHaveBeenNthCalledWith(14, 'climateControl', 'outdoorSilentMode', 'on', undefined);
392
-
393
- const indoorSilentFeature = homebridgeAccessory.service.featureManager.getFeature(IndoorSilentModeFeature);
394
- await indoorSilentFeature!.handleSet(true);
395
- expect(setDataSpy).toHaveBeenNthCalledWith(15, 'climateControl', 'fanControl', '/operationModes/heating/fanSpeed/currentMode', 'quiet');
396
- });