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

Add support for Stirling FS1-40DC fan.

From issue #67
Jason Rumney 4 лет назад
Родитель
Сommit
6d39027c43

+ 2 - 0
ACKNOWLEDGEMENTS.md

@@ -47,3 +47,5 @@ Further device support has been made with the assistance of users.  Please consi
  - [MrDeon](https://github.com/MrDeon) for assistance in supporting Kogan KAWFPAC09YA air conditioners.
  - [SatarisGIT](https://github.com/SatarisGIT) for assistance in supporting Eberg Qubo Q40HD portable heatpump.
  - [lucaxxaa](https://github.com/lucaxxaa) for assistance in supporting Beca BHT-002 thermostat.
+ - [nickdos](https://github.com/nickdos) for assistance in supporting Stirling FS1-40DC fan.
+ 

+ 1 - 0
README.md

@@ -80,6 +80,7 @@ the device will not work despite being listed below.
 - Lexy F501 fan
 - Deta fan controller
 - Arlec Grid Connect Smart Ceiling Fan (without light)
+- Stirling FS1-40DC Pedestal fan
 
 ### Air Purifiers
 - Renpho RP-AP001S air purifier

+ 78 - 0
custom_components/tuya_local/devices/stirling_fs140dc_fan.yaml

@@ -0,0 +1,78 @@
+name: Stirling FS1-40DC Pedestal Fan
+primary_entity:
+  entity: fan
+  dps:
+    - id: 1
+      name: switch
+      type: boolean
+    - id: 2
+      name: preset_mode
+      type: string
+      mapping:
+        - dps_val: normal
+          value: normal
+        - dps_val: nature
+          value: nature
+        - dps_val: sleep
+          value: sleep
+    - id: 3
+      name: speed
+      type: integer
+      range:
+        min: 0
+        max: 15
+      mapping:
+        - scale: 0.15
+    - id: 5
+      name: oscillate
+      type: boolean
+secondary_entities:
+  - entity: select
+    name: timer
+    dps:
+      - id: 22
+        name: option
+        type: string
+        mapping:
+          - dps_val: cancel
+            value: "Off"
+          - dps_val: "0_5"
+            value: "30 minutes"
+          - dps_val: "1_0"
+            value: "1 hour"
+          - dps_val: "1_5"
+            value: "1.5 hours"
+          - dps_val: "2_0"
+            value: "2 hours"
+          - dps_val: "2_5"
+            value: "2.5 hours"
+          - dps_val: "3_0"
+            value: "3 hours"
+          - dps_val: "3_5"
+            value: "3.5 hours"
+          - dps_val: "4_0"
+            value: "4 hours"
+          - dps_val: "4_5"
+            value: "4.5 hours"
+          - dps_val: "5_0"
+            value: "5 hours"
+          - dps_val: "5_5"
+            value: "5.5 hours"
+          - dps_val: "6_0"
+            value: "6 hours"
+          - dps_val: "6_5"
+            value: "6.5 hours"
+          - dps_val: "7_0"
+            value: "7 hours"
+          - dps_val: "7_5"
+            value: "7.5 hours"
+          - dps_val: "8_0"
+            value: "8 hours"
+          - dps_val: "8_5"
+            value: "8.5 hours"
+          - dps_val: "9_0"
+            value: "9 hours"
+          - dps_val: "9_5"
+            value: "9.5 hours"
+          - dps_val: "10_0"
+            value: "10 hours"

+ 8 - 0
tests/const.py

@@ -535,3 +535,11 @@ EBERG_QUBO_Q40HD_PAYLOAD = {
     "30": False,
     "101": "heat_s",
 }
+
+STIRLING_FS1_FAN_PAYLOAD = {
+    "1": True,
+    "2": "normal",
+    "3": 9,
+    "5": False,
+    "22": "cancel",
+}

+ 1 - 1
tests/devices/test_arlec_fan.py

@@ -114,7 +114,7 @@ class TestArlecFan(SwitchableTests, TuyaDeviceTestCase):
     def test_timer_options(self):
         self.assertCountEqual(
             self.timer.options,
-            {"Off", "2 hours", "4 hours", "8 hours"},
+            ["Off", "2 hours", "4 hours", "8 hours"],
         )
 
     def test_timer_current_option(self):

+ 152 - 0
tests/devices/test_stirling_fs140dc_fan.py

@@ -0,0 +1,152 @@
+from homeassistant.components.fan import (
+    SUPPORT_OSCILLATE,
+    SUPPORT_PRESET_MODE,
+    SUPPORT_SET_SPEED,
+)
+
+from ..const import STIRLING_FS1_FAN_PAYLOAD
+from ..helpers import assert_device_properties_set
+from .base_device_tests import SwitchableTests, TuyaDeviceTestCase
+
+SWITCH_DPS = "1"
+PRESET_DPS = "2"
+SPEED_DPS = "3"
+OSCILLATE_DPS = "5"
+TIMER_DPS = "22"
+
+
+class TestStirlingFS1Fan(SwitchableTests, TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("stirling_fs140dc_fan.yaml", STIRLING_FS1_FAN_PAYLOAD)
+        self.subject = self.entities.get("fan")
+        self.timer = self.entities.get("select_timer")
+        self.setUpSwitchable(SWITCH_DPS, self.subject)
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_OSCILLATE | SUPPORT_PRESET_MODE | SUPPORT_SET_SPEED,
+        )
+
+    def test_preset_mode(self):
+        self.dps[PRESET_DPS] = "normal"
+        self.assertEqual(self.subject.preset_mode, "normal")
+
+        self.dps[PRESET_DPS] = "nature"
+        self.assertEqual(self.subject.preset_mode, "nature")
+
+        self.dps[PRESET_DPS] = "sleep"
+        self.assertEqual(self.subject.preset_mode, "sleep")
+
+        self.dps[PRESET_DPS] = None
+        self.assertIs(self.subject.preset_mode, None)
+
+    def test_preset_modes(self):
+        self.assertCountEqual(
+            self.subject.preset_modes,
+            ["normal", "nature", "sleep"],
+        )
+
+    async def test_set_preset_mode_to_normal(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "normal"},
+        ):
+            await self.subject.async_set_preset_mode("normal")
+
+    async def test_set_preset_mode_to_nature(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "nature"},
+        ):
+            await self.subject.async_set_preset_mode("nature")
+
+    async def test_set_preset_mode_to_sleep(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "sleep"},
+        ):
+            await self.subject.async_set_preset_mode("sleep")
+
+    def test_oscillating(self):
+        self.dps[OSCILLATE_DPS] = False
+        self.assertFalse(self.subject.oscillating)
+
+        self.dps[OSCILLATE_DPS] = True
+        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: False}
+        ):
+            await self.subject.async_oscillate(False)
+
+    async def test_oscillate_on(self):
+        async with assert_device_properties_set(
+            self.subject._device, {OSCILLATE_DPS: True}
+        ):
+            await self.subject.async_oscillate(True)
+
+    def test_speed(self):
+        self.dps[SPEED_DPS] = "4"
+        self.assertAlmostEqual(self.subject.percentage, 26.67, 2)
+
+    def test_speed_step(self):
+        self.assertAlmostEqual(self.subject.percentage_step, 6.67, 2)
+        self.assertEqual(self.subject.speed_count, 15)
+
+    async def test_set_speed(self):
+        async with assert_device_properties_set(self.subject._device, {SPEED_DPS: 5}):
+            await self.subject.async_set_percentage(33)
+
+    async def test_set_speed_snaps(self):
+        async with assert_device_properties_set(self.subject._device, {SPEED_DPS: 10}):
+            await self.subject.async_set_percentage(64)
+
+    def test_device_state_attributes(self):
+        self.assertEqual(self.subject.device_state_attributes, {})
+        self.assertEqual(self.timer.device_state_attributes, {})
+
+    def test_timer_options(self):
+        self.assertCountEqual(
+            self.timer.options,
+            [
+                "Off",
+                "30 minutes",
+                "1 hour",
+                "1.5 hours",
+                "2 hours",
+                "2.5 hours",
+                "3 hours",
+                "3.5 hours",
+                "4 hours",
+                "4.5 hours",
+                "5 hours",
+                "5.5 hours",
+                "6 hours",
+                "6.5 hours",
+                "7 hours",
+                "7.5 hours",
+                "8 hours",
+                "8.5 hours",
+                "9 hours",
+                "9.5 hours",
+                "10 hours",
+            ],
+        )
+
+    def test_timer_current_option(self):
+        self.dps[TIMER_DPS] = "0_5"
+        self.assertEqual(self.timer.current_option, "30 minutes")
+
+    async def test_select_option(self):
+        async with assert_device_properties_set(
+            self.timer._device,
+            {TIMER_DPS: "4_0"},
+        ):
+            await self.timer.async_select_option("4 hours")