Add support for min/max dimmer brightness in Tuya (#58165)
This commit is contained in:
parent
c7b4542624
commit
b413f7434f
6 changed files with 194 additions and 14 deletions
|
@ -1136,6 +1136,7 @@ omit =
|
|||
homeassistant/components/tuya/sensor.py
|
||||
homeassistant/components/tuya/siren.py
|
||||
homeassistant/components/tuya/switch.py
|
||||
homeassistant/components/tuya/util.py
|
||||
homeassistant/components/tuya/vacuum.py
|
||||
homeassistant/components/twentemilieu/const.py
|
||||
homeassistant/components/twentemilieu/sensor.py
|
||||
|
|
|
@ -12,6 +12,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
|||
from homeassistant.helpers.entity import DeviceInfo, Entity
|
||||
|
||||
from .const import DOMAIN, TUYA_HA_SIGNAL_UPDATE_ENTITY
|
||||
from .util import remap_value
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
@ -53,9 +54,7 @@ class IntegerTypeData:
|
|||
reverse: bool = False,
|
||||
) -> float:
|
||||
"""Remap a value from this range to a new range."""
|
||||
if reverse:
|
||||
value = self.max - value + self.min
|
||||
return ((value - self.min) / (self.max - self.min)) * (to_max - to_min) + to_min
|
||||
return remap_value(value, self.min, self.max, to_min, to_max, reverse)
|
||||
|
||||
def remap_value_from(
|
||||
self,
|
||||
|
@ -65,11 +64,7 @@ class IntegerTypeData:
|
|||
reverse: bool = False,
|
||||
) -> float:
|
||||
"""Remap a value from its current range to this range."""
|
||||
if reverse:
|
||||
value = from_max - value + from_min
|
||||
return ((value - from_min) / (from_max - from_min)) * (
|
||||
self.max - self.min
|
||||
) + self.min
|
||||
return remap_value(value, from_min, from_max, self.min, self.max, reverse)
|
||||
|
||||
@classmethod
|
||||
def from_json(cls, data: str) -> IntegerTypeData:
|
||||
|
|
|
@ -140,6 +140,12 @@ class DPCode(str, Enum):
|
|||
BRIGHT_VALUE_2 = "bright_value_2"
|
||||
BRIGHT_VALUE_3 = "bright_value_3"
|
||||
BRIGHT_VALUE_V2 = "bright_value_v2"
|
||||
BRIGHTNESS_MAX_1 = "brightness_max_1"
|
||||
BRIGHTNESS_MAX_2 = "brightness_max_2"
|
||||
BRIGHTNESS_MAX_3 = "brightness_max_3"
|
||||
BRIGHTNESS_MIN_1 = "brightness_min_1"
|
||||
BRIGHTNESS_MIN_2 = "brightness_min_2"
|
||||
BRIGHTNESS_MIN_3 = "brightness_min_3"
|
||||
C_F = "c_f" # Temperature unit switching
|
||||
CH2O_STATE = "ch2o_state"
|
||||
CH2O_VALUE = "ch2o_value"
|
||||
|
|
|
@ -26,16 +26,19 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|||
from . import HomeAssistantTuyaData
|
||||
from .base import IntegerTypeData, TuyaEntity
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DPCode, WorkMode
|
||||
from .util import remap_value
|
||||
|
||||
|
||||
@dataclass
|
||||
class TuyaLightEntityDescription(LightEntityDescription):
|
||||
"""Describe an Tuya light entity."""
|
||||
|
||||
color_mode: DPCode | None = None
|
||||
brightness_max: DPCode | None = None
|
||||
brightness_min: DPCode | None = None
|
||||
brightness: DPCode | tuple[DPCode, ...] | None = None
|
||||
color_temp: DPCode | tuple[DPCode, ...] | None = None
|
||||
color_data: DPCode | tuple[DPCode, ...] | None = None
|
||||
color_mode: DPCode | None = None
|
||||
color_temp: DPCode | tuple[DPCode, ...] | None = None
|
||||
|
||||
|
||||
LIGHTS: dict[str, tuple[TuyaLightEntityDescription, ...]] = {
|
||||
|
@ -120,16 +123,22 @@ LIGHTS: dict[str, tuple[TuyaLightEntityDescription, ...]] = {
|
|||
key=DPCode.SWITCH_LED_1,
|
||||
name="Light",
|
||||
brightness=DPCode.BRIGHT_VALUE_1,
|
||||
brightness_max=DPCode.BRIGHTNESS_MAX_1,
|
||||
brightness_min=DPCode.BRIGHTNESS_MIN_1,
|
||||
),
|
||||
TuyaLightEntityDescription(
|
||||
key=DPCode.SWITCH_LED_2,
|
||||
name="Light 2",
|
||||
brightness=DPCode.BRIGHT_VALUE_2,
|
||||
brightness_max=DPCode.BRIGHTNESS_MAX_2,
|
||||
brightness_min=DPCode.BRIGHTNESS_MIN_2,
|
||||
),
|
||||
TuyaLightEntityDescription(
|
||||
key=DPCode.SWITCH_LED_3,
|
||||
name="Light 3",
|
||||
brightness=DPCode.BRIGHT_VALUE_3,
|
||||
brightness_max=DPCode.BRIGHTNESS_MAX_3,
|
||||
brightness_min=DPCode.BRIGHTNESS_MIN_3,
|
||||
),
|
||||
),
|
||||
# Dimmer
|
||||
|
@ -276,6 +285,8 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||
|
||||
entity_description: TuyaLightEntityDescription
|
||||
_brightness_dpcode: DPCode | None = None
|
||||
_brightness_max_type: IntegerTypeData | None = None
|
||||
_brightness_min_type: IntegerTypeData | None = None
|
||||
_brightness_type: IntegerTypeData | None = None
|
||||
_color_data_dpcode: DPCode | None = None
|
||||
_color_data_type: ColorTypeData | None = None
|
||||
|
@ -349,6 +360,20 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||
device.status_range[self._brightness_dpcode].values
|
||||
)
|
||||
|
||||
# Check if min/max capable
|
||||
if (
|
||||
description.brightness_max is not None
|
||||
and description.brightness_min is not None
|
||||
and description.brightness_max in device.function
|
||||
and description.brightness_min in device.function
|
||||
):
|
||||
self._brightness_max_type = IntegerTypeData.from_json(
|
||||
device.status_range[description.brightness_max].values
|
||||
)
|
||||
self._brightness_min_type = IntegerTypeData.from_json(
|
||||
device.status_range[description.brightness_min].values
|
||||
)
|
||||
|
||||
# Update internals based on found color temperature dpcode
|
||||
if self._color_temp_dpcode:
|
||||
self._attr_supported_color_modes.add(COLOR_MODE_COLOR_TEMP)
|
||||
|
@ -456,12 +481,47 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||
and self.color_mode != COLOR_MODE_HS
|
||||
and self._brightness_type
|
||||
):
|
||||
brightness = kwargs[ATTR_BRIGHTNESS]
|
||||
|
||||
# If there is a min/max value, the brightness is actually limited.
|
||||
# Meaning it is actually not on a 0-255 scale.
|
||||
if (
|
||||
self._brightness_max_type is not None
|
||||
and self._brightness_min_type is not None
|
||||
and self.entity_description.brightness_max is not None
|
||||
and self.entity_description.brightness_min is not None
|
||||
and (
|
||||
brightness_max := self.device.status.get(
|
||||
self.entity_description.brightness_max
|
||||
)
|
||||
)
|
||||
is not None
|
||||
and (
|
||||
brightness_min := self.device.status.get(
|
||||
self.entity_description.brightness_min
|
||||
)
|
||||
)
|
||||
is not None
|
||||
):
|
||||
# Remap values onto our scale
|
||||
brightness_max = self._brightness_max_type.remap_value_to(
|
||||
brightness_max
|
||||
)
|
||||
brightness_min = self._brightness_min_type.remap_value_to(
|
||||
brightness_min
|
||||
)
|
||||
|
||||
# Remap the brightness value from their min-max to our 0-255 scale
|
||||
brightness = remap_value(
|
||||
brightness,
|
||||
to_min=brightness_min,
|
||||
to_max=brightness_max,
|
||||
)
|
||||
|
||||
commands += [
|
||||
{
|
||||
"code": self._brightness_dpcode,
|
||||
"value": round(
|
||||
self._brightness_type.remap_value_from(kwargs[ATTR_BRIGHTNESS])
|
||||
),
|
||||
"value": round(self._brightness_type.remap_value_from(brightness)),
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -485,7 +545,41 @@ class TuyaLightEntity(TuyaEntity, LightEntity):
|
|||
if brightness is None:
|
||||
return None
|
||||
|
||||
return round(self._brightness_type.remap_value_to(brightness))
|
||||
# Remap value to our scale
|
||||
brightness = self._brightness_type.remap_value_to(brightness)
|
||||
|
||||
# If there is a min/max value, the brightness is actually limited.
|
||||
# Meaning it is actually not on a 0-255 scale.
|
||||
if (
|
||||
self._brightness_max_type is not None
|
||||
and self._brightness_min_type is not None
|
||||
and self.entity_description.brightness_max is not None
|
||||
and self.entity_description.brightness_min is not None
|
||||
and (
|
||||
brightness_max := self.device.status.get(
|
||||
self.entity_description.brightness_max
|
||||
)
|
||||
)
|
||||
is not None
|
||||
and (
|
||||
brightness_min := self.device.status.get(
|
||||
self.entity_description.brightness_min
|
||||
)
|
||||
)
|
||||
is not None
|
||||
):
|
||||
# Remap values onto our scale
|
||||
brightness_max = self._brightness_max_type.remap_value_to(brightness_max)
|
||||
brightness_min = self._brightness_min_type.remap_value_to(brightness_min)
|
||||
|
||||
# Remap the brightness value from their min-max to our 0-255 scale
|
||||
brightness = remap_value(
|
||||
brightness,
|
||||
from_min=brightness_min,
|
||||
from_max=brightness_max,
|
||||
)
|
||||
|
||||
return round(brightness)
|
||||
|
||||
@property
|
||||
def color_temp(self) -> int | None:
|
||||
|
|
|
@ -78,6 +78,74 @@ NUMBERS: dict[str, tuple[NumberEntityDescription, ...]] = {
|
|||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
),
|
||||
# Dimmer Switch
|
||||
# https://developer.tuya.com/en/docs/iot/categorytgkg?id=Kaiuz0ktx7m0o
|
||||
"tgkg": (
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MIN_1,
|
||||
name="Minimum Brightness",
|
||||
icon="mdi:lightbulb-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MAX_1,
|
||||
name="Maximum Brightness",
|
||||
icon="mdi:lightbulb-on-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MIN_2,
|
||||
name="Minimum Brightness 2",
|
||||
icon="mdi:lightbulb-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MAX_2,
|
||||
name="Maximum Brightness 2",
|
||||
icon="mdi:lightbulb-on-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MIN_3,
|
||||
name="Minimum Brightness 3",
|
||||
icon="mdi:lightbulb-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MAX_3,
|
||||
name="Maximum Brightness 3",
|
||||
icon="mdi:lightbulb-on-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
),
|
||||
# Dimmer Switch
|
||||
# https://developer.tuya.com/en/docs/iot/categorytgkg?id=Kaiuz0ktx7m0o
|
||||
"tgq": (
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MIN_1,
|
||||
name="Minimum Brightness",
|
||||
icon="mdi:lightbulb-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MAX_1,
|
||||
name="Maximum Brightness",
|
||||
icon="mdi:lightbulb-on-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MIN_2,
|
||||
name="Minimum Brightness 2",
|
||||
icon="mdi:lightbulb-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
NumberEntityDescription(
|
||||
key=DPCode.BRIGHTNESS_MAX_2,
|
||||
name="Maximum Brightness 2",
|
||||
icon="mdi:lightbulb-on-outline",
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
),
|
||||
),
|
||||
# Vibration Sensor
|
||||
# https://developer.tuya.com/en/docs/iot/categoryzd?id=Kaiuz3a5vrzno
|
||||
"zd": (
|
||||
|
|
16
homeassistant/components/tuya/util.py
Normal file
16
homeassistant/components/tuya/util.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
"""Utility methods for the Tuya integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
def remap_value(
|
||||
value: float | int,
|
||||
from_min: float | int = 0,
|
||||
from_max: float | int = 255,
|
||||
to_min: float | int = 0,
|
||||
to_max: float | int = 255,
|
||||
reverse: bool = False,
|
||||
) -> float:
|
||||
"""Remap a value from its current range, to a new range."""
|
||||
if reverse:
|
||||
value = from_max - value + from_min
|
||||
return ((value - from_min) / (from_max - from_min)) * (to_max - to_min) + to_min
|
Loading…
Add table
Reference in a new issue