test_ceiling_light.py 5.4 KB

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