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

Add support for a simple blind controller

dp 1 (command: open/close/stop), dp 2 (position, inverted from HA standard)
dp 5 (control_back_mode - reported only), dp 7 (work_state - reported only)

As dp 7 does not seem to change on the device investigated, it is not
used as `action`, instead action will be guessed from command and
position.

Issue #148
Jason Rumney 3 лет назад
Родитель
Сommit
e99a7e492d

+ 1 - 1
ACKNOWLEDGEMENTS.md

@@ -80,7 +80,7 @@ Further device support has been made with the assistance of users.  Please consi
 - [dieantu](https://github.com/dieantu) for contributing support for Himox H06 purifiers.
 - [pgistrand](https://github.com/pgistrand) for contributing support for Vork VK6067AW purifiers, and assistance with Parkside smart charger.
 - [markbvdh](https://github.com/markbvdh) for assistance with Kogan garage openers and confirmation of Summerwave Si pool heatpumps.
-- [tavicu](https://github.com/tavicu) for contributing support for Starlight Heatpumps, and for the idea to support inverted values.
+- [tavicu](https://github.com/tavicu) for contributing support for Starlight Heatpumps, Simple Blinds and for the idea to support inverted values.
 - [Chris061290](https://github.com/Chris061290) for contributing support for IPS Pro pool heatpumps, complete with unit tests.
 - [MartinCarbol](https://github.com/MartinCarbol) for contributing support for two models of Tesla Air Purifier.
 - [gschmidl](https://github.com/gschmidl) for assistance with Himox H05 purifiers

+ 1 - 0
README.md

@@ -150,6 +150,7 @@ Other brands may work with the above configurations
 
 ### Covers
 - Simple Garage Door
+- Simple Blind Controller
 - Kogan Garage Door with tilt sensor
 
 ### Vacuum Cleaners

+ 31 - 0
custom_components/tuya_local/devices/simple_blinds.yaml

@@ -0,0 +1,31 @@
+name: Blind Controller
+primary_entity:
+  entity: cover
+  class: blind
+  dps:
+    - id: 1
+      name: control
+      type: string
+      mapping:
+        - dps_val: open
+          value: open
+        - dps_val: close
+          value: close
+        - dps_val: stop
+          value: stop
+    - id: 2
+      name: position
+      type: integer
+      range:
+        min: 0
+        max: 100
+      mapping:
+        - invert: true
+    - id: 5
+      name: control_back_mode
+      type: boolean
+    - id: 7
+      name: work_state
+      type: string
+      # seems intended to match action, but doesn't change in observation
+

+ 7 - 0
tests/const.py

@@ -1130,3 +1130,10 @@ SD123_PRESENCE_PAYLOAD = {
     "113": 0,
     "114": True,
 }
+
+SIMPLE_BLINDS_PAYLOAD = {
+    "1": "stop",
+    "2": 0,
+    "5": False,
+    "7": "opening",
+}

+ 105 - 0
tests/devices/test_simple_blinds.py

@@ -0,0 +1,105 @@
+"""Tests for the simple blinds controller."""
+from homeassistant.components.cover import (
+    DEVICE_CLASS_BLIND,
+    SUPPORT_CLOSE,
+    SUPPORT_OPEN,
+    SUPPORT_SET_POSITION,
+    SUPPORT_STOP,
+)
+
+from ..const import SIMPLE_BLINDS_PAYLOAD
+from ..helpers import assert_device_properties_set
+from .base_device_tests import TuyaDeviceTestCase
+
+COMMAND_DPS = "1"
+POSITION_DPS = "2"
+BACKMODE_DPS = "5"
+ACTION_DPS = "7"
+
+
+class TestSimpleBlinds(TuyaDeviceTestCase):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("simple_blinds.yaml", SIMPLE_BLINDS_PAYLOAD)
+        self.subject = self.entities["cover"]
+
+    def test_device_class_is_blind(self):
+        self.assertEqual(self.subject.device_class, DEVICE_CLASS_BLIND)
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION | SUPPORT_STOP,
+        )
+
+    def test_current_cover_position(self):
+        self.dps[POSITION_DPS] = 47
+        self.assertEqual(self.subject.current_cover_position, 53)
+
+    def test_is_opening(self):
+        self.dps[COMMAND_DPS] = "open"
+        self.dps[POSITION_DPS] = 0
+        self.assertFalse(self.subject.is_opening)
+        self.dps[POSITION_DPS] = 50
+        self.assertTrue(self.subject.is_opening)
+        self.dps[COMMAND_DPS] = "close"
+        self.assertFalse(self.subject.is_opening)
+        self.dps[COMMAND_DPS] = "stop"
+        self.assertFalse(self.subject.is_opening)
+
+    def test_is_closing(self):
+        self.dps[COMMAND_DPS] = "close"
+        self.dps[POSITION_DPS] = 100
+        self.assertFalse(self.subject.is_closing)
+        self.dps[POSITION_DPS] = 50
+        self.assertTrue(self.subject.is_closing)
+        self.dps[COMMAND_DPS] = "open"
+        self.assertFalse(self.subject.is_closing)
+        self.dps[COMMAND_DPS] = "stop"
+        self.assertFalse(self.subject.is_closing)
+
+    def test_is_closed(self):
+        self.dps[POSITION_DPS] = 0
+        self.assertFalse(self.subject.is_closed)
+        self.dps[POSITION_DPS] = 100
+        self.assertTrue(self.subject.is_closed)
+
+    async def test_open_cover(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {COMMAND_DPS: "open"},
+        ):
+            await self.subject.async_open_cover()
+
+    async def test_close_cover(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {COMMAND_DPS: "close"},
+        ):
+            await self.subject.async_close_cover()
+
+    async def test_stop_cover(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {COMMAND_DPS: "stop"},
+        ):
+            await self.subject.async_stop_cover()
+
+    async def test_set_cover_position(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POSITION_DPS: 23},
+        ):
+            await self.subject.async_set_cover_position(77)
+
+    def test_extra_state_attributes(self):
+        self.dps[BACKMODE_DPS] = False
+        self.dps[ACTION_DPS] = "test2"
+        self.assertDictEqual(
+            self.subject.extra_state_attributes,
+            {
+                "control_back_mode": False,
+                "work_state": "test2",
+            },
+        )