test_climate.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. from unittest import IsolatedAsyncioTestCase
  2. from unittest.mock import AsyncMock, patch
  3. from homeassistant.components.climate.const import (
  4. ATTR_FAN_MODE,
  5. ATTR_HVAC_MODE,
  6. ATTR_PRESET_MODE,
  7. ATTR_SWING_MODE,
  8. HVAC_MODE_FAN_ONLY,
  9. HVAC_MODE_OFF,
  10. PRESET_ECO,
  11. PRESET_SLEEP,
  12. SUPPORT_FAN_MODE,
  13. SUPPORT_PRESET_MODE,
  14. SUPPORT_SWING_MODE,
  15. SWING_HORIZONTAL,
  16. SWING_OFF,
  17. )
  18. from homeassistant.const import ATTR_TEMPERATURE, STATE_UNAVAILABLE
  19. from custom_components.tuya_local.fan.climate import GoldairFan
  20. from custom_components.tuya_local.fan.const import (
  21. FAN_MODES,
  22. HVAC_MODE_TO_DPS_MODE,
  23. PRESET_MODE_TO_DPS_MODE,
  24. PRESET_NORMAL,
  25. PROPERTY_TO_DPS_ID,
  26. SWING_MODE_TO_DPS_MODE,
  27. )
  28. from ..const import FAN_PAYLOAD
  29. from ..helpers import assert_device_properties_set
  30. class TestGoldairFan(IsolatedAsyncioTestCase):
  31. def setUp(self):
  32. device_patcher = patch("custom_components.tuya_local.device.TuyaLocalDevice")
  33. self.addCleanup(device_patcher.stop)
  34. self.mock_device = device_patcher.start()
  35. self.subject = GoldairFan(self.mock_device())
  36. self.dps = FAN_PAYLOAD.copy()
  37. self.subject._device.get_property.side_effect = lambda id: self.dps[id]
  38. def test_supported_features(self):
  39. self.assertEqual(
  40. self.subject.supported_features,
  41. SUPPORT_FAN_MODE | SUPPORT_PRESET_MODE | SUPPORT_SWING_MODE,
  42. )
  43. def test_should_poll(self):
  44. self.assertTrue(self.subject.should_poll)
  45. def test_name_returns_device_name(self):
  46. self.assertEqual(self.subject.name, self.subject._device.name)
  47. def test_unique_id_returns_device_unique_id(self):
  48. self.assertEqual(self.subject.unique_id, self.subject._device.unique_id)
  49. def test_device_info_returns_device_info_from_device(self):
  50. self.assertEqual(self.subject.device_info, self.subject._device.device_info)
  51. def test_icon_is_fan(self):
  52. self.assertEqual(self.subject.icon, "mdi:fan")
  53. def test_temperature_unit_returns_device_temperature_unit(self):
  54. self.assertEqual(
  55. self.subject.temperature_unit, self.subject._device.temperature_unit
  56. )
  57. def test_hvac_mode(self):
  58. self.dps[PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE]] = True
  59. self.assertEqual(self.subject.hvac_mode, HVAC_MODE_FAN_ONLY)
  60. self.dps[PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE]] = False
  61. self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
  62. self.dps[PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE]] = None
  63. self.assertEqual(self.subject.hvac_mode, STATE_UNAVAILABLE)
  64. def test_hvac_modes(self):
  65. self.assertEqual(self.subject.hvac_modes, [HVAC_MODE_OFF, HVAC_MODE_FAN_ONLY])
  66. async def test_turn_on(self):
  67. async with assert_device_properties_set(
  68. self.subject._device, {PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE]: True}
  69. ):
  70. await self.subject.async_set_hvac_mode(HVAC_MODE_FAN_ONLY)
  71. async def test_turn_off(self):
  72. async with assert_device_properties_set(
  73. self.subject._device, {PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE]: False}
  74. ):
  75. await self.subject.async_set_hvac_mode(HVAC_MODE_OFF)
  76. def test_preset_mode(self):
  77. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  78. PRESET_NORMAL
  79. ]
  80. self.assertEqual(self.subject.preset_mode, PRESET_NORMAL)
  81. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  82. PRESET_ECO
  83. ]
  84. self.assertEqual(self.subject.preset_mode, PRESET_ECO)
  85. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  86. PRESET_SLEEP
  87. ]
  88. self.assertEqual(self.subject.preset_mode, PRESET_SLEEP)
  89. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = None
  90. self.assertIs(self.subject.preset_mode, None)
  91. def test_preset_modes(self):
  92. self.assertEqual(
  93. self.subject.preset_modes, [PRESET_NORMAL, PRESET_ECO, PRESET_SLEEP]
  94. )
  95. async def test_set_preset_mode_to_normal(self):
  96. async with assert_device_properties_set(
  97. self.subject._device,
  98. {
  99. PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]: PRESET_MODE_TO_DPS_MODE[
  100. PRESET_NORMAL
  101. ]
  102. },
  103. ):
  104. await self.subject.async_set_preset_mode(PRESET_NORMAL)
  105. async def test_set_preset_mode_to_eco(self):
  106. async with assert_device_properties_set(
  107. self.subject._device,
  108. {PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]: PRESET_MODE_TO_DPS_MODE[PRESET_ECO]},
  109. ):
  110. await self.subject.async_set_preset_mode(PRESET_ECO)
  111. async def test_set_preset_mode_to_sleep(self):
  112. async with assert_device_properties_set(
  113. self.subject._device,
  114. {
  115. PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]: PRESET_MODE_TO_DPS_MODE[
  116. PRESET_SLEEP
  117. ]
  118. },
  119. ):
  120. await self.subject.async_set_preset_mode(PRESET_SLEEP)
  121. def test_swing_mode(self):
  122. self.dps[PROPERTY_TO_DPS_ID[ATTR_SWING_MODE]] = SWING_MODE_TO_DPS_MODE[
  123. SWING_OFF
  124. ]
  125. self.assertEqual(self.subject.swing_mode, SWING_OFF)
  126. self.dps[PROPERTY_TO_DPS_ID[ATTR_SWING_MODE]] = SWING_MODE_TO_DPS_MODE[
  127. SWING_HORIZONTAL
  128. ]
  129. self.assertEqual(self.subject.swing_mode, SWING_HORIZONTAL)
  130. self.dps[PROPERTY_TO_DPS_ID[ATTR_SWING_MODE]] = None
  131. self.assertIs(self.subject.swing_mode, None)
  132. def test_swing_modes(self):
  133. self.assertEqual(self.subject.swing_modes, [SWING_OFF, SWING_HORIZONTAL])
  134. async def test_set_swing_mode_to_off(self):
  135. async with assert_device_properties_set(
  136. self.subject._device,
  137. {PROPERTY_TO_DPS_ID[ATTR_SWING_MODE]: SWING_MODE_TO_DPS_MODE[SWING_OFF]},
  138. ):
  139. await self.subject.async_set_swing_mode(SWING_OFF)
  140. async def test_set_swing_mode_to_horizontal(self):
  141. async with assert_device_properties_set(
  142. self.subject._device,
  143. {
  144. PROPERTY_TO_DPS_ID[ATTR_SWING_MODE]: SWING_MODE_TO_DPS_MODE[
  145. SWING_HORIZONTAL
  146. ]
  147. },
  148. ):
  149. await self.subject.async_set_swing_mode(SWING_HORIZONTAL)
  150. def test_fan_modes(self):
  151. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  152. PRESET_NORMAL
  153. ]
  154. self.assertEqual(self.subject.fan_modes, list(range(1, 13)))
  155. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  156. PRESET_ECO
  157. ]
  158. self.assertEqual(self.subject.fan_modes, [1, 2, 3])
  159. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  160. PRESET_SLEEP
  161. ]
  162. self.assertEqual(self.subject.fan_modes, [1, 2, 3])
  163. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = None
  164. self.assertEqual(self.subject.fan_modes, [])
  165. def test_fan_mode_for_normal_preset(self):
  166. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  167. PRESET_NORMAL
  168. ]
  169. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "1"
  170. self.assertEqual(self.subject.fan_mode, 1)
  171. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "6"
  172. self.assertEqual(self.subject.fan_mode, 6)
  173. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "12"
  174. self.assertEqual(self.subject.fan_mode, 12)
  175. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = None
  176. self.assertEqual(self.subject.fan_mode, None)
  177. async def test_set_fan_mode_for_normal_preset(self):
  178. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  179. PRESET_NORMAL
  180. ]
  181. async with assert_device_properties_set(
  182. self.subject._device, {PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]: "6"},
  183. ):
  184. await self.subject.async_set_fan_mode(6)
  185. def test_fan_mode_for_eco_preset(self):
  186. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  187. PRESET_ECO
  188. ]
  189. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "4"
  190. self.assertEqual(self.subject.fan_mode, 1)
  191. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "8"
  192. self.assertEqual(self.subject.fan_mode, 2)
  193. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "12"
  194. self.assertEqual(self.subject.fan_mode, 3)
  195. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = None
  196. self.assertEqual(self.subject.fan_mode, None)
  197. async def test_set_fan_mode_for_eco_preset(self):
  198. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  199. PRESET_ECO
  200. ]
  201. async with assert_device_properties_set(
  202. self.subject._device, {PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]: "4"},
  203. ):
  204. await self.subject.async_set_fan_mode(1)
  205. def test_fan_mode_for_sleep_preset(self):
  206. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  207. PRESET_SLEEP
  208. ]
  209. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "4"
  210. self.assertEqual(self.subject.fan_mode, 1)
  211. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "8"
  212. self.assertEqual(self.subject.fan_mode, 2)
  213. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = "12"
  214. self.assertEqual(self.subject.fan_mode, 3)
  215. self.dps[PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]] = None
  216. self.assertEqual(self.subject.fan_mode, None)
  217. async def test_set_fan_mode_for_sleep_preset(self):
  218. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = PRESET_MODE_TO_DPS_MODE[
  219. PRESET_SLEEP
  220. ]
  221. async with assert_device_properties_set(
  222. self.subject._device, {PROPERTY_TO_DPS_ID[ATTR_FAN_MODE]: "8"},
  223. ):
  224. await self.subject.async_set_fan_mode(2)
  225. async def test_set_fan_mode_does_nothing_when_preset_mode_is_not_set(self):
  226. self.dps[PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE]] = None
  227. with self.assertRaises(
  228. ValueError, msg="Fan mode can only be set when a preset mode is set"
  229. ):
  230. await self.subject.async_set_fan_mode(2)
  231. async def test_update(self):
  232. result = AsyncMock()
  233. self.subject._device.async_refresh.return_value = result()
  234. await self.subject.async_update()
  235. self.subject._device.async_refresh.assert_called_once()
  236. result.assert_awaited()