test_fan.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. from unittest.mock import AsyncMock
  2. import pytest
  3. from bleak.backends.device import BLEDevice
  4. from switchbot import SwitchBotAdvertisement, SwitchbotModel
  5. from switchbot.const.fan import FanMode
  6. from switchbot.devices import fan
  7. from .test_adv_parser import generate_ble_device
  8. def create_device_for_command_testing(init_data: dict | None = None):
  9. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  10. fan_device = fan.SwitchbotFan(ble_device)
  11. fan_device.update_from_advertisement(make_advertisement_data(ble_device, init_data))
  12. fan_device._send_command = AsyncMock()
  13. fan_device.update = AsyncMock()
  14. return fan_device
  15. def make_advertisement_data(ble_device: BLEDevice, init_data: dict | None = None):
  16. """Set advertisement data with defaults."""
  17. if init_data is None:
  18. init_data = {}
  19. return SwitchBotAdvertisement(
  20. address="aa:bb:cc:dd:ee:ff",
  21. data={
  22. "rawAdvData": b"~\x00R",
  23. "data": {
  24. "isOn": True,
  25. "mode": "NORMAL",
  26. "nightLight": 3,
  27. "oscillating": False,
  28. "battery": 60,
  29. "speed": 50,
  30. }
  31. | init_data,
  32. "isEncrypted": False,
  33. "model": ",",
  34. "modelFriendlyName": "Circulator Fan",
  35. "modelName": SwitchbotModel.CIRCULATOR_FAN,
  36. },
  37. device=ble_device,
  38. rssi=-80,
  39. active=True,
  40. )
  41. @pytest.mark.asyncio
  42. @pytest.mark.parametrize(
  43. "response, expected",
  44. [
  45. (b"\x00", None),
  46. (b"\x07", None),
  47. (b"\x01\x02\x03", b"\x01\x02\x03"),
  48. ],
  49. )
  50. async def test__get_basic_info(response, expected):
  51. fan_device = create_device_for_command_testing()
  52. fan_device._send_command = AsyncMock(return_value=response)
  53. result = await fan_device._get_basic_info(cmd="TEST_CMD")
  54. assert result == expected
  55. @pytest.mark.asyncio
  56. @pytest.mark.parametrize(
  57. "basic_info,firmware_info", [(True, False), (False, True), (False, False)]
  58. )
  59. async def test_get_basic_info_returns_none(basic_info, firmware_info):
  60. fan_device = create_device_for_command_testing()
  61. async def mock_get_basic_info(arg):
  62. if arg == fan.COMMAND_GET_BASIC_INFO:
  63. return basic_info
  64. elif arg == fan.DEVICE_GET_BASIC_SETTINGS_KEY:
  65. return firmware_info
  66. fan_device._get_basic_info = AsyncMock(side_effect=mock_get_basic_info)
  67. assert await fan_device.get_basic_info() is None
  68. @pytest.mark.asyncio
  69. @pytest.mark.parametrize(
  70. "basic_info,firmware_info,result",
  71. [
  72. (
  73. bytearray(b"\x01\x02W\x82g\xf5\xde4\x01=dPP\x03\x14P\x00\x00\x00\x00"),
  74. bytearray(b"\x01W\x0b\x17\x01"),
  75. [87, True, False, "NORMAL", 61, 1.1],
  76. ),
  77. (
  78. bytearray(b"\x01\x02U\xc2g\xf5\xde4\x04+dPP\x03\x14P\x00\x00\x00\x00"),
  79. bytearray(b"\x01U\x0b\x17\x01"),
  80. [85, True, True, "BABY", 43, 1.1],
  81. ),
  82. ],
  83. )
  84. async def test_get_basic_info(basic_info, firmware_info, result):
  85. fan_device = create_device_for_command_testing()
  86. async def mock_get_basic_info(arg):
  87. if arg == fan.COMMAND_GET_BASIC_INFO:
  88. return basic_info
  89. elif arg == fan.DEVICE_GET_BASIC_SETTINGS_KEY:
  90. return firmware_info
  91. fan_device._get_basic_info = AsyncMock(side_effect=mock_get_basic_info)
  92. info = await fan_device.get_basic_info()
  93. assert info["battery"] == result[0]
  94. assert info["isOn"] == result[1]
  95. assert info["oscillating"] == result[2]
  96. assert info["mode"] == result[3]
  97. assert info["speed"] == result[4]
  98. assert info["firmware"] == result[5]
  99. @pytest.mark.asyncio
  100. async def test_set_preset_mode():
  101. fan_device = create_device_for_command_testing({"mode": "BABY"})
  102. await fan_device.set_preset_mode("BABY")
  103. assert fan_device.get_current_mode() == "BABY"
  104. @pytest.mark.asyncio
  105. async def test_set_set_percentage_with_speed_is_0():
  106. fan_device = create_device_for_command_testing({"speed": 0, "isOn": False})
  107. await fan_device.turn_off()
  108. assert fan_device.get_current_percentage() == 0
  109. assert fan_device.is_on() is False
  110. @pytest.mark.asyncio
  111. async def test_set_set_percentage():
  112. fan_device = create_device_for_command_testing({"speed": 80})
  113. await fan_device.set_percentage(80)
  114. assert fan_device.get_current_percentage() == 80
  115. @pytest.mark.asyncio
  116. async def test_set_not_oscillation():
  117. fan_device = create_device_for_command_testing({"oscillating": False})
  118. await fan_device.set_oscillation(False)
  119. assert fan_device.get_oscillating_state() is False
  120. @pytest.mark.asyncio
  121. async def test_set_oscillation():
  122. fan_device = create_device_for_command_testing({"oscillating": True})
  123. await fan_device.set_oscillation(True)
  124. assert fan_device.get_oscillating_state() is True
  125. @pytest.mark.asyncio
  126. async def test_turn_on():
  127. fan_device = create_device_for_command_testing({"isOn": True})
  128. await fan_device.turn_on()
  129. assert fan_device.is_on() is True
  130. @pytest.mark.asyncio
  131. async def test_turn_off():
  132. fan_device = create_device_for_command_testing({"isOn": False})
  133. await fan_device.turn_off()
  134. assert fan_device.is_on() is False
  135. def test_get_modes():
  136. assert FanMode.get_modes() == ["NORMAL", "NATURAL", "SLEEP", "BABY"]