test_base_cover.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. from unittest.mock import AsyncMock, Mock
  2. import pytest
  3. from bleak.backends.device import BLEDevice
  4. from switchbot import SwitchBotAdvertisement, SwitchbotModel
  5. from switchbot.devices import base_cover, blind_tilt
  6. from .test_adv_parser import generate_ble_device
  7. def create_device_for_command_testing(position=50, calibration=True):
  8. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  9. base_cover_device = base_cover.SwitchbotBaseCover(False, ble_device)
  10. base_cover_device.update_from_advertisement(
  11. make_advertisement_data(ble_device, True, position, calibration)
  12. )
  13. base_cover_device._send_multiple_commands = AsyncMock()
  14. base_cover_device.update = AsyncMock()
  15. return base_cover_device
  16. def make_advertisement_data(
  17. ble_device: BLEDevice, in_motion: bool, position: int, calibration: bool = True
  18. ):
  19. """Set advertisement data with defaults."""
  20. return SwitchBotAdvertisement(
  21. address="aa:bb:cc:dd:ee:ff",
  22. data={
  23. "rawAdvData": b"c\xc0X\x00\x11\x04",
  24. "data": {
  25. "calibration": calibration,
  26. "battery": 88,
  27. "inMotion": in_motion,
  28. "tilt": position,
  29. "lightLevel": 1,
  30. "deviceChain": 1,
  31. },
  32. "isEncrypted": False,
  33. "model": "c",
  34. "modelFriendlyName": "Curtain",
  35. "modelName": SwitchbotModel.CURTAIN,
  36. },
  37. device=ble_device,
  38. rssi=-80,
  39. active=True,
  40. )
  41. @pytest.mark.asyncio
  42. async def test_send_multiple_commands():
  43. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  44. base_cover_device = base_cover.SwitchbotBaseCover(False, ble_device)
  45. base_cover_device.update_from_advertisement(
  46. make_advertisement_data(ble_device, True, 50, True)
  47. )
  48. base_cover_device._send_command = AsyncMock()
  49. base_cover_device._check_command_result = Mock(return_value=True)
  50. await base_cover_device._send_multiple_commands(blind_tilt.OPEN_KEYS)
  51. assert base_cover_device._send_command.await_count == 2
  52. @pytest.mark.asyncio
  53. async def test_stop():
  54. base_cover_device = create_device_for_command_testing()
  55. await base_cover_device.stop()
  56. base_cover_device._send_multiple_commands.assert_awaited_once_with(
  57. base_cover.STOP_KEYS
  58. )
  59. @pytest.mark.asyncio
  60. async def test_set_position():
  61. base_cover_device = create_device_for_command_testing()
  62. await base_cover_device.set_position(50)
  63. base_cover_device._send_multiple_commands.assert_awaited_once()
  64. @pytest.mark.asyncio
  65. @pytest.mark.parametrize("data_value", [(None), (b"\x07"), (b"\x00")])
  66. async def test_get_extended_info_adv_returns_none_when_bad_data(data_value):
  67. base_cover_device = create_device_for_command_testing()
  68. base_cover_device._send_command = AsyncMock(return_value=data_value)
  69. assert await base_cover_device.get_extended_info_adv() is None
  70. @pytest.mark.asyncio
  71. async def test_get_extended_info_adv_returns_single_device():
  72. base_cover_device = create_device_for_command_testing()
  73. base_cover_device._send_command = AsyncMock(
  74. return_value=bytes([0, 50, 20, 0, 0, 0, 0])
  75. )
  76. ext_result = await base_cover_device.get_extended_info_adv()
  77. assert ext_result["device0"]["battery"] == 50
  78. assert ext_result["device0"]["firmware"] == 2
  79. assert "device1" not in ext_result
  80. @pytest.mark.asyncio
  81. async def test_get_extended_info_adv_returns_both_devices():
  82. base_cover_device = create_device_for_command_testing()
  83. base_cover_device._send_command = AsyncMock(
  84. return_value=bytes([0, 50, 20, 0, 10, 30, 0])
  85. )
  86. ext_result = await base_cover_device.get_extended_info_adv()
  87. assert ext_result["device0"]["battery"] == 50
  88. assert ext_result["device0"]["firmware"] == 2
  89. assert ext_result["device1"]["battery"] == 10
  90. assert ext_result["device1"]["firmware"] == 3
  91. @pytest.mark.asyncio
  92. @pytest.mark.parametrize(
  93. "data_value,result",
  94. [
  95. (0, "not_charging"),
  96. (1, "charging_by_adapter"),
  97. (2, "charging_by_solar"),
  98. (3, "fully_charged"),
  99. (4, "solar_not_charging"),
  100. (5, "charging_error"),
  101. ],
  102. )
  103. async def test_get_extended_info_adv_returns_device0_charge_states(data_value, result):
  104. base_cover_device = create_device_for_command_testing()
  105. base_cover_device._send_command = AsyncMock(
  106. return_value=bytes([0, 50, 20, data_value, 10, 30, 0])
  107. )
  108. ext_result = await base_cover_device.get_extended_info_adv()
  109. assert ext_result["device0"]["stateOfCharge"] == result
  110. @pytest.mark.asyncio
  111. @pytest.mark.parametrize(
  112. "data_value,result",
  113. [
  114. (0, "not_charging"),
  115. (1, "charging_by_adapter"),
  116. (2, "charging_by_solar"),
  117. (3, "fully_charged"),
  118. (4, "solar_not_charging"),
  119. (5, "charging_error"),
  120. ],
  121. )
  122. async def test_get_extended_info_adv_returns_device1_charge_states(data_value, result):
  123. base_cover_device = create_device_for_command_testing()
  124. base_cover_device._send_command = AsyncMock(
  125. return_value=bytes([0, 50, 20, 0, 10, 30, data_value])
  126. )
  127. ext_result = await base_cover_device.get_extended_info_adv()
  128. assert ext_result["device1"]["stateOfCharge"] == result