valve.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. """
  2. Support for Tuya valve devices
  3. """
  4. import logging
  5. from homeassistant.components.valve import (
  6. ValveDeviceClass,
  7. ValveEntity,
  8. ValveEntityFeature,
  9. )
  10. from .device import TuyaLocalDevice
  11. from .entity import TuyaLocalEntity
  12. from .helpers.config import async_tuya_setup_platform
  13. from .helpers.device_config import TuyaEntityConfig
  14. _LOGGER = logging.getLogger(__name__)
  15. async def async_setup_entry(hass, config_entry, async_add_entities):
  16. config = {**config_entry.data, **config_entry.options}
  17. await async_tuya_setup_platform(
  18. hass,
  19. async_add_entities,
  20. config,
  21. "valve",
  22. TuyaLocalValve,
  23. )
  24. class TuyaLocalValve(TuyaLocalEntity, ValveEntity):
  25. """Representation of a Tuya Valve"""
  26. def __init__(self, device: TuyaLocalDevice, config: TuyaEntityConfig):
  27. """
  28. Initialise the valve.
  29. Args:
  30. device (TuyaLocalDevice): The device API instance.
  31. """
  32. super().__init__()
  33. dps_map = self._init_begin(device, config)
  34. self._valve_dp = dps_map.pop("valve")
  35. self._switch_dp = dps_map.pop("switch", None)
  36. self._current_position_dp = dps_map.pop("current_position", None)
  37. self._init_end(dps_map)
  38. if not self._valve_dp.readonly or self._switch_dp:
  39. self._attr_supported_features |= ValveEntityFeature.OPEN
  40. self._attr_supported_features |= ValveEntityFeature.CLOSE
  41. if self._valve_dp.type is int or (
  42. self._valve_dp.values(device)
  43. and self._valve_dp.values(device)[0] is int
  44. ):
  45. self._attr_supported_features |= ValveEntityFeature.SET_POSITION
  46. # HA defines translated names for valve classes, but does not use them
  47. def _default_to_device_class_name(self) -> bool:
  48. """Return True if an unnamed entity should be named by its device class.
  49. For valves we make this True if the entity has a device class.
  50. """
  51. return self.device_class is not None
  52. @property
  53. def device_class(self):
  54. """Return the class of this device"""
  55. dclass = self._config.device_class
  56. try:
  57. return ValveDeviceClass(dclass)
  58. except ValueError:
  59. if dclass:
  60. _LOGGER.warning(
  61. "%s/%s: Unrecognised valve device class of %s ignored",
  62. self._config._device.config,
  63. self.name or "valve",
  64. dclass,
  65. )
  66. @property
  67. def reports_position(self):
  68. """If the valve is an integer, it reports position."""
  69. return self._valve_dp.type is int or (
  70. self._valve_dp.values(self._device)
  71. and self._valve_dp.values(self._device)[0] is int
  72. )
  73. @property
  74. def current_valve_position(self):
  75. """Report the position of the valve."""
  76. position_dp = self._current_position_dp or self._valve_dp
  77. pos = position_dp.get_value(self._device)
  78. if isinstance(pos, int):
  79. return pos
  80. @property
  81. def is_closed(self):
  82. """Report whether the valve is closed."""
  83. if self._switch_dp and self._switch_dp.get_value(self._device) is False:
  84. return True
  85. pos = self.current_valve_position
  86. return not pos
  87. async def async_open_valve(self):
  88. """Open the valve."""
  89. if self._switch_dp:
  90. _LOGGER.info("%s opening valve", self._config.config_id)
  91. await self._switch_dp.async_set_value(self._device, True)
  92. if self._valve_dp.get_value(self._device):
  93. return
  94. _LOGGER.info("%s fully opening valve", self._config.config_id)
  95. await self._valve_dp.async_set_value(
  96. self._device,
  97. 100 if self.reports_position else True,
  98. )
  99. async def async_close_valve(self):
  100. """Close the valve"""
  101. if self._switch_dp:
  102. _LOGGER.info("%s closing valve", self._config.config_id)
  103. await self._switch_dp.async_set_value(self._device, False)
  104. else:
  105. _LOGGER.info("%s closing valve to 0%%", self._config.config_id)
  106. await self._valve_dp.async_set_value(
  107. self._device,
  108. 0 if self.reports_position else False,
  109. )
  110. async def async_set_valve_position(self, position):
  111. """Set the position of the valve"""
  112. if not self.reports_position:
  113. raise NotImplementedError()
  114. _LOGGER.info(
  115. "%s setting valve position to %s%%", self._config.config_id, position
  116. )
  117. await self._valve_dp.async_set_value(self._device, position)