Forráskód Böngészése

Add Moes Temperature and Humidity switch.

Partial functionality, as the user only has the waterproof temperature probe, not the (non-waterproof) temperature and humidity probe, and several dp purposes have not been reverse engineered yet.

Issue #182
Jason Rumney 3 éve
szülő
commit
e5cad8c944

+ 1 - 0
ACKNOWLEDGEMENTS.md

@@ -98,3 +98,4 @@ Further device support has been made with the assistance of users.  Please consi
 - [17hoehbr](https://github.com/17hoehbr) for assistance supporting APOSEN A550
 - [yurgh](https://github.com/yurgh) for assistant supporting Eesee Adam dehumidifier
 - [KaportsevIA](https://github.com/KaportsevIA) for assistance supporting Hyundai Sahara dehumidifier and Yandax color bulb.
+- [poolMiniDomo](https://github.com/poolMiniDomo) for assistance supporting Moes Temperature and Humidity switches.

+ 2 - 1
README.md

@@ -93,6 +93,7 @@ the device will not work despite being listed below.
 - Hysen HY08WE-2 thermostat
 - Nashone MTS-700-WB thermostat smartplug
 - Jiahong ET-72W thermostat
+- Moes MS-103 Temperature and Humidity Switch (partial functions, temperature only)
 
 ### Fans
 - Goldair GCPF315 fan
@@ -161,7 +162,7 @@ Other brands may work with the above configurations
 - Simple Switch with Timer - a single switch and timer, will probably work for a lot of smart switches that are not covered by the more advanced configs above.
 
 ### Lights
-- Generic RGBCW/RGBWW lightbulb (confirmed with Lijun and Yandex branded bulbs, expected to match many more)
+- Generic RGBCW/RGBWW lightbulb (confirmed with Lijun branded bulb, expected to match others also)
 
 ### Covers
 - Simple Garage Door

+ 131 - 0
custom_components/tuya_local/devices/moes_temp_humidity.yaml

@@ -0,0 +1,131 @@
+name: Moes Thermostat and Hydrostat
+product:
+  - id: dlsdk5zvkuuhufpy
+primary_entity:
+  entity: switch
+  name: Main Switch
+  category: config
+  dps:
+    - id: 1
+      type: boolean
+      name: switch
+# Known missing features: C/F switch, current humidity, High and Low temp alarms
+    - id: 8
+      type: boolean
+      name: unknown_8
+    - id: 9
+      type: integer
+      name: unknown_9
+    - id: 11
+      type: boolean
+      name: unknown_11
+    - id: 12
+      type: integer
+      name: unknown_12
+    - id: 20
+      type: integer
+      name: unknown_20
+    - id: 21
+      type: integer
+      name: unknown_21
+    - id: 22
+      type: integer
+      name: unknown_22
+    - id: 24
+      type: string
+      name: unknown_24
+    - id: 106
+      type: string
+      name: unknown_106
+secondary_entities:
+  - entity: switch
+    name: Switch 1
+    dps:
+      - id: 2
+        type: boolean
+        name: switch
+        # Auto rules are in an undocumented encoding, so just added as an attribute
+      - id: 101
+        type: hex
+        name: auto_rules
+  - entity: switch
+    name: Switch 2
+    dps:
+      - id: 3
+        type: boolean
+        name: switch
+        # Auto rules are in an undocumented encoding, so just added as an attribute
+      - id: 102
+        type: hex
+        name: auto_rules
+  - entity: select
+    name: Mode
+    category: config
+    dps:
+      - id: 4
+        type: string
+        name: option
+        mapping:
+          - dps_val: auto
+            value: Auto
+          - dps_val: manual
+            value: Manual
+  - entity: sensor
+    name: Current Temperature
+    class: temperature
+    dps:
+      - id: 6
+        type: integer
+        name: sensor
+        unit: C
+        class: measurement
+        mapping:
+          - scale: 10
+  - entity: number
+    name: Temperature Calibration
+    category: config
+    dps:
+      - id: 18
+        type: integer
+        name: value
+        range:
+          min: -99
+          max: 99
+        mapping:
+          - scale: 10
+  - entity: number
+    name: Timer 1
+    category: config
+    dps:
+      - id: 103
+        type: integer
+        name: value
+        unit: s
+        range:
+          min: 0
+          max: 86400
+  - entity: number
+    name: Timer 2
+    category: config
+    dps:
+      - id: 104
+        type: integer
+        name: value
+        unit: s
+        range:
+          min: 0
+          max: 86400
+  - entity: select
+    name: Power On State
+    category: config
+    dps:
+      - id: 105
+        type: string
+        name: option
+        mapping:
+          - dps_val: "on"
+            value: "On"
+          - dps_val: "off"
+            value: "Off"
+          - dps_val: memory
+            value: Last State

+ 1 - 1
custom_components/tuya_local/manifest.json

@@ -2,7 +2,7 @@
     "domain": "tuya_local",
     "iot_class": "local_polling",
     "name": "Tuya Local",
-    "version": "0.17.0",
+    "version": "0.17.1",
     "documentation": "https://github.com/make-all/tuya-local",
     "issue_tracker": "https://github.com/make-all/tuya-local/issues",
     "dependencies": [],

+ 23 - 0
tests/const.py

@@ -1291,3 +1291,26 @@ RGBCW_LIGHTBULB_PAYLOAD = {
     "25": "000e0d0000000000000000c80000",
     "26": 0,
 }
+
+MOES_TEMP_HUMID_PAYLOAD = {
+    "1": True,
+    "2": False,
+    "3": True,
+    "4": "manual",
+    "6": 374,
+    "8": False,
+    "9": 0,
+    "11": False,
+    "12": 0,
+    "18": 0,
+    "20": 0,
+    "21": 0,
+    "22": 0,
+    "24": "",
+    "101": "",
+    "102": "",
+    "103": 0,
+    "104": 0,
+    "105": "off",
+    "106": "mix",
+}

+ 158 - 0
tests/devices/test_moes_temp_humidity.py

@@ -0,0 +1,158 @@
+from homeassistant.components.sensor import SensorDeviceClass
+from homeassistant.const import TEMP_CELSIUS, TIME_SECONDS
+
+from ..const import MOES_TEMP_HUMID_PAYLOAD
+from ..mixins.number import MultiNumberTests
+from ..mixins.select import MultiSelectTests
+from ..mixins.sensor import BasicSensorTests
+from ..mixins.switch import MultiSwitchTests
+from .base_device_tests import TuyaDeviceTestCase
+
+MAINSW_DPS = "1"
+SW1_DPS = "2"
+SW2_DPS = "3"
+MODE_DPS = "4"
+TEMP_DPS = "6"
+UNKNOWN8_DPS = "8"
+UNKNOWN9_DPS = "9"
+UNKNOWN11_DPS = "11"
+UNKNOWN12_DPS = "12"
+CALIB_DPS = "18"
+UNKNOWN20_DPS = "20"
+UNKNOWN21_DPS = "21"
+UNKNOWN22_DPS = "22"
+UNKNOWN24_DPS = "24"
+RULE1_DPS = "101"
+RULE2_DPS = "102"
+TIMER1_DPS = "103"
+TIMER2_DPS = "104"
+INIT_DPS = "105"
+UNKNOWN106_DPS = "106"
+
+
+class TestMoesTempHumidity(
+    BasicSensorTests,
+    MultiNumberTests,
+    MultiSelectTests,
+    MultiSwitchTests,
+    TuyaDeviceTestCase,
+):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("moes_temp_humidity.yaml", MOES_TEMP_HUMID_PAYLOAD)
+        self.setUpBasicSensor(
+            TEMP_DPS,
+            self.entities.get("sensor_current_temperature"),
+            unit=TEMP_CELSIUS,
+            device_class=SensorDeviceClass.TEMPERATURE,
+            state_class="measurement",
+            testdata=(251, 25.1),
+        )
+        self.setUpMultiNumber(
+            [
+                {
+                    "dps": CALIB_DPS,
+                    "name": "number_temperature_calibration",
+                    "min": -9.9,
+                    "max": 9.9,
+                    "scale": 10,
+                    "step": 0.1,
+                },
+                {
+                    "dps": TIMER1_DPS,
+                    "name": "number_timer_1",
+                    "max": 86400,
+                    "unit": TIME_SECONDS,
+                },
+                {
+                    "dps": TIMER2_DPS,
+                    "name": "number_timer_2",
+                    "max": 86400,
+                    "unit": TIME_SECONDS,
+                },
+            ]
+        )
+        self.setUpMultiSelect(
+            [
+                {
+                    "dps": MODE_DPS,
+                    "name": "select_mode",
+                    "options": {
+                        "auto": "Auto",
+                        "manual": "Manual",
+                    },
+                },
+                {
+                    "dps": INIT_DPS,
+                    "name": "select_power_on_state",
+                    "options": {
+                        "on": "On",
+                        "off": "Off",
+                        "memory": "Last State",
+                    },
+                },
+            ]
+        )
+        self.setUpMultiSwitch(
+            [
+                {
+                    "dps": MAINSW_DPS,
+                    "name": "switch_main_switch",
+                },
+                {
+                    "dps": SW1_DPS,
+                    "name": "switch_switch_1",
+                },
+                {
+                    "dps": SW2_DPS,
+                    "name": "switch_switch_2",
+                },
+            ]
+        )
+        self.mark_secondary(
+            [
+                "switch_main_switch",
+                "select_mode",
+                "number_temperature_calibration",
+                "number_timer_1",
+                "number_timer_2",
+                "select_power_on_state",
+            ]
+        )
+
+    def test_multi_switch_state_attributes(self):
+        self.dps[UNKNOWN8_DPS] = True
+        self.dps[UNKNOWN9_DPS] = 9
+        self.dps[UNKNOWN11_DPS] = False
+        self.dps[UNKNOWN12_DPS] = 12
+        self.dps[UNKNOWN20_DPS] = 20
+        self.dps[UNKNOWN21_DPS] = 21
+        self.dps[UNKNOWN22_DPS] = 22
+        self.dps[UNKNOWN24_DPS] = "unknown24"
+        self.dps[UNKNOWN106_DPS] = "unknown106"
+        self.dps[RULE1_DPS] = "rules for switch 1"
+        self.dps[RULE2_DPS] = "rules for switch 2"
+
+        self.assertDictEqual(
+            self.multiSwitch["switch_main_switch"].extra_state_attributes,
+            {
+                "unknown_8": True,
+                "unknown_9": 9,
+                "unknown_11": False,
+                "unknown_12": 12,
+                "unknown_20": 20,
+                "unknown_21": 21,
+                "unknown_22": 22,
+                "unknown_24": "unknown24",
+                "unknown_106": "unknown106",
+            },
+        )
+        self.assertDictEqual(
+            self.multiSwitch["switch_switch_1"].extra_state_attributes,
+            {"auto_rules": "rules for switch 1"},
+        )
+        self.assertDictEqual(
+            self.multiSwitch["switch_switch_2"].extra_state_attributes,
+            {"auto_rules": "rules for switch 2"},
+        )