test_fan.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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. if arg == fan.DEVICE_GET_BASIC_SETTINGS_KEY:
  65. return firmware_info
  66. return None
  67. fan_device._get_basic_info = AsyncMock(side_effect=mock_get_basic_info)
  68. assert await fan_device.get_basic_info() is None
  69. @pytest.mark.asyncio
  70. @pytest.mark.parametrize(
  71. ("basic_info", "firmware_info", "result"),
  72. [
  73. (
  74. bytearray(b"\x01\x02W\x82g\xf5\xde4\x01=dPP\x03\x14P\x00\x00\x00\x00"),
  75. bytearray(b"\x01W\x0b\x17\x01"),
  76. [87, True, False, "normal", 61, 1.1],
  77. ),
  78. (
  79. bytearray(b"\x01\x02U\xc2g\xf5\xde4\x04+dPP\x03\x14P\x00\x00\x00\x00"),
  80. bytearray(b"\x01U\x0b\x17\x01"),
  81. [85, True, True, "baby", 43, 1.1],
  82. ),
  83. ],
  84. )
  85. async def test_get_basic_info(basic_info, firmware_info, result):
  86. fan_device = create_device_for_command_testing()
  87. async def mock_get_basic_info(arg):
  88. if arg == fan.COMMAND_GET_BASIC_INFO:
  89. return basic_info
  90. if arg == fan.DEVICE_GET_BASIC_SETTINGS_KEY:
  91. return firmware_info
  92. return None
  93. fan_device._get_basic_info = AsyncMock(side_effect=mock_get_basic_info)
  94. info = await fan_device.get_basic_info()
  95. assert info["battery"] == result[0]
  96. assert info["isOn"] == result[1]
  97. assert info["oscillating"] == result[2]
  98. assert info["mode"] == result[3]
  99. assert info["speed"] == result[4]
  100. assert info["firmware"] == result[5]
  101. @pytest.mark.asyncio
  102. async def test_set_preset_mode():
  103. fan_device = create_device_for_command_testing({"mode": "baby"})
  104. await fan_device.set_preset_mode("baby")
  105. assert fan_device.get_current_mode() == "baby"
  106. @pytest.mark.asyncio
  107. async def test_set_set_percentage_with_speed_is_0():
  108. fan_device = create_device_for_command_testing({"speed": 0, "isOn": False})
  109. await fan_device.turn_off()
  110. assert fan_device.get_current_percentage() == 0
  111. assert fan_device.is_on() is False
  112. @pytest.mark.asyncio
  113. async def test_set_set_percentage():
  114. fan_device = create_device_for_command_testing({"speed": 80})
  115. await fan_device.set_percentage(80)
  116. assert fan_device.get_current_percentage() == 80
  117. @pytest.mark.asyncio
  118. async def test_set_not_oscillation():
  119. fan_device = create_device_for_command_testing({"oscillating": False})
  120. await fan_device.set_oscillation(False)
  121. assert fan_device.get_oscillating_state() is False
  122. @pytest.mark.asyncio
  123. async def test_set_oscillation():
  124. fan_device = create_device_for_command_testing({"oscillating": True})
  125. await fan_device.set_oscillation(True)
  126. assert fan_device.get_oscillating_state() is True
  127. @pytest.mark.asyncio
  128. async def test_turn_on():
  129. fan_device = create_device_for_command_testing({"isOn": True})
  130. await fan_device.turn_on()
  131. assert fan_device.is_on() is True
  132. @pytest.mark.asyncio
  133. async def test_turn_off():
  134. fan_device = create_device_for_command_testing({"isOn": False})
  135. await fan_device.turn_off()
  136. assert fan_device.is_on() is False
  137. def test_get_modes():
  138. assert FanMode.get_modes() == ["normal", "natural", "sleep", "baby"]