bot.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. """Library to handle connection with Switchbot."""
  2. from __future__ import annotations
  3. import logging
  4. from typing import Any
  5. from .device import DEVICE_SET_EXTENDED_KEY, DEVICE_SET_MODE_KEY, SwitchbotDevice
  6. # Bot keys
  7. PRESS_KEY = "570100"
  8. ON_KEY = "570101"
  9. OFF_KEY = "570102"
  10. DOWN_KEY = "570103"
  11. UP_KEY = "570104"
  12. _LOGGER = logging.getLogger(__name__)
  13. class Switchbot(SwitchbotDevice):
  14. """Representation of a Switchbot."""
  15. def __init__(self, *args: Any, **kwargs: Any) -> None:
  16. """Switchbot Bot/WoHand constructor."""
  17. super().__init__(*args, **kwargs)
  18. self._inverse: bool = kwargs.pop("inverse_mode", False)
  19. self._settings: dict[str, Any] = {}
  20. async def update(self, interface: int | None = None) -> None:
  21. """Update mode, battery percent and state of device."""
  22. await self.get_device_data(retry=self._retry_count, interface=interface)
  23. async def turn_on(self) -> bool:
  24. """Turn device on."""
  25. result = await self._sendcommand(ON_KEY, self._retry_count)
  26. if result[0] == 1:
  27. return True
  28. if result[0] == 5:
  29. _LOGGER.debug("Bot is in press mode and doesn't have on state")
  30. return True
  31. return False
  32. async def turn_off(self) -> bool:
  33. """Turn device off."""
  34. result = await self._sendcommand(OFF_KEY, self._retry_count)
  35. if result[0] == 1:
  36. return True
  37. if result[0] == 5:
  38. _LOGGER.debug("Bot is in press mode and doesn't have off state")
  39. return True
  40. return False
  41. async def hand_up(self) -> bool:
  42. """Raise device arm."""
  43. result = await self._sendcommand(UP_KEY, self._retry_count)
  44. if result[0] == 1:
  45. return True
  46. if result[0] == 5:
  47. _LOGGER.debug("Bot is in press mode")
  48. return True
  49. return False
  50. async def hand_down(self) -> bool:
  51. """Lower device arm."""
  52. result = await self._sendcommand(DOWN_KEY, self._retry_count)
  53. if result[0] == 1:
  54. return True
  55. if result[0] == 5:
  56. _LOGGER.debug("Bot is in press mode")
  57. return True
  58. return False
  59. async def press(self) -> bool:
  60. """Press command to device."""
  61. result = await self._sendcommand(PRESS_KEY, self._retry_count)
  62. if result[0] == 1:
  63. return True
  64. if result[0] == 5:
  65. _LOGGER.debug("Bot is in switch mode")
  66. return True
  67. return False
  68. async def set_switch_mode(
  69. self, switch_mode: bool = False, strength: int = 100, inverse: bool = False
  70. ) -> bool:
  71. """Change bot mode."""
  72. mode_key = format(switch_mode, "b") + format(inverse, "b")
  73. strength_key = f"{strength:0{2}x}" # to hex with padding to double digit
  74. result = await self._sendcommand(
  75. DEVICE_SET_MODE_KEY + strength_key + mode_key, self._retry_count
  76. )
  77. if result[0] == 1:
  78. return True
  79. return False
  80. async def set_long_press(self, duration: int = 0) -> bool:
  81. """Set bot long press duration."""
  82. duration_key = f"{duration:0{2}x}" # to hex with padding to double digit
  83. result = await self._sendcommand(
  84. DEVICE_SET_EXTENDED_KEY + "08" + duration_key, self._retry_count
  85. )
  86. if result[0] == 1:
  87. return True
  88. return False
  89. async def get_basic_info(self) -> dict[str, Any] | None:
  90. """Get device basic settings."""
  91. if not (_data := await self._get_basic_info()):
  92. return None
  93. return {
  94. "battery": _data[1],
  95. "firmware": _data[2] / 10.0,
  96. "strength": _data[3],
  97. "timers": _data[8],
  98. "switchMode": bool(_data[9] & 16),
  99. "inverseDirection": bool(_data[9] & 1),
  100. "holdSeconds": _data[10],
  101. }
  102. def switch_mode(self) -> Any:
  103. """Return true or false from cache."""
  104. # To get actual position call update() first.
  105. return self._get_adv_value("switchMode")
  106. def is_on(self) -> Any:
  107. """Return switch state from cache."""
  108. # To get actual position call update() first.
  109. value = self._get_adv_value("isOn")
  110. if value is None:
  111. return None
  112. if self._inverse:
  113. return not value
  114. return value