climate.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. """
  2. Goldair WiFi Dehumidifier device.
  3. """
  4. from homeassistant.components.climate import ClimateDevice
  5. from homeassistant.components.climate.const import (
  6. ATTR_FAN_MODE,
  7. ATTR_HUMIDITY,
  8. ATTR_HVAC_MODE,
  9. ATTR_PRESET_MODE,
  10. FAN_HIGH,
  11. FAN_LOW,
  12. HVAC_MODE_OFF,
  13. SUPPORT_FAN_MODE,
  14. SUPPORT_PRESET_MODE,
  15. SUPPORT_TARGET_HUMIDITY,
  16. )
  17. from homeassistant.const import ATTR_TEMPERATURE, STATE_UNAVAILABLE
  18. from ..device import GoldairTuyaDevice
  19. from .const import (
  20. ATTR_AIR_CLEAN_ON,
  21. ATTR_DEFROSTING,
  22. ATTR_ERROR,
  23. ATTR_TARGET_HUMIDITY,
  24. ERROR_CODE_TO_DPS_CODE,
  25. ERROR_TANK,
  26. FAN_MODE_TO_DPS_MODE,
  27. HVAC_MODE_TO_DPS_MODE,
  28. PRESET_AIR_CLEAN,
  29. PRESET_DRY_CLOTHES,
  30. PRESET_HIGH,
  31. PRESET_LOW,
  32. PRESET_MODE_TO_DPS_MODE,
  33. PRESET_NORMAL,
  34. PROPERTY_TO_DPS_ID,
  35. )
  36. SUPPORT_FLAGS = SUPPORT_TARGET_HUMIDITY | SUPPORT_PRESET_MODE | SUPPORT_FAN_MODE
  37. class GoldairDehumidifier(ClimateDevice):
  38. """Representation of a Goldair WiFi dehumidifier."""
  39. def __init__(self, device):
  40. """Initialize the dehumidifier.
  41. Args:
  42. name (str): The device's name.
  43. device (GoldairTuyaDevice): The device API instance."""
  44. self._device = device
  45. self._support_flags = SUPPORT_FLAGS
  46. self._HUMIDITY_STEP = 5
  47. self._HUMIDITY_LIMITS = {"min": 30, "max": 80}
  48. @property
  49. def supported_features(self):
  50. """Return the list of supported features."""
  51. return self._support_flags
  52. @property
  53. def should_poll(self):
  54. """Return the polling state."""
  55. return True
  56. @property
  57. def name(self):
  58. """Return the name of the climate device."""
  59. return self._device.name
  60. @property
  61. def unique_id(self):
  62. """Return the unique id for this dehumidifier."""
  63. return self._device.unique_id
  64. @property
  65. def device_info(self):
  66. """Return device information about this dehumidifier."""
  67. return self._device.device_info
  68. @property
  69. def icon(self):
  70. """Return the icon to use in the frontend based on the device state."""
  71. if self.tank_full_or_missing:
  72. return "mdi:cup-water"
  73. elif self.defrosting:
  74. return "mdi:snowflake-melt"
  75. elif (
  76. self.hvac_mode is not HVAC_MODE_OFF
  77. and self.preset_mode is PRESET_DRY_CLOTHES
  78. ):
  79. return "mdi:tshirt-crew-outline"
  80. elif (
  81. self.hvac_mode is not HVAC_MODE_OFF and self.preset_mode is PRESET_AIR_CLEAN
  82. ):
  83. return "mdi:air-purifier"
  84. else:
  85. return "mdi:air-humidifier"
  86. @property
  87. def current_humidity(self):
  88. """Return the current reading of the humidity sensor."""
  89. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_HUMIDITY])
  90. @property
  91. def min_humidity(self):
  92. """Return the minimum humidity setting."""
  93. return self._HUMIDITY_LIMITS["min"]
  94. @property
  95. def max_humidity(self):
  96. """Return the maximum humidity setting."""
  97. return self._HUMIDITY_LIMITS["max"]
  98. @property
  99. def target_humidity(self):
  100. """Return the current target humidity."""
  101. if self.preset_mode is PRESET_NORMAL:
  102. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_TARGET_HUMIDITY])
  103. else:
  104. return None
  105. async def async_set_humidity(self, humidity):
  106. """Set the device's target humidity."""
  107. if self.preset_mode is not PRESET_NORMAL:
  108. raise ValueError(
  109. "Target humidity can only be changed while in Normal mode."
  110. )
  111. humidity = int(
  112. self._HUMIDITY_STEP * round(float(humidity) / self._HUMIDITY_STEP)
  113. )
  114. await self._device.async_set_property(
  115. PROPERTY_TO_DPS_ID[ATTR_TARGET_HUMIDITY], humidity
  116. )
  117. @property
  118. def temperature_unit(self):
  119. """Return the unit of measurement."""
  120. return self._device.temperature_unit
  121. @property
  122. def min_temp(self):
  123. """Return the minimum temperature setting."""
  124. return None
  125. @property
  126. def max_temp(self):
  127. """Return the maximum temperature setting."""
  128. return None
  129. @property
  130. def current_temperature(self):
  131. """Return the current temperature."""
  132. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_TEMPERATURE])
  133. @property
  134. def hvac_mode(self):
  135. """Return current HVAC mode, ie Dry or Off."""
  136. dps_mode = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE])
  137. if dps_mode is not None:
  138. return GoldairTuyaDevice.get_key_for_value(HVAC_MODE_TO_DPS_MODE, dps_mode)
  139. else:
  140. return STATE_UNAVAILABLE
  141. @property
  142. def hvac_modes(self):
  143. """Return the list of available HVAC modes."""
  144. return list(HVAC_MODE_TO_DPS_MODE.keys())
  145. async def async_set_hvac_mode(self, hvac_mode):
  146. """Set new HVAC mode."""
  147. dps_mode = HVAC_MODE_TO_DPS_MODE[hvac_mode]
  148. await self._device.async_set_property(
  149. PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE], dps_mode
  150. )
  151. @property
  152. def preset_mode(self):
  153. """Return current preset mode, ie Normal, Low, High, Dry Clothes, or Air Clean."""
  154. air_clean_on = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_AIR_CLEAN_ON])
  155. dps_mode = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE])
  156. if air_clean_on:
  157. return PRESET_AIR_CLEAN
  158. elif dps_mode is not None:
  159. return GoldairTuyaDevice.get_key_for_value(
  160. PRESET_MODE_TO_DPS_MODE, dps_mode
  161. )
  162. else:
  163. return None
  164. @property
  165. def preset_modes(self):
  166. """Return the list of available preset modes."""
  167. return list(PRESET_MODE_TO_DPS_MODE.keys()) + [PRESET_AIR_CLEAN]
  168. async def async_set_preset_mode(self, preset_mode):
  169. """Set new preset mode."""
  170. if preset_mode == PRESET_AIR_CLEAN:
  171. await self._device.async_set_property(
  172. PROPERTY_TO_DPS_ID[ATTR_AIR_CLEAN_ON], True
  173. )
  174. self._device.anticipate_property_value(
  175. PROPERTY_TO_DPS_ID[ATTR_FAN_MODE], FAN_HIGH
  176. )
  177. else:
  178. dps_mode = PRESET_MODE_TO_DPS_MODE[preset_mode]
  179. await self._device.async_set_property(
  180. PROPERTY_TO_DPS_ID[ATTR_AIR_CLEAN_ON], False
  181. )
  182. await self._device.async_set_property(
  183. PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE], dps_mode
  184. )
  185. if preset_mode == PRESET_LOW:
  186. self._device.anticipate_property_value(
  187. PROPERTY_TO_DPS_ID[ATTR_FAN_MODE], FAN_LOW
  188. )
  189. elif preset_mode in [PRESET_HIGH, PRESET_DRY_CLOTHES]:
  190. self._device.anticipate_property_value(
  191. PROPERTY_TO_DPS_ID[ATTR_FAN_MODE], FAN_HIGH
  192. )
  193. @property
  194. def fan_mode(self):
  195. """Return the fan mode."""
  196. preset = self.preset_mode
  197. if preset in [PRESET_HIGH, PRESET_DRY_CLOTHES, PRESET_AIR_CLEAN]:
  198. return FAN_HIGH
  199. elif preset == PRESET_LOW:
  200. return FAN_LOW
  201. else:
  202. dps_mode = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_FAN_MODE])
  203. if dps_mode is not None:
  204. return GoldairTuyaDevice.get_key_for_value(
  205. FAN_MODE_TO_DPS_MODE, dps_mode
  206. )
  207. else:
  208. return None
  209. @property
  210. def fan_modes(self):
  211. """List of fan modes."""
  212. preset = self.preset_mode
  213. if preset in [PRESET_HIGH, PRESET_DRY_CLOTHES, PRESET_AIR_CLEAN]:
  214. return [FAN_HIGH]
  215. elif preset == PRESET_LOW:
  216. return [FAN_LOW]
  217. elif preset == PRESET_NORMAL:
  218. return list(FAN_MODE_TO_DPS_MODE.keys())
  219. else:
  220. return []
  221. async def async_set_fan_mode(self, fan_mode):
  222. """Set new fan mode."""
  223. if self.preset_mode != PRESET_NORMAL:
  224. raise ValueError(
  225. "Fan mode can only be changed while in Normal preset mode."
  226. )
  227. if fan_mode not in FAN_MODE_TO_DPS_MODE.keys():
  228. raise ValueError(f"Invalid fan mode: {fan_mode}")
  229. dps_mode = FAN_MODE_TO_DPS_MODE[fan_mode]
  230. await self._device.async_set_property(
  231. PROPERTY_TO_DPS_ID[ATTR_FAN_MODE], dps_mode
  232. )
  233. @property
  234. def tank_full_or_missing(self):
  235. error = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_ERROR])
  236. return (
  237. GoldairTuyaDevice.get_key_for_value(ERROR_CODE_TO_DPS_CODE, error)
  238. == ERROR_TANK
  239. )
  240. @property
  241. def defrosting(self):
  242. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_DEFROSTING])
  243. @property
  244. def device_state_attributes(self):
  245. """Get additional attributes that HA doesn't naturally support."""
  246. error = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_ERROR])
  247. if error:
  248. error = GoldairTuyaDevice.get_key_for_value(
  249. ERROR_CODE_TO_DPS_CODE, error, error
  250. )
  251. return {ATTR_ERROR: error or None, ATTR_DEFROSTING: self.defrosting}
  252. async def async_update(self):
  253. await self._device.async_refresh()