climate.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. """
  2. Goldair WiFi Heater device.
  3. """
  4. from homeassistant.const import (
  5. ATTR_TEMPERATURE, TEMP_CELSIUS, STATE_UNAVAILABLE
  6. )
  7. from homeassistant.components.climate import ClimateDevice
  8. from homeassistant.components.climate.const import (
  9. ATTR_HVAC_MODE, ATTR_PRESET_MODE,
  10. SUPPORT_TARGET_TEMPERATURE, SUPPORT_PRESET_MODE, SUPPORT_SWING_MODE
  11. )
  12. from ..device import GoldairTuyaDevice
  13. from .const import (
  14. ATTR_TARGET_TEMPERATURE, ATTR_POWER_MODE_AUTO, ATTR_POWER_MODE_USER, ATTR_POWER_LEVEL, ATTR_POWER_MODE,
  15. ATTR_ECO_TARGET_TEMPERATURE, STATE_COMFORT, STATE_ECO, STATE_ANTI_FREEZE, PROPERTY_TO_DPS_ID, HVAC_MODE_TO_DPS_MODE,
  16. PRESET_MODE_TO_DPS_MODE, POWER_LEVEL_TO_DPS_LEVEL
  17. )
  18. SUPPORT_FLAGS = SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE | SUPPORT_SWING_MODE
  19. class GoldairHeater(ClimateDevice):
  20. """Representation of a Goldair WiFi heater."""
  21. def __init__(self, device):
  22. """Initialize the heater.
  23. Args:
  24. name (str): The device's name.
  25. device (GoldairTuyaDevice): The device API instance."""
  26. self._device = device
  27. self._support_flags = SUPPORT_FLAGS
  28. self._TEMPERATURE_STEP = 1
  29. self._TEMPERATURE_LIMITS = {
  30. STATE_COMFORT: {
  31. 'min': 5,
  32. 'max': 35
  33. },
  34. STATE_ECO: {
  35. 'min': 5,
  36. 'max': 21
  37. }
  38. }
  39. @property
  40. def supported_features(self):
  41. """Return the list of supported features."""
  42. return self._support_flags
  43. @property
  44. def should_poll(self):
  45. """Return the polling state."""
  46. return True
  47. @property
  48. def name(self):
  49. """Return the name of the climate device."""
  50. return self._device.name
  51. @property
  52. def temperature_unit(self):
  53. """Return the unit of measurement."""
  54. return self._device.temperature_unit
  55. @property
  56. def target_temperature(self):
  57. """Return the temperature we try to reach."""
  58. if self.preset_mode == STATE_COMFORT:
  59. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_TARGET_TEMPERATURE])
  60. elif self.preset_mode == STATE_ECO:
  61. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_ECO_TARGET_TEMPERATURE])
  62. else:
  63. return None
  64. @property
  65. def target_temperature_step(self):
  66. """Return the supported step of target temperature."""
  67. return self._TEMPERATURE_STEP
  68. @property
  69. def min_temp(self):
  70. """Return the minimum temperature."""
  71. if self.preset_mode and self.preset_mode != STATE_ANTI_FREEZE:
  72. return self._TEMPERATURE_LIMITS[self.preset_mode]['min']
  73. else:
  74. return None
  75. @property
  76. def max_temp(self):
  77. """Return the maximum temperature."""
  78. if self.preset_mode and self.preset_mode != STATE_ANTI_FREEZE:
  79. return self._TEMPERATURE_LIMITS[self.preset_mode]['max']
  80. else:
  81. return None
  82. async def async_set_temperature(self, **kwargs):
  83. """Set new target temperatures."""
  84. if kwargs.get(ATTR_PRESET_MODE) is not None:
  85. await self.async_set_preset_mode(kwargs.get(ATTR_PRESET_MODE))
  86. if kwargs.get(ATTR_TEMPERATURE) is not None:
  87. await self.async_set_target_temperature(kwargs.get(ATTR_TEMPERATURE))
  88. async def async_set_target_temperature(self, target_temperature):
  89. target_temperature = int(round(target_temperature))
  90. preset_mode = self.preset_mode
  91. if preset_mode == STATE_ANTI_FREEZE:
  92. raise ValueError('You cannot set the temperature in Anti-freeze mode.')
  93. limits = self._TEMPERATURE_LIMITS[preset_mode]
  94. if not limits['min'] <= target_temperature <= limits['max']:
  95. raise ValueError(
  96. f'Target temperature ({target_temperature}) must be between '
  97. f'{limits["min"]} and {limits["max"]}'
  98. )
  99. if preset_mode == STATE_COMFORT:
  100. await self._device.async_set_property(PROPERTY_TO_DPS_ID[ATTR_TARGET_TEMPERATURE], target_temperature)
  101. elif preset_mode == STATE_ECO:
  102. await self._device.async_set_property(PROPERTY_TO_DPS_ID[ATTR_ECO_TARGET_TEMPERATURE], target_temperature)
  103. @property
  104. def current_temperature(self):
  105. """Return the current temperature."""
  106. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_TEMPERATURE])
  107. @property
  108. def hvac_mode(self):
  109. """Return current HVAC mode, ie Heat or Off."""
  110. dps_mode = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE])
  111. if dps_mode is not None:
  112. return GoldairTuyaDevice.get_key_for_value(HVAC_MODE_TO_DPS_MODE, dps_mode)
  113. else:
  114. return STATE_UNAVAILABLE
  115. @property
  116. def hvac_modes(self):
  117. """Return the list of available HVAC modes."""
  118. return list(HVAC_MODE_TO_DPS_MODE.keys())
  119. async def async_set_hvac_mode(self, hvac_mode):
  120. """Set new HVAC mode."""
  121. dps_mode = HVAC_MODE_TO_DPS_MODE[hvac_mode]
  122. await self._device.async_set_property(PROPERTY_TO_DPS_ID[ATTR_HVAC_MODE], dps_mode)
  123. @property
  124. def preset_mode(self):
  125. """Return current preset mode, ie Comfort, Eco, Anti-freeze."""
  126. dps_mode = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE])
  127. if dps_mode is not None:
  128. return GoldairTuyaDevice.get_key_for_value(PRESET_MODE_TO_DPS_MODE, dps_mode)
  129. else:
  130. return None
  131. @property
  132. def preset_modes(self):
  133. """Return the list of available preset modes."""
  134. return list(PRESET_MODE_TO_DPS_MODE.keys())
  135. async def async_set_preset_mode(self, preset_mode):
  136. """Set new preset mode."""
  137. dps_mode = PRESET_MODE_TO_DPS_MODE[preset_mode]
  138. await self._device.async_set_property(PROPERTY_TO_DPS_ID[ATTR_PRESET_MODE], dps_mode)
  139. @property
  140. def swing_mode(self):
  141. """Return the power level."""
  142. dps_mode = self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_POWER_MODE])
  143. if dps_mode == ATTR_POWER_MODE_USER:
  144. return self._device.get_property(PROPERTY_TO_DPS_ID[ATTR_POWER_LEVEL])
  145. elif dps_mode == ATTR_POWER_MODE_AUTO:
  146. return GoldairTuyaDevice.get_key_for_value(POWER_LEVEL_TO_DPS_LEVEL, dps_mode)
  147. else:
  148. return None
  149. @property
  150. def swing_modes(self):
  151. """List of power levels."""
  152. return list(POWER_LEVEL_TO_DPS_LEVEL.keys())
  153. async def async_set_swing_mode(self, swing_mode):
  154. """Set new power level."""
  155. new_level = swing_mode
  156. if new_level not in POWER_LEVEL_TO_DPS_LEVEL.keys():
  157. raise ValueError(f'Invalid power level: {new_level}')
  158. dps_level = POWER_LEVEL_TO_DPS_LEVEL[new_level]
  159. await self._device.async_set_property(PROPERTY_TO_DPS_ID[ATTR_POWER_LEVEL], dps_level)
  160. async def async_update(self):
  161. await self._device.async_refresh()