| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- from unittest.mock import AsyncMock, Mock
- import pytest
- from bleak.backends.device import BLEDevice
- from switchbot import (
- SwitchBotAdvertisement,
- SwitchbotModel,
- SwitchbotOperationError,
- )
- from switchbot.devices import bot
- from .test_adv_parser import generate_ble_device
- def make_advertisement_data(
- ble_device: BLEDevice,
- ) -> SwitchBotAdvertisement:
- """Create Bot advertisement data for tests."""
- data: dict[str, bool | int | None] = {
- "battery": 89,
- "isOn": True,
- "switchMode": True,
- }
- return SwitchBotAdvertisement(
- address=ble_device.address,
- data={
- "rawAdvData": b"H\x90\xd9",
- "data": data,
- "isEncrypted": False,
- "model": "H",
- "modelFriendlyName": "Bot",
- "modelName": SwitchbotModel.BOT,
- },
- device=ble_device,
- rssi=-80,
- active=True,
- )
- def create_device_for_command_testing(
- *,
- inverse_direction: bool | None = None,
- ) -> bot.Switchbot:
- """Create a Bot device with mocked Bluetooth commands."""
- ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "WoHand")
- device = bot.Switchbot(ble_device)
- device.update_from_advertisement(make_advertisement_data(ble_device))
- if inverse_direction is not None:
- device._update_parsed_data({"inverseDirection": inverse_direction})
- device._send_command = AsyncMock(return_value=b"\x01")
- device.update = AsyncMock()
- return device
- @pytest.mark.asyncio
- async def test_update_reads_inverse_direction() -> None:
- """Test updating reads inverse direction."""
- device = create_device_for_command_testing()
- device.update = bot.Switchbot.update.__get__(device)
- device._get_basic_info = AsyncMock(
- return_value=bytes([1, 89, 31, 75, 0, 0, 0, 0, 2, 17, 0])
- )
- await device.update()
- assert device.inverse_direction() is True
- assert device.parsed_data["strength"] == 75
- @pytest.mark.asyncio
- @pytest.mark.parametrize(
- ("inverse_direction", "expected_command"),
- [(False, "57034b10"), (True, "57034b11")],
- )
- async def test_set_inverse_direction_preserves_mode_and_strength(
- inverse_direction: bool,
- expected_command: str,
- ) -> None:
- """Test changing inverse direction preserves the current Bot settings."""
- device = create_device_for_command_testing()
- device.get_basic_info = AsyncMock(
- return_value={
- "battery": 89,
- "firmware": 3.1,
- "strength": 75,
- "timers": 2,
- "switchMode": True,
- "inverseDirection": False,
- "holdSeconds": 0,
- }
- )
- assert await device.set_inverse_direction(inverse_direction) is True
- device._send_command.assert_awaited_once_with(expected_command)
- @pytest.mark.asyncio
- async def test_set_inverse_direction_raises_when_settings_unavailable() -> None:
- """Test changing inverse direction fails if current settings cannot be read."""
- device = create_device_for_command_testing()
- device.get_basic_info = AsyncMock(return_value=None)
- with pytest.raises(
- SwitchbotOperationError, match="Unable to get current Bot mode settings"
- ):
- await device.set_inverse_direction(True)
- @pytest.mark.asyncio
- async def test_set_inverse_direction_returns_false_for_rejected_command() -> None:
- """Test a rejected inverse direction command does not update the cache."""
- device = create_device_for_command_testing(inverse_direction=False)
- device.get_basic_info = AsyncMock(
- return_value={
- "switchMode": True,
- "strength": 75,
- }
- )
- device._send_command = AsyncMock(return_value=b"\x00")
- assert await device.set_inverse_direction(True) is False
- assert device.inverse_direction() is False
- @pytest.mark.asyncio
- async def test_set_switch_mode_uses_confirmed_settings() -> None:
- """Test setting switch mode caches the settings read back from the Bot."""
- device = create_device_for_command_testing(inverse_direction=False)
- device.update = bot.Switchbot.update.__get__(device)
- device._send_command = AsyncMock(
- side_effect=[
- b"\x01",
- bytes([1, 89, 31, 75, 0, 0, 0, 0, 2, 17, 0]),
- ]
- )
- callback = Mock()
- device.subscribe(callback)
- assert await device.set_switch_mode(
- switch_mode=True,
- strength=75,
- inverse=True,
- )
- assert device.switch_mode() is True
- assert device.inverse_direction() is True
- assert device.parsed_data["strength"] == 75
- assert device._send_command.await_args_list[0].args == ("57034b11",)
- callback.assert_called_once_with()
|