Răsfoiți Sursa

Add tests for ElectriQ CDPRO 20 and Tadiran.

Fix typo in Tadiran config revealed by tests.
Jason Rumney 4 ani în urmă
părinte
comite
b10919d2b8

+ 1 - 1
custom_components/tuya_local/devices/tadiran_heatpump.yaml

@@ -92,7 +92,7 @@ primary_entity:
       name: unknown_102
     - id: 103
       type: integer
-      name: unknwon_103
+      name: unknown_103
     - id: 104
       type: string
       name: unknown_104

+ 28 - 0
tests/const.py

@@ -203,6 +203,18 @@ ELECTRIQ_DEHUMIDIFIER_PAYLOAD = {
     "104": False,
 }
 
+ELECTRIQ_CD20PRO_DEHUMIDIFIER_PAYLOAD = {
+    "1": True,
+    "2": "high",
+    "3": 39,
+    "4": 45,
+    "5": False,
+    "10": False,
+    "101": False,
+    "102": "0_90",
+    "103": 30,
+}
+
 POOLEX_SILVERLINE_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "Heat", "13": 0}
 POOLEX_VERTIGO_HEATPUMP_PAYLOAD = {"1": True, "2": 30, "3": 28, "4": "heat", "9": 0}
 
@@ -261,3 +273,19 @@ HELLNAR_HEATPUMP_PAYLOAD = {
     "133": "0",
     "134": '{"t":1624086077,"s":false,"clr"true}',
 }
+
+TADIRAN_HEATPUMP_PAYLOAD = {
+    "1": True,
+    "2": 25,
+    "3": 250,
+    "4": "cooling",
+    "5": "low",
+    "101": 0,
+    "102": 260,
+    "103": 225,
+    "104": "low",
+    "105": "stop",
+    "106": -300,
+    "107": False,
+    "108": False,
+}

+ 271 - 0
tests/devices/test_electriq_cd20_dehumidifier.py

