cover.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. """
  2. Platform to control tuya cover devices.
  3. """
  4. import logging
  5. from homeassistant.components.cover import (
  6. CoverEntity,
  7. CoverDeviceClass,
  8. SUPPORT_CLOSE,
  9. SUPPORT_OPEN,
  10. SUPPORT_SET_POSITION,
  11. SUPPORT_STOP,
  12. )
  13. from ..device import TuyaLocalDevice
  14. from ..helpers.device_config import TuyaEntityConfig
  15. from ..helpers.mixin import TuyaLocalEntity
  16. _LOGGER = logging.getLogger(__name__)
  17. class TuyaLocalCover(TuyaLocalEntity, CoverEntity):
  18. """Representation of a Tuya Cover Entity."""
  19. def __init__(self, device: TuyaLocalDevice, config: TuyaEntityConfig):
  20. """
  21. Initialise the cover device.
  22. Args:
  23. device (TuyaLocalDevice): The device API instance
  24. config (TuyaEntityConfig): The entity config
  25. """
  26. dps_map = self._init_begin(device, config)
  27. self._position_dps = dps_map.pop("position", None)
  28. self._currentpos_dps = dps_map.pop("current_position", None)
  29. self._control_dps = dps_map.pop("control", None)
  30. self._action_dps = dps_map.pop("action", None)
  31. self._open_dps = dps_map.pop("open", None)
  32. self._init_end(dps_map)
  33. self._support_flags = 0
  34. if self._position_dps:
  35. self._support_flags |= SUPPORT_SET_POSITION
  36. if self._control_dps:
  37. if "stop" in self._control_dps.values(self._device):
  38. self._support_flags |= SUPPORT_STOP
  39. if "open" in self._control_dps.values(self._device):
  40. self._support_flags |= SUPPORT_OPEN
  41. if "close" in self._control_dps.values(self._device):
  42. self._support_flags |= SUPPORT_CLOSE
  43. # Tilt not yet supported, as no test devices known
  44. @property
  45. def device_class(self):
  46. """Return the class of ths device"""
  47. dclass = self._config.device_class
  48. try:
  49. return CoverDeviceClass(dclass)
  50. except ValueError:
  51. if dclass:
  52. _LOGGER.warning(f"Unrecognised cover device class of {dclass} ignored")
  53. return None
  54. @property
  55. def supported_features(self):
  56. """Inform HA of the supported features."""
  57. return self._support_flags
  58. @property
  59. def current_cover_position(self):
  60. """Return current position of cover."""
  61. if self._currentpos_dps:
  62. return self._currentpos_dps.get_value(self._device)
  63. if self._position_dps:
  64. return self._position_dps.get_value(self._device)
  65. if self._open_dps:
  66. state = self._open_dps.get_value(self._device)
  67. if state is not None:
  68. return 100 if state else 0
  69. if self._action_dps:
  70. state = self._action_dps.get_value(self._device)
  71. if state == "opened":
  72. return 100
  73. elif state == "closed":
  74. return 0
  75. else:
  76. return 50
  77. @property
  78. def is_opening(self):
  79. """Return if the cover is opening or not."""
  80. # If dps is available to inform current action, use that
  81. if self._action_dps:
  82. return self._action_dps.get_value(self._device) == "opening"
  83. # Otherwise use last command and check it hasn't completed
  84. if self._control_dps:
  85. return (
  86. self._control_dps.get_value(self._device) == "open"
  87. and self.current_cover_position != 100
  88. )
  89. @property
  90. def is_closing(self):
  91. """Return if the cover is closing or not."""
  92. # If dps is available to inform current action, use that
  93. if self._action_dps:
  94. return self._action_dps.get_value(self._device) == "closing"
  95. # Otherwise use last command and check it hasn't completed
  96. if self._control_dps:
  97. return (
  98. self._control_dps.get_value(self._device) == "close"
  99. and not self.is_closed
  100. )
  101. @property
  102. def is_closed(self):
  103. """Return if the cover is closed or not."""
  104. return self.current_cover_position == 0
  105. async def async_open_cover(self, **kwargs):
  106. """Open the cover."""
  107. if self._control_dps and "open" in self._control_dps.values(self._device):
  108. await self._control_dps.async_set_value(self._device, "open")
  109. elif self._position_dps:
  110. await self._position_dps.async_set_value(self._device, 100)
  111. else:
  112. raise NotImplementedError()
  113. async def async_close_cover(self, **kwargs):
  114. """Close the cover."""
  115. if self._control_dps and "close" in self._control_dps.values(self._device):
  116. await self._control_dps.async_set_value(self._device, "close")
  117. elif self._position_dps:
  118. await self._position_dps.async_set_value(self._device, 0)
  119. else:
  120. raise NotImplementedError()
  121. async def async_set_cover_position(self, position, **kwargs):
  122. """Set the cover to a specific position."""
  123. if position is None:
  124. raise AttributeError()
  125. if self._position_dps:
  126. await self._position_dps.async_set_value(self._device, position)
  127. else:
  128. raise NotImplementedError()
  129. async def async_stop_cover(self, **kwargs):
  130. """Stop the cover."""
  131. if self._control_dps and "stop" in self._control_dps.values(self._device):
  132. await self._control_dps.async_set_value(self._device, "stop")
  133. else:
  134. raise NotImplementedError()