climate.py 11 KB

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