Quellcode durchsuchen

Add units to number entities.

Based on release notes for 2021.12, it is also possible to set units on number entities.  It may improve the UI somehow.
Jason Rumney vor 4 Jahren
Ursprung
Commit
05839e8486
51 geänderte Dateien mit 238 neuen und 54 gelöschten Zeilen
  1. 1 0
      custom_components/tuya_local/devices/anko_fan.yaml
  2. 2 0
      custom_components/tuya_local/devices/awow_th213_thermostat.yaml
  3. 2 0
      custom_components/tuya_local/devices/digoo_dgsp202.yaml
  4. 1 0
      custom_components/tuya_local/devices/eberg_qubo_q40hd_heatpump.yaml
  5. 1 0
      custom_components/tuya_local/devices/goldair_dehumidifier.yaml
  6. 1 0
      custom_components/tuya_local/devices/goldair_geco_heater.yaml
  7. 1 0
      custom_components/tuya_local/devices/goldair_gpcv_heater.yaml
  8. 1 0
      custom_components/tuya_local/devices/goldair_gpph_heater.yaml
  9. 2 0
      custom_components/tuya_local/devices/grid_connect_usb_double_power_point.yaml
  10. 1 0
      custom_components/tuya_local/devices/inkbird_itc306a_thermostat.yaml
  11. 1 0
      custom_components/tuya_local/devices/kogan_kahtp_heater.yaml
  12. 1 0
      custom_components/tuya_local/devices/kogan_kawfhtp_heater.yaml
  13. 1 0
      custom_components/tuya_local/devices/lexy_f501_fan.yaml
  14. 25 1
      custom_components/tuya_local/devices/minco_mh1823d_thermostat.yaml
  15. 1 0
      custom_components/tuya_local/devices/nedis_htpl20f_heater.yaml
  16. 2 0
      custom_components/tuya_local/devices/qoto_03_sprinkler.yaml
  17. 2 0
      custom_components/tuya_local/devices/saswell_c16_thermostat.yaml
  18. 1 0
      custom_components/tuya_local/devices/simple_switch_timer.yaml
  19. 1 0
      custom_components/tuya_local/devices/smartplugv1.yaml
  20. 1 0
      custom_components/tuya_local/devices/smartplugv2.yaml
  21. 1 0
      custom_components/tuya_local/devices/smartplugv2_energy.yaml
  22. 1 0
      custom_components/tuya_local/devices/tmwf02_fan.yaml
  23. 4 0
      custom_components/tuya_local/devices/woox_r4028_powerstrip.yaml
  24. 14 16
      custom_components/tuya_local/generic/climate.py
  25. 12 1
      custom_components/tuya_local/generic/number.py
  26. 7 10
      custom_components/tuya_local/generic/sensor.py
  27. 14 0
      custom_components/tuya_local/helpers/mixin.py
  28. 7 1
      tests/devices/test_anko_fan.py
  29. 2 0
      tests/devices/test_awow_th213_thermostat.py
  30. 3 0
      tests/devices/test_digoo_dgsp202.py
  31. 12 2
      tests/devices/test_eberg_qubo_q40hd_heatpump.py
  32. 7 1
      tests/devices/test_goldair_dehumidifier.py
  33. 2 2
      tests/devices/test_goldair_geco_heater.py
  34. 2 2
      tests/devices/test_goldair_gpcv_heater.py
  35. 6 1
      tests/devices/test_goldair_gpph_heater.py
  36. 3 0
      tests/devices/test_grid_connect_double_power_point.py
  37. 5 1
      tests/devices/test_inkbird_itc306a_thermostat.py
  38. 7 2
      tests/devices/test_kogan_kahtp_heater.py
  39. 7 2
      tests/devices/test_kogan_kawfhtp_heater.py
  40. 7 1
      tests/devices/test_lexy_f501_fan.py
  41. 4 0
      tests/devices/test_minco_mh1823d_thermostat.py
  42. 7 2
      tests/devices/test_nedis_htpl20f_heater.py
  43. 4 1
      tests/devices/test_qoto_03_sprinkler.py
  44. 3 1
      tests/devices/test_saswell_c16_thermostat.py
  45. 6 1
      tests/devices/test_simple_switch_with_timer.py
  46. 7 1
      tests/devices/test_smartplugv1.py
  47. 7 1
      tests/devices/test_smartplugv2.py
  48. 7 1
      tests/devices/test_smartplugv2_energy.py
  49. 2 2
      tests/devices/test_tmwf02_fan.py
  50. 5 0
      tests/devices/test_woox_r4028_powerstrip.py
  51. 14 1
      tests/mixins/number.py

+ 1 - 0
custom_components/tuya_local/devices/anko_fan.yaml

@@ -43,6 +43,7 @@ secondary_entities:
       - id: 6
       - id: 6
         type: integer
         type: integer
         name: value
         name: value
+        unit: s
         range:
         range:
           min: 0
           min: 0
           max: 9
           max: 9

+ 2 - 0
custom_components/tuya_local/devices/awow_th213_thermostat.yaml

@@ -135,6 +135,7 @@ secondary_entities:
       - id: 103
       - id: 103
         type: integer
         type: integer
         name: value
         name: value
+        unit: C
         range:
         range:
           min: -9
           min: -9
           max: 9
           max: 9
@@ -146,6 +147,7 @@ secondary_entities:
       - id: 104
       - id: 104
         type: integer
         type: integer
         name: value
         name: value
+        unit: C
         range:
         range:
           min: 1
           min: 1
           max: 9
           max: 9

+ 2 - 0
custom_components/tuya_local/devices/digoo_dgsp202.yaml

@@ -63,6 +63,7 @@ secondary_entities:
       - id: 9
       - id: 9
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400
@@ -77,6 +78,7 @@ secondary_entities:
       - id: 10
       - id: 10
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400

+ 1 - 0
custom_components/tuya_local/devices/eberg_qubo_q40hd_heatpump.yaml

@@ -132,6 +132,7 @@ secondary_entities:
       - id: 22
       - id: 22
         type: integer
         type: integer
         name: value
         name: value
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 24
           max: 24

+ 1 - 0
custom_components/tuya_local/devices/goldair_dehumidifier.yaml

@@ -297,6 +297,7 @@ secondary_entities:
       - id: 12
       - id: 12
         name: value
         name: value
         type: integer
         type: integer
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 24
           max: 24

+ 1 - 0
custom_components/tuya_local/devices/goldair_geco_heater.yaml

@@ -54,6 +54,7 @@ secondary_entities:
       - id: 5
       - id: 5
         type: integer
         type: integer
         name: value
         name: value
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 24
           max: 24

