climate.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. """
  2. Platform to control tuya climate devices.
  3. """
  4. import logging
  5. from homeassistant.components.climate import ClimateEntity
  6. from homeassistant.components.climate.const import (
  7. ATTR_PRESET_MODE,
  8. DEFAULT_MAX_HUMIDITY,
  9. DEFAULT_MAX_TEMP,
  10. DEFAULT_MIN_HUMIDITY,
  11. DEFAULT_MIN_TEMP,
  12. HVAC_MODE_HEAT,
  13. SUPPORT_FAN_MODE,
  14. SUPPORT_PRESET_MODE,
  15. SUPPORT_SWING_MODE,
  16. SUPPORT_TARGET_HUMIDITY,
  17. SUPPORT_TARGET_TEMPERATURE,
  18. )
  19. from homeassistant.const import ATTR_TEMPERATURE, STATE_UNAVAILABLE
  20. from ..device import TuyaLocalDevice
  21. from ..helpers.device_config import TuyaEntityConfig
  22. _LOGGER = logging.getLogger(__name__)
  23. class TuyaLocalClimate(ClimateEntity):
  24. """Representation of a Tuya Climate entity."""
  25. def __init__(self, device: TuyaLocalDevice, config: TuyaEntityConfig):
  26. """
  27. Initialise the climate device.
  28. Args:
  29. device (TuyaLocalDevice): The device API instance.
  30. config (TuyaEntityConfig): The entity config.
  31. """
  32. self._device = device
  33. self._config = config
  34. self._support_flags = 0
  35. self._current_temperature_dps = None
  36. self._temperature_dps = None
  37. self._current_humidity_dps = None
  38. self._humidity_dps = None
  39. self._preset_mode_dps = None
  40. self._swing_mode_dps = None
  41. self._fan_mode_dps = None
  42. self._hvac_mode_dps = None
  43. self._attr_dps = []
  44. self._temperature_step = 1
  45. for d in config.dps():
  46. if d.name == "hvac_mode":
  47. self._hvac_mode_dps = d
  48. elif d.name == "temperature":
  49. self._temperature_dps = d
  50. self._support_flags |= SUPPORT_TARGET_TEMPERATURE
  51. elif d.name == "current_temperature":
  52. self._current_temperature_dps = d
  53. elif d.name == "humidity":
  54. self._humidity_dps = d
  55. self._support_flags |= SUPPORT_TARGET_HUMIDITY
  56. elif d.name == "current_humidity":
  57. self._current_humidity_dps = d
  58. elif d.name == "preset_mode":
  59. self._preset_mode_dps = d
  60. self._support_flags |= SUPPORT_PRESET_MODE
  61. elif d.name == "swing_mode":
  62. self._swing_mode_dps = d
  63. self._support_flags |= SUPPORT_SWING_MODE
  64. elif d.name == "fan_mode":
  65. self._fan_mode_dps = d
  66. self._support_flags |= SUPPORT_FAN_MODE
  67. else:
  68. self._attr_dps.append(d)
  69. @property
  70. def supported_features(self):
  71. """Return the features supported by this climate device."""
  72. return self._support_flags
  73. @property
  74. def should_poll(self):
  75. """Return the polling state."""
  76. return True
  77. @property
  78. def name(self):
  79. """Return the name of the climate device."""
  80. return self._device.name
  81. @property
  82. def friendly_name(self):
  83. """Return the friendly name of the climate entity for the UI."""
  84. return self._config.name
  85. @property
  86. def unique_id(self):
  87. """Return the unique id for this climate device."""
  88. return self._device.unique_id
  89. @property
  90. def device_info(self):
  91. """Return device information about this heater."""
  92. return self._device.device_info
  93. @property
  94. def icon(self):
  95. """Return the icon to use in the frontend for this device."""
  96. if self.hvac_mode == HVAC_MODE_HEAT:
  97. return "mdi:radiator"
  98. else:
  99. return "mdi:radiator-disabled"
  100. @property
  101. def temperature_unit(self):
  102. """Return the unit of measurement."""
  103. return self._device.temperature_unit
  104. @property
  105. def target_temperature(self):
  106. """Return the currently set target temperature."""
  107. if self._temperature_dps is None:
  108. raise NotImplementedError()
  109. return self._temperature_dps.get_value(self._device)
  110. @property
  111. def target_temperature_step(self):
  112. """Return the supported step of target temperature."""
  113. return self._temperature_step
  114. @property
  115. def min_temp(self):
  116. """Return the minimum supported target temperature."""
  117. if self._temperature_dps is None:
  118. return None
  119. if self._temperature_dps.range is None:
  120. return DEFAULT_MIN_TEMP
  121. return self._temperature_dps.range["min"]
  122. @property
  123. def max_temp(self):
  124. """Return the maximum supported target temperature."""
  125. if self._temperature_dps is None:
  126. return None
  127. if self._temperature_dps.range is None:
  128. return DEFAULT_MAX_TEMP
  129. return self._temperature_dps.range["max"]
  130. async def async_set_temperature(self, **kwargs):
  131. """Set new target temperature."""
  132. if kwargs.get(ATTR_PRESET_MODE) is not None:
  133. await self.async_set_preset_mode(kwargs.get(ATTR_PRESET_MODE))
  134. if kwargs.get(ATTR_TEMPERATURE) is not None:
  135. await self.async_set_target_temperature(kwargs.get(ATTR_TEMPERATURE))
  136. async def async_set_target_temperature(self, target_temperature):
  137. if self._temperature_dps is None:
  138. raise NotImplementedError()
  139. target_temperature = int(round(target_temperature))
  140. await self._temperature_dps.async_set_value(self._device, target_temperature)
  141. @property
  142. def current_temperature(self):
  143. """Return the current measured temperature."""
  144. if self._current_temperature_dps is None:
  145. return None
  146. return self._current_temperature_dps.get_value(self._device)
  147. @property
  148. def target_humidity(self):
  149. """Return the currently set target humidity."""
  150. if self._humidity_dps is None:
  151. raise NotImplementedError()
  152. return self._humidity_dps.get_value(self._device)
  153. @property
  154. def min_humidity(self):
  155. """Return the minimum supported target humidity."""
  156. if self._humidity_dps is None:
  157. return None
  158. if self._humidity_dps.range is None:
  159. return DEFAULT_MIN_HUMIDITY
  160. return self._humidity_dps.range["min"]
  161. @property
  162. def max_humidity(self):
  163. """Return the maximum supported target humidity."""
  164. if self._humidity_dps is None:
  165. return None
  166. if self._humidity_dps.range is None:
  167. return DEFAULT_MAX_HUMIDITY
  168. return self._humidity_dps.range["max"]
  169. async def async_set_humidity(self, target_humidity):
  170. if self._humidity_dps is None:
  171. raise NotImplementedError()
  172. await self._humidity_dps.async_set_value(self._device, target_humidity)
  173. @property
  174. def current_humidity(self):
  175. """Return the current measured humidity."""
  176. if self._current_humidity_dps is None:
  177. return None
  178. return self._current_humidity_dps.get_value(self._device)
  179. @property
  180. def hvac_mode(self):
  181. """Return current HVAC mode."""
  182. if self._hvac_mode_dps is None:
  183. raise NotImplementedError()
  184. hvac_mode = self._hvac_mode_dps.get_value(self._device)
  185. return STATE_UNAVAILABLE if hvac_mode is None else hvac_mode
  186. @property
  187. def hvac_modes(self):
  188. """Return available HVAC modes."""
  189. if self._hvac_mode_dps is None:
  190. return None
  191. else:
  192. return self._hvac_mode_dps.values
  193. async def async_set_hvac_mode(self, hvac_mode):
  194. """Set new HVAC mode."""
  195. if self._hvac_mode_dps is None:
  196. raise NotImplementedError()
  197. await self._hvac_mode_dps.async_set_value(self._device, hvac_mode)
  198. @property
  199. def preset_mode(self):
  200. """Return the current preset mode."""
  201. if self._preset_mode_dps is None:
  202. raise NotImplementedError()
  203. return self._preset_mode_dps.get_value(self._device)
  204. @property
  205. def preset_modes(self):
  206. """Return the list of presets that this device supports."""
  207. if self._preset_mode_dps is None:
  208. return None
  209. return self._preset_mode_dps.values
  210. async def async_set_preset_mode(self, preset_mode):
  211. """Set the preset mode."""
  212. if self._preset_mode_dps is None:
  213. raise NotImplementedError()
  214. await self._preset_mode_dps.async_set_value(self._device, preset_mode)
  215. @property
  216. def swing_mode(self):
  217. """Return the current swing mode."""
  218. if self._swing_mode_dps is None:
  219. raise NotImplementedError()
  220. return self._swing_mode_dps.get_value(self._device)
  221. @property
  222. def swing_modes(self):
  223. """Return the list of swing modes that this device supports."""
  224. if self._swing_mode_dps is None:
  225. return None
  226. return self._swing_mode_dps.values
  227. async def async_set_swing_mode(self, swing_mode):
  228. """Set the preset mode."""
  229. if self._swing_mode_dps is None:
  230. raise NotImplementedError()
  231. await self._swing_mode_dps.async_set_value(self._device, swing_mode)
  232. @property
  233. def fan_mode(self):
  234. """Return the current swing mode."""
  235. if self._fan_mode_dps is None:
  236. raise NotImplementedError()
  237. return self._fan_mode_dps.get_value(self._device)
  238. @property
  239. def fan_modes(self):
  240. """Return the list of swing modes that this device supports."""
  241. if self._fan_mode_dps is None:
  242. return None
  243. return self._fan_mode_dps.values
  244. async def async_set_fan_mode(self, fan_mode):
  245. """Set the preset mode."""
  246. if self._fan_mode_dps is None:
  247. raise NotImplementedError()
  248. await self._fan_mode_dps.async_set_value(self._device, fan_mode)
  249. @property
  250. def device_state_attributes(self):
  251. """Get additional attributes that the integration itself does not support."""
  252. attr = {}
  253. for a in self._attr_dps:
  254. attr[a.name] = a.get_value(self._device)
  255. return attr
  256. async def async_update(self):
  257. await self._device.async_refresh()