Просмотр исходного кода

Add support for Saswell T29UTK thermostat.

Per details in issue #45 by @Uaeguy
Jason Rumney 4 лет назад
Родитель
Сommit
1f96a378db

+ 113 - 0
custom_components/tuya_local/devices/saswell_t29utk_thermostat.yaml

@@ -0,0 +1,113 @@
+name: Saswell T29UTK-7-S-(TY) Thermostat
+primary_entity:
+  entity: climate
+  dps:
+    - id: 1
+      name: power
+      type: boolean
+      hidden: true
+      mapping:
+        - dps_val: false
+          value: "off"
+    - id: 2
+      name: temperature
+      type: integer
+      mapping:
+        - scale: 10
+          constraint: temperature_unit
+          conditions:
+            - dps_val: c
+              range:
+                min: 50
+                max: 350
+              step: 5
+            - dps_val: f
+              range:
+                min: 410
+                max: 950
+              step: 10
+    - id: 3
+      name: current_temperature
+      type: integer
+      mapping:
+        - scale: 10
+    - id: 4
+      name: hvac_action
+      type: string
+      mapping:
+        - dps_val: cold
+          value: cooling
+          icon: "mdi:thermometer-minus"
+        - dps_val: heat
+          value: heating
+          icon: "mdi:thermometer-plus"
+        - dps_val: "off"
+          constraint: power
+          conditions:
+            - dps_val: true
+              value: idle
+              icon: "mdi:thermometer"
+            - dps_val: false
+              value: "off"
+              icon: "mdi:thermometer-off"
+    - id: 5
+      name: fan_mode
+      type: string
+      mapping:
+        - dps_val: "auto"
+          value: "auto"
+        - dps_val: "on"
+          value: "on"
+    - id: 19
+      name: temperature_unit
+      type: string
+      mapping:
+        - dps_val: f
+          value: F
+        - dps_val: c
+          value: C
+    - id: 101
+      name: unknown_101
+      type: boolean
+    - id: 102
+      name: unknown_102
+      type: boolean
+    - id: 103
+      name: hvac_mode
+      type: string
+      mapping:
+        - dps_val: cold
+          constraint: power
+          conditions:
+            - dps_val: false
+              value_redirect: power
+            - dps_val: true
+              value: cool
+        - dps_val: heat
+          constraint: power
+          conditions:
+            - dps_val: false
+              value-redirect: power
+              value: "off"
+            - dps_val: true
+              value: heat
+    - id: 112
+      name: unknown_112
+      type: string
+    - id: 113
+      name: unknown_113
+      type: integer
+    - id: 114
+      name: temperature_c
+      type: integer
+    - id: 115
+      name: current_temperature_c
+      type: integer
+    - id: 116
+      name: temperature_f
+      type: integer
+    - id: 117
+      name: current_temperature_f
+      type: integer
+
+      

+ 18 - 0
tests/const.py

@@ -359,3 +359,21 @@ WETAIR_WCH750_HEATER_PAYLOAD = {
     "21": 0,
     "101": "level1",
 }
+
+SASWELL_T29UTK_THERMOSTAT_PAYLOAD = {
+    "1": True,
+    "2": 240,
+    "3": 241,
+    "4": "cold",
+    "5": "auto",
+    "19": "c",
+    "101": False,
+    "102": False,
+    "103": "cold",
+    "112": "1",
+    "113": 0,
+    "114": 24,
+    "115": 24,
+    "116": 75,
+    "117": 81,
+}

+ 207 - 0
tests/devices/test_saswell_t29utk_thermostat.py

