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

Convert Kogan Flame effect heater backlight and flame to use light effects.

Complete unit tests for the heater and make them pass.
Add translations for the flame and backlight light entities.
Jason Rumney 4 лет назад
Родитель
Сommit
8a8248eb2c

+ 1 - 0
ACKNOWLEDGEMENTS.md

@@ -50,3 +50,4 @@ Further device support has been made with the assistance of users.  Please consi
  - [nickdos](https://github.com/nickdos) for assistance in supporting Stirling FS1-40DC fan.
  - [Skro11-ru](https://github.com/Skro11-ru) for assistance in supporting Moes BHT-002 variant without external temperature sensor.
  - [novisys](https://github.com/novisys) for clarifications about BHT-6000 thermostat functionality.
+ - [nzcodarnoc](https://github.com/nzcodarnoc) for contributing support for Kogan KASHMFP heaters.

+ 1 - 0
README.md

@@ -39,6 +39,7 @@ the device will not work despite being listed below.
 - Eurom heater
 - Purline Hoti M100 heater
 - Wetair WCH-750 heater
+- Kogan Flame effect heater - KAWHMFP20BA model
 
 ### Air Conditioners / Heatpumps
 

+ 4 - 6
custom_components/tuya_local/devices/kogan_kashmfp20ba_heater.yaml

@@ -34,12 +34,11 @@ primary_entity:
       readonly: true
 secondary_entities:
   - entity: light
-    name: "backlight"
-    icon: "mdi:lightbulb"
+    name: "Backlight"
     dps:
       - id: 5
         type: string
-        name: back_light
+        name: effect
         mapping:
           - dps_val: "white"
             value: "white"
@@ -54,12 +53,11 @@ secondary_entities:
           - dps_val: "blueorange"
             value: "blueorange"
   - entity: light
-    name: "flame_colour"
-    icon: "mdi:lightbulb"
+    name: "Flame"
     dps:
       - id: 6
         type: string
-        name: flame_color
+        name: effect
         mapping:
           - dps_val: "orange"
             value: "orange"

+ 1 - 0
custom_components/tuya_local/generic/light.py

@@ -6,6 +6,7 @@ devices, so only providing simple on/off control.
 from homeassistant.components.light import (
     LightEntity,
     ATTR_BRIGHTNESS,
+    ATTR_EFFECT,
     COLOR_MODE_BRIGHTNESS,
     COLOR_MODE_ONOFF,
     COLOR_MODE_UNKNOWN,

+ 6 - 0
custom_components/tuya_local/translations/en.json

@@ -32,10 +32,13 @@
 		    "climate_dehumidifier_as_climate": "Include a climate entity for the dehumidifier (deprecated, recommend using humidifier and fan instead)",
 		    "fan_intensity": "Include intensity as a fan entitiy",
 		    "light_aq_indicator": "Include AQ indicator as a light entity",
+		    "light_backlight": "Include backlight as a light entity",
 		    "light_display": "Include display as a light entity",
+		    "light_flame": "Include flame as a light entity",
 		    "light_uv_sterilization": "Include UV sterilization as a light entitiy",
 		    "lock_child_lock": "Include child lock as a lock entity",
 		    "number_timer": "Include timer as a number entity",
+		    "select_timer": "Include timer as a select entity",
 		    "sensor_current_humidity": "Include current humidity as a sensor entity",
 		    "sensor_current_temperature": "Include current temperature as a sensor entity",
 		    "switch_air_clean": "Include air clean as a switch entity",
@@ -75,10 +78,13 @@
 		"climate_dehumidifier_as_climate": "Include a climate entity for the dehumidifier (deprecated, recommend using humidifier and fan instead)",
 		"fan_intensity": "Include intensity as a fan entitiy",
 		"light_aq_indicator": "Include AQ indicator as a light entity",
+		"light_backlight": "Include backlight as a light entity",
 		"light_display": "Include display as a light entity",
+		"light_flame": "Include flame as a light entity",
 		"light_uv_sterilization": "Include UV sterilization as a light entitiy",
 		"lock_child_lock": "Include child lock as a lock entity",
 		"number_timer": "Include timer as a number entity",
+		"select_timer": "Include timer as a select entity",
 		"sensor_current_humidity": "Include current humidity as a sensor entity",
 		"sensor_current_temperature": "Include current temperature as a sensor entity",
 		"switch_air_clean": "Include air clean as a switch entity",

+ 3 - 0
tests/devices/base_device_tests.py

@@ -164,6 +164,9 @@ class BasicLightTests:
         self.basicLight = subject
         self.basicLightDps = dps
 
+    def test_basic_light_supported_features(self):
+        self.assertEqual(self.basicLight.supported_features, 0)
+
     def test_basic_light_supported_color_modes(self):
         self.assertCountEqual(
             self.basicLight.supported_color_modes,

+ 102 - 27
tests/devices/test_kogan_kashmfp20ba_heater.py

@@ -4,19 +4,25 @@ from homeassistant.components.climate.const import (
     SUPPORT_PRESET_MODE,
     SUPPORT_TARGET_TEMPERATURE,
 )
-from homeassistant.components.lock import STATE_LOCKED, STATE_UNLOCKED
+from homeassistant.components.light import (
+    COLOR_MODE_UNKNOWN,
+    SUPPORT_EFFECT,
+)
 from homeassistant.const import STATE_UNAVAILABLE
 
 from ..const import KOGAN_KASHMFP20BA_HEATER_PAYLOAD
 from ..helpers import assert_device_properties_set
 from .base_device_tests import TuyaDeviceTestCase
 
-HVACMODE_DPS = "2"
+HVACMODE_DPS = "1"
+PRESET_DPS = "2"
 TEMPERATURE_DPS = "3"
 CURRENTTEMP_DPS = "4"
+BACKLIGHT_DPS = "5"
+FLAME_DPS = "6"
 
 
-class TestGoldairKoganKAHTPHeater(TuyaDeviceTestCase):
+class TestKoganKASHMF20BAHeater(TuyaDeviceTestCase):
     __test__ = True
 
     def setUp(self):
@@ -24,11 +30,13 @@ class TestGoldairKoganKAHTPHeater(TuyaDeviceTestCase):
             "kogan_kashmfp20ba_heater.yaml", KOGAN_KASHMFP20BA_HEATER_PAYLOAD
         )
         self.subject = self.entities.get("climate")
+        self.backlight = self.entities.get("light_backlight")
+        self.flame = self.entities.get("light_flame")
 
     def test_supported_features(self):
         self.assertEqual(
             self.subject.supported_features,
-            SUPPORT_TARGET_TEMPERATURE,
+            SUPPORT_TARGET_TEMPERATURE | SUPPORT_PRESET_MODE,
         )
 
     def test_icon(self):
@@ -51,10 +59,10 @@ class TestGoldairKoganKAHTPHeater(TuyaDeviceTestCase):
         self.assertEqual(self.subject.target_temperature_step, 1)
 
     def test_minimum_target_temperature(self):
-        self.assertEqual(self.subject.min_temp, 5)
+        self.assertEqual(self.subject.min_temp, 10)
 
     def test_maximum_target_temperature(self):
-        self.assertEqual(self.subject.max_temp, 40)
+        self.assertEqual(self.subject.max_temp, 30)
 
     async def test_legacy_set_temperature_with_temperature(self):
         async with assert_device_properties_set(
@@ -93,14 +101,14 @@ class TestGoldairKoganKAHTPHeater(TuyaDeviceTestCase):
 
     async def test_set_target_temperature_fails_outside_valid_range(self):
         with self.assertRaisesRegex(
-            ValueError, "temperature \\(4\\) must be between 5 and 40"
+            ValueError, "temperature \\(9\\) must be between 10 and 30"
         ):
-            await self.subject.async_set_target_temperature(4)
+            await self.subject.async_set_target_temperature(9)
 
         with self.assertRaisesRegex(
-            ValueError, "temperature \\(41\\) must be between 5 and 40"
+            ValueError, "temperature \\(31\\) must be between 10 and 30"
         ):
-            await self.subject.async_set_target_temperature(41)
+            await self.subject.async_set_target_temperature(31)
 
     def test_current_temperature(self):
         self.dps[CURRENTTEMP_DPS] = 25
@@ -132,38 +140,105 @@ class TestGoldairKoganKAHTPHeater(TuyaDeviceTestCase):
             await self.subject.async_set_hvac_mode(HVAC_MODE_OFF)
 
     def test_preset_mode(self):
-        self.dps[PRESET_DPS] = "Off"
-        self.assertEqual(self.subject.preset_mode, "Off")
-
-        self.dps[PRESET_DPS] = "Low"
-        self.assertEqual(self.subject.preset_mode, "Low")
+        self.dps[PRESET_DPS] = "low"
+        self.assertEqual(self.subject.preset_mode, "low")
 
-        self.dps[PRESET_DPS] = "High"
-        self.assertEqual(self.subject.preset_mode, "High")
+        self.dps[PRESET_DPS] = "high"
+        self.assertEqual(self.subject.preset_mode, "high")
 
         self.dps[PRESET_DPS] = None
         self.assertIs(self.subject.preset_mode, None)
 
     def test_preset_modes(self):
-        self.assertCountEqual(self.subject.preset_modes, ["Off", "Low", "High"])
+        self.assertCountEqual(self.subject.preset_modes, ["low", "high"])
 
     async def test_set_preset_mode_to_low(self):
         async with assert_device_properties_set(
             self.subject._device,
-            {PRESET_DPS: "Off"},
+            {PRESET_DPS: "low"},
         ):
-            await self.subject.async_set_preset_mode("Off")
+            await self.subject.async_set_preset_mode("low")
 
-    async def test_set_preset_mode_to_low(self):
+    async def test_set_preset_mode_to_high(self):
         async with assert_device_properties_set(
             self.subject._device,
-            {PRESET_DPS: "Low"},
+            {PRESET_DPS: "high"},
         ):
-            await self.subject.async_set_preset_mode("Low")
+            await self.subject.async_set_preset_mode("high")
+
+    def test_device_state_attribures(self):
+        self.assertEqual(self.subject.device_state_attributes, {})
+        self.assertEqual(self.backlight.device_state_attributes, {})
+        self.assertEqual(self.flame.device_state_attributes, {})
+
+    def test_lighting_supported_color_modes(self):
+        self.assertCountEqual(self.backlight.supported_color_modes, [])
+        self.assertCountEqual(self.flame.supported_color_modes, [])
+
+    def test_lighting_supported_features(self):
+        self.assertEqual(self.backlight.supported_features, SUPPORT_EFFECT)
+        self.assertEqual(self.flame.supported_features, SUPPORT_EFFECT)
+
+    def test_lighting_color_mode(self):
+        self.assertEqual(self.backlight.color_mode, COLOR_MODE_UNKNOWN)
+        self.assertEqual(self.flame.color_mode, COLOR_MODE_UNKNOWN)
+
+    def test_lighting_is_on(self):
+        self.assertTrue(self.backlight.is_on)
+        self.assertTrue(self.flame.is_on)
+
+    def test_lighting_brightness(self):
+        self.assertIsNone(self.backlight.brightness)
+        self.assertIsNone(self.flame.brightness)
+
+    def test_backlight_effect_list(self):
+        self.assertCountEqual(
+            self.backlight.effect_list,
+            [
+                "white",
+                "blue",
+                "orange",
+                "whiteblue",
+                "whiteorange",
+                "blueorange",
+            ],
+        )
 
-    async def test_set_preset_mode_to_high(self):
+    def test_flame_effect_list(self):
+        self.assertCountEqual(
+            self.flame.effect_list,
+            [
+                "orange",
+                "red",
+                "green",
+                "blue",
+                "redgreen",
+                "redblue",
+                "bluegreen",
+                "redorange",
+                "greenorange",
+                "blueorange",
+            ],
+        )
+
+    def test_backlight_effect(self):
+        self.dps[BACKLIGHT_DPS] = "orange"
+        self.assertEqual(self.backlight.effect, "orange")
+
+    def test_flame_effect(self):
+        self.dps[FLAME_DPS] = "bluegreen"
+        self.assertEqual(self.flame.effect, "bluegreen")
+
+    async def test_set_backlight_effect(self):
         async with assert_device_properties_set(
-            self.subject._device,
-            {PRESET_DPS: "High"},
+            self.backlight._device,
+            {BACKLIGHT_DPS: "whiteblue"},
+        ):
+            await self.backlight.async_turn_on(effect="whiteblue")
+
+    async def test_set_flame_effect(self):
+        async with assert_device_properties_set(
+            self.flame._device,
+            {FLAME_DPS: "red"},
         ):
-            await self.subject.async_set_preset_mode("High")
+            await self.flame.async_turn_on(effect="red")