test_ceiling_light.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. from unittest.mock import AsyncMock, MagicMock
  2. import pytest
  3. from bleak.backends.device import BLEDevice
  4. from switchbot import SwitchBotAdvertisement, SwitchbotModel
  5. from switchbot.devices import ceiling_light
  6. from .test_adv_parser import generate_ble_device
  7. def create_device_for_command_testing(init_data: dict | None = None):
  8. ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
  9. device = ceiling_light.SwitchbotCeilingLight(ble_device)
  10. device.update_from_advertisement(make_advertisement_data(ble_device, init_data))
  11. device._send_command = AsyncMock()
  12. device._check_command_result = MagicMock()
  13. device.update = AsyncMock()
  14. return 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"q\x00",
  23. "data": {
  24. "brightness": 1,
  25. "color_mode": 1,
  26. "cw": 6387,
  27. "isOn": False,
  28. "sequence_number": 10,
  29. }
  30. | init_data,
  31. "isEncrypted": False,
  32. "model": b"q\x00",
  33. "modelFriendlyName": "Ceiling Light",
  34. "modelName": SwitchbotModel.CEILING_LIGHT,
  35. },
  36. device=ble_device,
  37. rssi=-80,
  38. active=True,
  39. )
  40. @pytest.mark.asyncio
  41. async def test_default_info():
  42. """Test default initialization of the ceiling light."""
  43. device = create_device_for_command_testing()
  44. assert device.rgb is None
  45. device._state = {"cw": 3200}
  46. assert device.is_on() is False
  47. assert device.on is False
  48. assert device.color_mode == ceiling_light.CeilingLightColorMode.NIGHT
  49. assert device.color_modes == {ceiling_light.CeilingLightColorMode.COLOR_TEMP}
  50. assert device.color_temp == 3200
  51. assert device.brightness == 1
  52. assert device.min_temp == 2700
  53. assert device.max_temp == 6500
  54. assert device.get_effect_list is None
  55. @pytest.mark.asyncio
  56. @pytest.mark.parametrize(
  57. ("basic_info", "version_info"), [(True, False), (False, True), (False, False)]
  58. )
  59. async def test_get_basic_info_returns_none(basic_info, version_info):
  60. device = create_device_for_command_testing()
  61. async def mock_get_basic_info(arg):
  62. if arg == ceiling_light.DEVICE_GET_BASIC_SETTINGS_KEY:
  63. return basic_info
  64. if arg == ceiling_light.DEVICE_GET_VERSION_KEY:
  65. return version_info
  66. return None
  67. device._get_basic_info = AsyncMock(side_effect=mock_get_basic_info)
  68. assert await device.get_basic_info() is None
  69. @pytest.mark.asyncio
  70. @pytest.mark.parametrize(
  71. ("info_data", "result"),
  72. [
  73. (
  74. {
  75. "basic_info": b"\x01\x80=\x0f\xa1\x00\x01",
  76. "version_info": b"\x01d\x15\x0f\x00\x00\x00\x00\x00\x00\x00\n\x00",
  77. },
  78. [True, 61, 4001, 0, 2.1],
  79. ),
  80. (
  81. {
  82. "basic_info": b"\x01\x80\x0e\x12B\x00\x01",
  83. "version_info": b"\x01d\x15\x0f\x00\x00\x00\x00\x00\x00\x00\n\x00",
  84. },
  85. [True, 14, 4674, 0, 2.1],
  86. ),
  87. (
  88. {
  89. "basic_info": b"\x01\x00\x0e\x10\x96\x00\x01",
  90. "version_info": b"\x01d\x15\x0f\x00\x00\x00\x00\x00\x00\x00\n\x00",
  91. },
  92. [False, 14, 4246, 0, 2.1],
  93. ),
  94. ],
  95. )
  96. async def test_get_basic_info(info_data, result):
  97. """Test getting basic info from the ceiling light."""
  98. device = create_device_for_command_testing()
  99. async def mock_get_basic_info(args: str) -> list[int] | None:
  100. if args == ceiling_light.DEVICE_GET_BASIC_SETTINGS_KEY:
  101. return info_data["basic_info"]
  102. if args == ceiling_light.DEVICE_GET_VERSION_KEY:
  103. return info_data["version_info"]
  104. return None
  105. device._get_basic_info = AsyncMock(side_effect=mock_get_basic_info)
  106. info = await device.get_basic_info()
  107. assert info["isOn"] is result[0]
  108. assert info["brightness"] == result[1]
  109. assert info["cw"] == result[2]
  110. assert info["color_mode"] == result[3]
  111. assert info["firmware"] == result[4]
  112. @pytest.mark.asyncio
  113. async def test_set_color_temp():
  114. """Test setting color temperature."""
  115. device = create_device_for_command_testing()
  116. await device.set_color_temp(50, 3000)
  117. device._send_command.assert_called_with(f"{ceiling_light.CW_BRIGHTNESS_KEY}320BB8")
  118. @pytest.mark.asyncio
  119. async def test_turn_on():
  120. """Test turning on the ceiling light."""
  121. device = create_device_for_command_testing({"isOn": True})
  122. await device.turn_on()
  123. device._send_command.assert_called_with(ceiling_light.CEILING_LIGHT_ON_KEY)
  124. assert device.is_on() is True
  125. @pytest.mark.asyncio
  126. async def test_turn_off():
  127. """Test turning off the ceiling light."""
  128. device = create_device_for_command_testing({"isOn": False})
  129. await device.turn_off()
  130. device._send_command.assert_called_with(ceiling_light.CEILING_LIGHT_OFF_KEY)
  131. assert device.is_on() is False
  132. @pytest.mark.asyncio
  133. async def test_set_brightness():
  134. """Test setting brightness."""
  135. device = create_device_for_command_testing()
  136. await device.set_brightness(75)
  137. device._send_command.assert_called_with(f"{ceiling_light.BRIGHTNESS_KEY}4B0FA1")