Browse Source

Change garage door opener type to CoverDeviceClass.GARAGE in HA (#373)

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Retha Runolfsson 2 days ago
parent
commit
44ae30ba6b
4 changed files with 89 additions and 8 deletions
  1. 6 1
      switchbot/__init__.py
  2. 16 0
      switchbot/devices/device.py
  3. 23 1
      switchbot/devices/relay_switch.py
  4. 44 6
      tests/test_relay_switch.py

+ 6 - 1
switchbot/__init__.py

@@ -43,7 +43,11 @@ from .devices.humidifier import SwitchbotHumidifier
 from .devices.light_strip import SwitchbotLightStrip, SwitchbotStripLight3
 from .devices.lock import SwitchbotLock
 from .devices.plug import SwitchbotPlugMini
-from .devices.relay_switch import SwitchbotRelaySwitch, SwitchbotRelaySwitch2PM
+from .devices.relay_switch import (
+    SwitchbotGarageDoorOpener,
+    SwitchbotRelaySwitch,
+    SwitchbotRelaySwitch2PM,
+)
 from .devices.roller_shade import SwitchbotRollerShade
 from .devices.vacuum import SwitchbotVacuum
 from .discovery import GetSwitchbotDevices
@@ -77,6 +81,7 @@ __all__ = [
     "SwitchbotEncryptedDevice",
     "SwitchbotEvaporativeHumidifier",
     "SwitchbotFan",
+    "SwitchbotGarageDoorOpener",
     "SwitchbotHumidifier",
     "SwitchbotLightStrip",
     "SwitchbotLock",

+ 16 - 0
switchbot/devices/device.py

@@ -127,6 +127,8 @@ class SwitchbotBaseDevice:
 
     _turn_on_command: str | None = None
     _turn_off_command: str | None = None
+    _open_command: str | None = None
+    _close_command: str | None = None
     _press_command: str | None = None
 
     def __init__(
@@ -719,6 +721,20 @@ class SwitchbotBaseDevice:
         result = await self._send_command(self._turn_off_command)
         return self._check_command_result(result, 0, {1})
 
+    @update_after_operation
+    async def open(self) -> bool:
+        """Open the device."""
+        self._check_function_support(self._open_command)
+        result = await self._send_command(self._open_command)
+        return self._check_command_result(result, 0, {1})
+
+    @update_after_operation
+    async def close(self) -> bool:
+        """Close the device."""
+        self._check_function_support(self._close_command)
+        result = await self._send_command(self._close_command)
+        return self._check_command_result(result, 0, {1})
+
     @update_after_operation
     async def press(self) -> bool:
         """Press the device."""

+ 23 - 1
switchbot/devices/relay_switch.py

@@ -61,7 +61,6 @@ class SwitchbotRelaySwitch(SwitchbotSequenceDevice, SwitchbotEncryptedDevice):
 
     _turn_on_command = f"{COMMAND_CONTROL}010100"
     _turn_off_command = f"{COMMAND_CONTROL}010000"
-    _press_command = f"{COMMAND_CONTROL}110329"  # for garage door opener toggle
 
     def __init__(
         self,
@@ -205,6 +204,29 @@ class SwitchbotRelaySwitch(SwitchbotSequenceDevice, SwitchbotEncryptedDevice):
         """Return switch state from cache."""
         return self._get_adv_value("isOn")
 
+    def door_open(self) -> bool | None:
+        """Return garage door state from cache."""
+        return self._get_adv_value("door_open")
+
+
+class SwitchbotGarageDoorOpener(SwitchbotRelaySwitch):
+    """Representation of a Switchbot garage door opener."""
+
+    _open_command = f"{COMMAND_CONTROL}110129"
+    _close_command = f"{COMMAND_CONTROL}110229"
+    _press_command = f"{COMMAND_CONTROL}110329"  # for garage door opener toggle
+
+    def __init__(
+        self,
+        device: BLEDevice,
+        key_id: str,
+        encryption_key: str,
+        interface: int = 0,
+        model: SwitchbotModel = SwitchbotModel.GARAGE_DOOR_OPENER,
+        **kwargs: Any,
+    ) -> None:
+        super().__init__(device, key_id, encryption_key, interface, model, **kwargs)
+
 
 class SwitchbotRelaySwitch2PM(SwitchbotRelaySwitch):
     """Representation of a Switchbot relay switch 2pm."""

+ 44 - 6
tests/test_relay_switch.py

@@ -30,11 +30,12 @@ def create_device_for_command_testing(
 ):
     """Create a device for command testing."""
     ble_device = generate_ble_device("aa:bb:cc:dd:ee:ff", "any")
-    device_class = (
-        relay_switch.SwitchbotRelaySwitch2PM
-        if model == SwitchbotModel.RELAY_SWITCH_2PM
-        else relay_switch.SwitchbotRelaySwitch
-    )
+    if model == SwitchbotModel.GARAGE_DOOR_OPENER:
+        device_class = relay_switch.SwitchbotGarageDoorOpener
+    elif model == SwitchbotModel.RELAY_SWITCH_2PM:
+        device_class = relay_switch.SwitchbotRelaySwitch2PM
+    else:
+        device_class = relay_switch.SwitchbotRelaySwitch
     device = device_class(
         ble_device, "ff", "ffffffffffffffffffffffffffffffff", model=model
     )
@@ -453,12 +454,49 @@ def test_merge_data(old_data, new_data, expected_result):
     assert result == expected_result
 
 
+@pytest.mark.asyncio
+async def test_garage_door_opener_open():
+    """Test open the garage door."""
+    device = create_device_for_command_testing(
+        b">\x00\x00\x00", SwitchbotModel.GARAGE_DOOR_OPENER
+    )
+
+    await device.open()
+    device._send_command.assert_awaited_once_with(device._open_command)
+
+
+@pytest.mark.asyncio
+async def test_garage_door_opener_close():
+    """Test close the garage door."""
+    device = create_device_for_command_testing(
+        b">\x00\x00\x00", SwitchbotModel.GARAGE_DOOR_OPENER
+    )
+
+    await device.close()
+    device._send_command.assert_awaited_once_with(device._close_command)
+
+
+@pytest.mark.parametrize(
+    "door_open",
+    [
+        True,
+        False,
+    ],
+)
+@pytest.mark.asyncio
+async def test_garage_door_opener_door_open(door_open):
+    """Test get garage door state."""
+    device = create_device_for_command_testing(
+        b">\x00\x00\x00", SwitchbotModel.GARAGE_DOOR_OPENER, {"door_open": door_open}
+    )
+    assert device.door_open() is door_open
+
+
 @pytest.mark.asyncio
 async def test_press():
     """Test the press command for garage door opener."""
     device = create_device_for_command_testing(
         b">\x00\x00\x00", SwitchbotModel.GARAGE_DOOR_OPENER
     )
-
     await device.press()
     device._send_command.assert_awaited_once_with(device._press_command)