+ 1 - 0
custom_components/tuya_local/devices/goldair_gpcv_heater.yaml

@@ -62,6 +62,7 @@ secondary_entities:
       - id: 5
       - id: 5
         type: integer
         type: integer
         name: value
         name: value
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 24
           max: 24

+ 1 - 0
custom_components/tuya_local/devices/goldair_gpph_heater.yaml

@@ -158,6 +158,7 @@ secondary_entities:
       - id: 102
       - id: 102
         type: integer
         type: integer
         name: value
         name: value
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 1440
           max: 1440

+ 2 - 0
custom_components/tuya_local/devices/grid_connect_usb_double_power_point.yaml

@@ -170,6 +170,7 @@ secondary_entities:
       - id: 9
       - id: 9
         type: integer
         type: integer
         name: value
         name: value
+        unit: s
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400
@@ -181,6 +182,7 @@ secondary_entities:
       - id: 10
       - id: 10
         type: integer
         type: integer
         name: value
         name: value
+        unit: s
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400

+ 1 - 0
custom_components/tuya_local/devices/inkbird_itc306a_thermostat.yaml

@@ -155,6 +155,7 @@ secondary_entities:
       - id: 108
       - id: 108
         type: integer
         type: integer
         name: value
         name: value
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 96
           max: 96

+ 1 - 0
custom_components/tuya_local/devices/kogan_kahtp_heater.yaml

@@ -55,6 +55,7 @@ secondary_entities:
       - id: 8
       - id: 8
         name: value
         name: value
         type: integer
         type: integer
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 24
           max: 24

+ 1 - 0
custom_components/tuya_local/devices/kogan_kawfhtp_heater.yaml

@@ -54,6 +54,7 @@ secondary_entities:
       - id: 5
       - id: 5
         type: integer
         type: integer
         name: value
         name: value
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 24
           max: 24

+ 1 - 0
custom_components/tuya_local/devices/lexy_f501_fan.yaml

@@ -90,6 +90,7 @@ secondary_entities:
       - id: 6
       - id: 6
         type: integer
         type: integer
         name: value
         name: value
+        unit: h
         range:
         range:
           min: 0
           min: 0
           max: 7
           max: 7

+ 25 - 1
custom_components/tuya_local/devices/minco_mh1823d_thermostat.yaml

@@ -155,6 +155,15 @@ secondary_entities:
                 range:
                 range:
                   min: -15
                   min: -15
                   max: 15
                   max: 15
+      - id: 19
+        type: string
+        name: unit
+        hidden: true
+        mapping:
+          - dps_val: c
+            value: C
+          - dps_val: f
+            value: F
   - entity: number
   - entity: number
     name: Calibration Offset External
     name: Calibration Offset External
     category: config
     category: config
@@ -177,6 +186,11 @@ secondary_entities:
         type: string
         type: string
         name: unit
         name: unit
         hidden: true
         hidden: true
+        mapping:
+          - dps_val: c
+            value: C
+          - dps_val: f
+            value: F
   - entity: number
   - entity: number
     name: Calibration Swing
     name: Calibration Swing
     category: config
     category: config
@@ -199,6 +213,11 @@ secondary_entities:
         type: string
         type: string
         name: unit
         name: unit
         hidden: true
         hidden: true
+        mapping:
+          - dps_val: c
+            value: C
+          - dps_val: f
+            value: F
   - entity: number
   - entity: number
     category: config
     category: config
     name: High Temperature Limit
     name: High Temperature Limit
@@ -227,7 +246,12 @@ secondary_entities:
       - id: 19
       - id: 19
         type: string
         type: string
         name: unit
         name: unit
-        hidden: true        
+        hidden: true
+        mapping:
+          - dps_val: c
+            value: C
+          - dps_val: f
+            value: F
   - entity: select
   - entity: select
     name: Schedule
     name: Schedule
     category: config
     category: config

+ 1 - 0
custom_components/tuya_local/devices/nedis_htpl20f_heater.yaml

@@ -57,6 +57,7 @@ secondary_entities:
       - id: 13
       - id: 13
         type: integer
         type: integer
         name: value
         name: value
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 1440
           max: 1440

+ 2 - 0
custom_components/tuya_local/devices/qoto_03_sprinkler.yaml

@@ -6,6 +6,7 @@ primary_entity:
     - id: 102
     - id: 102
       type: integer
       type: integer
       name: value
       name: value
+      unit: "%"
       range:
       range:
         min: 0
         min: 0
         max: 100
         max: 100
@@ -38,6 +39,7 @@ secondary_entities:
       - id: 105
       - id: 105
         type: integer
         type: integer
         name: value
         name: value
+        unit: s
         range:
         range:
           min: 0
           min: 0
           max: 86399
           max: 86399

+ 2 - 0
custom_components/tuya_local/devices/saswell_c16_thermostat.yaml

@@ -119,6 +119,7 @@ secondary_entities:
       - id: 6
       - id: 6
         name: value
         name: value
         type: integer
         type: integer
+        unit: C
         range:
         range:
           min: 200
           min: 200
           max: 500
           max: 500
@@ -180,6 +181,7 @@ secondary_entities:
       - id: 22
       - id: 22
         name: value
         name: value
         type: integer
         type: integer
+        unit: W
         range:
         range:
           min: 0
           min: 0
           max: 3500
           max: 3500

+ 1 - 0
custom_components/tuya_local/devices/simple_switch_timer.yaml

@@ -15,6 +15,7 @@ secondary_entities:
       - id: 11
       - id: 11
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400

+ 1 - 0
custom_components/tuya_local/devices/smartplugv1.yaml

@@ -71,6 +71,7 @@ secondary_entities:
       - id: 2
       - id: 2
         type: integer
         type: integer
         name: value
         name: value
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 1440
           max: 1440

+ 1 - 0
custom_components/tuya_local/devices/smartplugv2.yaml

@@ -71,6 +71,7 @@ secondary_entities:
       - id: 9
       - id: 9
         type: integer
         type: integer
         name: value
         name: value
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 1440
           max: 1440

+ 1 - 0
custom_components/tuya_local/devices/smartplugv2_energy.yaml

@@ -39,6 +39,7 @@ secondary_entities:
       - id: 9
       - id: 9
         type: integer
         type: integer
         name: value
         name: value
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 1440
           max: 1440

+ 1 - 0
custom_components/tuya_local/devices/tmwf02_fan.yaml

@@ -23,6 +23,7 @@ secondary_entities:
       - id: 2
       - id: 2
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400

+ 4 - 0
custom_components/tuya_local/devices/woox_r4028_powerstrip.yaml

