Explorar o código

climate: add reporting of TURN_ON and TURN_OFF support

In HA 2024.2, climate devices are expected to report support of
turn_on and turn_off services.

During the deprecation period until 2025.1, warnings are reported in
the log if these methods are present and the device is not reporting
this support. This change will reduce these messages to just those
devices that actually do not support the methods (using the methods
would throw an exception).

Issue #1579
Jason Rumney %!s(int64=2) %!d(string=hai) anos
pai
achega
7780ddc726
Modificáronse 30 ficheiros con 88 adicións e 29 borrados
  1. 13 13
      custom_components/tuya_local/climate.py
  2. 1 1
      hacs.json
  3. 1 1
      requirements-dev.txt
  4. 3 1
      tests/devices/test_aspen_adv200_fan.py
  5. 2 0
      tests/devices/test_beca_bac002_thermostat.py
  6. 1 0
      tests/devices/test_beca_bhp6000_thermostat.py
  7. 2 0
      tests/devices/test_beca_bht002_thermostat.py
  8. 2 0
      tests/devices/test_beca_bht6000_thermostat.py
  9. 3 1
      tests/devices/test_beok_tr9b_thermostat.py
  10. 2 0
      tests/devices/test_betterlife_bl1500_heater.py
  11. 2 0
      tests/devices/test_eberg_cooly_c35hd.py
  12. 2 0
      tests/devices/test_eberg_qubo_q40hd_heatpump.py
  13. 3 1
      tests/devices/test_ecostrad_accentiq_heater.py
  14. 3 1
      tests/devices/test_eurom_600_heater.py
  15. 3 1
      tests/devices/test_eurom_600v2_heater.py
  16. 2 0
      tests/devices/test_eurom_601_heater.py
  17. 2 0
      tests/devices/test_fersk_vind_2_climate.py
  18. 3 1
      tests/devices/test_goldair_geco_heater.py
  19. 2 0
      tests/devices/test_goldair_gpph_heater.py
  20. 3 1
      tests/devices/test_inkbird_sousvide.py
  21. 3 1
      tests/devices/test_jiahong_et72w_thermostat.py
  22. 8 2
      tests/devices/test_kogan_glass_1_7l_kettle.py
  23. 4 1
      tests/devices/test_kogan_kawfpac09ya_airconditioner.py
  24. 2 0
      tests/devices/test_moes_bht002_thermostat.py
  25. 3 1
      tests/devices/test_nashone_mts700wb_thermostat.py
  26. 2 0
      tests/devices/test_nedis_htpl20f_heater.py
  27. 3 1
      tests/devices/test_poolex_qline_heatpump.py
  28. 2 0
      tests/devices/test_starlight_heatpump.py
  29. 4 1
      tests/devices/test_weau_pool_heatpumpv2.py
  30. 2 0
      tests/devices/test_wetair_wch750_heater.py

+ 13 - 13
custom_components/tuya_local/climate.py

@@ -93,28 +93,28 @@ class TuyaLocalClimate(TuyaLocalEntity, ClimateEntity):
         self._maxtemp_dps = dps_map.pop("max_temperature", None)
         self._maxtemp_dps = dps_map.pop("max_temperature", None)
 
 
         self._init_end(dps_map)
         self._init_end(dps_map)
-        self._support_flags = ClimateEntityFeature(0)
 
 
         if self._aux_heat_dps:
         if self._aux_heat_dps:
-            self._support_flags |= ClimateEntityFeature.AUX_HEAT
+            self._attr_supported_features |= ClimateEntityFeature.AUX_HEAT
         if self._fan_mode_dps:
         if self._fan_mode_dps:
-            self._support_flags |= ClimateEntityFeature.FAN_MODE
+            self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
         if self._humidity_dps:
         if self._humidity_dps:
-            self._support_flags |= ClimateEntityFeature.TARGET_HUMIDITY
+            self._attr_supported_features |= ClimateEntityFeature.TARGET_HUMIDITY
         if self._preset_mode_dps:
         if self._preset_mode_dps:
-            self._support_flags |= ClimateEntityFeature.PRESET_MODE
+            self._attr_supported_features |= ClimateEntityFeature.PRESET_MODE
         if self._swing_mode_dps:
         if self._swing_mode_dps:
-            self._support_flags |= ClimateEntityFeature.SWING_MODE
+            self._attr_supported_features |= ClimateEntityFeature.SWING_MODE
 
 
         if self._temp_high_dps and self._temp_low_dps:
         if self._temp_high_dps and self._temp_low_dps:
-            self._support_flags |= ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
+            self._attr_supported_features |= (
+                ClimateEntityFeature.TARGET_TEMPERATURE_RANGE
+            )
         elif self._temperature_dps is not None:
         elif self._temperature_dps is not None:
