@mp-consulting/homebridge-daikin-cloud 1.3.6 → 1.3.8

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 (291) 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/index.html +24 -24
  131. package/homebridge-ui/public/lib/kit.css +253 -0
  132. package/homebridge-ui/public/lib/kit.js +133 -0
  133. package/homebridge-ui/public/script.js +957 -898
  134. package/homebridge-ui/public/styles.css +0 -1
  135. package/homebridge-ui/server.js +739 -695
  136. package/package.json +30 -25
  137. package/.claude/settings.json +0 -3
  138. package/.claude/settings.local.json +0 -24
  139. package/CHANGELOG.md +0 -114
  140. package/CLAUDE.md +0 -269
  141. package/config.md +0 -2
  142. package/docs/ARCHITECTURE.md +0 -645
  143. package/docs/IMPLEMENTATION_GUIDE.md +0 -899
  144. package/docs/IMPROVEMENTS_SUMMARY.md +0 -415
  145. package/docs/NEXT_STEPS.md +0 -368
  146. package/docs/Screenshot 2024-07-04 at 18.41.28.png +0 -0
  147. package/docs/TROUBLESHOOTING.md +0 -475
  148. package/docs/api-response-for-BRP069A8x.json +0 -520
  149. package/docs/api-response-for-BRP069C4x-2.json +0 -881
  150. package/docs/api-response-for-BRP069C4x.json +0 -916
  151. package/docs/api-response-for-altherma.json +0 -759
  152. package/docs/api-response-for-altherma2.json +0 -2735
  153. package/docs/api-response-with-multiple-devices-incl-heatpump.json +0 -2544
  154. package/docs/cr-insance-altherma-id-0.json +0 -834
  155. package/docs/mock-air-to-air-dx23.json +0 -759
  156. package/docs/mock-air-to-air-dx4.json +0 -1134
  157. package/docs/mock-airpurifier-with-humidifier.json +0 -732
  158. package/docs/mock-airpurifier.json +0 -450
  159. package/docs/mock-altherma-air-to-water-lan.json +0 -845
  160. package/docs/mock-altherma-air-to-water-wlan.json +0 -845
  161. package/docs/mock-d2cnd-gas-boiler.json +0 -649
  162. package/docs/setpointmode-vs-controlmode-vs-setpoints-vs-sensorydata.txt +0 -6
  163. package/images/fan-speed.jpeg +0 -0
  164. package/images/homekit-controls.jpeg +0 -0
  165. package/images/homekit-settings.jpeg +0 -0
  166. package/images/swing-mode.png +0 -0
  167. package/jest.config.ts +0 -21
  168. package/test/fixtures/altherma-crSense-2.ts +0 -834
  169. package/test/fixtures/altherma-fraction.ts +0 -718
  170. package/test/fixtures/altherma-heat-pump-2.ts +0 -479
  171. package/test/fixtures/altherma-heat-pump.ts +0 -757
  172. package/test/fixtures/altherma-miladcerkic-off.ts +0 -524
  173. package/test/fixtures/altherma-miladcerkic.ts +0 -524
  174. package/test/fixtures/altherma-v1ckoeln.ts +0 -644
  175. package/test/fixtures/altherma-with-embedded-id-zero.ts +0 -834
  176. package/test/fixtures/dx23-airco-2.ts +0 -343
  177. package/test/fixtures/dx23-airco.ts +0 -518
  178. package/test/fixtures/dx4-airco.ts +0 -914
  179. package/test/fixtures/unknown-jan.ts +0 -488
  180. package/test/fixtures/unknown-kitchen-guests.ts +0 -488
  181. package/test/hbConfig/.daikin-mobile-tokenset +0 -8
  182. package/test/hbConfig/.uix-dashboard.json +0 -1
  183. package/test/hbConfig/.uix-secrets +0 -1
  184. package/test/hbConfig/accessories/.cachedAccessories.bak +0 -1
  185. package/test/hbConfig/accessories/cachedAccessories +0 -1
  186. package/test/hbConfig/accessories/uiAccessoriesLayout.json +0 -1
  187. package/test/hbConfig/auth.json +0 -10
  188. package/test/hbConfig/backups/config-backups/config.json.1767953686461 +0 -25
  189. package/test/hbConfig/backups/config-backups/config.json.1767953695236 +0 -29
  190. package/test/hbConfig/backups/config-backups/config.json.1767953814763 +0 -29
  191. package/test/hbConfig/backups/config-backups/config.json.1767953823101 +0 -29
  192. package/test/hbConfig/backups/config-backups/config.json.1767954822835 +0 -29
  193. package/test/hbConfig/backups/config-backups/config.json.1767954859218 +0 -29
  194. package/test/hbConfig/backups/config-backups/config.json.1767960145503 +0 -33
  195. package/test/hbConfig/backups/config-backups/config.json.1767960168068 +0 -44
  196. package/test/hbConfig/backups/config-backups/config.json.1767960170333 +0 -46
  197. package/test/hbConfig/backups/config-backups/config.json.1767960172731 +0 -44
  198. package/test/hbConfig/backups/config-backups/config.json.1767960179323 +0 -44
  199. package/test/hbConfig/backups/config-backups/config.json.1767960182114 +0 -44
  200. package/test/hbConfig/backups/config-backups/config.json.1767960189302 +0 -44
  201. package/test/hbConfig/backups/config-backups/config.json.1767960195194 +0 -44
  202. package/test/hbConfig/backups/config-backups/config.json.1767960197301 +0 -44
  203. package/test/hbConfig/backups/config-backups/config.json.1767960199151 +0 -44
  204. package/test/hbConfig/backups/config-backups/config.json.1767960199667 +0 -44
  205. package/test/hbConfig/backups/config-backups/config.json.1767960329839 +0 -44
  206. package/test/hbConfig/backups/config-backups/config.json.1767960334503 +0 -44
  207. package/test/hbConfig/backups/config-backups/config.json.1767960336208 +0 -44
  208. package/test/hbConfig/backups/config-backups/config.json.1767960338537 +0 -44
  209. package/test/hbConfig/backups/config-backups/config.json.1767963223953 +0 -44
  210. package/test/hbConfig/backups/config-backups/config.json.1767963241753 +0 -44
  211. package/test/hbConfig/backups/config-backups/config.json.1767963252785 +0 -44
  212. package/test/hbConfig/backups/config-backups/config.json.1767963463944 +0 -44
  213. package/test/hbConfig/backups/config-backups/config.json.1767963834475 +0 -44
  214. package/test/hbConfig/backups/config-backups/config.json.1767963838474 +0 -44
  215. package/test/hbConfig/backups/config-backups/config.json.1767963843066 +0 -44
  216. package/test/hbConfig/backups/config-backups/config.json.1767965217715 +0 -44
  217. package/test/hbConfig/backups/config-backups/config.json.1767965419624 +0 -25
  218. package/test/hbConfig/backups/config-backups/config.json.1767965870934 +0 -32
  219. package/test/hbConfig/backups/config-backups/config.json.1767977675045 +0 -32
  220. package/test/hbConfig/backups/config-backups/config.json.1767977677222 +0 -33
  221. package/test/hbConfig/backups/config-backups/config.json.1767977710226 +0 -33
  222. package/test/hbConfig/backups/config-backups/config.json.1767977741397 +0 -33
  223. package/test/hbConfig/backups/config-backups/config.json.1767977977093 +0 -35
  224. package/test/hbConfig/backups/config-backups/config.json.1767977981773 +0 -35
  225. package/test/hbConfig/backups/config-backups/config.json.1767977986514 +0 -35
  226. package/test/hbConfig/backups/config-backups/config.json.1767977991174 +0 -35
  227. package/test/hbConfig/backups/config-backups/config.json.1767979424487 +0 -35
  228. package/test/hbConfig/backups/config-backups/config.json.1767979424987 +0 -35
  229. package/test/hbConfig/backups/config-backups/config.json.1767979432646 +0 -47
  230. package/test/hbConfig/backups/config-backups/config.json.1767979433150 +0 -47
  231. package/test/hbConfig/backups/config-backups/config.json.1767979436933 +0 -47
  232. package/test/hbConfig/backups/config-backups/config.json.1767979437438 +0 -47
  233. package/test/hbConfig/backups/config-backups/config.json.1767979441676 +0 -47
  234. package/test/hbConfig/backups/config-backups/config.json.1767979442180 +0 -47
  235. package/test/hbConfig/backups/config-backups/config.json.1767979466735 +0 -47
  236. package/test/hbConfig/backups/config-backups/config.json.1767979903636 +0 -47
  237. package/test/hbConfig/backups/config-backups/config.json.1767979904135 +0 -47
  238. package/test/hbConfig/backups/config-backups/config.json.1767979906606 +0 -47
  239. package/test/hbConfig/backups/config-backups/config.json.1767979907108 +0 -47
  240. package/test/hbConfig/backups/config-backups/config.json.1767988702341 +0 -47
  241. package/test/hbConfig/backups/config-backups/config.json.1767988702837 +0 -47
  242. package/test/hbConfig/backups/config-backups/config.json.1767988713159 +0 -47
  243. package/test/hbConfig/backups/config-backups/config.json.1767988713664 +0 -47
  244. package/test/hbConfig/backups/config-backups/config.json.1767988918139 +0 -47
  245. package/test/hbConfig/backups/config-backups/config.json.1767988918639 +0 -47
  246. package/test/hbConfig/backups/config-backups/config.json.1767988921120 +0 -47
  247. package/test/hbConfig/backups/config-backups/config.json.1767988921624 +0 -47
  248. package/test/hbConfig/backups/config-backups/config.json.1767988930307 +0 -47
  249. package/test/hbConfig/backups/config-backups/config.json.1767988935070 +0 -47
  250. package/test/hbConfig/backups/config-backups/config.json.1767988935574 +0 -47
  251. package/test/hbConfig/backups/config-backups/config.json.1767989710262 +0 -47
  252. package/test/hbConfig/backups/config-backups/config.json.1767989710760 +0 -47
  253. package/test/hbConfig/backups/config-backups/config.json.1767989729668 +0 -47
  254. package/test/hbConfig/backups/config-backups/config.json.1767990295225 +0 -47
  255. package/test/hbConfig/backups/config-backups/config.json.1767990479921 +0 -47
  256. package/test/hbConfig/backups/config-backups/config.json.1767990481702 +0 -49
  257. package/test/hbConfig/backups/instance-backups/homebridge-backup-1E4A432551BA.1768010187391.tar.gz +0 -0
  258. package/test/hbConfig/backups/instance-backups/homebridge-backup-1E4A432551BA.1768096587387.tar.gz +0 -0
  259. package/test/hbConfig/backups/instance-backups/homebridge-backup-1E4A432551BA.1768182987404.tar.gz +0 -0
  260. package/test/hbConfig/config.json +0 -47
  261. package/test/hbConfig/daikin-cloud-certs/server.crt +0 -22
  262. package/test/hbConfig/daikin-cloud-certs/server.key +0 -28
  263. package/test/hbConfig/persist/AccessoryInfo.1E4A432551BA.json +0 -1
  264. package/test/hbConfig/persist/IdentifierCache.1E4A432551BA.json +0 -1
  265. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14758 +0 -1
  266. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14759 +0 -1
  267. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14760 +0 -1
  268. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14761 +0 -1
  269. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14762 +0 -1
  270. package/test/hbConfig/tmp/daikin_request/api.onecta.daikineurope.com_01-09-2026-23-29-52/request_14764 +0 -1
  271. package/test/helpers/test-isolation.ts +0 -228
  272. package/test/integration/air-conditioning.test.ts +0 -396
  273. package/test/integration/altherma.test.ts +0 -279
  274. package/test/integration/platform.test.ts +0 -118
  275. package/test/mobile-tokens.json +0 -8
  276. package/test/mocks/index.ts +0 -27
  277. package/test/test-gigya-auth.js +0 -443
  278. package/test/test-mobile-oauth.js +0 -175
  279. package/test/test-websocket-mobile.js +0 -123
  280. package/test/test-websocket.js +0 -116
  281. package/test/unit/api/__snapshots__/daikinCloud.test.ts.snap +0 -1320
  282. package/test/unit/api/daikin-api.test.ts +0 -442
  283. package/test/unit/api/daikin-cloud-repository.test.ts +0 -107
  284. package/test/unit/api/daikin-oauth.test.ts +0 -214
  285. package/test/unit/api/daikinCloud.test.ts +0 -12
  286. package/test/unit/api/token-storage.test.ts +0 -90
  287. package/test/unit/config/config-manager.test.ts +0 -271
  288. package/test/unit/device/daikin-device.test.ts +0 -73
  289. package/test/unit/services/hot-water-tank.service.test.ts +0 -123
  290. package/test/unit/utils/log-context.test.ts +0 -271
  291. 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
- });