@@ -0,0 +1,271 @@
+from homeassistant.components.fan import SUPPORT_PRESET_MODE
+from homeassistant.components.humidifier import SUPPORT_MODES
+from homeassistant.const import STATE_UNAVAILABLE
+
+from ..const import ELECTRIQ_CD20PRO_DEHUMIDIFIER_PAYLOAD
+from ..helpers import assert_device_properties_set
+from .base_device_tests import TuyaDeviceTestCase
+
+SWITCH_DPS = "1"
+MODE_DPS = "2"
+CURRENTHUMID_DPS = "3"
+HUMIDITY_DPS = "4"
+ANION_DPS = "5"
+UV_DPS = "10"
+LIGHT_DPS = "101"
+PRESET_DPS = "102"
+CURRENTTEMP_DPS = "103"
+
+
+class TestElectriqCD20ProDehumidifier(TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig(
+            "electriq_cd20pro_dehumidifier.yaml", ELECTRIQ_CD20PRO_DEHUMIDIFIER_PAYLOAD
+        )
+        self.subject = self.entities.get("humidifier")
+        self.fan = self.entities.get("fan")
+        self.light = self.entities.get("light")
+        self.switch = self.entities.get("switch")
+
+    def test_supported_features(self):
+        self.assertEqual(self.subject.supported_features, SUPPORT_MODES)
+        self.assertEqual(self.fan.supported_features, SUPPORT_PRESET_MODE)
+
+    def test_icon(self):
+        """Test that the icon is as expected."""
+        self.dps[SWITCH_DPS] = True
+        self.dps[MODE_DPS] = "auto"
+        self.assertEqual(self.subject.icon, "mdi:air-humidifier")
+
+        self.dps[SWITCH_DPS] = False
+        self.assertEqual(self.subject.icon, "mdi:air-humidifier-off")
+
+        self.dps[MODE_DPS] = "fan"
+        self.assertEqual(self.subject.icon, "mdi:air-humidifier-off")
+
+        self.dps[SWITCH_DPS] = True
+        self.assertEqual(self.subject.icon, "mdi:air-purifier")
+
+        self.dps[MODE_DPS] = "high"
+        self.assertEqual(self.subject.icon, "mdi:tshirt-crew-outline")
+
+        self.assertEqual(self.switch.icon, "mdi:solar-power")
+        self.dps[LIGHT_DPS] = True
+        self.assertEqual(self.light.icon, "mdi:led-on")
+        self.dps[LIGHT_DPS] = False
+        self.assertEqual(self.light.icon, "mdi:led-off")
+
+    def test_min_target_humidity(self):
+        self.assertEqual(self.subject.min_humidity, 35)
+
+    def test_max_target_humidity(self):
+        self.assertEqual(self.subject.max_humidity, 80)
+
+    def test_target_humidity(self):
+        self.dps[HUMIDITY_DPS] = 55
+        self.assertEqual(self.subject.target_humidity, 55)
+
+    async def test_set_target_humidity_rounds_up_to_5_percent(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {HUMIDITY_DPS: 55},
+        ):
+            await self.subject.async_set_humidity(53)
+
+    async def test_set_target_humidity_rounds_down_to_5_percent(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {HUMIDITY_DPS: 50},
+        ):
+            await self.subject.async_set_humidity(52)
+
+    def test_is_on(self):
+        self.dps[SWITCH_DPS] = True
+        self.assertTrue(self.subject.is_on)
+        self.assertTrue(self.fan.is_on)
+
+        self.dps[SWITCH_DPS] = False
+        self.assertFalse(self.subject.is_on)
+        self.assertFalse(self.fan.is_on)
+
+        self.dps[SWITCH_DPS] = None
+        self.assertEqual(self.subject.is_on, STATE_UNAVAILABLE)
+        self.assertEqual(self.fan.is_on, STATE_UNAVAILABLE)
+
+    async def test_turn_on(self):
+        async with assert_device_properties_set(
+            self.subject._device, {SWITCH_DPS: True}
+        ):
+            await self.subject.async_turn_on()
+
+    async def test_turn_off(self):
+        async with assert_device_properties_set(
+            self.subject._device, {SWITCH_DPS: False}
+        ):
+            await self.subject.async_turn_off()
+
+    async def test_fan_turn_on(self):
+        async with assert_device_properties_set(
+            self.subject._device, {SWITCH_DPS: True}
+        ):
+            await self.fan.async_turn_on()
+
+    async def test_fan_turn_off(self):
+        async with assert_device_properties_set(
+            self.subject._device, {SWITCH_DPS: False}
+        ):
+            await self.fan.async_turn_off()
+
+    def test_mode(self):
+        self.dps[MODE_DPS] = "low"
+        self.assertEqual(self.subject.mode, "Low")
+        self.dps[MODE_DPS] = "high"
+        self.assertEqual(self.subject.mode, "High")
+        self.dps[MODE_DPS] = "auto"
+        self.assertEqual(self.subject.mode, "Auto")
+        self.dps[MODE_DPS] = "fan"
+        self.assertEqual(self.subject.mode, "Air clean")
+
+    async def test_set_mode_to_auto(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                MODE_DPS: "auto",
+            },
+        ):
+            await self.subject.async_set_mode("Auto")
+            self.subject._device.anticipate_property_value.assert_not_called()
+
+    async def test_set_mode_to_low(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                MODE_DPS: "low",
+            },
+        ):
+            await self.subject.async_set_mode("Low")
+            self.subject._device.anticipate_property_value.assert_not_called()
+
+    async def test_set_mode_to_high(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                MODE_DPS: "high",
+            },
+        ):
+            await self.subject.async_set_mode("High")
+            self.subject._device.anticipate_property_value.assert_not_called()
+
+    async def test_set_mode_to_fan(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                MODE_DPS: "fan",
+            },
+        ):
+            await self.subject.async_set_mode("Air clean")
+            self.subject._device.anticipate_property_value.assert_not_called()
+
+    def test_fan_preset_mode(self):
+        self.dps[PRESET_DPS] = "45"
+        self.assertEqual(self.fan.preset_mode, "Half open")
+
+        self.dps[PRESET_DPS] = "90"
+        self.assertEqual(self.fan.preset_mode, "Fully open")
+
+        self.dps[PRESET_DPS] = "0_90"
+        self.assertEqual(self.fan.preset_mode, "Oscillate")
+
+    async def test_set_fan_to_half_open(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                PRESET_DPS: "45",
+            },
+        ):
+            await self.fan.async_set_preset_mode("Half open")
+            self.subject._device.anticipate_property_value.assert_not_called()
+
+    async def test_set_fan_to_fully_open(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                PRESET_DPS: "90",
+            },
+        ):
+            await self.fan.async_set_preset_mode("Fully open")
+            self.subject._device.anticipate_property_value.assert_not_called()
+
+    async def test_set_fan_to_oscillate(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                PRESET_DPS: "0_90",
+            },
+        ):
+            await self.fan.async_set_preset_mode("Oscillate")
+            self.subject._device.anticipate_property_value.assert_not_called()
+
+    def test_light_is_on(self):
+        self.dps[LIGHT_DPS] = True
+        self.assertTrue(self.light.is_on)
+
+        self.dps[LIGHT_DPS] = False
+        self.assertFalse(self.light.is_on)
+
+    async def test_light_turn_on(self):
+        async with assert_device_properties_set(self.light._device, {LIGHT_DPS: True}):
+            await self.light.async_turn_on()
+
+    async def test_light_turn_off(self):
+        async with assert_device_properties_set(self.light._device, {LIGHT_DPS: False}):
+            await self.light.async_turn_off()
+
+    async def test_toggle_turns_the_light_on_when_it_was_off(self):
+        self.dps[LIGHT_DPS] = False
+        async with assert_device_properties_set(self.light._device, {LIGHT_DPS: True}):
+            await self.light.async_toggle()
+
+    async def test_toggle_turns_the_light_off_when_it_was_on(self):
+        self.dps[LIGHT_DPS] = True
+        async with assert_device_properties_set(self.light._device, {LIGHT_DPS: False}):
+            await self.light.async_toggle()
+
+    def test_switch_is_on(self):
+        self.dps[UV_DPS] = True
+        self.assertTrue(self.switch.is_on)
+
+        self.dps[UV_DPS] = False
+        self.assertFalse(self.switch.is_on)
+
+    async def test_switch_turn_on(self):
+        async with assert_device_properties_set(self.switch._device, {UV_DPS: True}):
+            await self.switch.async_turn_on()
+
+    async def test_switch_turn_off(self):
+        async with assert_device_properties_set(self.switch._device, {UV_DPS: False}):
+            await self.switch.async_turn_off()
+
+    async def test_toggle_turns_the_switch_on_when_it_was_off(self):
+        self.dps[UV_DPS] = False
+        async with assert_device_properties_set(self.switch._device, {UV_DPS: True}):
+            await self.switch.async_toggle()
+
+    async def test_toggle_turns_the_switch_off_when_it_was_on(self):
+        self.dps[UV_DPS] = True
+        async with assert_device_properties_set(self.switch._device, {UV_DPS: False}):
+            await self.switch.async_toggle()
+
+    def test_state_attributes(self):
+        self.dps[CURRENTHUMID_DPS] = 50
+        self.dps[CURRENTTEMP_DPS] = 21
+        self.dps[ANION_DPS] = True
+        self.assertCountEqual(
+            self.subject.device_state_attributes,
+            {"current_humidity": 50, "current_temperature": 21, "anion": True},
+        )
+        self.assertEqual(self.fan.device_state_attributes, {})
+        self.assertEqual(self.light.device_state_attributes, {})
+        self.assertEqual(self.switch.device_state_attributes, {})

