Browse Source

fix: small fixes for light strips (#89)

J. Nick Koston 1 year ago
parent
commit
8e88df6b7f

+ 7 - 52
switchbot/devices/bot.py

@@ -24,7 +24,6 @@ class Switchbot(SwitchbotDevice):
         """Switchbot Bot/WoHand constructor."""
         super().__init__(*args, **kwargs)
         self._inverse: bool = kwargs.pop("inverse_mode", False)
-        self._settings: dict[str, Any] = {}
 
     async def update(self, interface: int | None = None) -> None:
         """Update mode, battery percent and state of device."""
@@ -33,67 +32,27 @@ class Switchbot(SwitchbotDevice):
     async def turn_on(self) -> bool:
         """Turn device on."""
         result = await self._sendcommand(ON_KEY)
-
-        if result[0] == 1:
-            return True
-
-        if result[0] == 5:
-            _LOGGER.debug(
-                "%s: Bot is in press mode and doesn't have on state", self.name
-            )
-            return True
-
-        return False
+        return self._check_command_result(result, 0, {1, 5})
 
     async def turn_off(self) -> bool:
         """Turn device off."""
         result = await self._sendcommand(OFF_KEY)
-        if result[0] == 1:
-            return True
-
-        if result[0] == 5:
-            _LOGGER.debug(
-                "%s: Bot is in press mode and doesn't have off state", self.name
-            )
-            return True
-
-        return False
+        return self._check_command_result(result, 0, {1, 5})
 
     async def hand_up(self) -> bool:
         """Raise device arm."""
         result = await self._sendcommand(UP_KEY)
-        if result[0] == 1:
-            return True
-
-        if result[0] == 5:
-            _LOGGER.debug("%s: Bot is in press mode", self.name)
-            return True
-
-        return False
+        return self._check_command_result(result, 0, {1, 5})
 
     async def hand_down(self) -> bool:
         """Lower device arm."""
         result = await self._sendcommand(DOWN_KEY)
-        if result[0] == 1:
-            return True
-
-        if result[0] == 5:
-            _LOGGER.debug("%s: Bot is in press mode", self.name)
-            return True
-
-        return False
+        return self._check_command_result(result, 0, {1, 5})
 
     async def press(self) -> bool:
         """Press command to device."""
         result = await self._sendcommand(PRESS_KEY)
-        if result[0] == 1:
-            return True
-
-        if result[0] == 5:
-            _LOGGER.debug("%s: Bot is in switch mode", self.name)
-            return True
-
-        return False
+        return self._check_command_result(result, 0, {1, 5})
 
     async def set_switch_mode(
         self, switch_mode: bool = False, strength: int = 100, inverse: bool = False
@@ -101,18 +60,14 @@ class Switchbot(SwitchbotDevice):
         """Change bot mode."""
         mode_key = format(switch_mode, "b") + format(inverse, "b")
         strength_key = f"{strength:0{2}x}"  # to hex with padding to double digit
-
         result = await self._sendcommand(DEVICE_SET_MODE_KEY + strength_key + mode_key)
-
-        return result[0] == 1
+        return self._check_command_result(result, 0, {1})
 
     async def set_long_press(self, duration: int = 0) -> bool:
         """Set bot long press duration."""
         duration_key = f"{duration:0{2}x}"  # to hex with padding to double digit
-
         result = await self._sendcommand(DEVICE_SET_EXTENDED_KEY + "08" + duration_key)
-
-        return result[0] == 1
+        return self._check_command_result(result, 0, {1})
 
     async def get_basic_info(self) -> dict[str, Any] | None:
         """Get device basic settings."""

+ 7 - 47
switchbot/devices/bulb.py

@@ -26,9 +26,10 @@ CW_KEY = f"{BULB_COMMAND}17"
 _LOGGER = logging.getLogger(__name__)
 
 from .device import ColorMode
+from .base_light import SwitchbotBaseLight
 
 
-class SwitchbotBulb(SwitchbotSequenceDevice):
+class SwitchbotBulb(SwitchbotBaseLight):
     """Representation of a Switchbot bulb."""
 
     def __init__(self, *args: Any, **kwargs: Any) -> None:
@@ -36,48 +37,11 @@ class SwitchbotBulb(SwitchbotSequenceDevice):
         super().__init__(*args, **kwargs)
         self._state: dict[str, Any] = {}
 
-    @property
-    def on(self) -> bool | None:
-        """Return if bulb is on."""
-        return self.is_on()
-
-    @property
-    def rgb(self) -> tuple[int, int, int] | None:
-        """Return the current rgb value."""
-        if "r" not in self._state or "g" not in self._state or "b" not in self._state:
-            return None
-        return self._state["r"], self._state["g"], self._state["b"]
-
-    @property
-    def color_temp(self) -> int | None:
-        """Return the current color temp value."""
-        return self._state.get("cw") or self.min_temp
-
-    @property
-    def brightness(self) -> int | None:
-        """Return the current brightness value."""
-        return self._get_adv_value("brightness") or 0
-
-    @property
-    def color_mode(self) -> ColorMode:
-        """Return the current color mode."""
-        return ColorMode(self._get_adv_value("color_mode") or 0)
-
     @property
     def color_modes(self) -> set[ColorMode]:
         """Return the supported color modes."""
         return {ColorMode.RGB, ColorMode.COLOR_TEMP}
 
-    @property
-    def min_temp(self) -> int:
-        """Return minimum color temp."""
-        return 2700
-
-    @property
-    def max_temp(self) -> int:
-        """Return maximum color temp."""
-        return 6500
-
     async def update(self) -> None:
         """Update state of device."""
         result = await self._sendcommand(BULB_REQUEST)
@@ -87,20 +51,20 @@ class SwitchbotBulb(SwitchbotSequenceDevice):
         """Turn device on."""
         result = await self._sendcommand(BULB_ON_KEY)
         self._update_state(result)
-        return result[1] == 0x80
+        return self._check_command_result(result, 1, {0x80})
 
     async def turn_off(self) -> bool:
         """Turn device off."""
         result = await self._sendcommand(BULB_OFF_KEY)
         self._update_state(result)
-        return result[1] == 0x00
+        return self._check_command_result(result, 1, {0x00})
 
     async def set_brightness(self, brightness: int) -> bool:
         """Set brightness."""
         assert 0 <= brightness <= 100, "Brightness must be between 0 and 100"
         result = await self._sendcommand(f"{BRIGHTNESS_KEY}{brightness:02X}")
         self._update_state(result)
-        return result[1] == 0x80
+        return self._check_command_result(result, 1, {0x80})
 
     async def set_color_temp(self, brightness: int, color_temp: int) -> bool:
         """Set color temp."""
@@ -110,7 +74,7 @@ class SwitchbotBulb(SwitchbotSequenceDevice):
             f"{CW_BRIGHTNESS_KEY}{brightness:02X}{color_temp:04X}"
         )
         self._update_state(result)
-        return result[1] == 0x80
+        return self._check_command_result(result, 1, {0x80})
 
     async def set_rgb(self, brightness: int, r: int, g: int, b: int) -> bool:
         """Set rgb."""
@@ -122,11 +86,7 @@ class SwitchbotBulb(SwitchbotSequenceDevice):
             f"{RGB_BRIGHTNESS_KEY}{brightness:02X}{r:02X}{g:02X}{b:02X}"
         )
         self._update_state(result)
