Browse Source

fix: override the stale adv when making a change (#92)

J. Nick Koston 1 year ago
parent
commit
700be22493

+ 7 - 7
switchbot/devices/bot.py

@@ -31,27 +31,27 @@ class Switchbot(SwitchbotDevice):
 
     async def turn_on(self) -> bool:
         """Turn device on."""
-        result = await self._sendcommand(ON_KEY)
+        result = await self._send_command(ON_KEY)
         return self._check_command_result(result, 0, {1, 5})
 
     async def turn_off(self) -> bool:
         """Turn device off."""
-        result = await self._sendcommand(OFF_KEY)
+        result = await self._send_command(OFF_KEY)
         return self._check_command_result(result, 0, {1, 5})
 
     async def hand_up(self) -> bool:
         """Raise device arm."""
-        result = await self._sendcommand(UP_KEY)
+        result = await self._send_command(UP_KEY)
         return self._check_command_result(result, 0, {1, 5})
 
     async def hand_down(self) -> bool:
         """Lower device arm."""
-        result = await self._sendcommand(DOWN_KEY)
+        result = await self._send_command(DOWN_KEY)
         return self._check_command_result(result, 0, {1, 5})
 
     async def press(self) -> bool:
         """Press command to device."""
-        result = await self._sendcommand(PRESS_KEY)
+        result = await self._send_command(PRESS_KEY)
         return self._check_command_result(result, 0, {1, 5})
 
     async def set_switch_mode(
@@ -60,13 +60,13 @@ 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)
+        result = await self._send_command(DEVICE_SET_MODE_KEY + strength_key + mode_key)
         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)
+        result = await self._send_command(DEVICE_SET_EXTENDED_KEY + "08" + duration_key)
         return self._check_command_result(result, 0, {1})
 
     async def get_basic_info(self) -> dict[str, Any] | None:

+ 10 - 6
switchbot/devices/bulb.py

@@ -44,25 +44,25 @@ class SwitchbotBulb(SwitchbotBaseLight):
 
     async def update(self) -> None:
         """Update state of device."""
-        result = await self._sendcommand(BULB_REQUEST)
+        result = await self._send_command(BULB_REQUEST)
         self._update_state(result)
 
     async def turn_on(self) -> bool:
         """Turn device on."""
-        result = await self._sendcommand(BULB_ON_KEY)
+        result = await self._send_command(BULB_ON_KEY)
         self._update_state(result)
         return self._check_command_result(result, 1, {0x80})
 
     async def turn_off(self) -> bool:
         """Turn device off."""
-        result = await self._sendcommand(BULB_OFF_KEY)
+        result = await self._send_command(BULB_OFF_KEY)
         self._update_state(result)
         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}")
+        result = await self._send_command(f"{BRIGHTNESS_KEY}{brightness:02X}")
         self._update_state(result)
         return self._check_command_result(result, 1, {0x80})
 
@@ -70,7 +70,7 @@ class SwitchbotBulb(SwitchbotBaseLight):
         """Set color temp."""
         assert 0 <= brightness <= 100, "Brightness must be between 0 and 100"
         assert 2700 <= color_temp <= 6500, "Color Temp must be between 0 and 100"
