Преглед на файлове

climate: implement precision attribute.

Similar to sensor native_precision, but this one expects something
like step (in fact it basically should be step, I don't know why they
have it in HA).
Jason Rumney преди 3 години
родител
ревизия
25c286c447

+ 7 - 0
custom_components/tuya_local/climate.py

@@ -127,6 +127,13 @@ class TuyaLocalClimate(TuyaLocalEntity, ClimateEntity):
         # Return the default unit
         return UnitOfTemperature.CELSIUS
 
+    @property
+    def precision(self):
+        """Return the precision of the temperature setting."""
+        # unlike sensor, this is a decimal of the smallest unit that can be
+        # represented, not a number of decimal places.
+        return 1.0 / self._temperature_dps.scale(self._device)
+
     @property
     def target_temperature(self):
         """Return the currently set target temperature."""

+ 18 - 33
custom_components/tuya_local/helpers/device_config.py

@@ -432,59 +432,51 @@ class TuyaDpsConfig:
 
     def range(self, device, scaled=True):
         """Return the range for this dps if configured."""
+        scale = self.scale(device) if scaled else 1
         mapping = self._find_map_for_dps(device.get_property(self.id))
-        scale = 1
+        r = self._config.get("range")
         if mapping:
             _LOGGER.debug(f"Considering mapping for range of {self.name}")
-            if scaled:
-                scale = mapping.get("scale", scale)
             cond = self._active_condition(mapping, device)
             if cond:
-                constraint = mapping.get("constraint")
-                if scaled:
-                    scale = mapping.get("scale", scale)
-                _LOGGER.debug(f"Considering condition on {constraint}")
-            r = None if cond is None else cond.get("range")
-            if r and "min" in r and "max" in r:
-                _LOGGER.debug(f"Conditional range returned for {self.name}")
-                return _scale_range(r, scale)
-        r = self._config.get("range")
+                r = cond.get("range", r)
+
         if r and "min" in r and "max" in r:
             return _scale_range(r, scale)
         else:
             return None
 
+    def scale(self, device):
+        scale = 1
+        mapping = self._find_map_for_dps(device.get_property(self.id))
+        if mapping:
+            scale = mapping.get("scale", 1)
+            cond = self._active_condition(mapping, device)
+            if cond:
+                scale = cond.get("scale", scale)
+        return scale
+
     def precision(self, device):
         if self.type is int:
-            scale = 1
-            mapping = self._find_map_for_dps(device.get_property(self.id))
-            if mapping:
-                scale = mapping.get("scale", 1)
-                cond = self._active_condition(mapping, device)
-                if cond:
-                    scale = cond.get("scale", scale)
+            scale = self.scale(device)
             precision = 0
-            _LOGGER.debug(f"calculating precision of scale {scale}...")
             while scale > 1.0:
                 scale /= 10.0
                 precision += 1
-            _LOGGER.debug(f"...precision calculated as {precision}")
             return precision
 
     def step(self, device, scaled=True):
         step = 1
-        scale = 1
+        scale = self.scale(device) if scaled else 1
         mapping = self._find_map_for_dps(device.get_property(self.id))
         if mapping:
             _LOGGER.debug(f"Considering mapping for step of {self.name}")
             step = mapping.get("step", 1)
-            scale = mapping.get("scale", 1)
             cond = self._active_condition(mapping, device)
             if cond:
                 constraint = mapping.get("constraint")
                 _LOGGER.debug(f"Considering condition on {constraint}")
                 step = cond.get("step", step)
-                scale = cond.get("scale", scale)
         if step != 1 or scale != 1:
             _LOGGER.debug(f"Step for {self.name} is {step} with scale {scale}")
         return step / scale if scaled else step
@@ -551,14 +543,11 @@ class TuyaDpsConfig:
             self.stringify = False
 
         result = value
+        scale = self.scale(device)
 
         mapping = self._find_map_for_dps(value)
         if mapping:
-            scale = mapping.get("scale", 1)
             invert = mapping.get("invert", False)