-        return result[1] == 0x80
-
-    def is_on(self) -> bool | None:
-        """Return bulb state from cache."""
-        return self._get_adv_value("isOn")
+        return self._check_command_result(result, 1, {0x80})
 
     def _update_state(self, result: bytes) -> None:
         """Update device state."""

+ 4 - 4
switchbot/devices/curtain.py

@@ -42,24 +42,24 @@ class SwitchbotCurtain(SwitchbotDevice):
     async def open(self) -> bool:
         """Send open command."""
         result = await self._sendcommand(OPEN_KEY)
-        return result[0] == 1
+        return self._check_command_result(result, 0, {1})
 
     async def close(self) -> bool:
         """Send close command."""
         result = await self._sendcommand(CLOSE_KEY)
-        return result[0] == 1
+        return self._check_command_result(result, 0, {1})
 
     async def stop(self) -> bool:
         """Send stop command to device."""
         result = await self._sendcommand(STOP_KEY)
-        return result[0] == 1
+        return self._check_command_result(result, 0, {1})
 
     async def set_position(self, position: int) -> bool:
         """Send position command (0-100) to device."""
         position = (100 - position) if self._reverse else position
         hex_position = "%0.2X" % position
         result = await self._sendcommand(POSITION_KEY + hex_position)
-        return result[0] == 1
+        return self._check_command_result(result, 0, {1})
 
     async def update(self, interface: int | None = None) -> None:
         """Update position, battery percent and light level of device."""

