Prechádzať zdrojové kódy

Merge pull request #150 from Chris061290/main

add IPS Pro Pool Heatpump
Jason Rumney 3 rokov pred
rodič
commit
eea5f3a96f

+ 1 - 0
README.md

@@ -64,6 +64,7 @@ the device will not work despite being listed below.
 - Remora pool heatpump
 - Remora pool heatpump
 - BWT FI 45 heatpump
 - BWT FI 45 heatpump
 - Poolex Silverline and Vertigo heatpump
 - Poolex Silverline and Vertigo heatpump
+- IPS Pro Pool-Systems Heatpump
 - these seem to use two common controllers, and many other Pool heatpumps
 - these seem to use two common controllers, and many other Pool heatpumps
   will work using the above configurations.
   will work using the above configurations.
   Report issues if there are any differences in presets or other features,
   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,
     "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 = {
 MADIMACK_HEATPUMP_PAYLOAD = {
     "1": True,
     "1": True,
     "102": 9,
     "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,
+            },
+        )