Procházet zdrojové kódy

Add some icons to new devices.

Add tests and fix some typo errors detected.
Jason Rumney před 4 roky
rodič
revize
ce1f313786

+ 6 - 1
custom_components/tuya_local/devices/beca_bhp6000_thermostat_c.yaml

@@ -30,14 +30,19 @@ primary_entity:
       mapping:
         - dps_val: 1
           value: cool
+          icon: "mdi:snowflake"
         - dps_val: 2
           value: heat
+          icon: "mdi:fire"
         - dps_val: 3
           value: "off"
+          icon: "mdi:hvac-off"
         - dps_val: 4
           value: heat_cool
+          icon: "mdi:fire-alert"
         - dps_val: 5
           value: auto
+          icon: "mdi:hvac"
     - id: 6
       name: fan_mode
       type: boolean
@@ -63,4 +68,4 @@ secondary_entities:
           - dps_val: true
             icon: "mdi:led-on"
           - dps_val: false
-            icon: "ldi:led-off"
+            icon: "mdi:led-off"

+ 6 - 1
custom_components/tuya_local/devices/beca_bhp6000_thermostat_f.yaml

@@ -31,14 +31,19 @@ primary_entity:
       mapping:
         - dps_val: 1
           value: cool
+          icon: "mdi:snowflake"
         - dps_val: 2
           value: heat
+          icon: "mdi:fire"
         - dps_val: 3
           value: "off"
+          icon: "mdi:hvac-off"
         - dps_val: 4
           value: heat_cool
+          icon: "mdi:fire-alert"
         - dps_val: 5
           value: auto
+          icon: "mdi:hvac"
     - id: 6
       name: fan_mode
       type: boolean
@@ -64,4 +69,4 @@ secondary_entities:
           - dps_val: true
             icon: "mdi:led-on"
           - dps_val: false
-            icon: "ldi:led-off"
+            icon: "mdi:led-off"

+ 10 - 0
custom_components/tuya_local/devices/lexy_f501_fan.yaml

@@ -51,6 +51,11 @@ secondary_entities:
       - id: 9
         name: switch
         type: boolean
+        mapping:
+          - dps_val: true
+            icon: "mdi:led-on"
+          - dps_val: false
+            icon: "mdi:led-off"
   - entity: lock
     name: Child Lock
     dps:
@@ -63,3 +68,8 @@ secondary_entities:
       - id: 17
         name: switch
         type: boolean
+        mapping:
+          - dps_val: true
+            icon: "mdi:volume-high"
+          - dps_val: false
+            icon: "mdi:volume-mute"

+ 21 - 0
tests/const.py

@@ -289,3 +289,24 @@ TADIRAN_HEATPUMP_PAYLOAD = {
     "107": False,
     "108": False,
 }
+
+BECA_BHP6000_PAYLOAD = {
+    "1": True,
+    "2": 77,
+    "3": 87,
+    "4": "3",
+    "5": "3",
+    "6": False,
+    "7": False,
+}
+
+LEXY_F501_PAYLOAD = {
+    "1": True,
+    "2": "forestwindhigh",
+    "4": "off",
+    "6": 0,
+    "9": False,
+    "16": False,
+    "17": False,
+    "102": 8,
+}

+ 2 - 2
tests/devices/test_anko_fan.py

@@ -90,10 +90,10 @@ class TestAnkoFan(TuyaDeviceTestCase):
             await self.subject.async_set_preset_mode("sleep")
 
     def test_oscillating(self):
-        self.dps[OSCILLATE_DPS] = False
+        self.dps[OSCILLATE_DPS] = "off"
         self.assertFalse(self.subject.oscillating)
 
-        self.dps[OSCILLATE_DPS] = True
+        self.dps[OSCILLATE_DPS] = "auto"
         self.assertTrue(self.subject.oscillating)
 
         self.dps[OSCILLATE_DPS] = None

+ 208 - 0
tests/devices/test_beca_bhp6000_thermostat.py

