test_curtain.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import pytest
  2. from typing import Any
  3. from bleak.backends.device import BLEDevice
  4. from switchbot import SwitchBotAdvertisement, SwitchbotModel
  5. from switchbot.devices import curtain
  6. from test_adv_parser import generate_ble_device
  7. from unittest.mock import Mock
  8. def set_advertisement_data(ble_device: BLEDevice, in_motion: bool, position: int):
  9. """Set advertisement data with defaults."""
  10. return SwitchBotAdvertisement(
  11. address="aa:bb:cc:dd:ee:ff",
  12. data={
  13. "rawAdvData": b"c\xc0X\x00\x11\x04",
  14. "data": {
  15. "calibration": True,
  16. "battery": 88,
  17. "inMotion": in_motion,
  18. "position": position,
  19. "lightLevel": 1,
  20. "deviceChain": 1,
  21. },
  22. "isEncrypted": False,
  23. "model": "c",
  24. "modelFriendlyName": "Curtain",
  25. "modelName": SwitchbotModel.CURTAIN,
  26. },
  27. device=ble_device,
  28. rssi=-80,
  29. active=True,
  30. )
  31. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  32. def test_device_passive_not_in_motion(reverse_mode):
  33. """Test passive not in motion advertisement."""
  34. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  35. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  36. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, False, 0))
  37. assert curtain_device.is_opening() is False
  38. assert curtain_device.is_closing() is False
  39. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  40. def test_device_passive_opening(reverse_mode):
  41. """Test passive opening advertisement."""
  42. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  43. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  44. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 0))
  45. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 10))
  46. assert curtain_device.is_opening() is True
  47. assert curtain_device.is_closing() is False
  48. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  49. def test_device_passive_closing(reverse_mode):
  50. """Test passive closing advertisement."""
  51. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  52. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  53. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 100))
  54. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 90))
  55. assert curtain_device.is_opening() is False
  56. assert curtain_device.is_closing() is True
  57. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  58. def test_device_passive_opening_then_stop(reverse_mode):
  59. """Test passive stopped after opening advertisement."""
  60. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  61. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  62. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 0))
  63. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 10))
  64. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, False, 10))
  65. assert curtain_device.is_opening() is False
  66. assert curtain_device.is_closing() is False
  67. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  68. def test_device_passive_closing_then_stop(reverse_mode):
  69. """Test passive stopped after closing advertisement."""
  70. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  71. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  72. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 100))
  73. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 90))
  74. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, False, 90))
  75. assert curtain_device.is_opening() is False
  76. assert curtain_device.is_closing() is False
  77. @pytest.mark.asyncio
  78. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  79. async def test_device_active_not_in_motion(reverse_mode):
  80. """Test active not in motion."""
  81. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  82. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  83. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, False, 0))
  84. basic_info = bytes([0,0,0,0,0,0,100,0])
  85. async def custom_implementation():
  86. return basic_info
  87. curtain_device._get_basic_info = Mock(side_effect=custom_implementation)
  88. await curtain_device.get_basic_info()
  89. assert curtain_device.is_opening() is False
  90. assert curtain_device.is_closing() is False
  91. @pytest.mark.asyncio
  92. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  93. async def test_device_active_opening(reverse_mode):
  94. """Test active opening."""
  95. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  96. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  97. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 0))
  98. basic_info = bytes([0,0,0,0,0,67,10,0])
  99. async def custom_implementation():
  100. return basic_info
  101. curtain_device._get_basic_info = Mock(side_effect=custom_implementation)
  102. await curtain_device.get_basic_info()
  103. assert curtain_device.is_opening() is True
  104. assert curtain_device.is_closing() is False
  105. @pytest.mark.asyncio
  106. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  107. async def test_device_active_closing(reverse_mode):
  108. """Test active closing."""
  109. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  110. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  111. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 100))
  112. basic_info = bytes([0,0,0,0,0,67,90,0])
  113. async def custom_implementation():
  114. return basic_info
  115. curtain_device._get_basic_info = Mock(side_effect=custom_implementation)
  116. await curtain_device.get_basic_info()
  117. assert curtain_device.is_opening() is False
  118. assert curtain_device.is_closing() is True
  119. @pytest.mark.asyncio
  120. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  121. async def test_device_active_opening_then_stop(reverse_mode):
  122. """Test active stopped after opening."""
  123. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  124. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  125. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 0))
  126. basic_info = bytes([0,0,0,0,0,67,10,0])
  127. async def custom_implementation():
  128. return basic_info
  129. curtain_device._get_basic_info = Mock(side_effect=custom_implementation)
  130. await curtain_device.get_basic_info()
  131. basic_info = bytes([0,0,0,0,0,0,10,0])
  132. await curtain_device.get_basic_info()
  133. assert curtain_device.is_opening() is False
  134. assert curtain_device.is_closing() is False
  135. @pytest.mark.asyncio
  136. @pytest.mark.parametrize("reverse_mode", [(True),(False)])
  137. async def test_device_active_closing_then_stop(reverse_mode):
  138. """Test active stopped after closing."""
  139. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  140. curtain_device = curtain.SwitchbotCurtain(ble_device, reverse_mode=reverse_mode)
  141. curtain_device.update_from_advertisement(set_advertisement_data(ble_device, True, 100))
  142. basic_info = bytes([0,0,0,0,0,67,90,0])
  143. async def custom_implementation():
  144. return basic_info
  145. curtain_device._get_basic_info = Mock(side_effect=custom_implementation)
  146. await curtain_device.get_basic_info()
  147. basic_info = bytes([0,0,0,0,0,0,90,0])
  148. await curtain_device.get_basic_info()
  149. assert curtain_device.is_opening() is False
  150. assert curtain_device.is_closing() is False