test_deta_fan.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. from unittest import IsolatedAsyncioTestCase, skip
  2. from unittest.mock import AsyncMock, patch
  3. from homeassistant.components.fan import (
  4. SUPPORT_SET_SPEED,
  5. )
  6. from homeassistant.const import STATE_UNAVAILABLE
  7. from custom_components.tuya_local.generic.fan import TuyaLocalFan
  8. from custom_components.tuya_local.generic.light import TuyaLocalLight
  9. from custom_components.tuya_local.generic.switch import TuyaLocalSwitch
  10. from custom_components.tuya_local.helpers.device_config import TuyaDeviceConfig
  11. from ..const import DETA_FAN_PAYLOAD
  12. from ..helpers import assert_device_properties_set
  13. SWITCH_DPS = "1"
  14. SPEED_DPS = "3"
  15. LIGHT_DPS = "9"
  16. MASTER_DPS = "101"
  17. TIMER_DPS = "102"
  18. LIGHT_TIMER_DPS = "103"
  19. class TestDetaFan(IsolatedAsyncioTestCase):
  20. def setUp(self):
  21. device_patcher = patch("custom_components.tuya_local.device.TuyaLocalDevice")
  22. self.addCleanup(device_patcher.stop)
  23. self.mock_device = device_patcher.start()
  24. cfg = TuyaDeviceConfig("deta_fan.yaml")
  25. entities = {}
  26. entities[cfg.primary_entity.entity] = cfg.primary_entity
  27. for e in cfg.secondary_entities():
  28. entities[e.entity] = e
  29. self.fan_name = (
  30. "missing" if "fan" not in entities.keys() else entities["fan"].name
  31. )
  32. self.light_name = (
  33. "missing" if "light" not in entities.keys() else entities["light"].name
  34. )
  35. self.switch_name = (
  36. "missing" if "switch" not in entities.keys() else entities["switch"].name
  37. )
  38. self.subject = TuyaLocalFan(self.mock_device(), entities.get("fan"))
  39. self.light = TuyaLocalLight(self.mock_device(), entities.get("light"))
  40. self.switch = TuyaLocalSwitch(self.mock_device(), entities.get("switch"))
  41. self.dps = DETA_FAN_PAYLOAD.copy()
  42. self.subject._device.get_property.side_effect = lambda id: self.dps[id]
  43. def test_supported_features(self):
  44. self.assertEqual(
  45. self.subject.supported_features,
  46. SUPPORT_SET_SPEED,
  47. )
  48. def test_should_poll(self):
  49. self.assertTrue(self.subject.should_poll)
  50. self.assertTrue(self.light.should_poll)
  51. self.assertTrue(self.switch.should_poll)
  52. def test_name_returns_device_name(self):
  53. self.assertEqual(self.subject.name, self.subject._device.name)
  54. self.assertEqual(self.light.name, self.subject._device.name)
  55. self.assertEqual(self.switch.name, self.subject._device.name)
  56. def test_friendly_name_returns_config_name(self):
  57. self.assertEqual(self.subject.friendly_name, self.fan_name)
  58. self.assertEqual(self.light.friendly_name, self.light_name)
  59. self.assertEqual(self.switch.friendly_name, self.switch_name)
  60. def test_unique_id_returns_device_unique_id(self):
  61. self.assertEqual(self.subject.unique_id, self.subject._device.unique_id)
  62. self.assertEqual(self.light.unique_id, self.subject._device.unique_id)
  63. self.assertEqual(self.switch.unique_id, self.subject._device.unique_id)
  64. def test_device_info_returns_device_info_from_device(self):
  65. self.assertEqual(self.subject.device_info, self.subject._device.device_info)
  66. self.assertEqual(self.light.device_info, self.subject._device.device_info)
  67. self.assertEqual(self.switch.device_info, self.subject._device.device_info)
  68. def test_is_on(self):
  69. self.dps[SWITCH_DPS] = True
  70. self.assertTrue(self.subject.is_on)
  71. self.dps[SWITCH_DPS] = False
  72. self.assertFalse(self.subject.is_on)
  73. self.dps[SWITCH_DPS] = None
  74. self.assertEqual(self.subject.is_on, STATE_UNAVAILABLE)
  75. async def test_turn_on(self):
  76. async with assert_device_properties_set(
  77. self.subject._device, {SWITCH_DPS: True}
  78. ):
  79. await self.subject.async_turn_on()
  80. async def test_turn_off(self):
  81. async with assert_device_properties_set(
  82. self.subject._device, {SWITCH_DPS: False}
  83. ):
  84. await self.subject.async_turn_off()
  85. def test_speed(self):
  86. self.dps[SPEED_DPS] = "1"
  87. self.assertAlmostEqual(self.subject.percentage, 33.3, 1)
  88. def test_speed_step(self):
  89. self.assertAlmostEqual(self.subject.percentage_step, 33.3, 1)
  90. async def test_set_speed(self):
  91. async with assert_device_properties_set(self.subject._device, {SPEED_DPS: 2}):
  92. await self.subject.async_set_percentage(66.7)
  93. async def test_auto_stringify_speed(self):
  94. self.dps[SPEED_DPS] = "1"
  95. self.assertAlmostEqual(self.subject.percentage, 33.3, 1)
  96. async with assert_device_properties_set(self.subject._device, {SPEED_DPS: "2"}):
  97. await self.subject.async_set_percentage(66.7)
  98. async def test_set_speed_snaps(self):
  99. async with assert_device_properties_set(self.subject._device, {SPEED_DPS: 2}):
  100. await self.subject.async_set_percentage(55)
  101. def test_device_state_attributes(self):
  102. self.dps[TIMER_DPS] = "5"
  103. self.dps[LIGHT_TIMER_DPS] = "6"
  104. self.assertEqual(self.subject.device_state_attributes, {"timer": 5})
  105. self.assertEqual(self.light.device_state_attributes, {"timer": 6})
  106. def test_light_is_on(self):
  107. self.dps[LIGHT_DPS] = True
  108. self.assertTrue(self.light.is_on)
  109. self.dps[LIGHT_DPS] = False
  110. self.assertFalse(self.light.is_on)
  111. async def test_light_turn_on(self):
  112. async with assert_device_properties_set(self.light._device, {LIGHT_DPS: True}):
  113. await self.light.async_turn_on()
  114. async def test_light_turn_off(self):
  115. async with assert_device_properties_set(self.light._device, {LIGHT_DPS: False}):
  116. await self.light.async_turn_off()
  117. def test_switch_is_on(self):
  118. self.dps[MASTER_DPS] = True
  119. self.assertTrue(self.switch.is_on)
  120. self.dps[MASTER_DPS] = False
  121. self.assertFalse(self.switch.is_on)
  122. self.dps[MASTER_DPS] = None
  123. self.assertEqual(self.switch.is_on, STATE_UNAVAILABLE)
  124. async def test_switch_turn_on(self):
  125. async with assert_device_properties_set(
  126. self.switch._device, {MASTER_DPS: True}
  127. ):
  128. await self.switch.async_turn_on()
  129. async def test_switch_turn_off(self):
  130. async with assert_device_properties_set(
  131. self.light._device, {MASTER_DPS: False}
  132. ):
  133. await self.switch.async_turn_off()
  134. async def test_update(self):
  135. result = AsyncMock()
  136. self.subject._device.async_refresh.return_value = result()
  137. await self.subject.async_update()
  138. self.subject._device.async_refresh.assert_called_once()
  139. result.assert_awaited()