test_beok_tr9b_thermostat.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. def setUp(self):
  37. self.setUpForConfig(
  38. "beok_tr9b_thermostat.yaml",
  39. BEOK_TR9B_PAYLOAD,
  40. )
  41. self.subject = self.entities.get("climate")
  42. self.setUpTargetTemperature(
  43. TEMPERATURE_DPS,
  44. self.subject,
  45. min=41.0,
  46. max=99.0,
  47. scale=10,
  48. step=10,
  49. )
  50. self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
  51. self.setUpMultiSelect(
  52. [
  53. {
  54. "dps": SCHED_DPS,
  55. "name": "select_schedule",
  56. "options": {
  57. "5_2": "Weekday+Weekend",
  58. "6_1": "Mon-Sat+Sun",
  59. "7": "Daily",
  60. },
  61. },
  62. {
  63. "dps": UNIT_DPS,
  64. "name": "select_temperature_unit",
  65. "options": {
  66. "c": "celsius",
  67. "f": "fahrenheit",
  68. },
  69. },
  70. ],
  71. )
  72. self.setUpBasicSwitch(
  73. ANTIFROST_DPS,
  74. self.entities.get("switch_anti_frost"),
  75. )
  76. self.setUpMultiBinarySensors(
  77. [
  78. {
  79. "dps": ERROR_DPS,
  80. "name": "binary_sensor_problem",
  81. "device_class": BinarySensorDeviceClass.PROBLEM,
  82. "testdata": (1, 0),
  83. },
  84. ],
  85. )
  86. self.setUpMultiNumber(
  87. [
  88. {
  89. "dps": MINTEMP_DPS,
  90. "name": "number_minimum_temperature",
  91. "device_class": NumberDeviceClass.TEMPERATURE,
  92. "min": 5.0,
  93. "max": 300.0,
  94. "step": 1.0,
  95. "scale": 10,
  96. "unit": UnitOfTemperature.CELSIUS,
  97. },
  98. {
  99. "dps": MAXTEMP_DPS,
  100. "name": "number_maximum_temperature",
  101. "device_class": NumberDeviceClass.TEMPERATURE,
  102. "min": 5.0,
  103. "max": 300.0,
  104. "step": 1.0,
  105. "scale": 10,
  106. "unit": UnitOfTemperature.CELSIUS,
  107. },
  108. ],
  109. )
  110. self.mark_secondary(
  111. [
  112. "binary_sensor_problem",
  113. "lock_child_lock",
  114. "number_minimum_temperature",
  115. "number_maximum_temperature",
  116. "select_schedule",
  117. "select_temperature_unit",
  118. "switch_anti_frost",
  119. ],
  120. )
  121. def test_supported_features(self):
  122. self.assertEqual(
  123. self.subject.supported_features,
  124. ClimateEntityFeature.TARGET_TEMPERATURE
  125. | ClimateEntityFeature.TURN_OFF
  126. | ClimateEntityFeature.TURN_ON,
  127. )
  128. def test_temperature_unit(self):
  129. self.dps[UNIT_DPS] = "c"
  130. self.assertEqual(
  131. self.subject.temperature_unit,
  132. UnitOfTemperature.CELSIUS,
  133. )
  134. self.assertEqual(self.subject.target_temperature_step, 0.5)
  135. self.dps[UNIT_DPS] = "f"
  136. self.assertEqual(
  137. self.subject.temperature_unit,
  138. UnitOfTemperature.FAHRENHEIT,
  139. )
  140. self.assertEqual(self.subject.target_temperature_step, 1.0)
  141. def test_precision(self):
  142. self.assertEqual(self.subject.precision, PRECISION_TENTHS)
  143. def test_current_temperature(self):
  144. self.dps[CURRENTTEMP_DPS] = 685
  145. self.assertEqual(self.subject.current_temperature, 68.5)
  146. def test_hvac_mode(self):
  147. self.dps[POWER_DPS] = False
  148. self.dps[HVACMODE_DPS] = "auto"
  149. self.assertEqual(self.subject.hvac_mode, HVACMode.OFF)
  150. self.dps[POWER_DPS] = True
  151. self.assertEqual(self.subject.hvac_mode, HVACMode.AUTO)
  152. self.dps[HVACMODE_DPS] = "manual"
  153. self.assertEqual(self.subject.hvac_mode, HVACMode.HEAT)
  154. def test_hvac_modes(self):
  155. self.assertCountEqual(
  156. self.subject.hvac_modes,
  157. [
  158. HVACMode.HEAT,
  159. HVACMode.AUTO,
  160. HVACMode.OFF,
  161. ],
  162. )
  163. # Override - since min and max are set by attributes, the range
  164. # allowed when setting is wider than normal. The thermostat seems
  165. # to be configurable as at least a water heater (to 212F), as tuya
  166. # doc says max 300.0 for one matching device, and 1000.0 for
  167. # another (after scaling)
  168. async def test_set_target_temperature_fails_outside_valid_range(self):
  169. with self.assertRaisesRegex(
  170. ValueError,
  171. "temperature \\(4.5\\) must be between 5.0 and 300.0",
  172. ):
  173. await self.subject.async_set_target_temperature(4.5)
  174. with self.assertRaisesRegex(
  175. ValueError,
  176. "temperature \\(1001\\) must be between 5.0 and 300.0",
  177. ):
  178. await self.subject.async_set_target_temperature(1001)
  179. def test_extra_state_attributes(self):
  180. self.dps[UNKNOWN101_DPS] = 101
  181. self.dps[UNKNOWN102_DPS] = 102
  182. self.assertDictEqual(
  183. self.subject.extra_state_attributes,
  184. {"unknown_101": 101, "unknown_102": 102},
  185. )
  186. def test_multi_bsensor_extra_state_attributes(self):
  187. self.dps[ERROR_DPS] = 8
  188. self.assertDictEqual(
  189. self.multiBSensor["binary_sensor_problem"].extra_state_attributes,
  190. {"fault_code": 8},
  191. )