test_ceiling_light.py 5.3 KB

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