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

Thermex water heater: changes from review

- rename file to more obviously reflect the device purpose, in case of
different branded compatible devices.
- flip the operation_mode logic.

Implement tests for this device, to cover away mode via operation mode.

Look in into conditions for default, return value not dps_val.
 - required for away_mode redirection to operation_mode.  The siren
 actually expects value rather than dps_val as well.
Jason Rumney 2 лет назад
Родитель
Сommit
0e82452260

+ 2 - 1
ACKNOWLEDGEMENTS.md

@@ -271,7 +271,7 @@ Further device support has been made with the assistance of users.  Please consi
 - [JonF-49](https://github.com/JonF-49) for contributing support for RGBW lightbulbs, 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.
-- [YodaDaCoda](https://github.com/YodaDaCoda) for contributing support for Kogan LX10 vacuum cleaners.
+- [YodaDaCoda](https://github.com/YodaDaCoda) for contributing support for Kogan LX10 vacuum cleaners and improvements to device detection debug feedback.
 - [itn3rd77](https://github.com/itn3rd77) for contributing support for Stadler Form Karl/Karl Big humidifiers.
 - [Mikey887](https://github.com/Mikey887) for contributing support for Catit Pixi Smart feeder.
 - [fcrozat](https://github.com/fcrozat) for contributing support for BLE connected Johgee water timers.
@@ -290,3 +290,4 @@ Further device support has been made with the assistance of users.  Please consi
 - [jirijanu](https://github.com/jirijanu) for assisting with support for ZTH08ZTU zigbee temperature and humidity sensors.
 - [AndaPlays](https://github.com/AndaPlays) for assisting with support for Linkoze dual button wall switch.
 - [alexeyatbluescape](https://github.com/alexeyatbluescape) for contributing support for Feit dimmer.
+- [g470258](https://github.com/g470258) for contributing support for Thermex IF water heaters.

+ 1 - 0
DEVICES.md

@@ -69,6 +69,7 @@
 ### Water heaters
 
 - Hydrotherm Dynamic/X8 heat pump hot water systems
+- Thermex IF series V pro hot water systems.
 
 ### Thermostats
 

+ 0 - 69
custom_components/tuya_local/devices/thermex_IF_50_V.yaml

@@ -1,69 +0,0 @@
-name: Thermex IF series V (pro) Wi-Fi
-product:
-  - id: sz9gfbdn5my6GCfR
-    name: Thermex IF 50 V (pro) Wi-Fi
-primary_entity:
-  entity: water_heater
-  dps:
-    - id: 101
-      type: boolean
-      name: power
-      hidden: true
-      mapping:
-        - dps_val: false
-          value: "off"
-    - id: 104
-      type: integer
-      name: temperature
-      range:
-        min: 15
-        max: 75
-    - id: 102
-      type: integer
-      name: current_temperature
-    - id: 105
-      type: string
-      name: operation_mode
-      mapping:
-        - dps_val: 3
-          constraint: power
-          conditions:
-            - dps_val: false
-              value_redirect: power
-            - dps_val: true
-              value: Economy
-        - dps_val: 2
-          constraint: power
-          conditions:
-            - dps_val: false
-              value_redirect: power
-              value: "off"
-            - dps_val: true
-              value: Optimal
-        - dps_val: 4
-          constraint: power
-          conditions:
-            - dps_val: false
-              value_redirect: power
-            - dps_val: true
-              value: No Frost
-        - dps_val: 1
-          constraint: power
-          conditions:
-            - dps_val: false
-              value_redirect: power
-            - dps_val: true
-              value: Turbo	
-secondary_entities:
-  - entity: binary_sensor
-    class: problem
-    name: ERROR
-    category: diagnostic
-    dps:
-      - id: 106
-        type: bitfield
-        name: sensor
-        mapping:
-          - dps_val: 0
-            value: false
-          - value: true                            

+ 54 - 0
custom_components/tuya_local/devices/thermex_if50v_waterheater.yaml

@@ -0,0 +1,54 @@
+name: Thermex water heater
+product:
+  - id: sz9gfbdn5my6GCfR
+    name: Thermex IF 50 V pro
+primary_entity:
+  entity: water_heater
+  dps:
+    - id: 101
+      type: boolean
+      name: operation_mode
+      mapping:
+        - dps_val: false
+          value: "off"
+        - dps_val: true
+          constraint: work_mode
+          conditions:
+            - dps_val: "3"
+              value: eco
+            - dps_val: "2"
+              value: electric
+              default: true
+            - dps_val: "4"
+              value: away
+            - dps_val: "1"
+              value: performance
+    - id: 104
+      type: integer
+      name: temperature
+      range:
+        min: 15
+        max: 75
+    - id: 102
+      type: integer
+      name: current_temperature
+    - id: 105
+      type: string
+      name: work_mode
+      hidden: true
+    - id: 106
+      type: bitfield
+      name: fault_code
+secondary_entities:
+  - entity: binary_sensor
+    class: problem
+    name: Fault
+    category: diagnostic
+    dps:
+      - id: 106
+        type: bitfield
+        name: sensor
+        mapping:
+          - dps_val: 0
+            value: false
+          - value: true                            

+ 4 - 1
custom_components/tuya_local/helpers/device_config.py

@@ -503,7 +503,10 @@ class TuyaDpsConfig:
             return None
         for m in self._config["mapping"]:
             if m.get("default", False):
-                return m.get("dps_val", None)
+                return m.get("value", m.get("dps_val", None))
+            for c in m.get("conditions", {}):
+                if c.get("default", False):
+                    return c.get("value", m.get("value", m.get("dps_val", None)))
 
     def range(self, device, scaled=True):
         """Return the range for this dps if configured."""

+ 8 - 0
tests/const.py

@@ -1593,3 +1593,11 @@ GOLDAIR_GPDH340_PAYLOAD = {
     "108": False,
     "109": False,
 }
+
+THERMEX_IF50V_PAYLOAD = {
+    "101": False,
+    "102": 37,
+    "104": 65,
+    "105": "2",
+    "106": 0,
+}

+ 177 - 0
tests/devices/test_thermex_if50v.py

@@ -0,0 +1,177 @@
+from homeassistant.components.binary_sensor import BinarySensorDeviceClass
+from homeassistant.components.water_heater import (
+    STATE_ECO,
+    STATE_ELECTRIC,
+    STATE_OFF,
+    STATE_PERFORMANCE,
+    WaterHeaterEntityFeature,
+)
+from homeassistant.const import PRECISION_WHOLE, UnitOfTemperature
+
+from ..const import THERMEX_IF50V_PAYLOAD
+from ..helpers import assert_device_properties_set
+from ..mixins.binary_sensor import BasicBinarySensorTests
+from .base_device_tests import TuyaDeviceTestCase
+
+POWER_DP = "101"
+TEMPERATURE_DP = "104"
+CURRENTTEMP_DP = "102"
+MODE_DP = "105"
+ERROR_DP = "106"
+
+
+class TestThermexIF50V(
+    BasicBinarySensorTests,
+    TuyaDeviceTestCase,
+):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig(
+            "thermex_if50v_waterheater.yaml",
+            THERMEX_IF50V_PAYLOAD,
+        )
+        self.subject = self.entities.get("water_heater")
+        self.setUpBasicBinarySensor(
+            ERROR_DP,
+            self.entities.get("binary_sensor_fault"),
+            device_class=BinarySensorDeviceClass.PROBLEM,
+            testdata=(1, 0),
+        )
+        self.mark_secondary(["binary_sensor_fault"])
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            WaterHeaterEntityFeature.OPERATION_MODE
+            | WaterHeaterEntityFeature.TARGET_TEMPERATURE
+            | WaterHeaterEntityFeature.AWAY_MODE,
+        )
+
+    def test_temperature_unit_returns_celsius(self):
+        self.assertEqual(self.subject.temperature_unit, UnitOfTemperature.CELSIUS)
+
+    def test_precision(self):
+        self.assertEqual(self.subject.precision, PRECISION_WHOLE)
+
+    def test_current_temperature(self):
+        self.dps[CURRENTTEMP_DP] = 55
+        self.assertEqual(self.subject.current_temperature, 55)
+
+    def test_min_temp(self):
+        self.assertEqual(self.subject.min_temp, 15)
+
+    def test_max_temp(self):
+        self.assertEqual(self.subject.max_temp, 75)
+
+    def test_target_temperature(self):
+        self.dps[TEMPERATURE_DP] = 61
+        self.assertEqual(self.subject.target_temperature, 61)
+
+    def test_target_temperature_step(self):
+        self.assertEqual(self.subject.target_temperature_step, 1)
+
+    def test_operation_list(self):
+        self.assertCountEqual(
+            self.subject.operation_list,
+            [
+                STATE_ECO,
+                STATE_ELECTRIC,
+                STATE_PERFORMANCE,
+                STATE_OFF,
+                "away",
+            ],
+        )
+
+    def test_current_operation(self):
+        self.dps[POWER_DP] = True
+        self.dps[MODE_DP] = "3"
+        self.assertEqual(self.subject.current_operation, STATE_ECO)
+        self.dps[MODE_DP] = "1"
+        self.assertEqual(self.subject.current_operation, STATE_PERFORMANCE)
+        self.dps[MODE_DP] = "2"
+        self.assertEqual(self.subject.current_operation, STATE_ELECTRIC)
+        self.dps[MODE_DP] = "4"
+        self.assertEqual(self.subject.current_operation, "away")
+        self.dps[POWER_DP] = False
+        self.assertEqual(self.subject.current_operation, STATE_OFF)
+
+    def test_is_away_mode_redirects_to_mode(self):
+        self.dps[POWER_DP] = True
+        self.dps[MODE_DP] = "4"
+        self.assertTrue(self.subject.is_away_mode_on)
+        self.dps[MODE_DP] = "2"
+        self.assertFalse(self.subject.is_away_mode_on)
+
+    async def test_set_temperature(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {TEMPERATURE_DP: 65},
+        ):
+            await self.subject.async_set_temperature(temperature=65)
+
+    async def test_set_operation_mode_to_eco(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: True, MODE_DP: "3"},
+        ):
+            await self.subject.async_set_operation_mode(STATE_ECO)
+
+    async def test_set_operation_mode_with_temperature_service(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: True, MODE_DP: "3"},
+        ):
+            await self.subject.async_set_temperature(operation_mode=STATE_ECO)
+
+    async def test_set_operation_mode_to_electric(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: True, MODE_DP: "2"},
+        ):
+            await self.subject.async_set_operation_mode(STATE_ELECTRIC)
+
+    async def test_set_operation_mode_to_performance(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: True, MODE_DP: "1"},
+        ):
+            await self.subject.async_set_operation_mode(STATE_PERFORMANCE)
+
+    async def test_set_operation_mode_to_off(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: False},
+        ):
+            await self.subject.async_set_operation_mode(STATE_OFF)
+
+    async def test_turn_on(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: True},
+        ):
+            await self.subject.async_turn_on()
+
+    async def test_turn_off(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: False},
+        ):
+            await self.subject.async_turn_off()
+
+    async def test_turn_away_mode_on(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: True, MODE_DP: "4"},
+        ):
+            await self.subject.async_turn_away_mode_on()
+
+    async def test_turn_away_mode_off(self):
+        self.dps[POWER_DP] = True
+        self.dps[MODE_DP] = "4"
+
+        async with assert_device_properties_set(
+            self.subject._device,
+            {POWER_DP: True, MODE_DP: "2"},
+        ):
+            await self.subject.async_turn_away_mode_off()