@@ -37,6 +37,7 @@ secondary_entities:
       - id: 101
       - id: 101
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400
@@ -51,6 +52,7 @@ secondary_entities:
       - id: 102
       - id: 102
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400
@@ -65,6 +67,7 @@ secondary_entities:
       - id: 103
       - id: 103
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400
@@ -79,6 +82,7 @@ secondary_entities:
       - id: 105
       - id: 105
         name: value
         name: value
         type: integer
         type: integer
+        unit: min
         range:
         range:
           min: 0
           min: 0
           max: 86400
           max: 86400

+ 14 - 16
custom_components/tuya_local/generic/climate.py

@@ -39,10 +39,17 @@ from homeassistant.const import (
 
 
 from ..device import TuyaLocalDevice
 from ..device import TuyaLocalDevice
 from ..helpers.device_config import TuyaEntityConfig
 from ..helpers.device_config import TuyaEntityConfig
-from ..helpers.mixin import TuyaLocalEntity
+from ..helpers.mixin import TuyaLocalEntity, unit_from_ascii
 
 
 _LOGGER = logging.getLogger(__name__)
 _LOGGER = logging.getLogger(__name__)
 
 
+VALID_TEMP_UNIT = [TEMP_CELSIUS, TEMP_FAHRENHEIT, TEMP_KELVIN]
+
+
+def validate_temp_unit(unit):
+    unit = unit_from_ascii(unit)
+    return unit if unit in VALID_TEMP_UNIT else None
+
 
 
 class TuyaLocalClimate(TuyaLocalEntity, ClimateEntity):
 class TuyaLocalClimate(TuyaLocalEntity, ClimateEntity):
     """Representation of a Tuya Climate entity."""
     """Representation of a Tuya Climate entity."""
@@ -101,24 +108,15 @@ class TuyaLocalClimate(TuyaLocalEntity, ClimateEntity):
         """Return the unit of measurement."""
         """Return the unit of measurement."""
         # If there is a separate DPS that returns the units, use that
         # If there is a separate DPS that returns the units, use that
         if self._unit_dps is not None:
         if self._unit_dps is not None:
-            unit = self._unit_dps.get_value(self._device)
+            unit = validate_temp_unit(self._unit_dps.get_value(self._device))
             # Only return valid units
             # Only return valid units
-            if unit == "C":
-                return TEMP_CELSIUS
-            elif unit == "F":
-                return TEMP_FAHRENHEIT
-            elif unit == "K":
-                return TEMP_KELVIN
+            if unit is not None:
+                return unit
         # If there unit attribute configured in the temperature dps, use that
         # If there unit attribute configured in the temperature dps, use that
         if self._temperature_dps:
         if self._temperature_dps:
-            unit = self._temperature_dps.unit
-            # Only return valid units
-            if unit == "C":
-                return TEMP_CELSIUS
-            elif unit == "F":
-                return TEMP_FAHRENHEIT
-            elif unit == "K":
-                return TEMP_KELVIN
+            unit = validate_temp_unit(self._temperature_dps.unit)
+            if unit is not None:
+                return unit
         # Return the default unit from the device
         # Return the default unit from the device
         return self._device.temperature_unit
         return self._device.temperature_unit
 
 

+ 12 - 1
custom_components/tuya_local/generic/number.py

@@ -9,7 +9,7 @@ from homeassistant.components.number.const import (
 
 
 from ..device import TuyaLocalDevice
 from ..device import TuyaLocalDevice
 from ..helpers.device_config import TuyaEntityConfig
 from ..helpers.device_config import TuyaEntityConfig
-from ..helpers.mixin import TuyaLocalEntity
+from ..helpers.mixin import TuyaLocalEntity, unit_from_ascii
 
 
 MODE_AUTO = "auto"
 MODE_AUTO = "auto"
 
 
@@ -28,6 +28,7 @@ class TuyaLocalNumber(TuyaLocalEntity, NumberEntity):
         self._value_dps = dps_map.pop("value")
         self._value_dps = dps_map.pop("value")
         if self._value_dps is None:
         if self._value_dps is None:
             raise AttributeError(f"{config.name} is missing a value dps")
             raise AttributeError(f"{config.name} is missing a value dps")
+        self._unit_dps = dps_map.pop("unit", None)
         self._init_end(dps_map)
         self._init_end(dps_map)
 
 
     @property
     @property
@@ -52,6 +53,16 @@ class TuyaLocalNumber(TuyaLocalEntity, NumberEntity):
             m = MODE_AUTO
             m = MODE_AUTO
         return m
         return m
 
 
+    @property
+    def unit_of_measurement(self):
+        """Return the unit associated with this number."""
+        if self._unit_dps is None:
+            unit = self._value_dps.unit
+        else:
+            unit = self._unit_dps.get_value(self._device)
+
+        return unit_from_ascii(unit)
+
     @property
     @property
     def value(self):
     def value(self):
         """Return the current value of the number."""
         """Return the current value of the number."""

+ 7 - 10
custom_components/tuya_local/generic/sensor.py

@@ -1,12 +1,15 @@
 """
 """
 Platform to read Tuya sensors.
 Platform to read Tuya sensors.
 """
 """
-from homeassistant.components.sensor import DEVICE_CLASSES, SensorEntity, STATE_CLASSES
-from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
+from homeassistant.components.sensor import (
+    DEVICE_CLASSES,
+    SensorEntity,
+    STATE_CLASSES,
+)
 
 
 from ..device import TuyaLocalDevice
 from ..device import TuyaLocalDevice
 from ..helpers.device_config import TuyaEntityConfig
 from ..helpers.device_config import TuyaEntityConfig
-from ..helpers.mixin import TuyaLocalEntity
+from ..helpers.mixin import TuyaLocalEntity, unit_from_ascii
 
 
 
 
 class TuyaLocalSensor(TuyaLocalEntity, SensorEntity):
 class TuyaLocalSensor(TuyaLocalEntity, SensorEntity):
@@ -58,10 +61,4 @@ class TuyaLocalSensor(TuyaLocalEntity, SensorEntity):
         else:
         else:
             unit = self._unit_dps.get_value(self._device)
             unit = self._unit_dps.get_value(self._device)
 
 
-        # Temperatures use Unicode characters, translate from simpler ASCII
-        if unit == "C":
-            unit = TEMP_CELSIUS
-        elif unit == "F":
-            unit = TEMP_FAHRENHEIT
-
-        return unit
+        return unit_from_ascii(unit)

+ 14 - 0
custom_components/tuya_local/helpers/mixin.py

@@ -2,6 +2,7 @@
 Mixins to make writing new platforms easier
 Mixins to make writing new platforms easier
 """
 """
 import logging
 import logging
+from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
 
 
 _LOGGER = logging.getLogger(__name__)
 _LOGGER = logging.getLogger(__name__)
 
 
@@ -67,3 +68,16 @@ class TuyaLocalEntity:
 
 
     async def async_update(self):
     async def async_update(self):
         await self._device.async_refresh()
         await self._device.async_refresh()
+
+
+UNIT_ASCII_MAP = {
+    "C": TEMP_CELSIUS,
+    "F": TEMP_FAHRENHEIT,
+}
+
+
+def unit_from_ascii(unit):
+    if unit in UNIT_ASCII_MAP:
+        return UNIT_ASCII_MAP[unit]
+
+    return unit

+ 7 - 1
tests/devices/test_anko_fan.py

@@ -3,6 +3,7 @@ from homeassistant.components.fan import (
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
     SUPPORT_SET_SPEED,
     SUPPORT_SET_SPEED,
 )
 )
+from homeassistant.const import TIME_SECONDS
 
 
 from ..const import ANKO_FAN_PAYLOAD
 from ..const import ANKO_FAN_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -24,7 +25,12 @@ class TestAnkoFan(SwitchableTests, BasicNumberTests, TuyaDeviceTestCase):
         self.setUpForConfig("anko_fan.yaml", ANKO_FAN_PAYLOAD)
         self.setUpForConfig("anko_fan.yaml", ANKO_FAN_PAYLOAD)
         self.subject = self.entities["fan"]
         self.subject = self.entities["fan"]
         self.setUpSwitchable(SWITCH_DPS, self.subject)
         self.setUpSwitchable(SWITCH_DPS, self.subject)
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=9)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=9,
+            unit=TIME_SECONDS,
+        )
         self.mark_secondary(["number_timer"])
         self.mark_secondary(["number_timer"])
 
 
     def test_supported_features(self):
     def test_supported_features(self):