-        result = await self._sendcommand(
+        result = await self._send_command(
             f"{CW_BRIGHTNESS_KEY}{brightness:02X}{color_temp:04X}"
         )
         self._update_state(result)
@@ -82,7 +82,7 @@ class SwitchbotBulb(SwitchbotBaseLight):
         assert 0 <= r <= 255, "r must be between 0 and 255"
         assert 0 <= g <= 255, "g must be between 0 and 255"
         assert 0 <= b <= 255, "b must be between 0 and 255"
-        result = await self._sendcommand(
+        result = await self._send_command(
             f"{RGB_BRIGHTNESS_KEY}{brightness:02X}{r:02X}{g:02X}{b:02X}"
         )
         self._update_state(result)
@@ -96,6 +96,10 @@ class SwitchbotBulb(SwitchbotBaseLight):
         self._state["g"] = result[4]
         self._state["b"] = result[5]
         self._state["cw"] = int(result[6:8].hex(), 16)
+        self._override_adv_data = {
+            "isOn": result[1] == 0x80,
+            "color_mode": result[10],
+        }
         _LOGGER.debug(
             "%s: Bulb update state: %s = %s", self.name, result.hex(), self._state
         )

+ 6 - 6
switchbot/devices/curtain.py

@@ -41,24 +41,24 @@ class SwitchbotCurtain(SwitchbotDevice):
 
     async def open(self) -> bool:
         """Send open command."""
-        result = await self._sendcommand(OPEN_KEY)
+        result = await self._send_command(OPEN_KEY)
         return self._check_command_result(result, 0, {1})
 
     async def close(self) -> bool:
         """Send close command."""
-        result = await self._sendcommand(CLOSE_KEY)
+        result = await self._send_command(CLOSE_KEY)
         return self._check_command_result(result, 0, {1})
 
     async def stop(self) -> bool:
         """Send stop command to device."""
-        result = await self._sendcommand(STOP_KEY)
+        result = await self._send_command(STOP_KEY)
         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)
+        result = await self._send_command(POSITION_KEY + hex_position)
         return self._check_command_result(result, 0, {1})
 
     async def update(self, interface: int | None = None) -> None:
@@ -95,7 +95,7 @@ class SwitchbotCurtain(SwitchbotDevice):
 
     async def get_extended_info_summary(self) -> dict[str, Any] | None:
         """Get basic info for all devices in chain."""
-        _data = await self._sendcommand(key=CURTAIN_EXT_SUM_KEY)
+        _data = await self._send_command(key=CURTAIN_EXT_SUM_KEY)
 
         if not _data:
             _LOGGER.error("%s: Unsuccessful, no result from device", self.name)
@@ -130,7 +130,7 @@ class SwitchbotCurtain(SwitchbotDevice):
     async def get_extended_info_adv(self) -> dict[str, Any] | None:
         """Get advance page info for device chain."""
 
-        _data = await self._sendcommand(key=CURTAIN_EXT_ADV_KEY)
+        _data = await self._send_command(key=CURTAIN_EXT_ADV_KEY)
         if not _data:
             _LOGGER.error("%s: Unsuccessful, no result from device", self.name)
             return None

+ 7 - 2
switchbot/devices/device.py

@@ -87,6 +87,7 @@ class SwitchbotDevice:
         self._interface = f"hci{interface}"
         self._device = device
         self._sb_adv_data: SwitchBotAdvertisement | None = None
+        self._override_adv_data: dict[str, Any] | None = None
         self._scan_timeout: int = kwargs.pop("scan_timeout", DEFAULT_SCAN_TIMEOUT)
         self._retry_count: int = kwargs.pop("retry_count", DEFAULT_RETRY_COUNT)
         self._connect_lock = asyncio.Lock()
@@ -114,7 +115,7 @@ class SwitchbotDevice:
         key_suffix = key[4:]
         return KEY_PASSWORD_PREFIX + key_action + self._password_encoded + key_suffix
 
-    async def _sendcommand(self, key: str, retry: int | None = None) -> bytes | None:
+    async def _send_command(self, key: str, retry: int | None = None) -> bytes | None:
         """Send command to device and read response."""
         if retry is None:
             retry = self._retry_count
@@ -344,6 +345,8 @@ class SwitchbotDevice:
 
     def _get_adv_value(self, key: str) -> Any:
         """Return value from advertisement data."""
+        if self._override_adv_data and key in self._override_adv_data:
+            return self._override_adv_data[key]
         if not self._sb_adv_data:
             return None
         return self._sb_adv_data.data["data"].get(key)
@@ -355,6 +358,7 @@ class SwitchbotDevice:
     def update_from_advertisement(self, advertisement: SwitchBotAdvertisement) -> None:
         """Update device data from advertisement."""
         self._sb_adv_data = advertisement
+        self._override_adv_data = None
         if self._device and ble_device_has_changed(self._device, advertisement.device):
             self._cached_services = None
         self._device = advertisement.device
@@ -382,7 +386,7 @@ class SwitchbotDevice:
 
     async def _get_basic_info(self) -> bytes | None:
         """Return basic info of device."""
-        _data = await self._sendcommand(
+        _data = await self._send_command(
             key=DEVICE_GET_BASIC_SETTINGS_KEY, retry=self._retry_count
         )
 
@@ -394,6 +398,7 @@ class SwitchbotDevice:
 
     def _fire_callbacks(self) -> None:
         """Fire callbacks."""
+        _LOGGER.debug("%s: Fire callbacks", self.name)
         for callback in self._callbacks:
             callback()
 

+ 9 - 5
switchbot/devices/light_strip.py

@@ -36,25 +36,25 @@ class SwitchbotLightStrip(SwitchbotBaseLight):
 
     async def update(self) -> None:
         """Update state of device."""
-        result = await self._sendcommand(STRIP_REQUEST)
+        result = await self._send_command(STRIP_REQUEST)
         self._update_state(result)
 
     async def turn_on(self) -> bool:
         """Turn device on."""
-        result = await self._sendcommand(STRIP_ON_KEY)
+        result = await self._send_command(STRIP_ON_KEY)
         self._update_state(result)
         return self._check_command_result(result, 1, {0x80})
 
     async def turn_off(self) -> bool:
         """Turn device off."""
-        result = await self._sendcommand(STRIP_OFF_KEY)
+        result = await self._send_command(STRIP_OFF_KEY)
         self._update_state(result)
         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}")
+        result = await self._send_command(f"{BRIGHTNESS_KEY}{brightness:02X}")
         self._update_state(result)
         return self._check_command_result(result, 1, {0x80})
 
@@ -68,7 +68,7 @@ class SwitchbotLightStrip(SwitchbotBaseLight):
         assert 0 <= r <= 255, "r must be between 0 and 255"
         assert 0 <= g <= 255, "g must be between 0 and 255"
         assert 0 <= b <= 255, "b must be between 0 and 255"
-        result = await self._sendcommand(
+        result = await self._send_command(
             f"{RGB_BRIGHTNESS_KEY}{brightness:02X}{r:02X}{g:02X}{b:02X}"
         )
         self._update_state(result)
@@ -81,6 +81,10 @@ class SwitchbotLightStrip(SwitchbotBaseLight):
         self._state["r"] = result[3]
         self._state["g"] = result[4]
         self._state["b"] = result[5]
+        self._override_adv_data = {
+            "isOn": result[1] == 0x80,
+            "color_mode": result[10],
+        }
         _LOGGER.debug(
             "%s: Bulb update state: %s = %s", self.name, result.hex(), self._state
         )

+ 2 - 2
switchbot/devices/plug.py

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