bot.py 4.2 KB

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