+ 2 - 0
tests/devices/test_awow_th213_thermostat.py

@@ -81,12 +81,14 @@ class TestAwowTH213Thermostat(
                     "dps": CALIBRATE_DPS,
                     "dps": CALIBRATE_DPS,
                     "min": -9,
                     "min": -9,
                     "max": 9,
                     "max": 9,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
                 {
                 {
                     "name": "number_calibration_swing",
                     "name": "number_calibration_swing",
                     "dps": CALIBSWING_DPS,
                     "dps": CALIBSWING_DPS,
                     "min": 1,
                     "min": 1,
                     "max": 9,
                     "max": 9,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
             ]
             ]
         )
         )

+ 3 - 0
tests/devices/test_digoo_dgsp202.py

@@ -7,6 +7,7 @@ from homeassistant.const import (
     ELECTRIC_CURRENT_MILLIAMPERE,
     ELECTRIC_CURRENT_MILLIAMPERE,
     ELECTRIC_POTENTIAL_VOLT,
     ELECTRIC_POTENTIAL_VOLT,
     POWER_WATT,
     POWER_WATT,
+    TIME_MINUTES,
 )
 )
 
 
 from ..const import DIGOO_DGSP202_SOCKET_PAYLOAD
 from ..const import DIGOO_DGSP202_SOCKET_PAYLOAD
@@ -54,12 +55,14 @@ class TestDigooDGSP202Switch(
                     "name": "number_timer_1",
                     "name": "number_timer_1",
                     "max": 1440,
                     "max": 1440,
                     "scale": 60,
                     "scale": 60,
+                    "unit": TIME_MINUTES,
                 },
                 },
                 {
                 {
                     "dps": TIMER2_DPS,
                     "dps": TIMER2_DPS,
                     "name": "number_timer_2",
                     "name": "number_timer_2",
                     "max": 1440,
                     "max": 1440,
                     "scale": 60,
                     "scale": 60,
+                    "unit": TIME_MINUTES,
                 },
                 },
             ]
             ]
         )
         )

+ 12 - 2
tests/devices/test_eberg_qubo_q40hd_heatpump.py

@@ -17,7 +17,12 @@ from homeassistant.components.climate.const import (
     SWING_OFF,
     SWING_OFF,
     SWING_VERTICAL,
     SWING_VERTICAL,
 )
 )
-from homeassistant.const import STATE_UNAVAILABLE, TEMP_CELSIUS, TEMP_FAHRENHEIT
+from homeassistant.const import (
+    STATE_UNAVAILABLE,
+    TEMP_CELSIUS,
+    TEMP_FAHRENHEIT,
+    TIME_HOURS,
+)
 
 
 from ..const import EBERG_QUBO_Q40HD_PAYLOAD
 from ..const import EBERG_QUBO_Q40HD_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -54,7 +59,12 @@ class TestEbergQuboQ40HDHeatpump(
             min=17,
             min=17,
             max=30,
             max=30,
         )
         )
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=24,
+            unit=TIME_HOURS,
+        )
         self.mark_secondary(["number_timer"])
         self.mark_secondary(["number_timer"])
 
 
     def test_supported_features(self):
     def test_supported_features(self):

+ 7 - 1
tests/devices/test_goldair_dehumidifier.py

@@ -19,6 +19,7 @@ from homeassistant.const import (
     DEVICE_CLASS_TEMPERATURE,
     DEVICE_CLASS_TEMPERATURE,
     STATE_UNAVAILABLE,
     STATE_UNAVAILABLE,
     TEMP_CELSIUS,
     TEMP_CELSIUS,
+    TIME_HOURS,
 )
 )
 
 
 from ..const import DEHUMIDIFIER_PAYLOAD
 from ..const import DEHUMIDIFIER_PAYLOAD