@@ -0,0 +1,208 @@
+from homeassistant.components.climate.const import (
+    HVAC_MODE_AUTO,
+    HVAC_MODE_COOL,
+    HVAC_MODE_HEAT,
+    HVAC_MODE_HEAT_COOL,
+    HVAC_MODE_OFF,
+    SUPPORT_FAN_MODE,
+    SUPPORT_PRESET_MODE,
+    SUPPORT_TARGET_TEMPERATURE,
+)
+from homeassistant.const import STATE_UNAVAILABLE, TEMP_CELSIUS, TEMP_FAHRENHEIT
+
+from ..const import BECA_BHP6000_PAYLOAD
+from ..helpers import assert_device_properties_set
+from .base_device_tests import TuyaDeviceTestCase
+
+LIGHT_DPS = "1"
+TEMPERATURE_DPS = "2"
+CURRENTTEMP_DPS = "3"
+PRESET_DPS = "4"
+HVACMODE_DPS = "5"
+FAN_DPS = "6"
+LOCK_DPS = "7"
+
+
+class TestBecaBHP6000Thermostat(TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("beca_bhp6000_thermostat_f.yaml", BECA_BHP6000_PAYLOAD)
+        self.subject = self.entities.get("climate")
+        self.light = self.entities.get("light")
+        self.lock = self.entities.get("lock")
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_FAN_MODE | SUPPORT_PRESET_MODE | SUPPORT_TARGET_TEMPERATURE,
+        )
+
+    def test_temperature_unit_returns_configured_temperature_unit(self):
+        self.assertEqual(self.subject.temperature_unit, TEMP_FAHRENHEIT)
+
+    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, 40)
+
+    def test_maximum_target_temperature(self):
+        self.assertEqual(self.subject.max_temp, 95)
+
+    async def test_legacy_set_temperature_with_temperature(self):
+        async with assert_device_properties_set(
+            self.subject._device, {TEMPERATURE_DPS: 80}
+        ):
+            await self.subject.async_set_temperature(temperature=80)
+
+    async def test_legacy_set_temperature_with_preset_mode(self):
+        async with assert_device_properties_set(self.subject._device, {PRESET_DPS: 1}):
+            await self.subject.async_set_temperature(preset_mode="Schedule")
+
+    async def test_legacy_set_temperature_with_both_properties(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {
+                TEMPERATURE_DPS: 78,
+                PRESET_DPS: 4,
+            },
+        ):
+            await self.subject.async_set_temperature(
+                temperature=78, preset_mode="Holiday Hold"
+            )
+
+    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: 75},
+        ):
+            await self.subject.async_set_target_temperature(75)
+
+    async def test_set_target_temperature_rounds_value_to_closest_integer(self):
+        async with assert_device_properties_set(
+            self.subject._device, {TEMPERATURE_DPS: 78}
+        ):
+            await self.subject.async_set_target_temperature(77.6)
+
+    async def test_set_target_temperature_fails_outside_valid_range(self):
+        with self.assertRaisesRegex(
+            ValueError, "temperature \\(39\\) must be between 40 and 95"
+        ):
+            await self.subject.async_set_target_temperature(39)
+
+        with self.assertRaisesRegex(
+            ValueError, "temperature \\(96\\) must be between 40 and 95"
+        ):
+            await self.subject.async_set_target_temperature(96)
+
+    def test_current_temperature(self):
+        self.dps[CURRENTTEMP_DPS] = 70
+        self.assertEqual(self.subject.current_temperature, 70)
+
+    def test_hvac_mode(self):
+        self.dps[HVACMODE_DPS] = "1"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_COOL)
+
+        self.dps[HVACMODE_DPS] = "2"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT)
+
+        self.dps[HVACMODE_DPS] = "3"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
+
+        self.dps[HVACMODE_DPS] = "4"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT_COOL)
+
+        self.dps[HVACMODE_DPS] = "5"
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_AUTO)
+
+        self.dps[HVACMODE_DPS] = None
+        self.assertEqual(self.subject.hvac_mode, STATE_UNAVAILABLE)
+
+    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_AUTO,
+            ],
+        )
+
+    def test_fan_mode(self):
+        self.dps[FAN_DPS] = False
+        self.assertEqual(self.subject.fan_mode, "auto")
+        self.dps[FAN_DPS] = True
+        self.assertEqual(self.subject.fan_mode, "on")
+
+    def test_fan_modes(self):
+        self.assertCountEqual(
+            self.subject.fan_modes,
+            [
+                "auto",
+                "on",
+            ],
+        )
+
+    async def test_set_fan_mode_to_auto(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: False},
+        ):
+            await self.subject.async_set_fan_mode("auto")
+
+    async def test_set_fan_mode_to_on(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {FAN_DPS: True},
+        ):
+            await self.subject.async_set_fan_mode("on")
+
+    def test_device_state_attribures(self):
+        self.assertEqual(self.subject.device_state_attributes, {})
+        self.assertEqual(self.light.device_state_attributes, {})
+        self.assertEqual(self.lock.device_state_attributes, {})
+
+    def test_icons(self):
+        self.dps[HVACMODE_DPS] = 1
+        self.assertEqual(self.subject.icon, "mdi:snowflake")
+        self.dps[HVACMODE_DPS] = 2
+        self.assertEqual(self.subject.icon, "mdi:fire")
+        self.dps[HVACMODE_DPS] = 3
+        self.assertEqual(self.subject.icon, "mdi:hvac-off")
+        self.dps[HVACMODE_DPS] = 4
+        self.assertEqual(self.subject.icon, "mdi:fire-alert")
+        self.dps[HVACMODE_DPS] = 5
+        self.assertEqual(self.subject.icon, "mdi:hvac")
+
+        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")
+
+
+class TestBecaBHP6000ThermostatC(TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("beca_bhp6000_thermostat_c.yaml", BECA_BHP6000_PAYLOAD)
+        self.subject = self.entities.get("climate")
+
+    def test_temperature_unit_returns_configured_temperature_unit(self):
+        self.assertEqual(self.subject.temperature_unit, TEMP_CELSIUS)
+
+    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)