-
-            if not isinstance(scale, (int, float)):
-                scale = 1
             redirect = mapping.get("value_redirect")
             mirror = mapping.get("value_mirror")
             replaced = "value" in mapping
@@ -569,7 +558,6 @@ class TuyaDpsConfig:
                     return None
                 replaced = replaced or "value" in cond
                 result = cond.get("value", result)
-                scale = cond.get("scale", scale)
                 redirect = cond.get("value_redirect", redirect)
                 mirror = cond.get("value_mirror", mirror)
                 for m in cond.get("mapping", {}):
@@ -667,14 +655,12 @@ class TuyaDpsConfig:
             return dps_map
 
         mapping = self._find_map_for_value(value, device)
+        scale = self.scale(device)
         if mapping:
             replaced = False
-            scale = mapping.get("scale", 1)
             redirect = mapping.get("value_redirect")
             invert = mapping.get("invert", False)
 
-            if not isinstance(scale, (int, float)):
-                scale = 1
             step = mapping.get("step")
             if not isinstance(step, (int, float)):
                 step = None
@@ -703,7 +689,6 @@ class TuyaDpsConfig:
                     if m.get("value") == value:
                         result = m.get("dps_val", result)
 
-                scale = cond.get("scale", scale)
                 step = cond.get("step", step)
                 redirect = cond.get("value_redirect", redirect)
 

+ 4 - 1
tests/devices/test_beca_bac002_thermostat.py

@@ -8,7 +8,7 @@ from homeassistant.components.climate.const import (
     PRESET_COMFORT,
     PRESET_ECO,
 )
-from homeassistant.const import UnitOfTemperature
+from homeassistant.const import PRECISION_HALVES, UnitOfTemperature
 
 from ..const import BECA_BAC002_PAYLOAD
 from ..helpers import assert_device_properties_set
@@ -69,6 +69,9 @@ class TestBecaBAC002Thermostat(
     def test_temperature_unit_returns_configured_temperature_unit(self):
         self.assertEqual(self.subject.temperature_unit, UnitOfTemperature.CELSIUS)
 
+    def test_precision(self):
+        self.assertEqual(self.subject.precision, PRECISION_HALVES)
+
     async def test_legacy_set_temperature_with_preset_mode(self):
         async with assert_device_properties_set(
             self.subject._device, {PRESET_DPS: True}

+ 4 - 1
tests/devices/test_beok_tr9b_thermostat.py

@@ -3,7 +3,7 @@ from homeassistant.components.climate.const import (
     ClimateEntityFeature,
     HVACMode,
 )
-from homeassistant.const import UnitOfTemperature
+from homeassistant.const import PRECISION_TENTHS, UnitOfTemperature
 
 from ..const import BEOK_TR9B_PAYLOAD
 from ..mixins.climate import TargetTemperatureTests
@@ -153,6 +153,9 @@ class TestBeokTR9BThermostat(
         )
         self.assertEqual(self.subject.target_temperature_step, 1.0)
 
+    def test_precision(self):
+        self.assertEqual(self.subject.precision, PRECISION_TENTHS)
+
     def test_current_temperature(self):
         self.dps[CURRENTTEMP_DPS] = 685
         self.assertEqual(self.subject.current_temperature, 68.5)

+ 9 - 1
tests/devices/test_goldair_gpph_heater.py

@@ -4,7 +4,12 @@ from homeassistant.components.climate.const import (
     HVACMode,
 )
 from homeassistant.components.sensor import SensorDeviceClass
-from homeassistant.const import PERCENTAGE, UnitOfTime, UnitOfTemperature
+from homeassistant.const import (
+    PERCENTAGE,
+    PRECISION_WHOLE,
+    UnitOfTime,
+    UnitOfTemperature,
+)
 
 from ..const import GPPH_HEATER_PAYLOAD
 from ..helpers import assert_device_properties_set
@@ -106,6 +111,9 @@ class TestGoldairHeater(
     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_target_temperature_in_eco_and_af_modes(self):
         self.dps[TEMPERATURE_DPS] = 25
         self.dps[ECOTEMP_DPS] = 15