@@ -73,7 +74,12 @@ class TestGoldairDehumidifier(
         self.light = self.entities.get("light_display")
         self.light = self.entities.get("light_display")
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicSwitch(AIRCLEAN_DPS, self.entities.get("switch_air_clean"))
         self.setUpBasicSwitch(AIRCLEAN_DPS, self.entities.get("switch_air_clean"))
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=24,
+            unit=TIME_HOURS,
+        )
 
 
         self.setUpMultiSensors(
         self.setUpMultiSensors(
             [
             [

+ 2 - 2
tests/devices/test_goldair_geco_heater.py

@@ -4,7 +4,7 @@ from homeassistant.components.climate.const import (
     HVAC_MODE_OFF,
     HVAC_MODE_OFF,
     SUPPORT_TARGET_TEMPERATURE,
     SUPPORT_TARGET_TEMPERATURE,
 )
 )
-from homeassistant.const import STATE_UNAVAILABLE
+from homeassistant.const import STATE_UNAVAILABLE, TIME_HOURS
 
 
 from ..const import GECO_HEATER_PAYLOAD
 from ..const import GECO_HEATER_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -41,7 +41,7 @@ class TestGoldairGECOHeater(
             max=35,
             max=35,
         )
         )
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24)
+        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24, unit=TIME_HOURS)
         self.setUpBasicBinarySensor(
         self.setUpBasicBinarySensor(
             ERROR_DPS,
             ERROR_DPS,
             self.entities.get("binary_sensor_error"),
             self.entities.get("binary_sensor_error"),

+ 2 - 2
tests/devices/test_goldair_gpcv_heater.py

@@ -5,7 +5,7 @@ from homeassistant.components.climate.const import (
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
     SUPPORT_TARGET_TEMPERATURE,
     SUPPORT_TARGET_TEMPERATURE,
 )
 )
-from homeassistant.const import STATE_UNAVAILABLE
+from homeassistant.const import STATE_UNAVAILABLE, TIME_HOURS
 
 
 from ..const import GPCV_HEATER_PAYLOAD
 from ..const import GPCV_HEATER_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -43,7 +43,7 @@ class TestGoldairGPCVHeater(
             max=35,
             max=35,
         )
         )
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24)
+        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24, unit=TIME_HOURS)
         self.setUpBasicBinarySensor(
         self.setUpBasicBinarySensor(
             ERROR_DPS,
             ERROR_DPS,
             self.entities.get("binary_sensor_error"),
             self.entities.get("binary_sensor_error"),

+ 6 - 1
tests/devices/test_goldair_gpph_heater.py

@@ -11,6 +11,7 @@ from homeassistant.const import (
     DEVICE_CLASS_POWER_FACTOR,
     DEVICE_CLASS_POWER_FACTOR,
     PERCENTAGE,
     PERCENTAGE,
     STATE_UNAVAILABLE,
     STATE_UNAVAILABLE,
+    TIME_MINUTES,
 )
 )
 
 
 from ..const import GPPH_HEATER_PAYLOAD
 from ..const import GPPH_HEATER_PAYLOAD
@@ -60,7 +61,11 @@ class TestGoldairHeater(
         self.setUpBasicLight(LIGHT_DPS, self.entities.get("light_display"))
         self.setUpBasicLight(LIGHT_DPS, self.entities.get("light_display"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicNumber(
         self.setUpBasicNumber(
-            TIMER_DPS, self.entities.get("number_timer"), min=0, max=1440, step=60
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=1440,
+            step=60,
+            unit=TIME_MINUTES,
         )
         )
         self.setUpBasicSensor(
         self.setUpBasicSensor(
             POWERLEVEL_DPS,
             POWERLEVEL_DPS,

+ 3 - 0
tests/devices/test_grid_connect_double_power_point.py

@@ -9,6 +9,7 @@ from homeassistant.const import (
     ELECTRIC_POTENTIAL_VOLT,
     ELECTRIC_POTENTIAL_VOLT,
     ENERGY_WATT_HOUR,
     ENERGY_WATT_HOUR,
     POWER_WATT,
     POWER_WATT,
+    TIME_SECONDS,
 )
 )
 
 
 from ..const import GRIDCONNECT_2SOCKET_PAYLOAD
 from ..const import GRIDCONNECT_2SOCKET_PAYLOAD
@@ -126,11 +127,13 @@ class TestGridConnectDoubleSwitch(
                     "name": "number_timer_1",
                     "name": "number_timer_1",
                     "dps": COUNTDOWN1_DPS,
                     "dps": COUNTDOWN1_DPS,
                     "max": 86400,
                     "max": 86400,
+                    "unit": TIME_SECONDS,
                 },
                 },
                 {
                 {
                     "name": "number_timer_2",
                     "name": "number_timer_2",
                     "dps": COUNTDOWN2_DPS,
                     "dps": COUNTDOWN2_DPS,
                     "max": 86400,
                     "max": 86400,
+                    "unit": TIME_SECONDS,
                 },
                 },
             ]
             ]
         )
         )

+ 5 - 1
tests/devices/test_inkbird_itc306a_thermostat.py

@@ -9,7 +9,7 @@ from homeassistant.components.climate.const import (
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
     SUPPORT_TARGET_TEMPERATURE_RANGE,
     SUPPORT_TARGET_TEMPERATURE_RANGE,
 )
 )
-from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT
+from homeassistant.const import TEMP_CELSIUS, TEMP_FAHRENHEIT, TIME_HOURS
 
 
 
 
 from ..const import INKBIRD_THERMOSTAT_PAYLOAD
 from ..const import INKBIRD_THERMOSTAT_PAYLOAD
@@ -95,11 +95,13 @@ class TestInkbirdThermostat(
                     "step": 0.1,
                     "step": 0.1,
                     "min": -9.9,
                     "min": -9.9,
                     "max": 9.9,
                     "max": 9.9,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
                 {
                 {
                     "name": "number_continuous_heat_hours",
                     "name": "number_continuous_heat_hours",
                     "dps": TIME_THRES_DPS,
                     "dps": TIME_THRES_DPS,
                     "max": 96,
                     "max": 96,
+                    "unit": TIME_HOURS,
                 },
                 },
                 {
                 {
                     "name": "number_high_temperature_limit",
                     "name": "number_high_temperature_limit",
@@ -108,6 +110,7 @@ class TestInkbirdThermostat(
                     "step": 0.1,
                     "step": 0.1,
                     "min": -40,
                     "min": -40,
                     "max": 100,
                     "max": 100,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
                 {
                 {
                     "name": "number_low_temperature_limit",
                     "name": "number_low_temperature_limit",
@@ -116,6 +119,7 @@ class TestInkbirdThermostat(
                     "step": 0.1,
                     "step": 0.1,
                     "min": -40,
                     "min": -40,
                     "max": 100,
                     "max": 100,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
             ]
             ]
         )
         )

+ 7 - 2
tests/devices/test_kogan_kahtp_heater.py

@@ -4,7 +4,7 @@ from homeassistant.components.climate.const import (
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
     SUPPORT_TARGET_TEMPERATURE,
     SUPPORT_TARGET_TEMPERATURE,
 )
 )
-from homeassistant.const import STATE_UNAVAILABLE
+from homeassistant.const import STATE_UNAVAILABLE, TIME_HOURS
 
 
 from ..const import KOGAN_HEATER_PAYLOAD
 from ..const import KOGAN_HEATER_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -36,7 +36,12 @@ class TestGoldairKoganKAHTPHeater(
             max=35,
             max=35,
         )
         )
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=24,
+            unit=TIME_HOURS,
+        )
         self.mark_secondary(["lock_child_lock", "number_timer"])
         self.mark_secondary(["lock_child_lock", "number_timer"])
 
 
     def test_supported_features(self):
     def test_supported_features(self):

