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

Merge pull request #150 from Chris061290/main

add IPS Pro Pool Heatpump
Jason Rumney 3 лет назад
Родитель
Сommit
eea5f3a96f

+ 1 - 0
README.md

@@ -64,6 +64,7 @@ the device will not work despite being listed below.
 - Remora pool heatpump
 - BWT FI 45 heatpump
 - Poolex Silverline and Vertigo heatpump
+- IPS Pro Pool-Systems Heatpump
 - these seem to use two common controllers, and many other Pool heatpumps
   will work using the above configurations.
   Report issues if there are any differences in presets or other features,

+ 103 - 0
custom_components/tuya_local/devices/ips_pro_heatpump.yaml

@@ -0,0 +1,103 @@
+name: IPS Inverter Heatpump
+primary_entity:
+  entity: climate
+  dps:
+    - id: 1
+      name: hvac_mode
+      type: boolean
+      mapping:
+        - dps_val: false
+          value: "off"
+          icon: "mdi:hvac-off"
+          icon_priority: 1
+        - dps_val: true
+          value: "heat"
+          icon: "mdi:hot-tub"
+          icon_priority: 3
+    - id: 2
+      name: preset_mode
+      type: string
+      mapping:
+        - dps_val: "silence"
+          value: "silence"
+          icon: "mdi:hot-tub"
+          icon_priority: 1
+        - dps_val: "smart"
+          value: "smart"
+          icon: "mdi:hot-tub"
+          icon_priority: 3
+        - dps_val: "turbo"
+          value: "turbo"
+          icon: "mdi:hot-tub"
+          icon_priority: 3
+    - id: 102
+      name: current_temperature
+      type: integer
+      readonly: true
+    - id: 103
+      name: temperature_unit
+      type: boolean
+      mapping:
+        - dps_val: false
+          value: F
+        - dps_val: true
+          value: C
+    - id: 104
+      name: power_level
+      type: integer
+      readonly: true
+    - id: 105
+      name: hvac_action
+      type: string
+      readonly: true
+      mapping:
+        - dps_val: warm
+          constraint: hvac_mode
+          conditions:
+            - dps_val: false
+              value: "off"
+            - dps_val: true
+              value: idle
+    - id: 106
+      name: temperature
+      type: integer
+      mapping:
+        - constraint: temperature_unit
+          conditions:
+            - dps_val: false
+              range:
+                min: 60
+                max: 115
+            - dps_val: true
+              range:
+                min: 18
+                max: 40
+      range:
+        min: 18
+        max: 45
+    - id: 107
+      type: integer
+      name: unknown_107
+    - id: 108
+      type: integer
+      name: unknown_108
+    - id: 115
+      type: integer
+      name: unknown_115
+    - id: 116
+      type: integer
+      name: unknown_116
+secondary_entities:
+  - entity: sensor
+    name: Power Level
+    class: power_factor
+    icon: "mdi:signal"
+    category: diagnostic
+    dps:
+      - id: 104
+        name: sensor
+        type: integer
+        unit: "%"
+        class: measurement
+        readonly: true
+

+ 14 - 0
tests/const.py

@@ -159,6 +159,20 @@ GARDENPAC_HEATPUMP_PAYLOAD = {
     "117": True,
 }
 