+ 257 - 0
tests/devices/test_lexy_f501_fan.py

@@ -0,0 +1,257 @@
+from homeassistant.components.fan import (
+    SUPPORT_OSCILLATE,
+    SUPPORT_PRESET_MODE,
+    SUPPORT_SET_SPEED,
+)
+from homeassistant.components.lock import STATE_LOCKED, STATE_UNLOCKED
+from homeassistant.const import STATE_UNAVAILABLE
+
+from ..const import LEXY_F501_PAYLOAD
+from ..helpers import assert_device_properties_set
+from .base_device_tests import TuyaDeviceTestCase
+
+POWER_DPS = "1"
+PRESET_DPS = "2"
+OSCILLATE_DPS = "4"
+TIMER_DPS = "6"
+LIGHT_DPS = "9"
+LOCK_DPS = "16"
+SWITCH_DPS = "17"
+SPEED_DPS = "102"
+
+
+class TestLexyF501Fan(TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("lexy_f501_fan.yaml", LEXY_F501_PAYLOAD)
+        self.subject = self.entities.get("fan")
+        self.light = self.entities.get("light")
+        self.lock = self.entities.get("lock")
+        self.switch = self.entities.get("switch")
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_OSCILLATE | SUPPORT_PRESET_MODE | SUPPORT_SET_SPEED,
+        )
+
+    def test_is_on(self):
+        self.dps[POWER_DPS] = True
+        self.assertTrue(self.subject.is_on)
+
+        self.dps[POWER_DPS] = False
+        self.assertFalse(self.subject.is_on)
+
+        self.dps[POWER_DPS] = None
+        self.assertEqual(self.subject.is_on, STATE_UNAVAILABLE)
+
+    async def test_turn_on(self):
+        async with assert_device_properties_set(
+            self.subject._device, {POWER_DPS: True}
+        ):
+            await self.subject.async_turn_on()
+
+    async def test_turn_off(self):
+        async with assert_device_properties_set(
+            self.subject._device, {POWER_DPS: False}
+        ):
+            await self.subject.async_turn_off()
+
+    def test_preset_mode(self):
+        self.dps[PRESET_DPS] = "forestwindhigh"
+        self.assertEqual(self.subject.preset_mode, "Forest High")
+
+        self.dps[PRESET_DPS] = "forestwindlow"
+        self.assertEqual(self.subject.preset_mode, "Forest Low")
+
+        self.dps[PRESET_DPS] = "sleepwindlow"
+        self.assertEqual(self.subject.preset_mode, "Sleep Low")
+
+        self.dps[PRESET_DPS] = "sleepwindhigh"
+        self.assertEqual(self.subject.preset_mode, "Sleep High")
+
+        self.dps[PRESET_DPS] = None
+        self.assertIs(self.subject.preset_mode, None)
+
+    def test_preset_modes(self):
+        self.assertCountEqual(
+            self.subject.preset_modes,
+            ["Forest High", "Forest Low", "Sleep High", "Sleep Low"],
+        )
+
+    async def test_set_preset_mode_to_foresthigh(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "forestwindhigh"},
+        ):
+            await self.subject.async_set_preset_mode("Forest High")
+
+    async def test_set_preset_mode_to_forestlow(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "forestwindlow"},
+        ):
+            await self.subject.async_set_preset_mode("Forest Low")
+
+    async def test_set_preset_mode_to_sleephigh(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "sleepwindhigh"},
+        ):
+            await self.subject.async_set_preset_mode("Sleep High")
+
+    async def test_set_preset_mode_to_sleeplow(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "sleepwindlow"},
+        ):
+            await self.subject.async_set_preset_mode("Sleep Low")
+
+    def test_oscillating(self):
+        self.dps[OSCILLATE_DPS] = "off"
+        self.assertFalse(self.subject.oscillating)
+
+        self.dps[OSCILLATE_DPS] = "30"
+        self.assertTrue(self.subject.oscillating)
+        self.dps[OSCILLATE_DPS] = "60"
+        self.assertTrue(self.subject.oscillating)
+        self.dps[OSCILLATE_DPS] = "90"
+        self.assertTrue(self.subject.oscillating)
+        self.dps[OSCILLATE_DPS] = "360positive"
+        self.assertTrue(self.subject.oscillating)
+        self.dps[OSCILLATE_DPS] = "360negative"
+        self.assertTrue(self.subject.oscillating)
+
+        self.dps[OSCILLATE_DPS] = None
+        self.assertFalse(self.subject.oscillating)
+
+    async def test_oscillate_off(self):
+        async with assert_device_properties_set(
+            self.subject._device, {OSCILLATE_DPS: "off"}
+        ):
+            await self.subject.async_oscillate(False)
+
+    def test_speed(self):
+        self.dps[SPEED_DPS] = "6"
+        self.assertEqual(self.subject.percentage, 40)
+
+    def test_speed_step(self):
+        self.assertAlmostEqual(self.subject.percentage_step, 6.7, 1)
+        self.assertEqual(self.subject.speed_count, 15)
+
+    async def test_set_speed(self):
+        async with assert_device_properties_set(self.subject._device, {SPEED_DPS: 3}):
+            await self.subject.async_set_percentage(20)
+
+    async def test_set_speed_snaps(self):
+        self.dps[PRESET_DPS] = "normal"
+        async with assert_device_properties_set(self.subject._device, {SPEED_DPS: 12}):
+            await self.subject.async_set_percentage(78)
+
+    def test_device_state_attributes(self):
+        self.dps[TIMER_DPS] = "5"
+        self.assertEqual(self.subject.device_state_attributes, {"timer": 5})
+
+    def test_light_is_on(self):
+        self.dps[LIGHT_DPS] = True
+        self.assertEqual(self.light.is_on, True)
+
+        self.dps[LIGHT_DPS] = False
+        self.assertEqual(self.light.is_on, False)
+
+    def test_light_state_attributes(self):
+        self.assertEqual(self.light.device_state_attributes, {})
+
+    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[SWITCH_DPS] = True
+        self.assertEqual(self.switch.is_on, True)
+
+        self.dps[SWITCH_DPS] = False
+        self.assertEqual(self.switch.is_on, False)
+
+    def test_switch_state_attributes(self):
+        self.assertEqual(self.switch.device_state_attributes, {})
+
+    async def test_switch_turn_on(self):
+        async with assert_device_properties_set(
+            self.switch._device, {SWITCH_DPS: True}
+        ):
+            await self.switch.async_turn_on()
+
+    async def test_switch_turn_off(self):
+        async with assert_device_properties_set(
+            self.switch._device, {SWITCH_DPS: False}
+        ):
+            await self.switch.async_turn_off()
+
+    async def test_toggle_turns_the_switch_on_when_it_was_off(self):
+        self.dps[SWITCH_DPS] = False
+
+        async with assert_device_properties_set(
+            self.switch._device, {SWITCH_DPS: True}
+        ):
+            await self.switch.async_toggle()
+
+    async def test_toggle_turns_the_switch_off_when_it_was_on(self):
+        self.dps[SWITCH_DPS] = True
+
+        async with assert_device_properties_set(
+            self.switch._device, {SWITCH_DPS: False}
+        ):
+            await self.switch.async_toggle()
+
+    def test_lock_state(self):
+        self.dps[LOCK_DPS] = True
+        self.assertEqual(self.lock.state, STATE_LOCKED)
+
+        self.dps[LOCK_DPS] = False
+        self.assertEqual(self.lock.state, STATE_UNLOCKED)
+
+        self.dps[LOCK_DPS] = None
+        self.assertEqual(self.lock.state, STATE_UNAVAILABLE)
+
+    def test_lock_is_locked(self):
+        self.dps[LOCK_DPS] = True
+        self.assertTrue(self.lock.is_locked)
+
+        self.dps[LOCK_DPS] = False
+        self.assertFalse(self.lock.is_locked)
+
+        self.dps[LOCK_DPS] = None
+        self.assertFalse(self.lock.is_locked)
+
+    async def test_lock_locks(self):
+        async with assert_device_properties_set(self.lock._device, {LOCK_DPS: True}):
+            await self.lock.async_lock()
+
+    async def test_lock_unlocks(self):
+        async with assert_device_properties_set(self.lock._device, {LOCK_DPS: False}):
+            await self.lock.async_unlock()
+
+    def test_icons(self):
+        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")