test_beok_tr9b_thermostat.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. from homeassistant.components.climate.const import (
  2. HVAC_MODE_AUTO,
  3. HVAC_MODE_HEAT,
  4. HVAC_MODE_OFF,
  5. SUPPORT_TARGET_TEMPERATURE,
  6. )
  7. from homeassistant.const import STATE_UNAVAILABLE, TEMP_CELSIUS, TEMP_FAHRENHEIT
  8. from ..const import BEOK_TR9B_PAYLOAD
  9. from ..helpers import assert_device_properties_set
  10. from ..mixins.climate import TargetTemperatureTests
  11. from ..mixins.binary_sensor import MultiBinarySensorTests
  12. from ..mixins.lock import BasicLockTests
  13. from ..mixins.number import MultiNumberTests
  14. from ..mixins.select import MultiSelectTests
  15. from ..mixins.switch import BasicSwitchTests
  16. from .base_device_tests import TuyaDeviceTestCase
  17. POWER_DPS = "1"
  18. HVACMODE_DPS = "2"
  19. ANTIFROST_DPS = "10"
  20. TEMPERATURE_DPS = "16"
  21. MAXTEMP_DPS = "19"
  22. UNIT_DPS = "23"
  23. CURRENTTEMP_DPS = "24"
  24. MINTEMP_DPS = "26"
  25. SCHED_DPS = "31"
  26. VALVE_DPS = "36"
  27. LOCK_DPS = "40"
  28. ERROR_DPS = "45"
  29. UNKNOWN101_DPS = "101"
  30. UNKNOWN102_DPS = "102"
  31. class TestBeokTR9BThermostat(
  32. MultiBinarySensorTests,
  33. BasicLockTests,
  34. MultiNumberTests,
  35. MultiSelectTests,
  36. BasicSwitchTests,
  37. TargetTemperatureTests,
  38. TuyaDeviceTestCase,
  39. ):
  40. __test__ = True
  41. def setUp(self):
  42. self.setUpForConfig(
  43. "beok_tr9b_thermostat.yaml",
  44. BEOK_TR9B_PAYLOAD,
  45. )
  46. self.subject = self.entities.get("climate")
  47. self.setUpTargetTemperature(
  48. TEMPERATURE_DPS,
  49. self.subject,
  50. min=41.0,
  51. max=99.0,
  52. scale=10,
  53. step=10,
  54. )
  55. self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
  56. self.setUpMultiSelect(
  57. [
  58. {
  59. "dps": SCHED_DPS,
  60. "name": "select_schedule",
  61. "options": {
  62. "5_2": "Weekday+Weekend",
  63. "6_1": "Mon-Sat+Sun",
  64. "7": "Daily",
  65. },
  66. },
  67. {
  68. "dps": UNIT_DPS,
  69. "name": "select_temperature_unit",
  70. "options": {
  71. "c": "Celsius",
  72. "f": "Fahrenheit",
  73. },
  74. },
  75. ],
  76. )
  77. self.setUpBasicSwitch(
  78. ANTIFROST_DPS,
  79. self.entities.get("switch_anti_frost"),
  80. )
  81. self.setUpMultiBinarySensors(
  82. [
  83. {
  84. "dps": ERROR_DPS,
  85. "name": "binary_sensor_error",
  86. "device_class": "problem",
  87. "testdata": (1, 0),
  88. },
  89. {
  90. "dps": VALVE_DPS,
  91. "name": "binary_sensor_valve",
  92. "device_class": "opening",
  93. "testdata": ("open", "close"),
  94. },
  95. ],
  96. )
  97. self.setUpMultiNumber(
  98. [
  99. {
  100. "dps": MINTEMP_DPS,
  101. "name": "number_low_temperature_limit",
  102. "min": 5.0,
  103. "max": 1000.0,
  104. "step": 1.0,
  105. "scale": 10,
  106. "unit": TEMP_CELSIUS,
  107. },
  108. {
  109. "dps": MAXTEMP_DPS,
  110. "name": "number_high_temperature_limit",
  111. "min": 5.0,
  112. "max": 1000.0,
  113. "step": 1.0,
  114. "scale": 10,
  115. "unit": TEMP_CELSIUS,
  116. },
  117. ],
  118. )
  119. self.mark_secondary(
  120. [
  121. "binary_sensor_error",
  122. "binary_sensor_valve",
  123. "lock_child_lock",
  124. "number_low_temperature_limit",
  125. "number_high_temperature_limit",
  126. "select_schedule",
  127. "select_temperature_unit",
  128. "switch_anti_frost",
  129. ],
  130. )
  131. def test_supported_features(self):
  132. self.assertEqual(
  133. self.subject.supported_features,
  134. SUPPORT_TARGET_TEMPERATURE,
  135. )
  136. def test_temperature_unit(self):
  137. self.dps[UNIT_DPS] = "c"
  138. self.assertEqual(
  139. self.subject.temperature_unit,
  140. TEMP_CELSIUS,
  141. )
  142. self.assertEqual(self.subject.target_temperature_step, 0.5)
  143. self.dps[UNIT_DPS] = "f"
  144. self.assertEqual(
  145. self.subject.temperature_unit,
  146. TEMP_FAHRENHEIT,
  147. )
  148. self.assertEqual(self.subject.target_temperature_step, 1.0)
  149. def test_current_temperature(self):
  150. self.dps[CURRENTTEMP_DPS] = 685
  151. self.assertEqual(self.subject.current_temperature, 68.5)
  152. def test_hvac_mode(self):
  153. self.dps[POWER_DPS] = False
  154. self.dps[HVACMODE_DPS] = "auto"
  155. self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
  156. self.dps[POWER_DPS] = True
  157. self.assertEqual(self.subject.hvac_mode, HVAC_MODE_AUTO)
  158. self.dps[HVACMODE_DPS] = "manual"
  159. self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT)
  160. self.dps[HVACMODE_DPS] = None
  161. self.assertEqual(self.subject.hvac_mode, STATE_UNAVAILABLE)
  162. def test_hvac_modes(self):
  163. self.assertCountEqual(
  164. self.subject.hvac_modes,
  165. [
  166. HVAC_MODE_HEAT,
  167. HVAC_MODE_AUTO,
  168. HVAC_MODE_OFF,
  169. ],
  170. )
  171. # Override - since min and max are set by attributes, the range
  172. # allowed when setting is wider than normal. The thermostat seems
  173. # to be configurable as at least a water heater (to 212F), as tuya
  174. # doc says max 1000.0 (after scaling)
  175. async def test_set_target_temperature_fails_outside_valid_range(self):
  176. with self.assertRaisesRegex(
  177. ValueError,
  178. f"temperature \\(4.5\\) must be between 5.0 and 1000.0",
  179. ):
  180. await self.subject.async_set_target_temperature(4.5)
  181. with self.assertRaisesRegex(
  182. ValueError,
  183. f"temperature \\(1001\\) must be between 5.0 and 1000.0",
  184. ):
  185. await self.subject.async_set_target_temperature(1001)
  186. def test_extra_state_attributes(self):
  187. self.dps[ERROR_DPS] = 8
  188. self.dps[UNKNOWN101_DPS] = 101
  189. self.dps[UNKNOWN102_DPS] = 102
  190. self.assertDictEqual(
  191. self.subject.extra_state_attributes,
  192. {"Error Code": 8, "unknown_101": 101, "unknown_102": 102},
  193. )
  194. def test_icons(self):
  195. self.dps[LOCK_DPS] = True
  196. self.assertEqual(self.basicLock.icon, "mdi:hand-back-right-off")
  197. self.dps[LOCK_DPS] = False
  198. self.assertEqual(self.basicLock.icon, "mdi:hand-back-right")