datetime.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. """
  2. Setup for Tuya datetime entities
  3. """
  4. import logging
  5. import time
  6. from datetime import datetime, timedelta, timezone
  7. from homeassistant.components.datetime import DateTimeEntity
  8. from .device import TuyaLocalDevice
  9. from .entity import TuyaLocalEntity
  10. from .helpers.config import async_tuya_setup_platform
  11. from .helpers.device_config import TuyaEntityConfig
  12. _LOGGER = logging.getLogger(__name__)
  13. EPOCH = datetime(1970, 1, 1, tzinfo=timezone.utc)
  14. async def async_setup_entry(hass, config_entry, async_add_entities):
  15. config = {**config_entry.data, **config_entry.options}
  16. await async_tuya_setup_platform(
  17. hass,
  18. async_add_entities,
  19. config,
  20. "datetime",
  21. TuyaLocalDateTime,
  22. )
  23. class TuyaLocalDateTime(TuyaLocalEntity, DateTimeEntity):
  24. """Representation of a Tuya DateTime"""
  25. def __init__(self, device: TuyaLocalDevice, config: TuyaEntityConfig):
  26. """
  27. Initialise the datetime entity.
  28. Args:
  29. device (TuyaLocalDevice): the device API instance
  30. config (TuyaEntityConfig): the configuration for this entity
  31. """
  32. super().__init__()
  33. dps_map = self._init_begin(device, config)
  34. self._year_dps = dps_map.pop("year", None)
  35. self._month_dps = dps_map.pop("month", None)
  36. self._day_dps = dps_map.pop("day", None)
  37. self._hour_dps = dps_map.pop("hour", None)
  38. self._minute_dps = dps_map.pop("minute", None)
  39. self._second_dps = dps_map.pop("second", None)
  40. if (
  41. self._year_dps is None
  42. and self._month_dps is None
  43. and self._day_dps is None
  44. and self._hour_dps is None
  45. and self._minute_dps is None
  46. and self._second_dps is None
  47. ):
  48. raise AttributeError(
  49. f"{config.config_id} is missing an hour, minute or second dp"
  50. )
  51. self._init_end(dps_map)
  52. @property
  53. def native_value(self):
  54. """Return the current value of the time."""
  55. year = month = day = hours = minutes = seconds = None
  56. tz = timezone.utc
  57. if self._year_dps:
  58. year = self._year_dps.get_value(self._device)
  59. tz = time.now().astimezone().tzinfo
  60. if self._month_dps:
  61. month = self._month_dps.get_value(self._device)
  62. if self._day_dps:
  63. day = self._day_dps.get_value(self._device)
  64. if self._hour_dps:
  65. hours = self._hour_dps.get_value(self._device)
  66. if self._minute_dps:
  67. minutes = self._minute_dps.get_value(self._device)
  68. if self._second_dps:
  69. seconds = self._second_dps.get_value(self._device)
  70. if (
  71. year is None
  72. and month is None
  73. and day is None
  74. and hours is None
  75. and minutes is None
  76. and seconds is None
  77. ):
  78. return None
  79. year = year or 1970
  80. month = month or 1
  81. days = (day or 1) - 1
  82. hours = hours or 0
  83. minutes = minutes or 0
  84. seconds = seconds or 0
  85. delta = timedelta(
  86. days=int(days),
  87. hours=int(hours),
  88. minutes=int(minutes),
  89. seconds=int(seconds),
  90. )
  91. return datetime(year=year, month=month, day=1, tzinfo=tz) + delta
  92. async def async_set_value(self, value: datetime):
  93. """Set the datetime."""
  94. settings = {}
  95. # Use Local time if split into components
  96. if self._year_dps:
  97. tz = time.now().astimezone().tzinfo
  98. value = value.astimezone(tz)
  99. year = value.year
  100. month = value.month
  101. day = value.day
  102. hour = value.hour
  103. minute = value.minute
  104. second = value.second
  105. if self._year_dps:
  106. settings.update(
  107. self._year_dps.get_values_to_set(self._device, year, settings)
  108. )
  109. month = month + (year - 1970) * 12
  110. if self._month_dps:
  111. settings.update(
  112. self._month_dps.get_values_to_set(self._device, month, settings)
  113. )
  114. else:
  115. if self._year_dps is None:
  116. from_year = 1970
  117. else:
  118. from_year = value.year
  119. day = (
  120. day
  121. + (
  122. datetime(value.year, value.month, 1) - datetime(from_year, 1, 1)
  123. ).days
  124. - 1
  125. )
  126. if self._day_dps:
  127. settings.update(
  128. self._day_dps.get_values_to_set(self._device, day, settings)
  129. )
  130. else:
  131. hour = hour + day * 24
  132. if self._hour_dps:
  133. settings.update(
  134. self._hour_dps.get_values_to_set(self._device, hour, settings)
  135. )
  136. else:
  137. minute = minute + hour * 60
  138. if self._minute_dps:
  139. settings.update(
  140. self._minute_dps.get_values_to_set(self._device, minute, settings)
  141. )
  142. else:
  143. second = second + minute * 60
  144. if self._second_dps:
  145. settings.update(
  146. self._second_dps.get_values_to_set(self._device, second, settings)
  147. )
  148. else:
  149. _LOGGER.debug(
  150. "%s: Discarding unused precision: %d seconds",
  151. self.name,
  152. second,
  153. )
  154. await self._device.async_set_properties(settings)