+ 7 - 2
tests/devices/test_kogan_kawfhtp_heater.py

@@ -4,7 +4,7 @@ from homeassistant.components.climate.const import (
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
     SUPPORT_TARGET_TEMPERATURE,
     SUPPORT_TARGET_TEMPERATURE,
 )
 )
-from homeassistant.const import STATE_UNAVAILABLE
+from homeassistant.const import STATE_UNAVAILABLE, TIME_HOURS
 
 
 from ..const import KOGAN_KAWFHTP_HEATER_PAYLOAD
 from ..const import KOGAN_KAWFHTP_HEATER_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -39,7 +39,12 @@ class TestGoldairKoganKAHTPHeater(
             max=40,
             max=40,
         )
         )
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=24)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=24,
+            unit=TIME_HOURS,
+        )
         self.mark_secondary(["lock_child_lock", "number_timer"])
         self.mark_secondary(["lock_child_lock", "number_timer"])
 
 
     def test_supported_features(self):
     def test_supported_features(self):

+ 7 - 1
tests/devices/test_lexy_f501_fan.py

@@ -3,6 +3,7 @@ from homeassistant.components.fan import (
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
     SUPPORT_SET_SPEED,
     SUPPORT_SET_SPEED,
 )
 )
+from homeassistant.const import TIME_HOURS
 
 
 from ..const import LEXY_F501_PAYLOAD
 from ..const import LEXY_F501_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -38,7 +39,12 @@ class TestLexyF501Fan(
         self.setUpSwitchable(POWER_DPS, self.subject)
         self.setUpSwitchable(POWER_DPS, self.subject)
         self.setUpBasicLight(LIGHT_DPS, self.entities.get("light"))
         self.setUpBasicLight(LIGHT_DPS, self.entities.get("light"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
         self.setUpBasicLock(LOCK_DPS, self.entities.get("lock_child_lock"))
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=7)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=7,
+            unit=TIME_HOURS,
+        )
         self.setUpBasicSwitch(SWITCH_DPS, self.entities.get("switch_sound"))
         self.setUpBasicSwitch(SWITCH_DPS, self.entities.get("switch_sound"))
         self.mark_secondary(
         self.mark_secondary(
             [
             [

+ 4 - 0
tests/devices/test_minco_mh1823d_thermostat.py

@@ -90,24 +90,28 @@ class TestMincoMH1823DThermostat(
                     "dps": CALIBINT_DPS,
                     "dps": CALIBINT_DPS,
                     "min": -9,
                     "min": -9,
                     "max": 9,
                     "max": 9,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
                 {
                 {
                     "name": "number_calibration_offset_external",
                     "name": "number_calibration_offset_external",
                     "dps": CALIBEXT_DPS,
                     "dps": CALIBEXT_DPS,
                     "min": -9,
                     "min": -9,
                     "max": 9,
                     "max": 9,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
                 {
                 {
                     "name": "number_calibration_swing",
                     "name": "number_calibration_swing",
                     "dps": CALIBSWING_DPS,
                     "dps": CALIBSWING_DPS,
                     "min": 1,
                     "min": 1,
                     "max": 9,
                     "max": 9,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
                 {
                 {
                     "name": "number_high_temperature_limit",
                     "name": "number_high_temperature_limit",
                     "dps": TEMPLIMIT_DPS,
                     "dps": TEMPLIMIT_DPS,
                     "min": 5,
                     "min": 5,
                     "max": 65,
                     "max": 65,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
             ]
             ]
         )
         )

+ 7 - 2
tests/devices/test_nedis_htpl20f_heater.py

@@ -7,7 +7,7 @@ from homeassistant.components.climate.const import (
     SUPPORT_TARGET_TEMPERATURE,
     SUPPORT_TARGET_TEMPERATURE,
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
 )
 )
-from homeassistant.const import STATE_UNAVAILABLE
+from homeassistant.const import STATE_UNAVAILABLE, TIME_MINUTES
 
 
 from ..const import NEDIS_HTPL20F_PAYLOAD
 from ..const import NEDIS_HTPL20F_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -44,7 +44,12 @@ class TestNedisHtpl20fHeater(
             LOCK_DPS,
             LOCK_DPS,
             self.entities.get("lock_child_lock"),
             self.entities.get("lock_child_lock"),
         )
         )
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=1440)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=1440,
+            unit=TIME_MINUTES,
+        )
         self.mark_secondary(["lock_child_lock", "number_timer"])
         self.mark_secondary(["lock_child_lock", "number_timer"])
 
 
     def test_supported_features(self):
     def test_supported_features(self):

+ 4 - 1
tests/devices/test_qoto_03_sprinkler.py

@@ -1,5 +1,6 @@
 """Tests for the Quto 03 Sprinkler."""
 """Tests for the Quto 03 Sprinkler."""
 from homeassistant.components.binary_sensor import DEVICE_CLASS_PROBLEM
 from homeassistant.components.binary_sensor import DEVICE_CLASS_PROBLEM
+from homeassistant.const import PERCENTAGE, TIME_SECONDS
 
 
 from ..const import QOTO_SPRINKLER_PAYLOAD
 from ..const import QOTO_SPRINKLER_PAYLOAD
 from ..mixins.binary_sensor import BasicBinarySensorTests
 from ..mixins.binary_sensor import BasicBinarySensorTests
@@ -14,7 +15,7 @@ TIMER_DPS = "105"
 ERROR_DPS = "108"
 ERROR_DPS = "108"
 
 
 
 
-class TestQoboSprinkler(
+class TestQotoSprinkler(
     BasicBinarySensorTests,
     BasicBinarySensorTests,
     MultiNumberTests,
     MultiNumberTests,
     MultiSensorTests,
     MultiSensorTests,
@@ -37,11 +38,13 @@ class TestQoboSprinkler(
                     "dps": TARGET_DPS,
                     "dps": TARGET_DPS,
                     "max": 100,
                     "max": 100,
                     "step": 5,
                     "step": 5,
+                    "unit": PERCENTAGE,
                 },
                 },
                 {
                 {
                     "name": "number_timer",
                     "name": "number_timer",
                     "dps": TIMER_DPS,
                     "dps": TIMER_DPS,
                     "max": 86399,
                     "max": 86399,
+                    "unit": TIME_SECONDS,
                 },
                 },
             ]
             ]
         )
         )

+ 3 - 1
tests/devices/test_saswell_c16_thermostat.py

@@ -9,7 +9,7 @@ from homeassistant.components.climate.const import (
     SUPPORT_PRESET_MODE,
     SUPPORT_PRESET_MODE,
     SUPPORT_TARGET_TEMPERATURE,
     SUPPORT_TARGET_TEMPERATURE,
 )
 )