+ 217 - 0
tests/devices/test_tadiran_heatpump.py

@@ -0,0 +1,217 @@
+from homeassistant.components.climate.const import (
+    HVAC_MODE_HEAT_COOL,
+    HVAC_MODE_COOL,
+    HVAC_MODE_DRY,
+    HVAC_MODE_FAN_ONLY,
+    HVAC_MODE_HEAT,
+    HVAC_MODE_OFF,
+    SUPPORT_FAN_MODE,
+    SUPPORT_TARGET_TEMPERATURE,
+)
+from homeassistant.const import STATE_UNAVAILABLE
+
+from ..const import TADIRAN_HEATPUMP_PAYLOAD
+from ..helpers import assert_device_properties_set
+from .base_device_tests import TuyaDeviceTestCase
+
+POWER_DPS = "1"
+TEMPERATURE_DPS = "2"
+CURRENTTEMP_DPS = "3"
+HVACMODE_DPS = "4"
+FAN_DPS = "5"
+
+
+class TestTadiranHeatpump(TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("tadiran_heatpump.yaml", TADIRAN_HEATPUMP_PAYLOAD)
+        self.subject = self.entities.get("climate")
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_FAN_MODE | SUPPORT_TARGET_TEMPERATURE,
+        )
+
+    def test_icon(self):
+        self.dps[POWER_DPS] = True
+        self.dps[HVACMODE_DPS] = "auto"
+        self.assertEqual(self.subject.icon, "mdi:hvac")
+        self.dps[HVACMODE_DPS] = "cooling"
+        self.assertEqual(self.subject.icon, "mdi:snowflake")
+        self.dps[HVACMODE_DPS] = "heating"
+        self.assertEqual(self.subject.icon, "mdi:fire")
+        self.dps[HVACMODE_DPS] = "dehum"
+        self.assertEqual(self.subject.icon, "mdi:water")
+        self.dps[HVACMODE_DPS] = "fan"
+        self.assertEqual(self.subject.icon, "mdi:fan")
+        self.dps[POWER_DPS] = False
+        self.assertEqual(self.subject.icon, "mdi:hvac-off")
+
+    def test_temperature_unit_returns_device_temperature_unit(self):
+        self.assertEqual(
+            self.subject.temperature_unit, self.subject._device.temperature_unit
+        )
+
+    def test_target_temperature(self):
+        self.dps[TEMPERATURE_DPS] = 25
+        self.assertEqual(self.subject.target_temperature, 25)
+
+    def test_target_temperature_step(self):
+        self.assertEqual(self.subject.target_temperature_step, 1)
+
+    def test_minimum_target_temperature(self):
+        self.assertEqual(self.subject.min_temp, 16)
+
+    def test_maximum_target_temperature(self):
+        self.assertEqual(self.subject.max_temp, 32)
+
+    async def test_legacy_set_temperature_with_temperature(self):
+        async with assert_device_properties_set(
+            self.subject._device, {TEMPERATURE_DPS: 24}
+        ):
+            await self.subject.async_set_temperature(temperature=24)
+
+    async def test_legacy_set_temperature_with_no_valid_properties(self):
+        await self.subject.async_set_temperature(something="else")
+        self.subject._device.async_set_property.assert_not_called
+
+    async def test_set_target_temperature_succeeds_within_valid_range(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {TEMPERATURE_DPS: 25},
+        ):
+            await self.subject.async_set_target_temperature(25)
+
+    async def test_set_target_temperature_fails_outside_valid_range(self):
+        with self.assertRaisesRegex(
+            ValueError, "temperature \\(15\\) must be between 16 and 32"
+        ):
+            await self.subject.async_set_target_temperature(15)
+
+        with self.assertRaisesRegex(
+            ValueError, "temperature \\(33\\) must be between 16 and 32"
+        ):
+            await self.subject.async_set_target_temperature(33)
+
+    def test_current_temperature(self):
+        self.dps[CURRENTTEMP_DPS] = 250
+        self.assertEqual(self.subject.current_temperature, 25)
+
+    def test_hvac_mode(self):
+        self.dps[POWER_DPS] = True
+        self.dps[HVACMODE_DPS] = "heating"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT)
+
+        self.dps[HVACMODE_DPS] = "cooling"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_COOL)
+
+        self.dps[HVACMODE_DPS] = "dehum"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_DRY)
+
+        self.dps[HVACMODE_DPS] = "fan"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_FAN_ONLY)
+
+        self.dps[HVACMODE_DPS] = "auto"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT_COOL)
+
+        self.dps[HVACMODE_DPS] = None
+        self.assertEqual(self.subject.hvac_mode, STATE_UNAVAILABLE)
+
+        self.dps[HVACMODE_DPS] = "auto"
+        self.dps[POWER_DPS] = False
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
+
+    def test_hvac_modes(self):
+        self.assertCountEqual(
+            self.subject.hvac_modes,
+            [
+                HVAC_MODE_OFF,
+                HVAC_MODE_HEAT,
+                HVAC_MODE_HEAT_COOL,
+                HVAC_MODE_COOL,
+                HVAC_MODE_DRY,
+                HVAC_MODE_FAN_ONLY,
+            ],
+        )
+
+    async def test_turn_on(self):
+        async with assert_device_properties_set(
+            self.subject._device, {POWER_DPS: True, HVACMODE_DPS: "heating"}
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_HEAT)
+
+    async def test_turn_off(self):
+        async with assert_device_properties_set(
+            self.subject._device, {POWER_DPS: False}
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_OFF)
+
+    def test_fan_modes(self):
+        self.assertCountEqual(
+            self.subject.fan_modes,
+            ["auto", "low", "medium", "high"],
+        )
+
+    def test_fan_mode(self):
+        self.dps[FAN_DPS] = "low"
+        self.assertEqual(self.subject.fan_mode, "low")
+        self.dps[FAN_DPS] = "middle"
+        self.assertEqual(self.subject.fan_mode, "medium")
+        self.dps[FAN_DPS] = "high"
+        self.assertEqual(self.subject.fan_mode, "high")
+        self.dps[FAN_DPS] = "auto"
+        self.assertEqual(self.subject.fan_mode, "auto")
+
+    async def test_set_fan_to_low(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: "low"},
+        ):
+            await self.subject.async_set_fan_mode("low")
+
+    async def test_set_fan_to_medium(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: "middle"},
+        ):
+            await self.subject.async_set_fan_mode("medium")
+
+    async def test_set_fan_to_high(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: "high"},
+        ):
+            await self.subject.async_set_fan_mode("high")
+
+    async def test_set_fan_to_auto(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: "auto"},
+        ):
+            await self.subject.async_set_fan_mode("auto")
+
+    def test_device_state_attributes(self):
+        self.dps["101"] = 101
+        self.dps["102"] = 102
+        self.dps["103"] = 103
+        self.dps["104"] = "unknown104"
+        self.dps["105"] = "unknown105"
+        self.dps["106"] = 106
+        self.dps["107"] = True
+        self.dps["108"] = False
+
+        self.assertCountEqual(
+            self.subject.device_state_attributes,
+            {
+                "unknown_101": 101,
+                "unknown_102": 102,
+                "unknown_103": 103,
+                "unknown_104": "unknown104",
+                "unknown_105": "unknown105",
+                "unknown_106": 120,
+                "unknown_107": True,
+                "unknown_108": False,
+            },
+        )