-            self._support_flags |= ClimateEntityFeature.TARGET_TEMPERATURE
-
-    @property
-    def supported_features(self):
-        """Return the features supported by this climate device."""
-        return self._support_flags
+            self._attr_supported_features |= ClimateEntityFeature.TARGET_TEMPERATURE
+        if HVACMode.OFF in self.hvac_modes:
+            self._attr_supported_features |= ClimateEntityFeature.TURN_OFF
+        if self._hvac_mode_dps and self._hvac_mode_dps.type is bool:
+            self._attr_supported_features |= ClimateEntityFeature.TURN_ON
 
 
     @property
     @property
     def temperature_unit(self):
     def temperature_unit(self):

+ 1 - 1
hacs.json

@@ -1,5 +1,5 @@
 {
 {
   "name": "Tuya Local",
   "name": "Tuya Local",
   "render_readme": true,
   "render_readme": true,
-  "homeassistant": "2024.1.0"
+  "homeassistant": "2024.2.0"
 }
 }

+ 1 - 1
requirements-dev.txt

@@ -1,6 +1,6 @@
 fuzzywuzzy
 fuzzywuzzy
 levenshtein
 levenshtein
-pytest-homeassistant-custom-component~=0.13.88
+pytest-homeassistant-custom-component~=0.13.99
 pytest
 pytest
 pytest-asyncio
 pytest-asyncio
 pytest-cov
 pytest-cov

+ 3 - 1
tests/devices/test_aspen_adv200_fan.py

@@ -63,7 +63,9 @@ class TestAspenASP200Fan(
         )
         )
         self.assertEqual(
         self.assertEqual(
             self.climate.supported_features,
             self.climate.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_fan_direction(self):
     def test_fan_direction(self):

+ 2 - 0
tests/devices/test_beca_bac002_thermostat.py

@@ -63,6 +63,8 @@ class TestBecaBAC002Thermostat(
                 ClimateEntityFeature.FAN_MODE
                 ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 1 - 0
tests/devices/test_beca_bhp6000_thermostat.py

@@ -48,6 +48,7 @@ class TestBecaBHP6000Thermostat(
                 ClimateEntityFeature.FAN_MODE
                 ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
+                | ClimateEntityFeature.TURN_OFF
             ),
             ),
         )
         )
 
 

+ 2 - 0
tests/devices/test_beca_bht002_thermostat.py