-from homeassistant.const import DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS
+from homeassistant.const import DEVICE_CLASS_TEMPERATURE, POWER_WATT, TEMP_CELSIUS
 
 
 from ..const import SASWELL_C16_THERMOSTAT_PAYLOAD
 from ..const import SASWELL_C16_THERMOSTAT_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -85,11 +85,13 @@ class TestSaswellC16Thermostat(
                     "max": 50.0,
                     "max": 50.0,
                     "scale": 10,
                     "scale": 10,
                     "step": 0.5,
                     "step": 0.5,
+                    "unit": TEMP_CELSIUS,
                 },
                 },
                 {
                 {
                     "name": "number_power_rating",
                     "name": "number_power_rating",
                     "dps": POWERRATING_DPS,
                     "dps": POWERRATING_DPS,
                     "max": 3500,
                     "max": 3500,
+                    "unit": POWER_WATT,
                 },
                 },
             ]
             ]
         )
         )

+ 6 - 1
tests/devices/test_simple_switch_with_timer.py

@@ -1,5 +1,6 @@
 """Tests for a simple switch with timer"""
 """Tests for a simple switch with timer"""
 from homeassistant.components.switch import DEVICE_CLASS_OUTLET
 from homeassistant.components.switch import DEVICE_CLASS_OUTLET
+from homeassistant.const import TIME_MINUTES
 
 
 from ..const import TIMED_SOCKET_PAYLOAD
 from ..const import TIMED_SOCKET_PAYLOAD
 from ..mixins.number import BasicNumberTests
 from ..mixins.number import BasicNumberTests
@@ -18,7 +19,11 @@ class TestTimedSwitch(BasicNumberTests, SwitchableTests, TuyaDeviceTestCase):
         self.subject = self.entities.get("switch")
         self.subject = self.entities.get("switch")
         self.setUpSwitchable(SWITCH_DPS, self.subject)
         self.setUpSwitchable(SWITCH_DPS, self.subject)
         self.setUpBasicNumber(
         self.setUpBasicNumber(
-            TIMER_DPS, self.entities.get("number_timer"), max=1440, scale=60
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=1440,
+            scale=60,
+            unit=TIME_MINUTES,
         )
         )
         self.mark_secondary(["number_timer"])
         self.mark_secondary(["number_timer"])
 
 

+ 7 - 1
tests/devices/test_smartplugv1.py

@@ -7,6 +7,7 @@ from homeassistant.const import (
     ELECTRIC_CURRENT_MILLIAMPERE,
     ELECTRIC_CURRENT_MILLIAMPERE,
     ELECTRIC_POTENTIAL_VOLT,
     ELECTRIC_POTENTIAL_VOLT,
     POWER_WATT,
     POWER_WATT,
+    TIME_MINUTES,
 )
 )
 
 
 from ..const import KOGAN_SOCKET_PAYLOAD
 from ..const import KOGAN_SOCKET_PAYLOAD
