valve.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  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._init_end(dps_map)
  36. if not self._valve_dp.readonly:
  37. self._attr_supported_features |= ValveEntityFeature.OPEN
  38. self._attr_supported_features |= ValveEntityFeature.CLOSE
  39. if self._valve_dp.type is int or (
  40. self._valve_dp.values(device)
  41. and self._valve_dp.values(device)[0] is int
  42. ):
  43. self._attr_supported_features |= ValveEntityFeature.SET_POSITION
  44. # HA defines translated names for valve classes, but does not use them
  45. def _default_to_device_class_name(self) -> bool:
  46. """Return True if an unnamed entity should be named by its device class.
  47. For valves we make this True if the entity has a device class.
  48. """
  49. return self.device_class is not None
  50. @property
  51. def device_class(self):
  52. """Return the class of this device"""
  53. dclass = self._config.device_class
  54. try:
  55. return ValveDeviceClass(dclass)
  56. except ValueError:
  57. if dclass:
  58. _LOGGER.warning(
  59. "%s/%s: Unrecognised valve device class of %s ignored",
  60. self._config._device.config,
  61. self.name or "valve",
  62. dclass,
  63. )
  64. @property
  65. def reports_position(self):
  66. """If the valve is an integer, it reports position."""
  67. return self._valve_dp.type is int or (
  68. self._valve_dp.values(self._device)
  69. and self._valve_dp.values(self._device)[0] is int
  70. )
  71. @property
  72. def current_position(self):
  73. """Report the position of the valve."""
  74. pos = self._valve_dp.get_value(self._device)
  75. if isinstance(pos, int):
  76. return pos
  77. @property
  78. def is_closed(self):
  79. """Report whether the valve is closed."""
  80. pos = self._valve_dp.get_value(self._device)
  81. return not pos
  82. async def async_open_valve(self):
  83. """Open the valve."""
  84. await self._valve_dp.async_set_value(
  85. self._device,
  86. 100 if self.reports_position else True,
  87. )
  88. async def async_close_valve(self):
  89. """Close the valve"""
  90. await self._valve_dp.async_set_value(
  91. self._device,
  92. 0 if self.reports_position else False,
  93. )
  94. async def async_set_valve_position(self, position):
  95. """Set the position of the valve"""
  96. if not self.reports_position:
  97. raise NotImplementedError()
  98. await self._valve_dp.async_set_value(self._device, position)