ソースを参照

Add Immax NEO LITE VENTO Smart

DPS:
```
{'dps': {'1': False, '2': 'normal', '3': 2, '8': 'forward', '15': False, '22': '1hour'}}
```
Lukas Drbal 2 年 前
コミット
d0ac380ac1

+ 1 - 1
ACKNOWLEDGEMENTS.md

@@ -267,7 +267,7 @@ Further device support has been made with the assistance of users.  Please consi
 - [mattbruman](https://github.com/mattbruman) for assisting with support for Atomi ceiling fans.
 - [dh0llyw00d](https://github.com/dh0llyw00d) for assisting with support for Skyfan DC fans with light.
 - [syepes](https://github.com/syepes) for contributing support for Klarstein DryFy Connect, which was merged into Shinco 30D config, and ZN-2C09 air quality monitor.
-- [LesTR](https://github.com/LesTR) for early assistance with the subdevice support, and contribution of test improvements for subdevices.
+- [LesTR](https://github.com/LesTR) for contributing support for Immax neo light vent, early assistance with the subdevice support, and contribution of test improvements for subdevices.
 - [JonF-49](https://github.com/JonF-49) for contributing support for RGBW lightbulbs, Carro fan with light, and improvements to color light entities that lack color temperature control.
 - [charliesjc](https://github.com/charliesjc) for contributing support for CBI Astute smart controller breaker switches.
 - [stijnb1234](https://github.com/stijnb1234) for assisting with support for CCT lightbulbs.

+ 1 - 0
DEVICES.md

@@ -130,6 +130,7 @@
 - TMWF02 fan controller
 - Treatlife DS02-F fan switch
 - Treatlife DS03 fan with dimmable light
+- IMMAX NEO LITE VENTO SMART with light
 
 ### Air Purifiers
 

+ 80 - 0
custom_components/tuya_local/devices/immax_neo_light_vento.yaml

@@ -0,0 +1,80 @@
+name: Immax NEO LITE VENTO Smart
+products:
+  - id: ea6vpac5hfe5rqw4
+    name: Immax NEO LITE VENTO Smart
+primary_entity:
+  entity: fan
+  dps:
+    - id: 1
+      type: boolean
+      name: switch
+      mapping:
+        - dps_val: true
+          value: ON
+        - dps_val: false
+          value: OFF
+    - id: 2
+      type: string
+      name: preset_mode
+      category: config
+      mapping:
+        - dps_val: normal
+          value: Normal
+        - dps_val: sleep
+          value: Sleep
+        - dps_val: nature
+          value: Natural
+    - id: 3
+      name: speed
+      type: integer
+      category: config
+      range:
+        min: 0
+        max: 6
+      mapping:
+        - scale: 0.06
+          constraint: preset_mode
+          conditions:
+            - dps_val: nature
+              step: 5
+            - dps_val: sleep
+              step: 5
+    - id: 8
+      name: direction
+      type: string
+      category: config
+      mapping:
+        - dps_val: forward
+          value: forward
+        - dps_val: reverse
+          value: reverse
+secondary_entities:
+  - entity: light
+    dps:
+      - id: 15
+        type: boolean
+        name: switch
+        mapping:
+          - dps_val: true
+            value: ON
+          - dps_val: false
+            value: OFF
+  - entity: select
+    name: timer
+    icon: "mdi:timer"
+    category: config
+    dps:
+      - id: 22
+        name: option
+        type: string
+        mapping:
+          - dps_val: "off"
+            value: "Off"
+          - dps_val: 1hour
+            value: "1 hour"
+          - dps_val: 2hour
+            value: "2 hours"
+          - dps_val: 4hour
+            value: "4 hours"
+          - dps_val: 8hour
+            value: "8 hours"

+ 119 - 0
tests/devices/test_immax_neo_light_vento.py

@@ -0,0 +1,119 @@
+from homeassistant.components.fan import (
+    FanEntityFeature,
+    DIRECTION_FORWARD,
+    DIRECTION_REVERSE,
+)
+
+from ..helpers import assert_device_properties_set
+from ..mixins.light import BasicLightTests
+from ..mixins.select import BasicSelectTests
+from ..mixins.switch import SwitchableTests
+from .base_device_tests import TuyaDeviceTestCase
+
+IMAX_NEO_LIGHT_VENTO_PAYLOAD = {
+    "1": True,
+    "2": "normal",
+    "3": "1",
+    "8": "forward",
+    "15": False,
+    "22": "off",
+}
+
+SWITCH_DPS = "1"
+PRESET_DPS = "2"
+SPEED_DPS = "3"
+DIRECTION_DPS = "8"
+LIGHT_DPS = "15"
+TIMER_DPS = "22"
+
+
+class TestImmaxNeoLightVento(
+    SwitchableTests, BasicSelectTests, BasicLightTests, TuyaDeviceTestCase
+):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("immax_neo_light_vento.yaml", IMAX_NEO_LIGHT_VENTO_PAYLOAD)
+        self.fan = self.entities["fan"]
+        self.light = self.entities["light"]
+        self.stop_timer = self.entities["select_timer"]
+        self.setUpSwitchable(SWITCH_DPS, self.fan)
+        self.setUpBasicLight(LIGHT_DPS, self.light)
+        self.setUpBasicSelect(
+            TIMER_DPS,
+            self.stop_timer,
+            {
+                "off": "Off",
+                "1hour": "1 hour",
+                "2hour": "2 hours",
+                "4hour": "4 hours",
+                "8hour": "8 hours",
+            },
+        )
+        self.mark_secondary(["select_timer"])
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.fan.supported_features,
+            FanEntityFeature.DIRECTION
+            | FanEntityFeature.PRESET_MODE
+            | FanEntityFeature.SET_SPEED,
+        )
+
+    def test_preset_modes(self):
+        self.assertCountEqual(self.fan.preset_modes, ["Normal", "Natural", "Sleep"])
+
+    def test_speed(self):
+        self.dps[SPEED_DPS] = 2
+        self.assertAlmostEqual(33.3, self.fan.percentage, 1)
+        self.dps[SPEED_DPS] = 3
+        self.assertEqual(50, self.fan.percentage)
+        self.dps[SPEED_DPS] = 4
+        self.assertAlmostEqual(66.7, self.fan.percentage, 1)
+        self.dps[SPEED_DPS] = 5
+        self.assertAlmostEqual(83.3, self.fan.percentage, 1)
+        self.dps[SPEED_DPS] = 6
+        self.assertEqual(100, self.fan.percentage)
+        self.dps[SPEED_DPS] = 0
+        self.assertEqual(0, self.fan.percentage)
+
+    def test_preset_mode(self):
+        self.dps[PRESET_DPS] = "normal"
+        self.assertEqual(self.fan.preset_mode, "Normal")
+
+        self.dps[PRESET_DPS] = "nature"
+        self.assertEqual(self.fan.preset_mode, "Natural")
+
+        self.dps[PRESET_DPS] = "Sleep"
+        self.assertEqual(self.fan.preset_mode, "Sleep")
+
+    def test_direction(self):
+        self.dps[DIRECTION_DPS] = "forward"
+        self.assertEqual(self.fan.current_direction, DIRECTION_FORWARD)
+        self.dps[DIRECTION_DPS] = "reverse"
+        self.assertEqual(self.fan.current_direction, DIRECTION_REVERSE)
+
+    async def test_set_direction_forward(self):
+        async with assert_device_properties_set(
+            self.fan._device, {DIRECTION_DPS: "forward"}
+        ):
+            await self.fan.async_set_direction(DIRECTION_FORWARD)
+
+    async def test_set_direction_reverse(self):
+        async with assert_device_properties_set(
+            self.fan._device, {DIRECTION_DPS: "reverse"}
+        ):
+            await self.fan.async_set_direction(DIRECTION_REVERSE)
+
+    def test_set_stop_timer(self):
+        self.dps[TIMER_DPS] = "2hour"
+        self.assertEqual(self.stop_timer.current_option, "2 hours")
+
+    async def test_set_speed(self):
+        async with assert_device_properties_set(self.fan._device, {SPEED_DPS: 2}):
+            await self.fan.async_set_percentage(33)
+
+    async def test_set_speed_in_normal_mode_snaps(self):
+        self.dps[PRESET_DPS] = "normal"
+        async with assert_device_properties_set(self.fan._device, {SPEED_DPS: 5}):
+            await self.fan.async_set_percentage(80)