@@ -62,6 +62,8 @@ class TestBecaBHT002Thermostat(
             (
             (
                 ClimateEntityFeature.PRESET_MODE
                 ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 2 - 0
tests/devices/test_beca_bht6000_thermostat.py

@@ -59,6 +59,8 @@ class TestBecaBHT6000Thermostat(
             (
             (
                 ClimateEntityFeature.PRESET_MODE
                 ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 3 - 1
tests/devices/test_beok_tr9b_thermostat.py

@@ -135,7 +135,9 @@ class TestBeokTR9BThermostat(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_temperature_unit(self):
     def test_temperature_unit(self):

+ 2 - 0
tests/devices/test_betterlife_bl1500_heater.py

@@ -72,6 +72,8 @@ class TestBetterlifeBL1500Heater(
             (
             (
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 2 - 0
tests/devices/test_eberg_cooly_c35hd.py

@@ -61,6 +61,8 @@ class TestEbergCoolyC35HDHeatpump(
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.SWING_MODE
                 | ClimateEntityFeature.SWING_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 2 - 0
tests/devices/test_eberg_qubo_q40hd_heatpump.py

@@ -60,6 +60,8 @@ class TestEbergQuboQ40HDHeatpump(
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.SWING_MODE
                 | ClimateEntityFeature.SWING_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 3 - 1
tests/devices/test_ecostrad_accentiq_heater.py

@@ -39,7 +39,9 @@ class TestEcostradAccentIqHeater(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_temperature_unit(self):
     def test_temperature_unit(self):

+ 3 - 1
tests/devices/test_eurom_600_heater.py

@@ -39,7 +39,9 @@ class TestEurom600Heater(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_icon(self):
     def test_icon(self):

+ 3 - 1
tests/devices/test_eurom_600v2_heater.py

@@ -39,7 +39,9 @@ class TestEurom600v2Heater(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_icon(self):
     def test_icon(self):

+ 2 - 0
tests/devices/test_eurom_601_heater.py

@@ -48,6 +48,8 @@ class TestEurom601Heater(
             (
             (
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 2 - 0
tests/devices/test_fersk_vind_2_climate.py

@@ -47,6 +47,8 @@ class TestFerskVind2Climate(TargetTemperatureTests, TuyaDeviceTestCase):
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.SWING_MODE
                 | ClimateEntityFeature.SWING_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 3 - 1
tests/devices/test_goldair_geco_heater.py

@@ -60,7 +60,9 @@ class TestGoldairGECOHeater(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_icon(self):
     def test_icon(self):

+ 2 - 0
tests/devices/test_goldair_gpph_heater.py

@@ -91,6 +91,8 @@ class TestGoldairHeater(
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.SWING_MODE
                 | ClimateEntityFeature.SWING_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 3 - 1
tests/devices/test_inkbird_sousvide.py

@@ -105,7 +105,9 @@ class TestInkbirdSousVideCooker(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_icon(self):
     def test_icon(self):

+ 3 - 1
tests/devices/test_jiahong_et72w_thermostat.py

@@ -136,7 +136,9 @@ class TestJiahongEt72wThermostat(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_temperature_unit(self):
     def test_temperature_unit(self):

+ 8 - 2
tests/devices/test_kogan_glass_1_7l_kettle.py

@@ -1,4 +1,7 @@
-from homeassistant.components.climate.const import HVACMode
+from homeassistant.components.climate.const import (
+    ClimateEntityFeature,
+    HVACMode,
+)
 
 
 from ..const import KOGAN_GLASS_1_7L_KETTLE_PAYLOAD
 from ..const import KOGAN_GLASS_1_7L_KETTLE_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -20,7 +23,10 @@ class TestKoganGlass1_7LKettle(TuyaDeviceTestCase):
         self.subject = self.entities.get("climate")
         self.subject = self.entities.get("climate")
 
 
     def test_supported_features(self):
     def test_supported_features(self):
-        self.assertEqual(self.subject.supported_features, 0)
+        self.assertEqual(
+            self.subject.supported_features,
+            ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON,
+        )
 
 
     def test_icon(self):
     def test_icon(self):
         self.dps[HVACMODE_DPS] = True
         self.dps[HVACMODE_DPS] = True

+ 4 - 1
tests/devices/test_kogan_kawfpac09ya_airconditioner.py

@@ -36,7 +36,10 @@ class TestKoganKAWFPAC09YA(TargetTemperatureTests, TuyaDeviceTestCase):
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            (ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE),
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.FAN_MODE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_icon(self):
     def test_icon(self):

+ 2 - 0
tests/devices/test_moes_bht002_thermostat.py

@@ -48,6 +48,8 @@ class TestMoesBHT002Thermostat(
             (
             (
                 ClimateEntityFeature.PRESET_MODE
                 ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.TARGET_TEMPERATURE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 3 - 1
tests/devices/test_nashone_mts700wb_thermostat.py

@@ -85,7 +85,9 @@ class TestNashoneMTS700WBThermostat(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_current_temperature(self):
     def test_current_temperature(self):

+ 2 - 0
tests/devices/test_nedis_htpl20f_heater.py

@@ -56,6 +56,8 @@ class TestNedisHtpl20fHeater(
             (
             (
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 3 - 1
tests/devices/test_poolex_qline_heatpump.py

@@ -57,7 +57,9 @@ class TestPoolexQlineHeatpump(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_icon(self):
     def test_icon(self):

+ 2 - 0
tests/devices/test_starlight_heatpump.py

@@ -56,6 +56,8 @@ class TestStarLightHeatpump(
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.FAN_MODE
                 | ClimateEntityFeature.SWING_MODE
                 | ClimateEntityFeature.SWING_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )
 
 

+ 4 - 1
tests/devices/test_weau_pool_heatpumpv2.py

@@ -45,7 +45,10 @@ class TestWeauPoolHeatpumpV2(
     def test_supported_features(self):
     def test_supported_features(self):
         self.assertEqual(
         self.assertEqual(
             self.subject.supported_features,
             self.subject.supported_features,
-            ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE,
+            ClimateEntityFeature.TARGET_TEMPERATURE
+            | ClimateEntityFeature.PRESET_MODE
+            | ClimateEntityFeature.TURN_OFF
+            | ClimateEntityFeature.TURN_ON,
         )
         )
 
 
     def test_current_temperature(self):
     def test_current_temperature(self):

+ 2 - 0
tests/devices/test_wetair_wch750_heater.py

@@ -105,6 +105,8 @@ class TestWetairWCH750Heater(
             (
             (
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 ClimateEntityFeature.TARGET_TEMPERATURE
                 | ClimateEntityFeature.PRESET_MODE
                 | ClimateEntityFeature.PRESET_MODE
+                | ClimateEntityFeature.TURN_OFF
+                | ClimateEntityFeature.TURN_ON
             ),
             ),
         )
         )