+ 16 - 0
switchbot/devices/device.py

@@ -54,6 +54,10 @@ class CharacteristicMissingError(Exception):
     """Raised when a characteristic is missing."""
 
 
+class SwitchbotOperationError(Exception):
+    """Raised when an operation fails."""
+
+
 def _sb_uuid(comms_type: str = "service") -> UUID | str:
     """Return Switchbot UUID."""
 
@@ -406,8 +410,20 @@ class SwitchbotDevice:
     async def update(self) -> None:
         """Update state of device."""
 
+    def _check_command_result(
+        self, result: bytes, index: int, values: set[int]
+    ) -> bool:
+        """Check command result."""
+        if not result:
+            raise SwitchbotOperationError(
+                f"{self.name}: Sending command failed (rssi={self.rssi})"
+            )
+        return result[index] in values
+
 
 class SwitchbotSequenceDevice(SwitchbotDevice):
+    """A Switchbot sequence device."""
+
     def update_from_advertisement(self, advertisement: SwitchBotAdvertisement) -> None:
         """Update device data from advertisement."""
         current_state = self._get_adv_value("sequence_number")

+ 4 - 4
switchbot/devices/light_strip.py

@@ -43,20 +43,20 @@ class SwitchbotLightStrip(SwitchbotBaseLight):
         """Turn device on."""
         result = await self._sendcommand(STRIP_ON_KEY)
         self._update_state(result)
-        return result[1] == 0x80
+        return self._check_command_result(result, 1, {0x80})
 
     async def turn_off(self) -> bool:
         """Turn device off."""
         result = await self._sendcommand(STRIP_OFF_KEY)
         self._update_state(result)
-        return result[1] == 0x00
+        return self._check_command_result(result, 1, {0x00})
 
     async def set_brightness(self, brightness: int) -> bool:
         """Set brightness."""
         assert 0 <= brightness <= 100, "Brightness must be between 0 and 100"
         result = await self._sendcommand(f"{BRIGHTNESS_KEY}{brightness:02X}")
         self._update_state(result)
-        return result[1] == 0x80
+        return self._check_command_result(result, 1, {0x80})
 
     async def set_color_temp(self, brightness: int, color_temp: int) -> bool:
         """Set color temp."""
@@ -72,7 +72,7 @@ class SwitchbotLightStrip(SwitchbotBaseLight):
             f"{RGB_BRIGHTNESS_KEY}{brightness:02X}{r:02X}{g:02X}{b:02X}"
         )
         self._update_state(result)
-        return result[1] == 0x80
+        return self._check_command_result(result, 1, {0x80})
 
     def _update_state(self, result: bytes) -> None:
         """Update device state."""

+ 2 - 2
switchbot/devices/plug.py

@@ -20,12 +20,12 @@ class SwitchbotPlugMini(SwitchbotDevice):
     async def turn_on(self) -> bool:
         """Turn device on."""
         result = await self._sendcommand(PLUG_ON_KEY)
-        return result[1] == 0x80
+        return self._check_command_result(result, 1, {0x80})
 
     async def turn_off(self) -> bool:
         """Turn device off."""
         result = await self._sendcommand(PLUG_OFF_KEY)
-        return result[1] == 0x00
+        return self._check_command_result(result, 1, {0x00})
 
     def is_on(self) -> bool | None:
         """Return switch state from cache."""