cover.py 5.5 KB

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