test_beok_tr9b_thermostat.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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_problem",
  82. "device_class": BinarySensorDeviceClass.PROBLEM,
  83. "testdata": (1, 0),
  84. },
  85. ],
  86. )
  87. self.setUpMultiNumber(
  88. [
  89. {
  90. "dps": MINTEMP_DPS,
  91. "name": "number_minimum_temperature",
  92. "device_class": NumberDeviceClass.TEMPERATURE,
  93. "min": 5.0,
  94. "max": 300.0,
  95. "step": 1.0,
  96. "scale": 10,
  97. "unit": UnitOfTemperature.CELSIUS,
  98. },
  99. {
  100. "dps": MAXTEMP_DPS,
  101. "name": "number_maximum_temperature",
  102. "device_class": NumberDeviceClass.TEMPERATURE,
  103. "min": 5.0,
  104. "max": 300.0,
  105. "step": 1.0,
  106. "scale": 10,
  107. "unit": UnitOfTemperature.CELSIUS,
  108. },
  109. ],
  110. )
  111. self.mark_secondary(
  112. [
  113. "binary_sensor_problem",
  114. "lock_child_lock",
  115. "number_minimum_temperature",
  116. "number_maximum_temperature",
  117. "select_schedule",
  118. "select_temperature_unit",
  119. "switch_anti_frost",
  120. ],
  121. )
  122. def test_supported_features(self):
  123. self.assertEqual(
  124. self.subject.supported_features,
  125. ClimateEntityFeature.TARGET_TEMPERATURE
  126. | ClimateEntityFeature.TURN_OFF
  127. | ClimateEntityFeature.TURN_ON,
  128. )
  129. def test_temperature_unit(self):
  130. self.dps[UNIT_DPS] = "c"
  131. self.assertEqual(
  132. self.subject.temperature_unit,
  133. UnitOfTemperature.CELSIUS,
  134. )
  135. self.assertEqual(self.subject.target_temperature_step, 0.5)
  136. self.dps[UNIT_DPS] = "f"
  137. self.assertEqual(
  138. self.subject.temperature_unit,
  139. UnitOfTemperature.FAHRENHEIT,
  140. )
  141. self.assertEqual(self.subject.target_temperature_step, 1.0)
  142. def test_precision(self):
  143. self.assertEqual(self.subject.precision, PRECISION_TENTHS)
  144. def test_current_temperature(self):
  145. self.dps[CURRENTTEMP_DPS] = 685
  146. self.assertEqual(self.subject.current_temperature, 68.5)
  147. def test_hvac_mode(self):
  148. self.dps[POWER_DPS] = False
  149. self.dps[HVACMODE_DPS] = "auto"
  150. self.assertEqual(self.subject.hvac_mode, HVACMode.OFF)
  151. self.dps[POWER_DPS] = True
  152. self.assertEqual(self.subject.hvac_mode, HVACMode.AUTO)
  153. self.dps[HVACMODE_DPS] = "manual"
  154. self.assertEqual(self.subject.hvac_mode, HVACMode.HEAT)
  155. def test_hvac_modes(self):
  156. self.assertCountEqual(
  157. self.subject.hvac_modes,
  158. [
  159. HVACMode.HEAT,
  160. HVACMode.AUTO,
  161. HVACMode.OFF,
  162. ],
  163. )
  164. # Override - since min and max are set by attributes, the range
  165. # allowed when setting is wider than normal. The thermostat seems
  166. # to be configurable as at least a water heater (to 212F), as tuya
  167. # doc says max 300.0 for one matching device, and 1000.0 for
  168. # another (after scaling)
  169. async def test_set_target_temperature_fails_outside_valid_range(self):
  170. with self.assertRaisesRegex(
  171. ValueError,
  172. "temperature \\(4.5\\) must be between 5.0 and 300.0",
  173. ):
  174. await self.subject.async_set_target_temperature(4.5)
  175. with self.assertRaisesRegex(
  176. ValueError,
  177. "temperature \\(1001\\) must be between 5.0 and 300.0",
  178. ):
  179. await self.subject.async_set_target_temperature(1001)
  180. def test_extra_state_attributes(self):
  181. self.dps[UNKNOWN101_DPS] = 101
  182. self.dps[UNKNOWN102_DPS] = 102
  183. self.assertDictEqual(
  184. self.subject.extra_state_attributes,
  185. {"unknown_101": 101, "unknown_102": 102},
  186. )
  187. def test_multi_bsensor_extra_state_attributes(self):
  188. self.dps[ERROR_DPS] = 8
  189. self.assertDictEqual(
  190. self.multiBSensor["binary_sensor_problem"].extra_state_attributes,
  191. {"fault_code": 8},
  192. )