1
0

fan.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. """Library to handle connection with Switchbot."""
  2. from __future__ import annotations
  3. import logging
  4. from typing import Any
  5. from ..const.fan import FanMode
  6. from .device import (
  7. DEVICE_GET_BASIC_SETTINGS_KEY,
  8. SwitchbotSequenceDevice,
  9. update_after_operation,
  10. )
  11. _LOGGER = logging.getLogger(__name__)
  12. COMMAND_HEAD = "570f41"
  13. COMMAND_START_OSCILLATION = f"{COMMAND_HEAD}020101ff"
  14. COMMAND_STOP_OSCILLATION = f"{COMMAND_HEAD}020102ff"
  15. COMMAND_SET_MODE = {
  16. FanMode.NORMAL.name.lower(): f"{COMMAND_HEAD}030101ff",
  17. FanMode.NATURAL.name.lower(): f"{COMMAND_HEAD}030102ff",
  18. FanMode.SLEEP.name.lower(): f"{COMMAND_HEAD}030103",
  19. FanMode.BABY.name.lower(): f"{COMMAND_HEAD}030104",
  20. }
  21. COMMAND_SET_PERCENTAGE = f"{COMMAND_HEAD}0302" # +speed
  22. COMMAND_GET_BASIC_INFO = "570f428102"
  23. class SwitchbotFan(SwitchbotSequenceDevice):
  24. """Representation of a Switchbot Circulator Fan."""
  25. _turn_on_command = f"{COMMAND_HEAD}0101"
  26. _turn_off_command = f"{COMMAND_HEAD}0102"
  27. async def get_basic_info(self) -> dict[str, Any] | None:
  28. """Get device basic settings."""
  29. if not (_data := await self._get_basic_info(COMMAND_GET_BASIC_INFO)):
  30. return None
  31. if not (_data1 := await self._get_basic_info(DEVICE_GET_BASIC_SETTINGS_KEY)):
  32. return None
  33. _LOGGER.debug("data: %s", _data)
  34. battery = _data[2] & 0b01111111
  35. isOn = bool(_data[3] & 0b10000000)
  36. oscillating = bool(_data[3] & 0b01100000)
  37. _mode = _data[8] & 0b00000111
  38. mode = FanMode(_mode).name.lower() if 1 <= _mode <= 4 else None
  39. speed = _data[9]
  40. firmware = _data1[2] / 10.0
  41. return {
  42. "battery": battery,
  43. "isOn": isOn,
  44. "oscillating": oscillating,
  45. "mode": mode,
  46. "speed": speed,
  47. "firmware": firmware,
  48. }
  49. async def _get_basic_info(self, cmd: str) -> bytes | None:
  50. """Return basic info of device."""
  51. _data = await self._send_command(key=cmd, retry=self._retry_count)
  52. if _data in (b"\x07", b"\x00"):
  53. _LOGGER.error("Unsuccessful, please try again")
  54. return None
  55. return _data
  56. @update_after_operation
  57. async def set_preset_mode(self, preset_mode: str) -> bool:
  58. """Send command to set fan preset_mode."""
  59. return await self._send_command(COMMAND_SET_MODE[preset_mode])
  60. @update_after_operation
  61. async def set_percentage(self, percentage: int) -> bool:
  62. """Send command to set fan percentage."""
  63. return await self._send_command(f"{COMMAND_SET_PERCENTAGE}{percentage:02X}")
  64. @update_after_operation
  65. async def set_oscillation(self, oscillating: bool) -> bool:
  66. """Send command to set fan oscillation"""
  67. if oscillating:
  68. return await self._send_command(COMMAND_START_OSCILLATION)
  69. return await self._send_command(COMMAND_STOP_OSCILLATION)
  70. def get_current_percentage(self) -> Any:
  71. """Return cached percentage."""
  72. return self._get_adv_value("speed")
  73. def is_on(self) -> bool | None:
  74. """Return fan state from cache."""
  75. return self._get_adv_value("isOn")
  76. def get_oscillating_state(self) -> Any:
  77. """Return cached oscillating."""
  78. return self._get_adv_value("oscillating")
  79. def get_current_mode(self) -> Any:
  80. """Return cached mode."""
  81. return self._get_adv_value("mode")