test_beok_tr9b_thermostat.py 7.0 KB

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