@@ -0,0 +1,207 @@
+from homeassistant.components.climate.const import (
+    CURRENT_HVAC_COOL,
+    CURRENT_HVAC_HEAT,
+    CURRENT_HVAC_IDLE,
+    CURRENT_HVAC_OFF,
+    FAN_AUTO,
+    FAN_ON,
+    HVAC_MODE_COOL,
+    HVAC_MODE_HEAT,
+    HVAC_MODE_OFF,
+    SUPPORT_TARGET_TEMPERATURE,
+    SUPPORT_FAN_MODE,
+)
+from homeassistant.const import STATE_UNAVAILABLE, TEMP_CELSIUS, TEMP_FAHRENHEIT
+from unittest.mock import ANY
+
+from ..const import SASWELL_T29UTK_THERMOSTAT_PAYLOAD
+from ..helpers import assert_device_properties_set
+from .base_device_tests import TuyaDeviceTestCase
+
+POWER_DPS = "1"
+TEMPERATURE_DPS = "2"
+CURRENTTEMP_DPS = "3"
+HVACACTION_DPS = "4"
+FAN_DPS = "5"
+UNITS_DPS = "19"
+UNKNOWN101_DPS = "101"
+UNKNOWN102_DPS = "102"
+HVACMODE_DPS = "103"
+UNKNOWN112_DPS = "112"
+UNKNOWN113_DPS = "113"
+TEMPC_DPS = "114"
+CURTEMPC_DPS = "115"
+TEMPF_DPS = "116"
+CURTEMPF_DPS = "117"
+
+
+class TestSaswellT29UTKThermostat(TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig(
+            "saswell_t29utk_thermostat.yaml", SASWELL_T29UTK_THERMOSTAT_PAYLOAD
+        )
+        self.subject = self.entities.get("climate")
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_TARGET_TEMPERATURE | SUPPORT_FAN_MODE,
+        )
+
+    def test_icon(self):
+        self.dps[POWER_DPS] = True
+        self.dps[HVACACTION_DPS] = "cold"
+        self.assertEqual(self.subject.icon, "mdi:thermometer-minus")
+
+        self.dps[HVACACTION_DPS] = "heat"
+        self.assertEqual(self.subject.icon, "mdi:thermometer-plus")
+
+        self.dps[HVACACTION_DPS] = "off"
+        self.assertEqual(self.subject.icon, "mdi:thermometer")
+
+        self.dps[POWER_DPS] = False
+        self.assertEqual(self.subject.icon, "mdi:thermometer-off")
+
+    def test_temperature_unit(self):
+        self.dps[UNITS_DPS] = "c"
+        self.assertEqual(self.subject.temperature_unit, TEMP_CELSIUS)
+
+        self.dps[UNITS_DPS] = "f"
+        self.assertEqual(self.subject.temperature_unit, TEMP_FAHRENHEIT)
+
+    def test_target_temperature(self):
+        self.dps[TEMPERATURE_DPS] = 250
+        self.assertEqual(self.subject.target_temperature, 25.0)
+
+    def test_target_temperature_step(self):
+        self.dps[UNITS_DPS] = "c"
+        self.assertEqual(self.subject.target_temperature_step, 0.5)
+        self.dps[UNITS_DPS] = "f"
+        self.assertEqual(self.subject.target_temperature_step, 1)
+
+    def test_minimum_target_temperature(self):
+        self.assertEqual(self.subject.min_temp, 5)
+
+    def test_maximum_target_temperature(self):
+        self.assertEqual(self.subject.max_temp, 35)
+
+    async def test_set_target_temperature(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {TEMPERATURE_DPS: 245},
+        ):
+            await self.subject.async_set_target_temperature(24.5)
+
+    async def test_set_target_temperature_rounds_value_to_half_degrees(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {TEMPERATURE_DPS: 245},
+        ):
+            await self.subject.async_set_target_temperature(24.6)
+
+    async def test_set_target_temperature_fails_outside_valid_range(self):
+        with self.assertRaisesRegex(
+            ValueError, "temperature \\(4\\) must be between 5.0 and 35.0"
+        ):
+            await self.subject.async_set_target_temperature(4)
+
+    def test_current_temperature(self):
+        self.dps[CURRENTTEMP_DPS] = 250
+        self.assertEqual(self.subject.current_temperature, 25.0)
+
+    def test_hvac_mode(self):
+        self.dps[POWER_DPS] = False
+        self.dps[HVACMODE_DPS] = "cold"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
+
+        self.dps[POWER_DPS] = True
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_COOL)
+
+        self.dps[HVACMODE_DPS] = "heat"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT)
+
+    def test_hvac_modes(self):
+        self.assertCountEqual(
+            self.subject.hvac_modes,
+            [HVAC_MODE_COOL, HVAC_MODE_HEAT, HVAC_MODE_OFF],
+        )
+
+    async def test_turn_off(self):
+        async with assert_device_properties_set(
+            self.subject._device, {POWER_DPS: False, HVACMODE_DPS: ANY}
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_OFF)
+
+    async def test_set_hvac_mode_cool(self):
+        async with assert_device_properties_set(
+            self.subject._device, {POWER_DPS: True, HVACMODE_DPS: "cold"}
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_COOL)
+
+    async def test_set_hvac_mode_heat(self):
+        async with assert_device_properties_set(
+            self.subject._device, {POWER_DPS: True, HVACMODE_DPS: "heat"}
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_HEAT)
+
+    def test_hvac_action(self):
+        self.dps[POWER_DPS] = True
+        self.dps[HVACACTION_DPS] = "cold"
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_COOL)
+
+        self.dps[HVACACTION_DPS] = "heat"
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_HEAT)
+        self.dps[HVACACTION_DPS] = "off"
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_IDLE)
+
+        self.dps[POWER_DPS] = False
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_OFF)
+
+    def test_fan_mode(self):
+        self.dps[FAN_DPS] = "auto"
+        self.assertEqual(self.subject.fan_mode, FAN_AUTO)
+        self.dps[FAN_DPS] = "on"
+        self.assertEqual(self.subject.fan_mode, FAN_ON)
+
+    def test_fan_modes(self):
+        self.assertCountEqual(self.subject.fan_modes, [FAN_AUTO, FAN_ON])
+
+    async def test_set_fan_on(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: "on"},
+        ):
+            await self.subject.async_set_fan_mode(FAN_ON)
+
+    async def test_set_fan_auto(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: "auto"},
+        ):
+            await self.subject.async_set_fan_mode(FAN_AUTO)
+
+    def test_device_state_attributes(self):
+        self.dps[UNKNOWN101_DPS] = True
+        self.dps[UNKNOWN102_DPS] = False
+        self.dps[UNKNOWN112_DPS] = "unknown112"
+        self.dps[UNKNOWN113_DPS] = 113
+        self.dps[TEMPC_DPS] = 114
+        self.dps[CURTEMPC_DPS] = 115
+        self.dps[TEMPF_DPS] = 116
+        self.dps[CURTEMPF_DPS] = 117
+
+        self.assertCountEqual(
+            self.subject.device_state_attributes,
+            {
+                "unknown_101": True,
+                "unknown_102": False,
+                "unknown_112": "unknown112",
+                "unknown_113": 113,
+                "temperature_c": 114,
+                "current_temperature_c": 115,
+                "temperature_f": 116,
+                "current_temperature_f": 117,
+            },
+        )