from unittest.mock import AsyncMock, Mock import pytest from bleak.backends.device import BLEDevice from switchbot import SwitchBotAdvertisement, SwitchbotModel from switchbot.devices import base_cover, blind_tilt from .test_adv_parser import generate_ble_device def create_device_for_command_testing(position=50, calibration=True): ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any") base_cover_device = base_cover.SwitchbotBaseCover(False, ble_device) base_cover_device.update_from_advertisement( make_advertisement_data(ble_device, True, position, calibration) ) base_cover_device._send_multiple_commands = AsyncMock() base_cover_device.update = AsyncMock() return base_cover_device def make_advertisement_data( ble_device: BLEDevice, in_motion: bool, position: int, calibration: bool = True ): """Set advertisement data with defaults.""" return SwitchBotAdvertisement( address="aa:bb:cc:dd:ee:ff", data={ "rawAdvData": b"c\xc0X\x00\x11\x04", "data": { "calibration": calibration, "battery": 88, "inMotion": in_motion, "tilt": position, "lightLevel": 1, "deviceChain": 1, }, "isEncrypted": False, "model": "c", "modelFriendlyName": "Curtain", "modelName": SwitchbotModel.CURTAIN, }, device=ble_device, rssi=-80, active=True, ) @pytest.mark.asyncio async def test_send_multiple_commands(): ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any") base_cover_device = base_cover.SwitchbotBaseCover(False, ble_device) base_cover_device.update_from_advertisement( make_advertisement_data(ble_device, True, 50, True) ) base_cover_device._send_command = AsyncMock() base_cover_device._check_command_result = Mock(return_value=True) await base_cover_device._send_multiple_commands(blind_tilt.OPEN_KEYS) assert base_cover_device._send_command.await_count == 2 @pytest.mark.asyncio async def test_stop(): base_cover_device = create_device_for_command_testing() await base_cover_device.stop() base_cover_device._send_multiple_commands.assert_awaited_once_with( base_cover.STOP_KEYS ) @pytest.mark.asyncio async def test_set_position(): base_cover_device = create_device_for_command_testing() await base_cover_device.set_position(50) base_cover_device._send_multiple_commands.assert_awaited_once() @pytest.mark.asyncio @pytest.mark.parametrize("data_value", [(None), (b"\x07"), (b"\x00")]) async def test_get_extended_info_adv_returns_none_when_bad_data(data_value): base_cover_device = create_device_for_command_testing() base_cover_device._send_command = AsyncMock(return_value=data_value) assert await base_cover_device.get_extended_info_adv() is None @pytest.mark.asyncio async def test_get_extended_info_adv_returns_single_device(): base_cover_device = create_device_for_command_testing() base_cover_device._send_command = AsyncMock( return_value=bytes([0, 50, 20, 0, 0, 0, 0]) ) ext_result = await base_cover_device.get_extended_info_adv() assert ext_result["device0"]["battery"] == 50 assert ext_result["device0"]["firmware"] == 2 assert "device1" not in ext_result @pytest.mark.asyncio async def test_get_extended_info_adv_returns_both_devices(): base_cover_device = create_device_for_command_testing() base_cover_device._send_command = AsyncMock( return_value=bytes([0, 50, 20, 0, 10, 30, 0]) ) ext_result = await base_cover_device.get_extended_info_adv() assert ext_result["device0"]["battery"] == 50 assert ext_result["device0"]["firmware"] == 2 assert ext_result["device1"]["battery"] == 10 assert ext_result["device1"]["firmware"] == 3 @pytest.mark.asyncio @pytest.mark.parametrize( "data_value,result", [ (0, "not_charging"), (1, "charging_by_adapter"), (2, "charging_by_solar"), (3, "fully_charged"), (4, "solar_not_charging"), (5, "charging_error"), ], ) async def test_get_extended_info_adv_returns_device0_charge_states(data_value, result): base_cover_device = create_device_for_command_testing() base_cover_device._send_command = AsyncMock( return_value=bytes([0, 50, 20, data_value, 10, 30, 0]) ) ext_result = await base_cover_device.get_extended_info_adv() assert ext_result["device0"]["stateOfCharge"] == result @pytest.mark.asyncio @pytest.mark.parametrize( "data_value,result", [ (0, "not_charging"), (1, "charging_by_adapter"), (2, "charging_by_solar"), (3, "fully_charged"), (4, "solar_not_charging"), (5, "charging_error"), ], ) async def test_get_extended_info_adv_returns_device1_charge_states(data_value, result): base_cover_device = create_device_for_command_testing() base_cover_device._send_command = AsyncMock( return_value=bytes([0, 50, 20, 0, 10, 30, data_value]) ) ext_result = await base_cover_device.get_extended_info_adv() assert ext_result["device1"]["stateOfCharge"] == result