+IPS_HEATPUMP_PAYLOAD = {
+    "1": True,
+    "2": "silence",
+    "102": 10,
+    "103": True,
+    "104": 100,
+    "105": "warm",
+    "106": 30,
+    "107": 18,
+    "108": 40,
+    "115": 0,
+    "116": 0,
+}
+
 MADIMACK_HEATPUMP_PAYLOAD = {
     "1": True,
     "102": 9,

+ 176 - 0
tests/devices/test_ips_pro_heatpump.py

@@ -0,0 +1,176 @@
+from homeassistant.components.climate.const import (
+    HVAC_MODE_HEAT,
+    HVAC_MODE_OFF,
+    CURRENT_HVAC_HEAT,
+    CURRENT_HVAC_IDLE,
+    CURRENT_HVAC_OFF,
+    SUPPORT_PRESET_MODE,
+    SUPPORT_TARGET_TEMPERATURE,
+)
+from homeassistant.const import (
+    DEVICE_CLASS_POWER_FACTOR,
+    PERCENTAGE,
+    STATE_UNAVAILABLE,
+    TEMP_CELSIUS,
+    TEMP_FAHRENHEIT,
+)
+
+from ..const import IPS_HEATPUMP_PAYLOAD
+from ..helpers import assert_device_properties_set
+from ..mixins.climate import TargetTemperatureTests
+from ..mixins.sensor import BasicSensorTests
+from .base_device_tests import TuyaDeviceTestCase
+
+HVACMODE_DPS = "1"
+CURRENTTEMP_DPS = "102"
+UNITS_DPS = "103"
+POWERLEVEL_DPS = "104"
+OPMODE_DPS = "105"
+TEMPERATURE_DPS = "106"
+UNKNOWN107_DPS = "107"
+UNKNOWN108_DPS = "108"
+UNKNOWN115_DPS = "115"
+UNKNOWN116_DPS = "116"
+PRESET_DPS = "2"
+
+
+class TestIpsProHeatpump(
+    BasicSensorTests,
+    TargetTemperatureTests,
+    TuyaDeviceTestCase,
+):
+    __test__ = True
+
+    def setUp(self):
+        self.setUpForConfig("ips_pro_heatpump.yaml", IPS_HEATPUMP_PAYLOAD)
+        self.subject = self.entities.get("climate")
+        self.setUpTargetTemperature(
+            TEMPERATURE_DPS,
+            self.subject,
+            min=18,
+            max=40,
+        )
+        self.setUpBasicSensor(
+            POWERLEVEL_DPS,
+            self.entities.get("sensor_power_level"),
+            unit=PERCENTAGE,
+            device_class=DEVICE_CLASS_POWER_FACTOR,
+            state_class="measurement",
+        )
+        self.mark_secondary(["sensor_power_level"])
+
+    def test_supported_features(self):
+        self.assertEqual(
+            self.subject.supported_features,
+            SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE,
+        )
+
+    def test_icon(self):
+        self.dps[HVACMODE_DPS] = True
+        self.assertEqual(self.subject.icon, "mdi:hot-tub")
+
+        self.dps[HVACMODE_DPS] = False
+        self.assertEqual(self.subject.icon, "mdi:hvac-off")
+
+    def test_temperature_unit(self):
+        self.dps[UNITS_DPS] = False
+        self.assertEqual(self.subject.temperature_unit, TEMP_FAHRENHEIT)
+        self.dps[UNITS_DPS] = True
+        self.assertEqual(self.subject.temperature_unit, TEMP_CELSIUS)
+
+    def test_minimum_fahrenheit_temperature(self):
+        self.dps[UNITS_DPS] = False
+        self.assertEqual(self.subject.min_temp, 60)
+
+    def test_maximum_fahrenheit_temperature(self):
+        self.dps[UNITS_DPS] = False
+        self.assertEqual(self.subject.max_temp, 115)
+
+    def test_current_temperature(self):
+        self.dps[CURRENTTEMP_DPS] = 25
+        self.assertEqual(self.subject.current_temperature, 25)
+
+    def test_hvac_mode(self):
+        self.dps[HVACMODE_DPS] = True
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_HEAT)
+
+        self.dps[HVACMODE_DPS] = False
+        self.assertEqual(self.subject.hvac_mode, HVAC_MODE_OFF)
+
+        self.dps[HVACMODE_DPS] = None
+        self.assertEqual(self.subject.hvac_mode, STATE_UNAVAILABLE)
+
+    def test_hvac_modes(self):
+        self.assertCountEqual(self.subject.hvac_modes, [HVAC_MODE_OFF, HVAC_MODE_HEAT])
+
+    async def test_turn_on(self):
+        async with assert_device_properties_set(
+            self.subject._device, {HVACMODE_DPS: True}
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_HEAT)
+
+    async def test_turn_off(self):
+        async with assert_device_properties_set(
+            self.subject._device, {HVACMODE_DPS: False}
+        ):
+            await self.subject.async_set_hvac_mode(HVAC_MODE_OFF)
+
+    def test_preset_mode(self):
+        self.dps[PRESET_DPS] = "silence"
+        self.assertEqual(self.subject.preset_mode, "silence")
+
+        self.dps[PRESET_DPS] = "smart"
+        self.assertEqual(self.subject.preset_mode, "smart")
+
+        self.dps[PRESET_DPS] = "turbo"
+        self.assertEqual(self.subject.preset_mode, "turbo")
+
+    def test_preset_modes(self):
+        self.assertCountEqual(self.subject.preset_modes, ["silence", "smart", "turbo"])
+
+    async def test_set_preset_mode_to_silent(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "silence"},
+        ):
+            await self.subject.async_set_preset_mode("silence")
+
+    async def test_set_preset_mode_to_smart(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "smart"},
+        ):
+            await self.subject.async_set_preset_mode("smart")
+
+    async def test_set_preset_mode_to_smart(self):
+        async with assert_device_properties_set(
+            self.subject._device,
+            {PRESET_DPS: "turbo"},
+        ):
+            await self.subject.async_set_preset_mode("turbo")
+
+    def test_hvac_action(self):
+        self.dps[HVACMODE_DPS] = True
+        self.dps[OPMODE_DPS] = "heating"
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_HEAT)
+        self.dps[OPMODE_DPS] = "warm"
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_IDLE)
+        self.dps[HVACMODE_DPS] = False
+        self.assertEqual(self.subject.hvac_action, CURRENT_HVAC_OFF)
+
+    def test_extra_state_attributes(self):
+        self.dps[POWERLEVEL_DPS] = 50
+        self.dps[UNKNOWN107_DPS] = 1
+        self.dps[UNKNOWN108_DPS] = 2
+        self.dps[UNKNOWN115_DPS] = 3
+        self.dps[UNKNOWN116_DPS] = 4
+        self.assertDictEqual(
+            self.subject.extra_state_attributes,
+            {
+                "power_level": 50,
+                "unknown_107": 1,
+                "unknown_108": 2,
+                "unknown_115": 3,
+                "unknown_116": 4,
+            },
+        )