@@ -31,7 +32,12 @@ class TestKoganSwitch(
         self.setUpForConfig("smartplugv1.yaml", KOGAN_SOCKET_PAYLOAD)
         self.setUpForConfig("smartplugv1.yaml", KOGAN_SOCKET_PAYLOAD)
         self.subject = self.entities.get("switch")
         self.subject = self.entities.get("switch")
         self.setUpSwitchable(SWITCH_DPS, self.subject)
         self.setUpSwitchable(SWITCH_DPS, self.subject)
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=1440)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=1440,
+            unit=TIME_MINUTES,
+        )
         self.setUpMultiSensors(
         self.setUpMultiSensors(
             [
             [
                 {
                 {

+ 7 - 1
tests/devices/test_smartplugv2.py

@@ -7,6 +7,7 @@ from homeassistant.const import (
     ELECTRIC_CURRENT_MILLIAMPERE,
     ELECTRIC_CURRENT_MILLIAMPERE,
     ELECTRIC_POTENTIAL_VOLT,
     ELECTRIC_POTENTIAL_VOLT,
     POWER_WATT,
     POWER_WATT,
+    TIME_MINUTES,
 )
 )
 
 
 from ..const import KOGAN_SOCKET_PAYLOAD2
 from ..const import KOGAN_SOCKET_PAYLOAD2
@@ -31,7 +32,12 @@ class TestSwitchV2(
         self.setUpForConfig("smartplugv2.yaml", KOGAN_SOCKET_PAYLOAD2)
         self.setUpForConfig("smartplugv2.yaml", KOGAN_SOCKET_PAYLOAD2)
         self.subject = self.entities.get("switch")
         self.subject = self.entities.get("switch")
         self.setUpSwitchable(SWITCH_DPS, self.subject)
         self.setUpSwitchable(SWITCH_DPS, self.subject)
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=1440)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=1440,
+            unit=TIME_MINUTES,
+        )
         self.setUpMultiSensors(
         self.setUpMultiSensors(
             [
             [
                 {
                 {

+ 7 - 1
tests/devices/test_smartplugv2_energy.py

@@ -10,6 +10,7 @@ from homeassistant.const import (
     ELECTRIC_POTENTIAL_VOLT,
     ELECTRIC_POTENTIAL_VOLT,
     ENERGY_WATT_HOUR,
     ENERGY_WATT_HOUR,
     POWER_WATT,
     POWER_WATT,
+    TIME_MINUTES,
 )
 )
 
 
 from ..const import SMARTSWITCH_ENERGY_PAYLOAD
 from ..const import SMARTSWITCH_ENERGY_PAYLOAD
@@ -69,7 +70,12 @@ class TestSwitchV2Energy(
             device_class=DEVICE_CLASS_PROBLEM,
             device_class=DEVICE_CLASS_PROBLEM,
             testdata=(1, 0),
             testdata=(1, 0),
         )
         )
-        self.setUpBasicNumber(TIMER_DPS, self.entities.get("number_timer"), max=1440)
+        self.setUpBasicNumber(
+            TIMER_DPS,
+            self.entities.get("number_timer"),
+            max=1440,
+            unit=TIME_MINUTES,
+        )
         self.setUpBasicSelect(
         self.setUpBasicSelect(
             INITIAL_DPS,
             INITIAL_DPS,
             self.entities.get("select_initial_state"),
             self.entities.get("select_initial_state"),

+ 2 - 2
tests/devices/test_tmwf02_fan.py

@@ -1,7 +1,6 @@
 from homeassistant.components.fan import SUPPORT_SET_SPEED
 from homeassistant.components.fan import SUPPORT_SET_SPEED
 from homeassistant.const import (
 from homeassistant.const import (
-    DEVICE_CLASS_POWER_FACTOR,
-    PERCENTAGE,
+    TIME_MINUTES,
 )
 )
 from ..const import TMWF02_FAN_PAYLOAD
 from ..const import TMWF02_FAN_PAYLOAD
 from ..helpers import assert_device_properties_set
 from ..helpers import assert_device_properties_set
@@ -27,6 +26,7 @@ class TestTMWF02Fan(BasicNumberTests, SwitchableTests, TuyaDeviceTestCase):
             self.entities.get("number_timer"),
             self.entities.get("number_timer"),
             max=1440,
             max=1440,
             scale=60,
             scale=60,
+            unit=TIME_MINUTES,
         )
         )
         self.mark_secondary(["number_timer"])
         self.mark_secondary(["number_timer"])
 
 

+ 5 - 0
tests/devices/test_woox_r4028_powerstrip.py

@@ -1,5 +1,6 @@
 """Tests for the Woox R4028 powerstrip."""
 """Tests for the Woox R4028 powerstrip."""
 from homeassistant.components.switch import DEVICE_CLASS_OUTLET
 from homeassistant.components.switch import DEVICE_CLASS_OUTLET
+from homeassistant.const import TIME_MINUTES
 
 
 from ..const import WOOX_R4028_SOCKET_PAYLOAD
 from ..const import WOOX_R4028_SOCKET_PAYLOAD
 from ..mixins.number import MultiNumberTests
 from ..mixins.number import MultiNumberTests
@@ -52,24 +53,28 @@ class TestWooxR4028Powerstrip(
                     "name": "number_timer_1",
                     "name": "number_timer_1",
                     "max": 1440,
                     "max": 1440,
                     "scale": 60,
                     "scale": 60,
+                    "unit": TIME_MINUTES,
                 },
                 },
                 {
                 {
                     "dps": TIMER2_DPS,
                     "dps": TIMER2_DPS,
                     "name": "number_timer_2",
                     "name": "number_timer_2",
                     "max": 1440,
                     "max": 1440,
                     "scale": 60,
                     "scale": 60,
+                    "unit": TIME_MINUTES,
                 },
                 },
                 {
                 {
                     "dps": TIMER3_DPS,
                     "dps": TIMER3_DPS,
                     "name": "number_timer_3",
                     "name": "number_timer_3",
                     "max": 1440,
                     "max": 1440,
                     "scale": 60,
                     "scale": 60,
+                    "unit": TIME_MINUTES,
                 },
                 },
                 {
                 {
                     "dps": TIMERUSB_DPS,
                     "dps": TIMERUSB_DPS,
                     "name": "number_usb_timer",
                     "name": "number_usb_timer",
                     "max": 1440,
                     "max": 1440,
                     "scale": 60,
                     "scale": 60,
+                    "unit": TIME_MINUTES,
                 },
                 },
             ]
             ]
         )
         )

+ 14 - 1
tests/mixins/number.py

@@ -3,7 +3,9 @@ from ..helpers import assert_device_properties_set
 
 
 
 
 class BasicNumberTests:
 class BasicNumberTests:
-    def setUpBasicNumber(self, dps, subject, max, min=0, step=1, mode="auto", scale=1):
+    def setUpBasicNumber(
+        self, dps, subject, max, min=0, step=1, mode="auto", scale=1, unit=None
+    ):
         self.basicNumber = subject
         self.basicNumber = subject
         self.basicNumberDps = dps
         self.basicNumberDps = dps
         self.basicNumberMin = min
         self.basicNumberMin = min
@@ -11,6 +13,7 @@ class BasicNumberTests:
         self.basicNumberStep = step
         self.basicNumberStep = step
         self.basicNumberMode = mode
         self.basicNumberMode = mode
         self.basicNumberScale = scale
         self.basicNumberScale = scale
+        self.basicNumberUnit = unit
 
 
     def test_number_min_value(self):
     def test_number_min_value(self):
         self.assertEqual(self.basicNumber.min_value, self.basicNumberMin)
         self.assertEqual(self.basicNumber.min_value, self.basicNumberMin)
@@ -24,6 +27,9 @@ class BasicNumberTests:
     def test_number_mode(self):
     def test_number_mode(self):
         self.assertEqual(self.basicNumber.mode, self.basicNumberMode)
         self.assertEqual(self.basicNumber.mode, self.basicNumberMode)
 
 
+    def test_number_unit_of_measurement(self):
+        self.assertEqual(self.basicNumber.unit_of_measurement, self.basicNumberUnit)
+
     def test_number_value(self):
     def test_number_value(self):
         val = min(max(self.basicNumberMin, self.basicNumberStep), self.basicNumberMax)
         val = min(max(self.basicNumberMin, self.basicNumberStep), self.basicNumberMax)
         dps_val = val * self.basicNumberScale
         dps_val = val * self.basicNumberScale
@@ -51,6 +57,7 @@ class MultiNumberTests:
         self.multiNumberStep = {}
         self.multiNumberStep = {}
         self.multiNumberMode = {}
         self.multiNumberMode = {}
         self.multiNumberScale = {}
         self.multiNumberScale = {}
+        self.multiNumberUnit = {}
 
 
         for n in numbers:
         for n in numbers:
             name = n.get("name")
             name = n.get("name")
@@ -64,6 +71,7 @@ class MultiNumberTests:
             self.multiNumberStep[name] = n.get("step", 1)
             self.multiNumberStep[name] = n.get("step", 1)
             self.multiNumberMode[name] = n.get("mode", "auto")
             self.multiNumberMode[name] = n.get("mode", "auto")
             self.multiNumberScale[name] = n.get("scale", 1)
             self.multiNumberScale[name] = n.get("scale", 1)
+            self.multiNumberUnit[name] = n.get("unit", None)
 
 
     def test_multi_number_min_value(self):
     def test_multi_number_min_value(self):
         for key, subject in self.multiNumber.items():
         for key, subject in self.multiNumber.items():
@@ -85,6 +93,11 @@ class MultiNumberTests:
             with self.subTest(key):
             with self.subTest(key):
                 self.assertEqual(subject.mode, self.multiNumberMode[key])
                 self.assertEqual(subject.mode, self.multiNumberMode[key])
 
 
+    def test_multi_number_unit_of_measurement(self):
+        for key, subject in self.multiNumber.items():
+            with self.subTest(key):
+                self.assertEqual(subject.unit_of_measurement, self.multiNumberUnit[key])
+
     def test_multi_number_value(self):
     def test_multi_number_value(self):
         for key, subject in self.multiNumber.items():
         for key, subject in self.multiNumber.items():
             with self.subTest(key):
             with self.subTest(key):