siren.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. """
  2. Setup for Tuya siren devices
  3. """
  4. from homeassistant.components.siren import (
  5. SirenEntity,
  6. SirenEntityFeature,
  7. )
  8. from homeassistant.components.siren.const import (
  9. ATTR_DURATION,
  10. ATTR_TONE,
  11. ATTR_VOLUME_LEVEL,
  12. )
  13. from .device import TuyaLocalDevice
  14. from .helpers.config import async_tuya_setup_platform
  15. from .helpers.device_config import TuyaEntityConfig
  16. from .helpers.mixin import TuyaLocalEntity
  17. async def async_setup_entry(hass, config_entry, async_add_entities):
  18. config = {**config_entry.data, **config_entry.options}
  19. await async_tuya_setup_platform(
  20. hass,
  21. async_add_entities,
  22. config,
  23. "siren",
  24. TuyaLocalSiren,
  25. )
  26. class TuyaLocalSiren(TuyaLocalEntity, SirenEntity):
  27. """Representation of a Tuya siren"""
  28. def __init__(self, device: TuyaLocalDevice, config: TuyaEntityConfig):
  29. """
  30. Initialize the siren.
  31. Args:
  32. device (TuyaLocalDevice): The device API instance.
  33. config (TuyaEntityConfig): The config for this entity.
  34. """
  35. super().__init__()
  36. dps_map = self._init_begin(device, config)
  37. self._tone_dp = dps_map.get(ATTR_TONE, None)
  38. self._volume_dp = dps_map.get(ATTR_VOLUME_LEVEL, None)
  39. self._duration_dp = dps_map.get(ATTR_DURATION, None)
  40. self._switch_dp = dps_map.get("switch", None)
  41. self._init_end(dps_map)
  42. # All control of features is through the turn_on service, so we need to
  43. # support that, even if the siren does not support direct control
  44. support = 0
  45. if self._tone_dp:
  46. support |= (
  47. SirenEntityFeature.TONES
  48. | SirenEntityFeature.TURN_ON
  49. | SirenEntityFeature.TURN_OFF
  50. )
  51. self._attr_available_tones = [
  52. x for x in self._tone_dp.values(device) if x != "off"
  53. ]
  54. self._default_tone = self._tone_dp.default
  55. if self._volume_dp:
  56. support |= SirenEntityFeature.VOLUME_SET
  57. if self._duration_dp:
  58. support |= SirenEntityFeature.DURATION
  59. self._attr_supported_features = support
  60. @property
  61. def is_on(self):
  62. """Return whether the siren is on."""
  63. if self._switch_dp:
  64. return self._switch_dp.get_value(self._device)
  65. if self._tone_dp:
  66. return self._tone_dp.get_value(self._device) != "off"
  67. async def async_turn_on(self, **kwargs) -> None:
  68. tone = kwargs.get(ATTR_TONE, None)
  69. duration = kwargs.get(ATTR_DURATION, None)
  70. volume = kwargs.get(ATTR_VOLUME_LEVEL, None)
  71. set_dps = {}
  72. if self._tone_dp:
  73. if tone is None and not self._switch_dp:
  74. tone = self._tone_dp.get_value(self._device)
  75. if tone == "off":
  76. tone = self._default_tone
  77. set_dps = {
  78. **set_dps,
  79. **self._tone_dp.get_values_to_set(self._device, tone),
  80. }
  81. if duration is not None and self._duration_dp:
  82. set_dps = {
  83. **set_dps,
  84. **self._duration_dp.get_values_to_set(self._device, duration),
  85. }
  86. if volume is not None and self._volume_dp:
  87. # Volume is a float, range 0.0-1.0 in Home Assistant
  88. # In tuya it is likely an integer or a fixed list of values.
  89. # For integer, expect scale and step to do the conversion,
  90. # for fixed values, we need to snap to closest value.
  91. if self._volume_dp.values(self._device) is not None:
  92. volume = min(
  93. self._volume_dp.values(self._device),
  94. key=lambda x: abs(x - volume),
  95. )
  96. set_dps = {
  97. **set_dps,
  98. **self._volume_dp.get_values_to_set(self._device, volume),
  99. }
  100. if self._switch_dp and not self.is_on:
  101. set_dps = {
  102. **set_dps,
  103. **self._switch_dp.get_values_to_set(self._device, True),
  104. }
  105. await self._device.async_set_properties(set_dps)
  106. async def async_turn_off(self) -> None:
  107. """Turn off the siren"""
  108. if self._switch_dp:
  109. await self._switch_dp.async_set_value(self._device, False)
  110. elif self._tone_dp:
  111. await self._tone_dp.async_set_value(self._device, "off")