mirror of
https://github.com/home-assistant/core
synced 2024-09-06 10:29:55 +02:00
Replace all Tuya device property constants with an Enum (#57559)
This commit is contained in:
parent
c55e9136ee
commit
a4357fdb95
@ -29,33 +29,10 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import HomeAssistantTuyaData
|
||||
from .base import TuyaHaEntity
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DPCode
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Air Conditioner
|
||||
# https://developer.tuya.com/en/docs/iot/f?id=K9gf46qujdmwb
|
||||
DPCODE_SWITCH = "switch"
|
||||
DPCODE_TEMP_SET = "temp_set"
|
||||
DPCODE_TEMP_SET_F = "temp_set_f"
|
||||
DPCODE_MODE = "mode"
|
||||
DPCODE_HUMIDITY_SET = "humidity_set"
|
||||
DPCODE_FAN_SPEED_ENUM = "fan_speed_enum"
|
||||
|
||||
# Temperature unit
|
||||
DPCODE_TEMP_UNIT_CONVERT = "temp_unit_convert"
|
||||
DPCODE_C_F = "c_f"
|
||||
|
||||
# swing flap switch
|
||||
DPCODE_SWITCH_HORIZONTAL = "switch_horizontal"
|
||||
DPCODE_SWITCH_VERTICAL = "switch_vertical"
|
||||
|
||||
# status
|
||||
DPCODE_TEMP_CURRENT = "temp_current"
|
||||
DPCODE_TEMP_CURRENT_F = "temp_current_f"
|
||||
DPCODE_HUMIDITY_CURRENT = "humidity_current"
|
||||
|
||||
SWING_OFF = "swing_off"
|
||||
SWING_VERTICAL = "swing_vertical"
|
||||
SWING_HORIZONTAL = "swing_horizontal"
|
||||
@ -72,6 +49,7 @@ TUYA_HVAC_TO_HA = {
|
||||
"auto": HVAC_MODE_AUTO,
|
||||
}
|
||||
|
||||
# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
|
||||
TUYA_SUPPORT_TYPE = {
|
||||
"kt", # Air conditioner
|
||||
"qn", # Heater
|
||||
@ -108,14 +86,14 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
def __init__(self, device: TuyaDevice, device_manager: TuyaDeviceManager) -> None:
|
||||
"""Init Tuya Ha Climate."""
|
||||
super().__init__(device, device_manager)
|
||||
if DPCODE_C_F in self.tuya_device.status:
|
||||
self.dp_temp_unit = DPCODE_C_F
|
||||
if DPCode.C_F in self.tuya_device.status:
|
||||
self.dp_temp_unit = DPCode.C_F
|
||||
else:
|
||||
self.dp_temp_unit = DPCODE_TEMP_UNIT_CONVERT
|
||||
self.dp_temp_unit = DPCode.TEMP_UNIT_CONVERT
|
||||
|
||||
def get_temp_set_scale(self) -> int | None:
|
||||
"""Get temperature set scale."""
|
||||
dp_temp_set = DPCODE_TEMP_SET if self.is_celsius() else DPCODE_TEMP_SET_F
|
||||
dp_temp_set = DPCode.TEMP_SET if self.is_celsius() else DPCode.TEMP_SET_F
|
||||
temp_set_value_range_item = self.tuya_device.status_range.get(dp_temp_set)
|
||||
if not temp_set_value_range_item:
|
||||
return None
|
||||
@ -126,7 +104,7 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
def get_temp_current_scale(self) -> int | None:
|
||||
"""Get temperature current scale."""
|
||||
dp_temp_current = (
|
||||
DPCODE_TEMP_CURRENT if self.is_celsius() else DPCODE_TEMP_CURRENT_F
|
||||
DPCode.TEMP_CURRENT if self.is_celsius() else DPCode.TEMP_CURRENT_F
|
||||
)
|
||||
temp_current_value_range_item = self.tuya_device.status_range.get(
|
||||
dp_temp_current
|
||||
@ -143,46 +121,46 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
"""Set new target hvac mode."""
|
||||
commands = []
|
||||
if hvac_mode == HVAC_MODE_OFF:
|
||||
commands.append({"code": DPCODE_SWITCH, "value": False})
|
||||
commands.append({"code": DPCode.SWITCH, "value": False})
|
||||
else:
|
||||
commands.append({"code": DPCODE_SWITCH, "value": True})
|
||||
commands.append({"code": DPCode.SWITCH, "value": True})
|
||||
|
||||
for tuya_mode, ha_mode in TUYA_HVAC_TO_HA.items():
|
||||
if ha_mode == hvac_mode:
|
||||
commands.append({"code": DPCODE_MODE, "value": tuya_mode})
|
||||
commands.append({"code": DPCode.MODE, "value": tuya_mode})
|
||||
break
|
||||
|
||||
self._send_command(commands)
|
||||
|
||||
def set_fan_mode(self, fan_mode: str) -> None:
|
||||
"""Set new target fan mode."""
|
||||
self._send_command([{"code": DPCODE_FAN_SPEED_ENUM, "value": fan_mode}])
|
||||
self._send_command([{"code": DPCode.FAN_SPEED_ENUM, "value": fan_mode}])
|
||||
|
||||
def set_humidity(self, humidity: float) -> None:
|
||||
"""Set new target humidity."""
|
||||
self._send_command([{"code": DPCODE_HUMIDITY_SET, "value": int(humidity)}])
|
||||
self._send_command([{"code": DPCode.HUMIDITY_SET, "value": int(humidity)}])
|
||||
|
||||
def set_swing_mode(self, swing_mode: str) -> None:
|
||||
"""Set new target swing operation."""
|
||||
if swing_mode == SWING_BOTH:
|
||||
commands = [
|
||||
{"code": DPCODE_SWITCH_VERTICAL, "value": True},
|
||||
{"code": DPCODE_SWITCH_HORIZONTAL, "value": True},
|
||||
{"code": DPCode.SWITCH_VERTICAL, "value": True},
|
||||
{"code": DPCode.SWITCH_HORIZONTAL, "value": True},
|
||||
]
|
||||
elif swing_mode == SWING_HORIZONTAL:
|
||||
commands = [
|
||||
{"code": DPCODE_SWITCH_VERTICAL, "value": False},
|
||||
{"code": DPCODE_SWITCH_HORIZONTAL, "value": True},
|
||||
{"code": DPCode.SWITCH_VERTICAL, "value": False},
|
||||
{"code": DPCode.SWITCH_HORIZONTAL, "value": True},
|
||||
]
|
||||
elif swing_mode == SWING_VERTICAL:
|
||||
commands = [
|
||||
{"code": DPCODE_SWITCH_VERTICAL, "value": True},
|
||||
{"code": DPCODE_SWITCH_HORIZONTAL, "value": False},
|
||||
{"code": DPCode.SWITCH_VERTICAL, "value": True},
|
||||
{"code": DPCode.SWITCH_HORIZONTAL, "value": False},
|
||||
]
|
||||
else:
|
||||
commands = [
|
||||
{"code": DPCODE_SWITCH_VERTICAL, "value": False},
|
||||
{"code": DPCODE_SWITCH_HORIZONTAL, "value": False},
|
||||
{"code": DPCode.SWITCH_VERTICAL, "value": False},
|
||||
{"code": DPCode.SWITCH_HORIZONTAL, "value": False},
|
||||
]
|
||||
|
||||
self._send_command(commands)
|
||||
@ -190,7 +168,7 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
def set_temperature(self, **kwargs: Any) -> None:
|
||||
"""Set new target temperature."""
|
||||
_LOGGER.debug("climate temp-> %s", kwargs)
|
||||
code = DPCODE_TEMP_SET if self.is_celsius() else DPCODE_TEMP_SET_F
|
||||
code = DPCode.TEMP_SET if self.is_celsius() else DPCode.TEMP_SET_F
|
||||
temp_set_scale = self.get_temp_set_scale()
|
||||
if not temp_set_scale:
|
||||
return
|
||||
@ -212,8 +190,8 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
):
|
||||
return True
|
||||
if (
|
||||
DPCODE_TEMP_SET in self.tuya_device.status
|
||||
or DPCODE_TEMP_CURRENT in self.tuya_device.status
|
||||
DPCode.TEMP_SET in self.tuya_device.status
|
||||
or DPCode.TEMP_CURRENT in self.tuya_device.status
|
||||
):
|
||||
return True
|
||||
return False
|
||||
@ -229,8 +207,8 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
def current_temperature(self) -> float | None:
|
||||
"""Return the current temperature."""
|
||||
if (
|
||||
DPCODE_TEMP_CURRENT not in self.tuya_device.status
|
||||
and DPCODE_TEMP_CURRENT_F not in self.tuya_device.status
|
||||
DPCode.TEMP_CURRENT not in self.tuya_device.status
|
||||
and DPCode.TEMP_CURRENT_F not in self.tuya_device.status
|
||||
):
|
||||
return None
|
||||
|
||||
@ -239,12 +217,12 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
return None
|
||||
|
||||
if self.is_celsius():
|
||||
temperature = self.tuya_device.status.get(DPCODE_TEMP_CURRENT)
|
||||
temperature = self.tuya_device.status.get(DPCode.TEMP_CURRENT)
|
||||
if not temperature:
|
||||
return None
|
||||
return temperature * 1.0 / (10 ** temp_current_scale)
|
||||
|
||||
temperature = self.tuya_device.status.get(DPCODE_TEMP_CURRENT_F)
|
||||
temperature = self.tuya_device.status.get(DPCode.TEMP_CURRENT_F)
|
||||
if not temperature:
|
||||
return None
|
||||
return temperature * 1.0 / (10 ** temp_current_scale)
|
||||
@ -252,7 +230,7 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
@property
|
||||
def current_humidity(self) -> int:
|
||||
"""Return the current humidity."""
|
||||
return int(self.tuya_device.status.get(DPCODE_HUMIDITY_CURRENT, 0))
|
||||
return int(self.tuya_device.status.get(DPCode.HUMIDITY_CURRENT, 0))
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> float | None:
|
||||
@ -261,7 +239,7 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
if temp_set_scale is None:
|
||||
return None
|
||||
|
||||
dpcode_temp_set = self.tuya_device.status.get(DPCODE_TEMP_SET)
|
||||
dpcode_temp_set = self.tuya_device.status.get(DPCode.TEMP_SET)
|
||||
if dpcode_temp_set is None:
|
||||
return None
|
||||
|
||||
@ -275,10 +253,10 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
return DEFAULT_MAX_TEMP
|
||||
|
||||
if self.is_celsius():
|
||||
if DPCODE_TEMP_SET not in self.tuya_device.function:
|
||||
if DPCode.TEMP_SET not in self.tuya_device.function:
|
||||
return DEFAULT_MAX_TEMP
|
||||
|
||||
function_item = self.tuya_device.function.get(DPCODE_TEMP_SET)
|
||||
function_item = self.tuya_device.function.get(DPCode.TEMP_SET)
|
||||
if function_item is None:
|
||||
return DEFAULT_MAX_TEMP
|
||||
|
||||
@ -288,10 +266,10 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
if temp_max is None:
|
||||
return DEFAULT_MAX_TEMP
|
||||
return temp_max * 1.0 / (10 ** scale)
|
||||
if DPCODE_TEMP_SET_F not in self.tuya_device.function:
|
||||
if DPCode.TEMP_SET_F not in self.tuya_device.function:
|
||||
return DEFAULT_MAX_TEMP
|
||||
|
||||
function_item_f = self.tuya_device.function.get(DPCODE_TEMP_SET_F)
|
||||
function_item_f = self.tuya_device.function.get(DPCode.TEMP_SET_F)
|
||||
if function_item_f is None:
|
||||
return DEFAULT_MAX_TEMP
|
||||
|
||||
@ -310,10 +288,10 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
return DEFAULT_MIN_TEMP
|
||||
|
||||
if self.is_celsius():
|
||||
if DPCODE_TEMP_SET not in self.tuya_device.function:
|
||||
if DPCode.TEMP_SET not in self.tuya_device.function:
|
||||
return DEFAULT_MIN_TEMP
|
||||
|
||||
function_temp_item = self.tuya_device.function.get(DPCODE_TEMP_SET)
|
||||
function_temp_item = self.tuya_device.function.get(DPCode.TEMP_SET)
|
||||
if function_temp_item is None:
|
||||
return DEFAULT_MIN_TEMP
|
||||
temp_value = json.loads(function_temp_item.values)
|
||||
@ -322,10 +300,10 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
return DEFAULT_MIN_TEMP
|
||||
return temp_min * 1.0 / (10 ** temp_set_scal)
|
||||
|
||||
if DPCODE_TEMP_SET_F not in self.tuya_device.function:
|
||||
if DPCode.TEMP_SET_F not in self.tuya_device.function:
|
||||
return DEFAULT_MIN_TEMP
|
||||
|
||||
temp_value_temp_f = self.tuya_device.function.get(DPCODE_TEMP_SET_F)
|
||||
temp_value_temp_f = self.tuya_device.function.get(DPCode.TEMP_SET_F)
|
||||
if temp_value_temp_f is None:
|
||||
return DEFAULT_MIN_TEMP
|
||||
temp_value_f = json.loads(temp_value_temp_f.values)
|
||||
@ -340,13 +318,13 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
def target_temperature_step(self) -> float | None:
|
||||
"""Return target temperature setp."""
|
||||
if (
|
||||
DPCODE_TEMP_SET not in self.tuya_device.status_range
|
||||
and DPCODE_TEMP_SET_F not in self.tuya_device.status_range
|
||||
DPCode.TEMP_SET not in self.tuya_device.status_range
|
||||
and DPCode.TEMP_SET_F not in self.tuya_device.status_range
|
||||
):
|
||||
return 1.0
|
||||
temp_set_value_range = json.loads(
|
||||
self.tuya_device.status_range.get(
|
||||
DPCODE_TEMP_SET if self.is_celsius() else DPCODE_TEMP_SET_F
|
||||
DPCode.TEMP_SET if self.is_celsius() else DPCode.TEMP_SET_F
|
||||
).values
|
||||
)
|
||||
step = temp_set_value_range.get("step")
|
||||
@ -362,25 +340,25 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
@property
|
||||
def target_humidity(self) -> int:
|
||||
"""Return target humidity."""
|
||||
return int(self.tuya_device.status.get(DPCODE_HUMIDITY_SET, 0))
|
||||
return int(self.tuya_device.status.get(DPCode.HUMIDITY_SET, 0))
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> str:
|
||||
"""Return hvac mode."""
|
||||
if not self.tuya_device.status.get(DPCODE_SWITCH, False):
|
||||
if not self.tuya_device.status.get(DPCode.SWITCH, False):
|
||||
return HVAC_MODE_OFF
|
||||
if DPCODE_MODE not in self.tuya_device.status:
|
||||
if DPCode.MODE not in self.tuya_device.status:
|
||||
return HVAC_MODE_OFF
|
||||
if self.tuya_device.status.get(DPCODE_MODE) is not None:
|
||||
return TUYA_HVAC_TO_HA[self.tuya_device.status[DPCODE_MODE]]
|
||||
if self.tuya_device.status.get(DPCode.MODE) is not None:
|
||||
return TUYA_HVAC_TO_HA[self.tuya_device.status[DPCode.MODE]]
|
||||
return HVAC_MODE_OFF
|
||||
|
||||
@property
|
||||
def hvac_modes(self) -> list[str]:
|
||||
"""Return hvac modes for select."""
|
||||
if DPCODE_MODE not in self.tuya_device.function:
|
||||
if DPCode.MODE not in self.tuya_device.function:
|
||||
return []
|
||||
modes = json.loads(self.tuya_device.function.get(DPCODE_MODE, {}).values).get(
|
||||
modes = json.loads(self.tuya_device.function.get(DPCode.MODE, {}).values).get(
|
||||
"range"
|
||||
)
|
||||
|
||||
@ -394,12 +372,12 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
@property
|
||||
def fan_mode(self) -> str | None:
|
||||
"""Return fan mode."""
|
||||
return self.tuya_device.status.get(DPCODE_FAN_SPEED_ENUM)
|
||||
return self.tuya_device.status.get(DPCode.FAN_SPEED_ENUM)
|
||||
|
||||
@property
|
||||
def fan_modes(self) -> list[str]:
|
||||
"""Return fan modes for select."""
|
||||
fan_speed_device_function = self.tuya_device.function.get(DPCODE_FAN_SPEED_ENUM)
|
||||
fan_speed_device_function = self.tuya_device.function.get(DPCode.FAN_SPEED_ENUM)
|
||||
if not fan_speed_device_function:
|
||||
return []
|
||||
return json.loads(fan_speed_device_function.values).get("range", [])
|
||||
@ -409,13 +387,13 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
"""Return swing mode."""
|
||||
mode = 0
|
||||
if (
|
||||
DPCODE_SWITCH_HORIZONTAL in self.tuya_device.status
|
||||
and self.tuya_device.status.get(DPCODE_SWITCH_HORIZONTAL)
|
||||
DPCode.SWITCH_HORIZONTAL in self.tuya_device.status
|
||||
and self.tuya_device.status.get(DPCode.SWITCH_HORIZONTAL)
|
||||
):
|
||||
mode += 1
|
||||
if (
|
||||
DPCODE_SWITCH_VERTICAL in self.tuya_device.status
|
||||
and self.tuya_device.status.get(DPCODE_SWITCH_VERTICAL)
|
||||
DPCode.SWITCH_VERTICAL in self.tuya_device.status
|
||||
and self.tuya_device.status.get(DPCode.SWITCH_VERTICAL)
|
||||
):
|
||||
mode += 2
|
||||
|
||||
@ -437,17 +415,17 @@ class TuyaHaClimate(TuyaHaEntity, ClimateEntity):
|
||||
"""Flag supported features."""
|
||||
supports = 0
|
||||
if (
|
||||
DPCODE_TEMP_SET in self.tuya_device.status
|
||||
or DPCODE_TEMP_SET_F in self.tuya_device.status
|
||||
DPCode.TEMP_SET in self.tuya_device.status
|
||||
or DPCode.TEMP_SET_F in self.tuya_device.status
|
||||
):
|
||||
supports |= SUPPORT_TARGET_TEMPERATURE
|
||||
if DPCODE_FAN_SPEED_ENUM in self.tuya_device.status:
|
||||
if DPCode.FAN_SPEED_ENUM in self.tuya_device.status:
|
||||
supports |= SUPPORT_FAN_MODE
|
||||
if DPCODE_HUMIDITY_SET in self.tuya_device.status:
|
||||
if DPCode.HUMIDITY_SET in self.tuya_device.status:
|
||||
supports |= SUPPORT_TARGET_HUMIDITY
|
||||
if (
|
||||
DPCODE_SWITCH_HORIZONTAL in self.tuya_device.status
|
||||
or DPCODE_SWITCH_VERTICAL in self.tuya_device.status
|
||||
DPCode.SWITCH_HORIZONTAL in self.tuya_device.status
|
||||
or DPCode.SWITCH_VERTICAL in self.tuya_device.status
|
||||
):
|
||||
supports |= SUPPORT_SWING_MODE
|
||||
return supports
|
||||
|
@ -1,5 +1,6 @@
|
||||
"""Constants for the Tuya integration."""
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum
|
||||
|
||||
from tuya_iot import TuyaCloudOpenAPIEndpoint
|
||||
|
||||
@ -54,6 +55,45 @@ SMARTLIFE_APP = "smartlife"
|
||||
PLATFORMS = ["climate", "fan", "light", "scene", "switch"]
|
||||
|
||||
|
||||
class DPCode(str, Enum):
|
||||
"""Device Property Codes used by Tuya.
|
||||
|
||||
https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
|
||||
"""
|
||||
|
||||
ANION = "anion" # Ionizer unit
|
||||
BRIGHT_VALUE = "bright_value" # Brightness
|
||||
C_F = "c_f" # Temperature unit switching
|
||||
COLOUR_DATA = "colour_data" # Colored light mode
|
||||
COLOUR_DATA_V2 = "colour_data_v2" # Colored light mode
|
||||
FAN_DIRECTION = "fan_direction" # Fan direction
|
||||
FAN_SPEED_ENUM = "fan_speed_enum" # Speed mode
|
||||
FAN_SPEED_PERCENT = "fan_speed_percent" # Stepless speed
|
||||
FILTER_RESET = "filter_reset" # Filter (cartridge) reset
|
||||
HUMIDITY_CURRENT = "humidity_current" # Current humidity
|
||||
HUMIDITY_SET = "humidity_set" # Humidity setting
|
||||
LIGHT = "light" # Light
|
||||
LOCK = "lock" # Lock / Child lock
|
||||
MODE = "mode" # Working mode / Mode
|
||||
PUMP_RESET = "pump_reset" # Water pump reset
|
||||
SPEED = "speed" # Speed level
|
||||
START = "start" # Start
|
||||
SWITCH = "switch" # Switch
|
||||
SWITCH_HORIZONTAL = "switch_horizontal" # Horizontal swing flap switch
|
||||
SWITCH_LED = "switch_led" # Switch
|
||||
SWITCH_VERTICAL = "switch_vertical" # Vertical swing flap switch
|
||||
TEMP_CURRENT = "temp_current" # Current temperature in °C
|
||||
TEMP_CURRENT_F = "temp_current_f" # Current temperature in °F
|
||||
TEMP_SET = "temp_set" # Set the temperature in °C
|
||||
TEMP_SET_F = "temp_set_f" # Set the temperature in °F
|
||||
TEMP_UNIT_CONVERT = "temp_unit_convert" # Temperature unit switching
|
||||
TEMP_VALUE = "temp_value" # Color temperature
|
||||
UV = "uv" # UV sterilization
|
||||
WATER_RESET = "water_reset" # Resetting of water usage days
|
||||
WET = "wet" # Humidification
|
||||
WORK_MODE = "work_mode" # Working mode
|
||||
|
||||
|
||||
@dataclass
|
||||
class Country:
|
||||
"""Describe a supported country."""
|
||||
|
@ -2,7 +2,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from tuya_iot import TuyaDevice, TuyaDeviceManager
|
||||
@ -27,23 +26,7 @@ from homeassistant.util.percentage import (
|
||||
|
||||
from . import HomeAssistantTuyaData
|
||||
from .base import TuyaHaEntity
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Fan
|
||||
# https://developer.tuya.com/en/docs/iot/f?id=K9gf45vs7vkge
|
||||
DPCODE_SWITCH = "switch"
|
||||
DPCODE_FAN_SPEED = "fan_speed_percent"
|
||||
DPCODE_MODE = "mode"
|
||||
DPCODE_SWITCH_HORIZONTAL = "switch_horizontal"
|
||||
DPCODE_FAN_DIRECTION = "fan_direction"
|
||||
|
||||
# Air Purifier
|
||||
# https://developer.tuya.com/en/docs/iot/s?id=K9gf48r41mn81
|
||||
DPCODE_AP_FAN_SPEED = "speed"
|
||||
DPCODE_AP_FAN_SPEED_ENUM = "fan_speed_enum"
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DPCode
|
||||
|
||||
TUYA_SUPPORT_TYPE = {
|
||||
"fs", # Fan
|
||||
@ -82,9 +65,9 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
super().__init__(device, device_manager)
|
||||
|
||||
self.ha_preset_modes = []
|
||||
if DPCODE_MODE in self.tuya_device.function:
|
||||
if DPCode.MODE in self.tuya_device.function:
|
||||
self.ha_preset_modes = json.loads(
|
||||
self.tuya_device.function[DPCODE_MODE].values
|
||||
self.tuya_device.function[DPCode.MODE].values
|
||||
).get("range", [])
|
||||
|
||||
# Air purifier fan can be controlled either via the ranged values or via the enum.
|
||||
@ -94,13 +77,13 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
self.air_purifier_speed_range_len = 0
|
||||
self.air_purifier_speed_range_enum = []
|
||||
if self.tuya_device.category == "kj" and (
|
||||
DPCODE_AP_FAN_SPEED_ENUM in self.tuya_device.function
|
||||
or DPCODE_AP_FAN_SPEED in self.tuya_device.function
|
||||
DPCode.FAN_SPEED_ENUM in self.tuya_device.function
|
||||
or DPCode.SPEED in self.tuya_device.function
|
||||
):
|
||||
if DPCODE_AP_FAN_SPEED_ENUM in self.tuya_device.function:
|
||||
self.dp_code_speed_enum = DPCODE_AP_FAN_SPEED_ENUM
|
||||
if DPCode.FAN_SPEED_ENUM in self.tuya_device.function:
|
||||
self.dp_code_speed_enum = DPCode.FAN_SPEED_ENUM
|
||||
else:
|
||||
self.dp_code_speed_enum = DPCODE_AP_FAN_SPEED
|
||||
self.dp_code_speed_enum = DPCode.SPEED
|
||||
|
||||
data = json.loads(
|
||||
self.tuya_device.function[self.dp_code_speed_enum].values
|
||||
@ -111,11 +94,11 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
|
||||
def set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode of the fan."""
|
||||
self._send_command([{"code": DPCODE_MODE, "value": preset_mode}])
|
||||
self._send_command([{"code": DPCode.MODE, "value": preset_mode}])
|
||||
|
||||
def set_direction(self, direction: str) -> None:
|
||||
"""Set the direction of the fan."""
|
||||
self._send_command([{"code": DPCODE_FAN_DIRECTION, "value": direction}])
|
||||
self._send_command([{"code": DPCode.FAN_DIRECTION, "value": direction}])
|
||||
|
||||
def set_percentage(self, percentage: int) -> None:
|
||||
"""Set the speed of the fan, as a percentage."""
|
||||
@ -132,11 +115,13 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
]
|
||||
)
|
||||
else:
|
||||
self._send_command([{"code": DPCODE_FAN_SPEED, "value": percentage}])
|
||||
self._send_command(
|
||||
[{"code": DPCode.FAN_SPEED_PERCENT, "value": percentage}]
|
||||
)
|
||||
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the fan off."""
|
||||
self._send_command([{"code": DPCODE_SWITCH, "value": False}])
|
||||
self._send_command([{"code": DPCode.SWITCH, "value": False}])
|
||||
|
||||
def turn_on(
|
||||
self,
|
||||
@ -146,28 +131,28 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Turn on the fan."""
|
||||
self._send_command([{"code": DPCODE_SWITCH, "value": True}])
|
||||
self._send_command([{"code": DPCode.SWITCH, "value": True}])
|
||||
|
||||
def oscillate(self, oscillating: bool) -> None:
|
||||
"""Oscillate the fan."""
|
||||
self._send_command([{"code": DPCODE_SWITCH_HORIZONTAL, "value": oscillating}])
|
||||
self._send_command([{"code": DPCode.SWITCH_HORIZONTAL, "value": oscillating}])
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if fan is on."""
|
||||
return self.tuya_device.status.get(DPCODE_SWITCH, False)
|
||||
return self.tuya_device.status.get(DPCode.SWITCH, False)
|
||||
|
||||
@property
|
||||
def current_direction(self) -> str:
|
||||
"""Return the current direction of the fan."""
|
||||
if self.tuya_device.status[DPCODE_FAN_DIRECTION]:
|
||||
if self.tuya_device.status[DPCode.FAN_DIRECTION]:
|
||||
return DIRECTION_FORWARD
|
||||
return DIRECTION_REVERSE
|
||||
|
||||
@property
|
||||
def oscillating(self) -> bool:
|
||||
"""Return true if the fan is oscillating."""
|
||||
return self.tuya_device.status.get(DPCODE_SWITCH_HORIZONTAL, False)
|
||||
return self.tuya_device.status.get(DPCode.SWITCH_HORIZONTAL, False)
|
||||
|
||||
@property
|
||||
def preset_modes(self) -> list[str]:
|
||||
@ -177,7 +162,7 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
@property
|
||||
def preset_mode(self) -> str:
|
||||
"""Return the current preset_mode."""
|
||||
return self.tuya_device.status[DPCODE_MODE]
|
||||
return self.tuya_device.status[DPCode.MODE]
|
||||
|
||||
@property
|
||||
def percentage(self) -> int | None:
|
||||
@ -189,16 +174,16 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
self.tuya_device.category == "kj"
|
||||
and self.air_purifier_speed_range_len > 1
|
||||
and not self.air_purifier_speed_range_enum
|
||||
and DPCODE_AP_FAN_SPEED_ENUM in self.tuya_device.status
|
||||
and DPCode.FAN_SPEED_ENUM in self.tuya_device.status
|
||||
):
|
||||
# if air-purifier speed enumeration is supported we will prefer it.
|
||||
return ordered_list_item_to_percentage(
|
||||
self.air_purifier_speed_range_enum,
|
||||
self.tuya_device.status[DPCODE_AP_FAN_SPEED_ENUM],
|
||||
self.tuya_device.status[DPCode.FAN_SPEED_ENUM],
|
||||
)
|
||||
|
||||
# some type may not have the fan_speed_percent key
|
||||
return self.tuya_device.status.get(DPCODE_FAN_SPEED)
|
||||
return self.tuya_device.status.get(DPCode.FAN_SPEED_PERCENT)
|
||||
|
||||
@property
|
||||
def speed_count(self) -> int:
|
||||
@ -211,19 +196,19 @@ class TuyaHaFan(TuyaHaEntity, FanEntity):
|
||||
def supported_features(self):
|
||||
"""Flag supported features."""
|
||||
supports = 0
|
||||
if DPCODE_MODE in self.tuya_device.status:
|
||||
if DPCode.MODE in self.tuya_device.status:
|
||||
supports |= SUPPORT_PRESET_MODE
|
||||
if DPCODE_FAN_SPEED in self.tuya_device.status:
|
||||
if DPCode.FAN_SPEED_PERCENT in self.tuya_device.status:
|
||||
supports |= SUPPORT_SET_SPEED
|
||||
if DPCODE_SWITCH_HORIZONTAL in self.tuya_device.status:
|
||||
if DPCode.SWITCH_HORIZONTAL in self.tuya_device.status:
|
||||
supports |= SUPPORT_OSCILLATE
|
||||
if DPCODE_FAN_DIRECTION in self.tuya_device.status:
|
||||
if DPCode.FAN_DIRECTION in self.tuya_device.status:
|
||||
supports |= SUPPORT_DIRECTION
|
||||
|
||||
# Air Purifier specific
|
||||
if (
|
||||
DPCODE_AP_FAN_SPEED in self.tuya_device.status
|
||||
or DPCODE_AP_FAN_SPEED_ENUM in self.tuya_device.status
|
||||
DPCode.SPEED in self.tuya_device.status
|
||||
or DPCode.FAN_SPEED_ENUM in self.tuya_device.status
|
||||
):
|
||||
supports |= SUPPORT_SET_SPEED
|
||||
return supports
|
||||
|
@ -24,21 +24,10 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import HomeAssistantTuyaData
|
||||
from .base import TuyaHaEntity
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DPCode
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Light(dj)
|
||||
# https://developer.tuya.com/en/docs/iot/f?id=K9i5ql3v98hn3
|
||||
DPCODE_SWITCH = "switch_led"
|
||||
DPCODE_WORK_MODE = "work_mode"
|
||||
DPCODE_BRIGHT_VALUE = "bright_value"
|
||||
DPCODE_TEMP_VALUE = "temp_value"
|
||||
DPCODE_COLOUR_DATA = "colour_data"
|
||||
DPCODE_COLOUR_DATA_V2 = "colour_data_v2"
|
||||
DPCODE_LIGHT = "light"
|
||||
|
||||
MIREDS_MAX = 500
|
||||
MIREDS_MIN = 153
|
||||
|
||||
@ -50,6 +39,7 @@ HSV_HA_SATURATION_MAX = 100
|
||||
WORK_MODE_WHITE = "white"
|
||||
WORK_MODE_COLOUR = "colour"
|
||||
|
||||
# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
|
||||
TUYA_SUPPORT_TYPE = {
|
||||
"dj", # Light
|
||||
"dd", # Light strip
|
||||
@ -102,16 +92,16 @@ class TuyaHaLight(TuyaHaEntity, LightEntity):
|
||||
|
||||
def __init__(self, device: TuyaDevice, device_manager: TuyaDeviceManager) -> None:
|
||||
"""Init TuyaHaLight."""
|
||||
self.dp_code_bright = DPCODE_BRIGHT_VALUE
|
||||
self.dp_code_temp = DPCODE_TEMP_VALUE
|
||||
self.dp_code_colour = DPCODE_COLOUR_DATA
|
||||
self.dp_code_bright = DPCode.BRIGHT_VALUE
|
||||
self.dp_code_temp = DPCode.TEMP_VALUE
|
||||
self.dp_code_colour = DPCode.COLOUR_DATA
|
||||
|
||||
for key in device.function:
|
||||
if key.startswith(DPCODE_BRIGHT_VALUE):
|
||||
if key.startswith(DPCode.BRIGHT_VALUE):
|
||||
self.dp_code_bright = key
|
||||
elif key.startswith(DPCODE_TEMP_VALUE):
|
||||
elif key.startswith(DPCode.TEMP_VALUE):
|
||||
self.dp_code_temp = key
|
||||
elif key.startswith(DPCODE_COLOUR_DATA):
|
||||
elif key.startswith(DPCode.COLOUR_DATA):
|
||||
self.dp_code_colour = key
|
||||
|
||||
super().__init__(device, device_manager)
|
||||
@ -119,7 +109,7 @@ class TuyaHaLight(TuyaHaEntity, LightEntity):
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if light is on."""
|
||||
return self.tuya_device.status.get(DPCODE_SWITCH, False)
|
||||
return self.tuya_device.status.get(DPCode.SWITCH_LED, False)
|
||||
|
||||
def turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn on or control the light."""
|
||||
@ -127,12 +117,12 @@ class TuyaHaLight(TuyaHaEntity, LightEntity):
|
||||
_LOGGER.debug("light kwargs-> %s", kwargs)
|
||||
|
||||
if (
|
||||
DPCODE_LIGHT in self.tuya_device.status
|
||||
and DPCODE_SWITCH not in self.tuya_device.status
|
||||
DPCode.LIGHT in self.tuya_device.status
|
||||
and DPCode.SWITCH_LED not in self.tuya_device.status
|
||||
):
|
||||
commands += [{"code": DPCODE_LIGHT, "value": True}]
|
||||
commands += [{"code": DPCode.LIGHT, "value": True}]
|
||||
else:
|
||||
commands += [{"code": DPCODE_SWITCH, "value": True}]
|
||||
commands += [{"code": DPCode.SWITCH_LED, "value": True}]
|
||||
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
if self._work_mode().startswith(WORK_MODE_COLOUR):
|
||||
@ -177,8 +167,8 @@ class TuyaHaLight(TuyaHaEntity, LightEntity):
|
||||
commands += [
|
||||
{"code": self.dp_code_colour, "value": json.dumps(colour_data)}
|
||||
]
|
||||
if self.tuya_device.status[DPCODE_WORK_MODE] != "colour":
|
||||
commands += [{"code": DPCODE_WORK_MODE, "value": "colour"}]
|
||||
if self.tuya_device.status[DPCode.WORK_MODE] != "colour":
|
||||
commands += [{"code": DPCode.WORK_MODE, "value": "colour"}]
|
||||
|
||||
if ATTR_COLOR_TEMP in kwargs:
|
||||
# temp color
|
||||
@ -200,20 +190,20 @@ class TuyaHaLight(TuyaHaEntity, LightEntity):
|
||||
)
|
||||
commands += [{"code": self.dp_code_bright, "value": int(tuya_brightness)}]
|
||||
|
||||
if self.tuya_device.status[DPCODE_WORK_MODE] != "white":
|
||||
commands += [{"code": DPCODE_WORK_MODE, "value": "white"}]
|
||||
if self.tuya_device.status[DPCode.WORK_MODE] != "white":
|
||||
commands += [{"code": DPCode.WORK_MODE, "value": "white"}]
|
||||
|
||||
self._send_command(commands)
|
||||
|
||||
def turn_off(self, **kwargs: Any) -> None:
|
||||
"""Instruct the light to turn off."""
|
||||
if (
|
||||
DPCODE_LIGHT in self.tuya_device.status
|
||||
and DPCODE_SWITCH not in self.tuya_device.status
|
||||
DPCode.LIGHT in self.tuya_device.status
|
||||
and DPCode.SWITCH_LED not in self.tuya_device.status
|
||||
):
|
||||
commands = [{"code": DPCODE_LIGHT, "value": False}]
|
||||
commands = [{"code": DPCode.LIGHT, "value": False}]
|
||||
else:
|
||||
commands = [{"code": DPCODE_SWITCH, "value": False}]
|
||||
commands = [{"code": DPCode.SWITCH_LED, "value": False}]
|
||||
self._send_command(commands)
|
||||
|
||||
@property
|
||||
@ -319,7 +309,7 @@ class TuyaHaLight(TuyaHaEntity, LightEntity):
|
||||
return None
|
||||
colour_data = json.loads(colour_json)
|
||||
if (
|
||||
self.dp_code_colour == DPCODE_COLOUR_DATA_V2
|
||||
self.dp_code_colour == DPCode.COLOUR_DATA_V2
|
||||
or colour_data.get("v", 0) > 255
|
||||
or colour_data.get("s", 0) > 255
|
||||
):
|
||||
@ -327,7 +317,7 @@ class TuyaHaLight(TuyaHaEntity, LightEntity):
|
||||
return DEFAULT_HSV
|
||||
|
||||
def _work_mode(self) -> str:
|
||||
return self.tuya_device.status.get(DPCODE_WORK_MODE, "")
|
||||
return self.tuya_device.status.get(DPCode.WORK_MODE, "")
|
||||
|
||||
def _get_hsv(self) -> dict[str, int]:
|
||||
return json.loads(self.tuya_device.status[self.dp_code_colour])
|
||||
|
@ -1,7 +1,6 @@
|
||||
"""Support for Tuya switches."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from tuya_iot import TuyaDevice, TuyaDeviceManager
|
||||
@ -14,10 +13,9 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import HomeAssistantTuyaData
|
||||
from .base import TuyaHaEntity
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
from .const import DOMAIN, TUYA_DISCOVERY_NEW, DPCode
|
||||
|
||||
# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq
|
||||
TUYA_SUPPORT_TYPE = {
|
||||
"kg", # Switch
|
||||
"cz", # Socket
|
||||
@ -29,28 +27,6 @@ TUYA_SUPPORT_TYPE = {
|
||||
"xxj", # Diffuser
|
||||
}
|
||||
|
||||
# Switch(kg), Socket(cz), Power Strip(pc)
|
||||
# https://developer.tuya.com/en/docs/iot/categorykgczpc?id=Kaiuz08zj1l4y
|
||||
DPCODE_SWITCH = "switch"
|
||||
|
||||
# Air Purifier
|
||||
# https://developer.tuya.com/en/docs/iot/categorykj?id=Kaiuz1atqo5l7
|
||||
# Pet Water Feeder
|
||||
# https://developer.tuya.com/en/docs/iot/f?id=K9gf46aewxem5
|
||||
DPCODE_ANION = "anion" # Air Purifier - Ionizer unit
|
||||
# Air Purifier - Filter cartridge resetting; Pet Water Feeder - Filter cartridge resetting
|
||||
DPCODE_FRESET = "filter_reset"
|
||||
DPCODE_LIGHT = "light" # Air Purifier - Light
|
||||
DPCODE_LOCK = "lock" # Air Purifier - Child lock
|
||||
# Air Purifier - UV sterilization; Pet Water Feeder - UV sterilization
|
||||
DPCODE_UV = "uv"
|
||||
DPCODE_WET = "wet" # Air Purifier - Humidification unit
|
||||
DPCODE_PRESET = "pump_reset" # Pet Water Feeder - Water pump resetting
|
||||
DPCODE_WRESET = "water_reset" # Pet Water Feeder - Resetting of water usage days
|
||||
|
||||
|
||||
DPCODE_START = "start"
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
@ -88,12 +64,12 @@ def _setup_entities(
|
||||
for function in device.function:
|
||||
if device.category == "kj":
|
||||
if function in [
|
||||
DPCODE_ANION,
|
||||
DPCODE_FRESET,
|
||||
DPCODE_LIGHT,
|
||||
DPCODE_LOCK,
|
||||
DPCODE_UV,
|
||||
DPCODE_WET,
|
||||
DPCode.ANION,
|
||||
DPCode.FILTER_RESET,
|
||||
DPCode.LIGHT,
|
||||
DPCode.LOCK,
|
||||
DPCode.UV,
|
||||
DPCode.WET,
|
||||
]:
|
||||
entities.append(TuyaHaSwitch(device, device_manager, function))
|
||||
|
||||
@ -101,17 +77,17 @@ def _setup_entities(
|
||||
if (
|
||||
function
|
||||
in [
|
||||
DPCODE_FRESET,
|
||||
DPCODE_UV,
|
||||
DPCODE_PRESET,
|
||||
DPCODE_WRESET,
|
||||
DPCode.FILTER_RESET,
|
||||
DPCode.UV,
|
||||
DPCode.PUMP_RESET,
|
||||
DPCode.WATER_RESET,
|
||||
]
|
||||
or function.startswith(DPCODE_SWITCH)
|
||||
or function.startswith(DPCode.SWITCH)
|
||||
):
|
||||
entities.append(TuyaHaSwitch(device, device_manager, function))
|
||||
|
||||
elif function.startswith(DPCODE_START) or function.startswith(
|
||||
DPCODE_SWITCH
|
||||
elif function.startswith(DPCode.START) or function.startswith(
|
||||
DPCode.SWITCH
|
||||
):
|
||||
entities.append(TuyaHaSwitch(device, device_manager, function))
|
||||
|
||||
@ -121,8 +97,8 @@ def _setup_entities(
|
||||
class TuyaHaSwitch(TuyaHaEntity, SwitchEntity):
|
||||
"""Tuya Switch Device."""
|
||||
|
||||
dp_code_switch = DPCODE_SWITCH
|
||||
dp_code_start = DPCODE_START
|
||||
dp_code_switch = DPCode.SWITCH
|
||||
dp_code_start = DPCode.START
|
||||
|
||||
def __init__(
|
||||
self, device: TuyaDevice, device_manager: TuyaDeviceManager, dp_code: str = ""
|
||||
@ -132,15 +108,11 @@ class TuyaHaSwitch(TuyaHaEntity, SwitchEntity):
|
||||
|
||||
self.dp_code = dp_code
|
||||
self.channel = (
|
||||
dp_code.replace(DPCODE_SWITCH, "")
|
||||
if dp_code.startswith(DPCODE_SWITCH)
|
||||
dp_code.replace(DPCode.SWITCH, "")
|
||||
if dp_code.startswith(DPCode.SWITCH)
|
||||
else dp_code
|
||||
)
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str | None:
|
||||
"""Return a unique ID."""
|
||||
return f"{super().unique_id}{self.channel}"
|
||||
self._attr_unique_id = f"{super().unique_id}{self.channel}"
|
||||
|
||||
@property
|
||||
def name(self) -> str | None:
|
||||
|
Loading…
Reference in New Issue
Block a user