test_minco_mh1823d_thermostat.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. from homeassistant.components.climate.const import (
  2. CURRENT_HVAC_HEAT,
  3. CURRENT_HVAC_IDLE,
  4. CURRENT_HVAC_OFF,
  5. HVAC_MODE_HEAT,
  6. HVAC_MODE_OFF,
  7. SUPPORT_PRESET_MODE,
  8. SUPPORT_TARGET_TEMPERATURE,
  9. )
  10. from homeassistant.const import (
  11. DEVICE_CLASS_TEMPERATURE,
  12. STATE_UNAVAILABLE,
  13. TEMP_CELSIUS,
  14. TEMP_FAHRENHEIT,
  15. )
  16. from ..const import MINCO_MH1823D_THERMOSTAT_PAYLOAD
  17. from ..helpers import assert_device_properties_set
  18. from ..mixins.number import MultiNumberTests
  19. from ..mixins.select import MultiSelectTests
  20. from ..mixins.sensor import BasicSensorTests
  21. from .base_device_tests import TuyaDeviceTestCase
  22. HVACMODE_DPS = "1"
  23. UNKNOWN2_DPS = "2"
  24. HVACACTION_DPS = "3"
  25. UNKNOWN5_DPS = "5"
  26. PRESET_DPS = "9"
  27. UNKNOWN12_DPS = "12"
  28. SELECT_DPS = "18"
  29. UNIT_DPS = "19"
  30. TEMPERATURE_DPS = "22"
  31. TEMPF_DPS = "23"
  32. UNKNOWN32_DPS = "32"
  33. CURRENTTEMP_DPS = "33"
  34. UNKNOWN35_DPS = "35"
  35. CURTEMPF_DPS = "37"
  36. SCHEDULE_DPS = "39"
  37. UNKNOWN45_DPS = "45"
  38. EXTERNTEMP_DPS = "101"
  39. EXTTEMPF_DPS = "102"
  40. CALIBRATE_DPS = "103"
  41. CALIBSWING_DPS = "104"
  42. UNKNOWN105_DPS = "105"
  43. TEMPLIMIT_DPS = "106"
  44. TEMPLIMITF_DPS = "107"
  45. class TestMincoMH1823DThermostat(
  46. BasicSensorTests,
  47. MultiNumberTests,
  48. MultiSelectTests,
  49. TuyaDeviceTestCase,
  50. ):
  51. __test__ = True
  52. def setUp(self):
  53. self.setUpForConfig(
  54. "minco_mh1823d_thermostat.yaml",
  55. MINCO_MH1823D_THERMOSTAT_PAYLOAD,
  56. )
  57. self.subject = self.entities.get("climate")
  58. self.setUpBasicSensor(
  59. EXTERNTEMP_DPS,
  60. self.entities.get("sensor_external_temperature"),
  61. unit=TEMP_CELSIUS,
  62. device_class=DEVICE_CLASS_TEMPERATURE,
  63. state_class="measurement",
  64. testdata=(300, 30.0),
  65. )
  66. self.setUpMultiNumber(
  67. [
  68. {
  69. "name": "number_calibration_offset",
  70. "dps": CALIBRATE_DPS,
  71. "min": -9,
  72. "max": 9,
  73. },
  74. {
  75. "name": "number_calibration_swing",
  76. "dps": CALIBSWING_DPS,
  77. "min": 1,
  78. "max": 9,
  79. },
  80. {
  81. "name": "number_high_temperature_limit",
  82. "dps": TEMPLIMIT_DPS,
  83. "min": 5,
  84. "max": 65,
  85. },
  86. ]
  87. )
  88. self.setUpMultiSelect(
  89. [
  90. {
  91. "name": "select_sensor",
  92. "dps": SELECT_DPS,
  93. "options": {
  94. "in": "Internal",
  95. "out": "External",
  96. },
  97. },
  98. {
  99. "name": "select_temperature_unit",
  100. "dps": UNIT_DPS,
  101. "options": {
  102. "c": "Celsius",
  103. "f": "Fahrenheit",
  104. },
  105. },
  106. {
  107. "name": "select_schedule",
  108. "dps": SCHEDULE_DPS,
  109. "options": {
  110. "7": "7 day",
  111. "5_2": "5+2 day",
  112. "6_1": "6+1 day",
  113. },
  114. },
  115. ]
  116. )
  117. def test_supported_features(self):
  118. self.assertEqual(
  119. self.subject.supported_features,
  120. SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE,
  121. )
  122. def test_icon(self):
  123. self.dps[HVACMODE_DPS] = True
  124. self.dps[HVACACTION_DPS] = "start"
  125. self.dps[PRESET_DPS] = False
  126. self.assertEqual(self.subject.icon, "mdi:thermometer")
  127. self.dps[HVACACTION_DPS] = "stop"
  128. self.assertEqual(self.subject.icon, "mdi:thermometer-off")
  129. self.dps[PRESET_DPS] = True
  130. self.assertEqual(self.subject.icon, "mdi:snowflake")
  131. def test_temperature_unit(self):
  132. self.dps[UNIT_DPS] = "c"
  133. self.assertEqual(self.subject.temperature_unit, TEMP_CELSIUS)
  134. self.dps[UNIT_DPS] = "f"
  135. self.assertEqual(self.subject.temperature_unit, TEMP_FAHRENHEIT)
  136. def test_target_temperature(self):
  137. self.dps[TEMPERATURE_DPS] = 25
  138. self.dps[TEMPF_DPS] = 70
  139. self.dps[UNIT_DPS] = "c"
  140. self.assertEqual(self.subject.target_temperature, 25)
  141. self.dps[UNIT_DPS] = "f"
  142. self.assertEqual(self.subject.target_temperature, 70)
  143. def test_target_temperature_step(self):
  144. self.assertEqual(self.subject.target_temperature_step, 1)
  145. def test_minimum_target_temperature(self):
  146. self.dps[UNIT_DPS] = "c"
  147. self.assertEqual(self.subject.min_temp, 5)
  148. self.dps[UNIT_DPS] = "f"
  149. self.assertEqual(self.subject.min_temp, 41)
  150. def test_maximum_target_temperature(self):
  151. self.dps[UNIT_DPS] = "c"
  152. self.assertEqual(self.subject.max_temp, 50)
  153. self.dps[UNIT_DPS] = "f"
  154. self.assertEqual(self.subject.max_temp, 99)
  155. async def test_legacy_set_temperature_with_temperature(self):
  156. async with assert_device_properties_set(
  157. self.subject._device, {TEMPERATURE_DPS: 24}
  158. ):
  159. await self.subject.async_set_temperature(temperature=24)
  160. async def test_legacy_set_temperature_with_preset_mode(self):
  161. async with assert_device_properties_set(
  162. self.subject._device, {PRESET_DPS: True}
  163. ):
  164. await self.subject.async_set_temperature(preset_mode="away")
  165. async def test_legacy_set_temperature_with_both_properties(self):
  166. async with assert_device_properties_set(
  167. self.subject._device,
  168. {
  169. TEMPERATURE_DPS: 25,
  170. PRESET_DPS: False,
  171. },
  172. ):
  173. await self.subject.async_set_temperature(temperature=25, preset_mode="home")
  174. async def test_legacy_set_temperature_with_no_valid_properties(self):
  175. await self.subject.async_set_temperature(something="else")
  176. self.subject._device.async_set_property.assert_not_called()
  177. async def test_set_target_temperature(self):
  178. async with assert_device_properties_set(
  179. self.subject._device, {TEMPERATURE_DPS: 25}
  180. ):
  181. await self.subject.async_set_target_temperature(25)
  182. async def test_set_target_temperature_rounds_value_to_closest_integer(self):
  183. async with assert_device_properties_set(
  184. self.subject._device,
  185. {TEMPERATURE_DPS: 25},
  186. ):
  187. await self.subject.async_set_target_temperature(24.6)
  188. async def test_set_target_temperature_fails_outside_valid_range(self):
  189. self.dps[UNIT_DPS] = "c"
  190. with self.assertRaisesRegex(
  191. ValueError, "temperature \\(4\\) must be between 5 and 50"
  192. ):
  193. await self.subject.async_set_target_temperature(4)
  194. with self.assertRaisesRegex(
  195. ValueError, "temperature \\(51\\) must be between 5 and 50"
  196. ):
  197. await self.subject.async_set_target_temperature(51)
  198. self.dps[UNIT_DPS] = "f"
  199. with self.assertRaisesRegex(
  200. ValueError, "temp_f \\(40\\) must be between 41 and 99"
  201. ):
  202. await self.subject.async_set_target_temperature(40)
  203. with self.assertRaisesRegex(
  204. ValueError, "temp_f \\(100\\) must be between 41 and 99"
  205. ):
  206. await self.subject.async_set_target_temperature(100)
  207. def test_current_temperature(self):
  208. self.dps[CURRENTTEMP_DPS] = 251
  209. self.dps[CURTEMPF_DPS] = 783
  210. self.dps[UNIT_DPS] = "c"
  211. self.assertEqual(self.subject.current_temperature, 25.1)
  212. self.dps[UNIT_DPS] = "f"
  213. self.assertEqual(self.subject.current_temperature, 78.3)
  214. def test_hvac_mode(self):
  215. self.dps[HVACMODE_DPS] = True
  216. self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT)
  217. self.dps[HVACMODE_DPS] = False
  218. self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
  219. self.dps[HVACMODE_DPS] = None
  220. self.assertEqual(self.subject.hvac_mode, STATE_UNAVAILABLE)
  221. def test_hvac_modes(self):
  222. self.assertCountEqual(self.subject.hvac_modes, [HVAC_MODE_OFF, HVAC_MODE_HEAT])
  223. async def test_turn_on(self):
  224. async with assert_device_properties_set(
  225. self.subject._device, {HVACMODE_DPS: True}
  226. ):
  227. await self.subject.async_set_hvac_mode(HVAC_MODE_HEAT)
  228. async def test_turn_off(self):
  229. async with assert_device_properties_set(
  230. self.subject._device, {HVACMODE_DPS: False}
  231. ):
  232. await self.subject.async_set_hvac_mode(HVAC_MODE_OFF)
  233. def test_preset_mode(self):
  234. self.dps[PRESET_DPS] = False
  235. self.assertEqual(self.subject.preset_mode, "home")
  236. self.dps[PRESET_DPS] = True
  237. self.assertEqual(self.subject.preset_mode, "away")
  238. self.dps[PRESET_DPS] = None
  239. self.assertEqual(self.subject.preset_mode, None)
  240. def test_preset_modes(self):
  241. self.assertCountEqual(
  242. self.subject.preset_modes,
  243. ["home", "away"],
  244. )
  245. async def test_set_preset_mode_to_home(self):
  246. async with assert_device_properties_set(
  247. self.subject._device,
  248. {PRESET_DPS: False},
  249. ):
  250. await self.subject.async_set_preset_mode("home")
  251. async def test_set_preset_mode_to_away(self):
  252. async with assert_device_properties_set(
  253. self.subject._device,
  254. {PRESET_DPS: True},
  255. ):
  256. await self.subject.async_set_preset_mode("away")
  257. def test_hvac_action(self):
  258. self.dps[HVACMODE_DPS] = True
  259. self.dps[HVACACTION_DPS] = "start"
  260. self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_HEAT)
  261. self.dps[HVACACTION_DPS] = "stop"
  262. self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_IDLE)
  263. self.dps[HVACMODE_DPS] = False
  264. self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_OFF)
  265. def test_device_state_attributes(self):
  266. self.dps[UNKNOWN2_DPS] = "unknown 2"
  267. self.dps[UNKNOWN5_DPS] = True
  268. self.dps[UNKNOWN12_DPS] = False
  269. self.dps[UNKNOWN32_DPS] = 32
  270. self.dps[UNKNOWN35_DPS] = 35
  271. self.dps[UNKNOWN45_DPS] = 45
  272. self.dps[UNKNOWN105_DPS] = "unknown 105"
  273. self.assertDictEqual(
  274. self.subject.device_state_attributes,
  275. {
  276. "unknown_2": "unknown 2",
  277. "unknown_5": True,
  278. "unknown_12": False,
  279. "unknown_32": 32,
  280. "unknown_35": 35,
  281. "unknown_45": 45,
  282. "unknown_105": "unknown 105",
  283. },
  284. )