diff --git a/custom_components/localtuya/__init__.py b/custom_components/localtuya/__init__.py index be9c0ff41..8807d30c4 100644 --- a/custom_components/localtuya/__init__.py +++ b/custom_components/localtuya/__init__.py @@ -199,6 +199,84 @@ async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry): i = i + 1 config_entry.version = new_version hass.config_entries.async_update_entry(config_entry, data=new_data) + if config_entry.version <= 3: + # Convert values and friendly name values to dict. + from .const import ( + Platform, + CONF_OPTIONS, + CONF_HVAC_MODE_SET, + CONF_HVAC_ACTION_SET, + CONF_PRESET_SET, + CONF_SCENE_VALUES, + # Deprecated + CONF_SCENE_VALUES_FRIENDLY, + CONF_OPTIONS_FRIENDLY, + CONF_HVAC_ADD_OFF, + ) + from .climate import ( + RENAME_HVAC_MODE_SETS, + RENAME_ACTION_SETS, + RENAME_PRESET_SETS, + HVAC_OFF, + ) + + def convert_str_to_dict(list1: str, list2: str = ""): + to_dict = {} + if not isinstance(list1, str): + return list1 + list1, list2 = list1.replace(";", ","), list2.replace(";", ",") + v, v_fn = list1.split(","), list2.split(",") + for k in range(len(v)): + to_dict[v[k]] = ( + v_fn[k] if k < len(v_fn) and v_fn[k] else v[k].capitalize() + ) + return to_dict + + new_data = config_entry.data.copy() + for device in new_data[CONF_DEVICES]: + current_entity = 0 + for entity in new_data[CONF_DEVICES][device][CONF_ENTITIES]: + new_entity_data = {} + if entity[CONF_PLATFORM] == Platform.SELECT: + # Merge 2 Lists Values and Values friendly names into dict. + v_fn = entity.get(CONF_OPTIONS_FRIENDLY, "") + if v := entity.get(CONF_OPTIONS): + new_entity_data[CONF_OPTIONS] = convert_str_to_dict(v, v_fn) + if entity[CONF_PLATFORM] == Platform.LIGHT: + v_fn = entity.get(CONF_SCENE_VALUES_FRIENDLY, "") + if v := entity.get(CONF_SCENE_VALUES): + new_entity_data[CONF_SCENE_VALUES] = convert_str_to_dict( + v, v_fn + ) + if entity[CONF_PLATFORM] == Platform.CLIMATE: + # Merge 2 Lists Values and Values friendly names into dict. + climate_to_dict = {} + for conf, new_values in ( + (CONF_HVAC_MODE_SET, RENAME_HVAC_MODE_SETS), + (CONF_HVAC_ACTION_SET, RENAME_ACTION_SETS), + (CONF_PRESET_SET, RENAME_PRESET_SETS), + ): + climate_to_dict[conf] = {} + if hvac_set := entity.get(conf, ""): + if entity.get(CONF_HVAC_ADD_OFF, False): + if conf == CONF_HVAC_MODE_SET: + climate_to_dict[conf].update(HVAC_OFF) + if not isinstance(conf, str): + continue + hvac_set = hvac_set.replace("/", ",") + for i in hvac_set.split(","): + for k, v in new_values.items(): + if i in k: + new_v = True if i == "True" else i + new_v = False if i == "False" else new_v + climate_to_dict[conf].update({v: new_v}) + new_entity_data = climate_to_dict + new_data[CONF_DEVICES][device][CONF_ENTITIES][current_entity].update( + new_entity_data + ) + current_entity += 1 + config_entry.version = new_version + hass.config_entries.async_update_entry(config_entry, data=new_data) _LOGGER.info( "Entry %s successfully migrated to version %s.", diff --git a/custom_components/localtuya/climate.py b/custom_components/localtuya/climate.py index fc8449efe..874f66fbe 100644 --- a/custom_components/localtuya/climate.py +++ b/custom_components/localtuya/climate.py @@ -5,6 +5,7 @@ import logging from functools import partial from .config_flow import _col_to_select +from homeassistant.helpers import selector import voluptuous as vol from homeassistant.components.climate import ( @@ -54,93 +55,49 @@ _LOGGER = logging.getLogger(__name__) + +HVAC_OFF = {HVACMode.OFF.value: "off"} +RENAME_HVAC_MODE_SETS = { # Mirgae to 3 + ("manual", "Manual", "hot", "m", "True"): HVACMode.HEAT.value, + ("auto", "0", "p", "Program"): HVACMode.AUTO.value, + ("freeze", "cold", "1"): HVACMode.COOL.value, + ("wet"): HVACMode.DRY.value, +} +RENAME_ACTION_SETS = { # Mirgae to 3 + ("open", "opened", "heating", "Heat", "True"): HVACAction.HEATING.value, + ("closed", "close", "no_heating"): HVACAction.IDLE.value, + ("Warming", "warming", "False"): HVACAction.IDLE.value, + ("cooling"): HVACAction.COOLING.value, + ("off"): HVACAction.OFF.value, +} +RENAME_PRESET_SETS = { + "Holiday": (PRESET_AWAY), + "Program": (PRESET_HOME), + "Manual": (PRESET_NONE, "manual"), + "Auto": "auto", + "Manual": "manual", + "Smart": "smart", + "Comfort": "comfortable", + "ECO": "eco", +} + + HVAC_MODE_SETS = { - "manual/auto": { - HVACMode.HEAT: "manual", - HVACMode.AUTO: "auto", - }, - "Manual/Program": { - HVACMode.HEAT: "Manual", - HVACMode.AUTO: "Program", - }, - "freeze/manual/auto": { - HVACMode.COOL: "freeze", - HVACMode.HEAT: "manual", - HVACMode.AUTO: "auto", - }, - "auto/cold/hot/wet": { - HVACMode.AUTO: "auto", - HVACMode.COOL: "cold", - HVACMode.HEAT: "hot", - HVACMode.DRY: "wet", - }, - "m/p": { - HVACMode.HEAT: "m", - HVACMode.AUTO: "p", - }, - "True/False": { - HVACMode.HEAT: True, - }, - "1/0": { - HVACMode.HEAT: "1", - HVACMode.AUTO: "0", - }, - "smart/auto": { - HVACMode.HEAT_COOL: "1", - HVACMode.AUTO: "auto", - }, + HVACMode.OFF: False, + HVACMode.AUTO: "auto", + HVACMode.COOL: "cold", + HVACMode.HEAT: "hot", + HVACMode.HEAT_COOL: "heat", + HVACMode.DRY: "wet", + HVACMode.FAN_ONLY: "wind", } + HVAC_ACTION_SETS = { - "True/False": { - HVACAction.HEATING: True, - HVACAction.IDLE: False, - }, - "open/close": { - HVACAction.HEATING: "open", - HVACAction.IDLE: "close", - }, - "opened/closed": { - HVACAction.HEATING: "opened", - HVACAction.IDLE: "closed", - }, - "heating/no_heating": { - HVACAction.HEATING: "heating", - HVACAction.IDLE: "no_heating", - }, - "heating/cooling": { - HVACAction.HEATING: "heating", - HVACAction.COOLING: "cooling", - HVACAction.IDLE: "ventilation", - HVACAction.OFF: "off", - }, - "Heat/Warming": { - HVACAction.HEATING: "Heat", - HVACAction.IDLE: "Warming", - }, - "heating/warming": { - HVACAction.HEATING: "heating", - HVACAction.IDLE: "warming", - }, -} -PRESET_SETS = { - "Manual/Holiday/Program": { - PRESET_AWAY: "Holiday", - PRESET_HOME: "Program", - PRESET_NONE: "Manual", - }, - "auto/smart": { - "auto": "Auto", - "smart": "Smart", - }, - "auto/manual/smart/comfortable/eco": { - "auto": "Auto", - "manual": "Manual", - "smart": "Smart", - "comfortable": "Comfort", - "eco": "ECO", - }, + HVACAction.HEATING: "opened", + HVACAction.IDLE: "closed", } + TEMPERATURE_CELSIUS = "celsius" TEMPERATURE_FAHRENHEIT = "fahrenheit" DEFAULT_TEMPERATURE_UNIT = TEMPERATURE_CELSIUS @@ -160,26 +117,24 @@ def flow_schema(dps): ), vol.Optional(CONF_MIN_TEMP, default=DEFAULT_MIN_TEMP): vol.Coerce(float), vol.Optional(CONF_MAX_TEMP, default=DEFAULT_MAX_TEMP): vol.Coerce(float), - vol.Optional(CONF_PRECISION): _col_to_select( + vol.Optional(CONF_PRECISION, default=str(DEFAULT_PRECISION)): _col_to_select( [PRECISION_WHOLE, PRECISION_HALVES, PRECISION_TENTHS] ), vol.Optional(CONF_HVAC_MODE_DP): _col_to_select(dps, is_dps=True), - vol.Optional(CONF_HVAC_MODE_SET): _col_to_select(list(HVAC_MODE_SETS.keys())), + vol.Optional( + CONF_HVAC_MODE_SET, default=HVAC_MODE_SETS + ): selector.ObjectSelector(), vol.Optional(CONF_HVAC_ACTION_DP): _col_to_select(dps, is_dps=True), - vol.Optional(CONF_HVAC_ACTION_SET): _col_to_select( - list(HVAC_ACTION_SETS.keys()) - ), + vol.Optional( + CONF_HVAC_ACTION_SET, default=HVAC_ACTION_SETS + ): selector.ObjectSelector(), vol.Optional(CONF_ECO_DP): _col_to_select(dps, is_dps=True), vol.Optional(CONF_ECO_VALUE): str, vol.Optional(CONF_PRESET_DP): _col_to_select(dps, is_dps=True), - vol.Optional(CONF_PRESET_SET): _col_to_select(list(PRESET_SETS.keys())), + vol.Optional(CONF_PRESET_SET, default={}): selector.ObjectSelector(), vol.Optional(CONF_TEMPERATURE_UNIT): _col_to_select( [TEMPERATURE_CELSIUS, TEMPERATURE_FAHRENHEIT] ), - vol.Optional(CONF_TARGET_PRECISION): _col_to_select( - [PRECISION_WHOLE, PRECISION_HALVES, PRECISION_TENTHS] - ), - vol.Optional(CONF_HVAC_ADD_OFF, default=True): bool, vol.Optional(CONF_HEURISTIC_ACTION): bool, } @@ -203,19 +158,17 @@ def __init__( self._preset_mode = None self._hvac_action = None self._precision = float(self._config.get(CONF_PRECISION, DEFAULT_PRECISION)) - self._target_precision = float( - self._config.get(CONF_TARGET_PRECISION, self._precision) - ) self._conf_hvac_mode_dp = self._config.get(CONF_HVAC_MODE_DP) - self._conf_hvac_mode_set = HVAC_MODE_SETS.get( - self._config.get(CONF_HVAC_MODE_SET), {} - ) + if modes_set := self._config.get(CONF_HVAC_MODE_SET, {}): + # HA HVAC Modes are all lower case. + modes_set = {k.lower(): v for k, v in modes_set.copy().items()} + self._conf_hvac_mode_set = modes_set self._conf_preset_dp = self._config.get(CONF_PRESET_DP) - self._conf_preset_set = PRESET_SETS.get(self._config.get(CONF_PRESET_SET), {}) + self._conf_preset_set: dict = self._config.get(CONF_PRESET_SET, {}) self._conf_hvac_action_dp = self._config.get(CONF_HVAC_ACTION_DP) - self._conf_hvac_action_set = HVAC_ACTION_SETS.get( - self._config.get(CONF_HVAC_ACTION_SET), {} - ) + if actions_set := self._config.get(CONF_HVAC_ACTION_SET, {}): + actions_set = {k.lower(): v for k, v in actions_set.copy().items()} + self._conf_hvac_action_set = actions_set self._conf_eco_dp = self._config.get(CONF_ECO_DP) self._conf_eco_value = self._config.get(CONF_ECO_VALUE, "ECO") self._has_presets = self.has_config(CONF_ECO_DP) or self.has_config( @@ -225,7 +178,7 @@ def __init__( @property def supported_features(self): """Flag supported features.""" - supported_features = 0 + supported_features = ClimateEntityFeature(0) if self.has_config(CONF_TARGET_TEMPERATURE_DP): supported_features |= ClimateEntityFeature.TARGET_TEMPERATURE if self.has_config(CONF_PRESET_DP) or self.has_config(CONF_ECO_DP): @@ -237,11 +190,6 @@ def precision(self): """Return the precision of the system.""" return self._precision - @property - def target_precision(self): - """Return the precision of the target.""" - return self._target_precision - @property def temperature_unit(self): """Return the unit of measurement used by the platform.""" @@ -313,7 +261,7 @@ def preset_modes(self): """Return the list of available presets modes.""" if not self._has_presets: return None - presets = list(self._conf_preset_set) + presets = list(self._conf_preset_set.values()) if self._conf_eco_dp: presets.append(PRESET_ECO) return presets @@ -346,7 +294,7 @@ def fan_modes(self): async def async_set_temperature(self, **kwargs): """Set new target temperature.""" if ATTR_TEMPERATURE in kwargs and self.has_config(CONF_TARGET_TEMPERATURE_DP): - temperature = round(kwargs[ATTR_TEMPERATURE] / self._target_precision) + temperature = round(kwargs[ATTR_TEMPERATURE] / self.precision) await self._device.set_dp( temperature, self._config[CONF_TARGET_TEMPERATURE_DP] ) @@ -364,6 +312,7 @@ async def async_set_hvac_mode(self, hvac_mode): await self._device.set_dp(True, self._dp_id) # Some thermostats need a small wait before sending another update await asyncio.sleep(MODE_WAIT) + await self._device.set_dp( self._conf_hvac_mode_set[hvac_mode], self._conf_hvac_mode_dp ) @@ -381,9 +330,7 @@ async def async_set_preset_mode(self, preset_mode): if preset_mode == PRESET_ECO: await self._device.set_dp(self._conf_eco_value, self._conf_eco_dp) return - await self._device.set_dp( - self._conf_preset_set[preset_mode], self._conf_preset_dp - ) + await self._device.set_dp(preset_mode, self._conf_preset_dp) def status_updated(self): """Device status was updated.""" @@ -391,7 +338,7 @@ def status_updated(self): if self.has_config(CONF_TARGET_TEMPERATURE_DP): self._target_temperature = ( - self.dp_value(CONF_TARGET_TEMPERATURE_DP) * self._target_precision + self.dp_value(CONF_TARGET_TEMPERATURE_DP) * self._precision ) if self.has_config(CONF_CURRENT_TEMPERATURE_DP): @@ -406,9 +353,9 @@ def status_updated(self): ): self._preset_mode = PRESET_ECO else: - for preset, value in self._conf_preset_set.items(): # todo remove - if self.dp_value(CONF_PRESET_DP) == value: - self._preset_mode = preset + for preset_value, preset_name in self._conf_preset_set.items(): + if self.dp_value(CONF_PRESET_DP) == preset_value: + self._preset_mode = preset_name break else: self._preset_mode = PRESET_NONE diff --git a/custom_components/localtuya/cloud_api.py b/custom_components/localtuya/cloud_api.py index ce0a581a4..3e3f875a6 100644 --- a/custom_components/localtuya/cloud_api.py +++ b/custom_components/localtuya/cloud_api.py @@ -84,9 +84,13 @@ async def async_make_request(self, method, url, body=None, headers={}): full_url = self._base_url + url # _LOGGER.debug("\n" + method + ": [%s]", full_url) + request_timeout = 3 if method == "GET": func = functools.partial( - requests.get, full_url, headers=dict(default_par, **headers) + requests.get, + full_url, + headers=dict(default_par, **headers), + timeout=request_timeout, ) elif method == "POST": func = functools.partial( @@ -94,6 +98,7 @@ async def async_make_request(self, method, url, body=None, headers={}): full_url, headers=dict(default_par, **headers), data=json.dumps(body), + timeout=request_timeout, ) # _LOGGER.debug("BODY: [%s]", body) elif method == "PUT": @@ -102,9 +107,14 @@ async def async_make_request(self, method, url, body=None, headers={}): full_url, headers=dict(default_par, **headers), data=json.dumps(body), + timeout=request_timeout, ) - resp = await self._hass.async_add_executor_job(func) + try: + resp = await self._hass.async_add_executor_job(func) + except requests.exceptions.ReadTimeout as ex: + _LOGGER.debug(f"Requests read timeout: {ex}") + return # r = json.dumps(r.json(), indent=2, ensure_ascii=False) # Beautify the format return resp @@ -120,6 +130,9 @@ async def async_get_access_token(self) -> str | None: self._token_expire_time = 0 return "Request failed, status ConnectionError" + if not resp: + self._token_expire_time = 0 + return if not resp.ok: return "Request failed, status " + str(resp.status) @@ -156,8 +169,11 @@ async def async_get_devices_list(self) -> str | None: self.device_list = {dev["id"]: dev for dev in r_json["result"]} # Get Devices DPS Data. - get_functions = [self.get_device_functions(devid) for devid in self.device_list] - await asyncio.gather(*get_functions) + get_functions = [ + self._hass.async_create_task(self.get_device_functions(devid)) + for devid in self.device_list + ] + # await asyncio.run(*get_functions) return "ok" @@ -195,6 +211,25 @@ async def async_get_device_query_properties(self, device_id) -> dict[dict, str]: return r_json["result"], "ok" + async def async_get_device_query_things_data_model( + self, device_id + ) -> dict[str, dict]: + """Obtain the DP ID mappings for a device.""" + resp = await self.async_make_request( + "GET", url=f"/v2.0/cloud/thing/{device_id}/model" + ) + + if not resp: + return + if not resp.ok: + return {}, "Request failed, status " + str(resp.status) + + r_json = resp.json() + if not r_json["success"]: + return {}, f"Error {r_json['code']}: {r_json['msg']}" + + return r_json["result"], "ok" + async def get_device_functions(self, device_id) -> dict[str, dict]: """Pull Devices Properties and Specifications to devices_list""" cached = device_id in self.cached_device_list @@ -206,8 +241,9 @@ async def get_device_functions(self, device_id) -> dict[str, dict]: get_data = [ self.async_get_device_specifications(device_id), self.async_get_device_query_properties(device_id), + self.async_get_device_query_things_data_model(device_id), ] - specs, query_props = await asyncio.gather(*get_data) + specs, query_props, query_model = await asyncio.gather(*get_data) if query_props[1] == "ok": device_data = {str(p["dp_id"]): p for p in query_props[0].get("properties")} if specs[1] == "ok": @@ -216,6 +252,27 @@ async def get_device_functions(self, device_id) -> dict[str, dict]: device_data[str(func["dp_id"])].update(func) elif dp_id := func.get("dp_id"): device_data[str(dp_id)] = func + if query_model[1] == "ok": + model_data = json.loads(query_model[0]["model"]) + services = model_data.get("services", [{}])[0] + properties = services.get("properties") + for dp_data in properties if properties else {}: + refactored = { + "id": dp_data.get("abilityId"), + # "code": dp_data.get("code"), + "accessMode": dp_data.get("accessMode"), + # values: json.loads later + "values": str(dp_data.get("typeSpec")).replace("'", '"'), + } + if str(dp_data["abilityId"]) in device_data: + device_data[str(dp_data["abilityId"])].update(refactored) + else: + refactored["code"] = dp_data.get("code") + device_data[str(dp_data["abilityId"])] = refactored + + if "28841002" in str(query_props[1]): + # No permissions This affect auto configure feature. + self.device_list[device_id]["localtuya_note"] = str(query_props[1]) if device_data: self.device_list[device_id]["dps_data"] = device_data @@ -228,12 +285,11 @@ async def async_connect(self): if (res := await self.async_get_access_token()) and res != "ok": _LOGGER.error("Cloud API connection failed: %s", res) return "authentication_failed", res - - if (res := await self.async_get_devices_list()) and res != "ok": + if res and (res := await self.async_get_devices_list()) and res != "ok": _LOGGER.error("Cloud API connection failed: %s", res) return "device_list_failed", res - - _LOGGER.info("Cloud API connection succeeded.") + if res: + _LOGGER.info("Cloud API connection succeeded.") return True, res @property diff --git a/custom_components/localtuya/config_flow.py b/custom_components/localtuya/config_flow.py index 166418480..3e3455e5d 100644 --- a/custom_components/localtuya/config_flow.py +++ b/custom_components/localtuya/config_flow.py @@ -75,7 +75,7 @@ _LOGGER = logging.getLogger(__name__) -ENTRIES_VERSION = 3 +ENTRIES_VERSION = 4 PLATFORM_TO_ADD = "platform_to_add" USE_TEMPLATE = "use_template" diff --git a/custom_components/localtuya/core/ha_entities/__init__.py b/custom_components/localtuya/core/ha_entities/__init__.py index e2b21bcf4..b8cf43b33 100644 --- a/custom_components/localtuya/core/ha_entities/__init__.py +++ b/custom_components/localtuya/core/ha_entities/__init__.py @@ -123,8 +123,7 @@ def gen_localtuya_entities(localtuya_data: dict, tuya_category: str) -> list[dic for k, v in localtuya_entity_configs.items(): if isinstance(v, CLOUD_VALUE): config_dp = local_entity.get(v.dp_config) - pref_type = v.prefer_type - dp_values = get_dp_values(config_dp, dps_data, pref_type) or {} + dp_values = get_dp_values(config_dp, dps_data, v) or {} # special case for lights # if v.value_key in dp_values and "kelvin" in k: @@ -170,7 +169,7 @@ def parse_enum(dp_code: Enum) -> str: return parsed_dp_code -def get_dp_values(dp: str, dps_data: dict, prefer_type: type = None) -> dict: +def get_dp_values(dp: str, dps_data: dict, req_info: CLOUD_VALUE = None) -> dict: """Get DP Values""" if not dp or not dps_data: return @@ -195,7 +194,7 @@ def get_dp_values(dp: str, dps_data: dict, prefer_type: type = None) -> dict: if dp_values and dp_type == DPType.ENUM: dp_values["min"] = dp_values.get("range", [])[0] # first value dp_values["max"] = dp_values.get("range", [])[-1] # Last value - dp_values["range"] = convert_list(dp_values.get("range"), prefer_type) + dp_values["range"] = convert_list(dp_values.get("range"), req_info) return dp_values @@ -204,11 +203,13 @@ def scale(value: int, scale: int, _type: type = int) -> float: return _type(value) / (10**scale) -def convert_list(_list: list, prefer_type: dict | str = str): +def convert_list(_list: list, req_info: CLOUD_VALUE = str): """Return list to dict values.""" if not _list: return "" + prefer_type = req_info.prefer_type + if prefer_type == str: # Return str "value1,value2,value3" to_str = ",".join(str(v) for v in _list) @@ -216,7 +217,18 @@ def convert_list(_list: list, prefer_type: dict | str = str): if prefer_type == dict: # Return dict {value_1: Value 1, value_2: Value 2, value_3: Value 3} - to_dict = {v: v.replace("_", " ").capitalize() for v in _list} + to_dict = {} + for k in _list: + k_name = k.replace("_", " ").capitalize() # Default name + if isinstance(req_info.default_value, dict): + k_name = req_info.default_value.get(k, k_name) + if remaped_value := req_info.remap_values.get(k): + k_name = remaped_value + + if req_info.reverse_dict: + to_dict.update({k_name: k}) + else: + to_dict.update({k: k_name}) return to_dict # otherwise return prefer type list diff --git a/custom_components/localtuya/core/ha_entities/base.py b/custom_components/localtuya/core/ha_entities/base.py index 943dd6b01..cb7073ae9 100644 --- a/custom_components/localtuya/core/ha_entities/base.py +++ b/custom_components/localtuya/core/ha_entities/base.py @@ -1,5 +1,5 @@ from enum import StrEnum -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import Any from homeassistant.const import ( @@ -21,13 +21,17 @@ class CLOUD_VALUE: `default_value`: The value that will be used if it fails to retrieve from the cloud.\n `dp_config(str)`: The dp config key that will be used to look for the values into it.\n `value_key(str)`: The "key" name of the targeted value.\n - `prefer_type(dict | str)`: Used for enums to convert the values to [dict or str splitted by comma, default is list]. + `prefer_type(dict | str)`: Used for enums to convert the values to [dict or str splitted by comma, default is list].\n + `remap_values(dict)`: Used to remap dict values, if prefer_type is dict.\n + `reverse_dict(bool)`: Reverse dict keys, value, if prefer_type is dict.\n """ default_value: Any dp_config: str value_key: str prefer_type: type = None + remap_values: dict[str, Any] = field(default_factory=dict) + reverse_dict: bool = False class LocalTuyaEntity: @@ -515,4 +519,4 @@ class DPCode(StrEnum): WORK_MODE = "work_mode" # Working mode WORK_POWER = "work_power" WORK_STATE = "work_state" - WORK_STATUS = "work_status" \ No newline at end of file + WORK_STATUS = "work_status" diff --git a/custom_components/localtuya/core/ha_entities/climates.py b/custom_components/localtuya/core/ha_entities/climates.py index b1fa46de8..c83e3a50a 100644 --- a/custom_components/localtuya/core/ha_entities/climates.py +++ b/custom_components/localtuya/core/ha_entities/climates.py @@ -8,6 +8,7 @@ from homeassistant.components.climate import ( HVACMode, + HVACAction, DEFAULT_MAX_TEMP, DEFAULT_MIN_TEMP, ATTR_MAX_TEMP, @@ -15,7 +16,7 @@ ) from homeassistant.const import CONF_TEMPERATURE_UNIT -from .base import DPCode, LocalTuyaEntity, CONF_DEVICE_CLASS, EntityCategory +from .base import DPCode, LocalTuyaEntity, CLOUD_VALUE from ...const import ( CONF_ECO_VALUE, CONF_HVAC_ACTION_SET, @@ -24,7 +25,11 @@ CONF_PRESET_SET, CONF_TARGET_PRECISION, CONF_TEMPERATURE_STEP, - CONF_HVAC_ADD_OFF, + CONF_HVAC_ACTION_DP, + CONF_HVAC_MODE_DP, + CONF_CURRENT_TEMPERATURE_DP, + CONF_MAX_TEMP, + CONF_MIN_TEMP, ) @@ -39,22 +44,30 @@ def localtuya_climate( echo_value=None, preset_set=None, unit=None, + min_temperature=7, + max_temperature=35, values_precsion=0.1, target_precision=0.1, - includes_off_mode=True, ) -> dict: """Create localtuya climate configs""" data = {ATTR_MIN_TEMP: DEFAULT_MIN_TEMP, ATTR_MAX_TEMP: DEFAULT_MAX_TEMP} for key, conf in { - CONF_HVAC_MODE_SET: hvac_mode_set, + CONF_HVAC_MODE_SET: CLOUD_VALUE( + hvac_mode_set, CONF_HVAC_MODE_DP, "range", dict, MAP_CLIMATE_MODES, True + ), + CONF_MIN_TEMP: CLOUD_VALUE(min_temperature, CONF_CURRENT_TEMPERATURE_DP, "min"), + CONF_MAX_TEMP: CLOUD_VALUE(max_temperature, CONF_CURRENT_TEMPERATURE_DP, "max"), CONF_TEMPERATURE_STEP: temp_step, - CONF_HVAC_ACTION_SET: actions_set, + CONF_HVAC_ACTION_SET: CLOUD_VALUE( + actions_set, CONF_HVAC_ACTION_DP, "range", dict, MAP_CLIMATE_ACTIONS, True + ), CONF_ECO_VALUE: echo_value, CONF_PRESET_SET: preset_set, CONF_TEMPERATURE_UNIT: unit, - CONF_PRECISION: values_precsion, + CONF_PRECISION: CLOUD_VALUE( + values_precsion, CONF_CURRENT_TEMPERATURE_DP, "scale" + ), CONF_TARGET_PRECISION: target_precision, - CONF_HVAC_ADD_OFF: includes_off_mode, }.items(): if conf: data.update({key: conf}) @@ -62,6 +75,28 @@ def localtuya_climate( return data +# Map used for cloud value obtain. +MAP_CLIMATE_MODES = { + "off": HVACMode.OFF, + "auto": HVACMode.AUTO, + "cold": HVACMode.COOL, + "freeze": HVACMode.COOL, + "hot": HVACMode.HEAT, + "manual": HVACMode.HEAT_COOL, + "wet": HVACMode.DRY, + "wind": HVACMode.FAN_ONLY, +} +MAP_CLIMATE_ACTIONS = { + "heating": HVACAction.HEATING, + "cooling": HVACAction.COOLING, + "heating": HVACAction.HEATING, + "warming": HVACAction.IDLE, + "heating": HVACAction.HEATING, + "warming": HVACAction.IDLE, + "opened": HVACAction.HEATING, + "closed": HVACAction.IDLE, +} + CLIMATES: dict[str, tuple[LocalTuyaEntity, ...]] = { # Air conditioner # https://developer.tuya.com/en/docs/iot/categorykt?id=Kaiuz0z71ov2n @@ -73,9 +108,17 @@ def localtuya_climate( hvac_mode_dp=DPCode.MODE, hvac_action_dp=(DPCode.WORK_MODE, DPCode.WORK_STATUS, DPCode.WORK_STATE), custom_configs=localtuya_climate( - hvac_mode_set="auto/cold/hot/wet", + hvac_mode_set={ + HVACMode.AUTO: "auto", + HVACMode.COOL: "cold", + HVACMode.HEAT: "hot", + HVACMode.DRY: "wet", + }, temp_step=1, - actions_set="heating/cooling", + actions_set={ + HVACAction.HEATING: "heating", + HVACAction.COOLING: "cooling", + }, unit=UNIT_C, values_precsion=0.1, target_precision=0.1, @@ -92,8 +135,15 @@ def localtuya_climate( preset_dp=DPCode.MODE, hvac_action_dp=(DPCode.WORK_STATE, DPCode.WORK_MODE, DPCode.WORK_STATUS), custom_configs=localtuya_climate( + hvac_mode_set={ + HVACMode.OFF: "off", + HVACMode.HEAT: "hot", + }, temp_step=1, - actions_set="heating/warming", + actions_set={ + HVACAction.HEATING: "heating", + HVACAction.IDLE: "warming", + }, values_precsion=0.1, target_precision=0.1, preset_set="auto/smart", @@ -110,8 +160,15 @@ def localtuya_climate( preset_dp=DPCode.MODE, hvac_action_dp=(DPCode.WORK_STATE, DPCode.WORK_MODE, DPCode.WORK_STATUS), custom_configs=localtuya_climate( + hvac_mode_set={ + HVACMode.OFF: "off", + HVACMode.HEAT: "hot", + }, temp_step=1, - actions_set="heating/warming", + actions_set={ + HVACAction.HEATING: "heating", + HVACAction.IDLE: "warming", + }, unit=UNIT_C, values_precsion=0.1, target_precision=0.1, @@ -130,9 +187,12 @@ def localtuya_climate( hvac_action_dp=(DPCode.WORK_STATE, DPCode.WORK_MODE, DPCode.WORK_STATUS), preset_dp=DPCode.MODE, custom_configs=localtuya_climate( - hvac_mode_set="True/False", + hvac_mode_set={HVACMode.HEAT: True, HVACMode.OFF: False}, temp_step=1, - actions_set="True/False", + actions_set={ + HVACAction.HEATING: True, + HVACAction.IDLE: False, + }, unit=UNIT_C, values_precsion=0.1, target_precision=0.1, @@ -149,9 +209,12 @@ def localtuya_climate( hvac_mode_dp=DPCode.MODE, hvac_action_dp=(DPCode.WORK_STATE, DPCode.WORK_MODE, DPCode.WORK_STATUS), custom_configs=localtuya_climate( - hvac_mode_set="manual/auto", + hvac_mode_set={ + HVACMode.HEAT: "manual", + HVACMode.AUTO: "auto", + }, temp_step=1, - actions_set="opened/closed", + actions_set={HVACAction.HEATING: "opened", HVACAction.IDLE: "closed"}, unit=UNIT_C, values_precsion=0.1, target_precision=0.1, diff --git a/custom_components/localtuya/core/ha_entities/numbers.py b/custom_components/localtuya/core/ha_entities/numbers.py index 14d51d984..375221c29 100644 --- a/custom_components/localtuya/core/ha_entities/numbers.py +++ b/custom_components/localtuya/core/ha_entities/numbers.py @@ -160,6 +160,13 @@ def localtuya_numbers(_min, _max, _step=1, _scale=1, unit=None) -> dict: name="Light 4 Timer", custom_configs=localtuya_numbers(0, 86400, 1, 1, UnitOfTime.SECONDS), ), + LocalTuyaEntity( + id=DPCode.COUNTDOWN, + icon="mdi:timer", + entity_category=EntityCategory.CONFIG, + name="Light 4 Timer", + custom_configs=localtuya_numbers(0, 86400, 1, 1, UnitOfTime.SECONDS), + ), ), # Human Presence Sensor # https://developer.tuya.com/en/docs/iot/categoryhps?id=Kaiuz42yhn1hs @@ -377,9 +384,9 @@ def localtuya_numbers(_min, _max, _step=1, _scale=1, unit=None) -> dict: ), LocalTuyaEntity( id=DPCode.TIM, - icon="mdi:signal-distance-variant", + icon="mdi:timer-10", entity_category=EntityCategory.CONFIG, - name="Hold Time", + name="Timer Duration", custom_configs=localtuya_numbers(10, 900, 1, 1, UnitOfTime.SECONDS), ), LocalTuyaEntity( diff --git a/custom_components/localtuya/core/ha_entities/selects.py b/custom_components/localtuya/core/ha_entities/selects.py index 8b17ef87b..471e942d3 100644 --- a/custom_components/localtuya/core/ha_entities/selects.py +++ b/custom_components/localtuya/core/ha_entities/selects.py @@ -4,23 +4,46 @@ Credits: official HA Tuya integration. Modified by: xZetsubou - #TODO get values using "Get the instructions set by category" """ -from .base import DPCode, LocalTuyaEntity, CONF_DEVICE_CLASS, EntityCategory +from .base import ( + DPCode, + LocalTuyaEntity, + CONF_DEVICE_CLASS, + EntityCategory, + CLOUD_VALUE, +) # from const.py this is temporarily. from ...select import CONF_OPTIONS as OPS_VALS -from ...select import CONF_OPTIONS_FRIENDLY as OPS_NAME -def localtuya_selector(options, options_name=None): +def localtuya_selector(options): """Generate localtuya select configs""" - data = {OPS_VALS: options, OPS_NAME: options_name} + data = {OPS_VALS: CLOUD_VALUE(options, "id", "range", dict)} return data +COUNT_DOWN = { + "cancel": "Disable", + "1": "1 Hour", + "2": "2 Hours", + "3": "3 Hours", + "4": "4 Hours", + "5": "5 Hours", + "6": "6 Hours", +} +COUNT_DOWN_HOURS = { + "cancel": "Disable", + "1h": "1 Hour", + "2h": "2 Hours", + "3h": "3 Hours", + "4h": "4 Hours", + "5h": "5 Hours", + "6h": "6 Hours", +} + SELECTS: dict[str, tuple[LocalTuyaEntity, ...]] = { # Smart panel with switches and zigbee hub ? # Not documented @@ -30,19 +53,14 @@ def localtuya_selector(options, options_name=None): name="Source", icon="mdi:volume-source", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector( - "cloud,local,aux,bluetooth", "Cloud,Local,Aux,Bluetooth" - ), + custom_configs=localtuya_selector("cloud,local,aux,bluetooth"), ), LocalTuyaEntity( id=DPCode.PLAY_MODE, name="Mode", icon="mdi:cog-outline", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector( - "order,repeat_all,repeat_one,random", - "Order,Repeat ALL,Repeat One,Random", - ), + custom_configs=localtuya_selector("order,repeat_all,repeat_one,random"), ), LocalTuyaEntity( id=DPCode.SOUND_EFFECTS, @@ -50,8 +68,7 @@ def localtuya_selector(options, options_name=None): icon="mdi:sine-wave", entity_category=EntityCategory.CONFIG, custom_configs=localtuya_selector( - "normal,pop,opera,classical,jazz,rock,folk,heavy_metal,hip_hop,wave", - "Normal,POP,Opera,Classical,Jazz,Rock,Folk,Heavy Metal,Hip Hop,Wave", + "normal,pop,opera,classical,jazz,rock,folk,heavy_metal,hip_hop,wave" ), ), ), @@ -62,15 +79,13 @@ def localtuya_selector(options, options_name=None): id=DPCode.ALARM_VOLUME, name="volume", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector( - "low,middle,high,mute", "Low,Middle,High,Mute" - ), + custom_configs=localtuya_selector("low,middle,high,mute"), ), LocalTuyaEntity( id=DPCode.ALARM_RINGTONE, name="Ringtone", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector("1,2,3,4,5", "1,2,3,4,5"), + custom_configs=localtuya_selector("1,2,3,4,5"), ), ), # Heater @@ -78,7 +93,7 @@ def localtuya_selector(options, options_name=None): LocalTuyaEntity( id=(DPCode.C_F, DPCode.TEMP_UNIT_CONVERT), name="Temperature Unit", - custom_configs=localtuya_selector("c,f", "Celsius,Fahrenheit"), + custom_configs=localtuya_selector({"c": "Celsius", "f": "Fahrenheit"}), ), ), # Heater @@ -86,13 +101,13 @@ def localtuya_selector(options, options_name=None): LocalTuyaEntity( id=(DPCode.C_F, DPCode.TEMP_UNIT_CONVERT), name="Temperature Unit", - custom_configs=localtuya_selector("c,f", "Celsius,Fahrenheit"), + custom_configs=localtuya_selector({"c": "Celsius", "f": "Fahrenheit"}), ), LocalTuyaEntity( id=DPCode.CRUISE_MODE, name="Cruise mode", custom_configs=localtuya_selector( - "all_day,water_control,single_cruise", "Always,Water,Once" + {"all_day": "Always", "water_control": "Water", "single_cruise": "Once"} ), ), ), @@ -103,32 +118,27 @@ def localtuya_selector(options, options_name=None): id=DPCode.CUP_NUMBER, name="Cups", icon="mdi:numeric", - custom_configs=localtuya_selector( - "1,2,3,4,5,6,7,8,9,10,11,12", "1,2,3,4,5,6,7,8,9,10,11,12" - ), + custom_configs=localtuya_selector("1,2,3,4,5,6,7,8,9,10,11,12"), ), LocalTuyaEntity( id=DPCode.CONCENTRATION_SET, name="Concentration", icon="mdi:altimeter", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector( - "regular,middle,bold", "Regular,Middle,Bold" - ), + custom_configs=localtuya_selector("regular,middle,bold"), ), LocalTuyaEntity( id=DPCode.MATERIAL, name="Material", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector("bean,powder", "Bean,Powder"), + custom_configs=localtuya_selector("bean,powder"), ), LocalTuyaEntity( id=DPCode.MODE, name="Mode", icon="mdi:coffee", custom_configs=localtuya_selector( - "espresso,americano,machiatto,caffe_latte,cafe_mocha,cappuccino", - "Espresso,Americano,Machiatto,Caffe Latte,Cafe Mocha,Cappuccino", + "espresso,americano,machiatto,caffe_latte,cafe_mocha,cappuccino" ), ), ), @@ -141,7 +151,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Power-on behavior", custom_configs=localtuya_selector( - "power_on,power_off,last", "ON,OFF,Last State" + {"power_on": "ON", "power_off": "OFF", "last": "Last State"} ), condition_contains_any=["power_on", "power_off", "last"], ), @@ -150,7 +160,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -158,7 +170,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.RELAY_STATUS_1, @@ -166,7 +180,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Power-on behavior 1", custom_configs=localtuya_selector( - "power_on,power_off,last", "ON,OFF,Last State" + {"power_on": "ON", "power_off": "OFF", "last": "Last State"} ), condition_contains_any=["power_on", "power_off", "last"], ), @@ -175,7 +189,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 1", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -183,7 +199,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 1", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.RELAY_STATUS_2, @@ -191,7 +209,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Power-on behavior 2", custom_configs=localtuya_selector( - "power_on,power_off,last", "ON,OFF,Last State" + {"power_on": "ON", "power_off": "OFF", "last": "Last State"} ), condition_contains_any=["power_on", "power_off", "last"], ), @@ -200,7 +218,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 2", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -208,7 +228,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 2", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.RELAY_STATUS_3, @@ -216,7 +238,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Power-on behavior 3", custom_configs=localtuya_selector( - "power_on,power_off,last", "ON,OFF,Last State" + {"power_on": "ON", "power_off": "OFF", "last": "Last State"} ), condition_contains_any=["power_on", "power_off", "last"], ), @@ -225,7 +247,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 3", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -233,7 +257,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 3", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.RELAY_STATUS_4, @@ -241,7 +267,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Power-on behavior 4", custom_configs=localtuya_selector( - "power_on,power_off,last", "ON,OFF,Last State" + {"power_on": "ON", "power_off": "OFF", "last": "Last State"} ), condition_contains_any=["power_on", "power_off", "last"], ), @@ -250,7 +276,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 4", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -258,7 +286,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 4", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.RELAY_STATUS_5, @@ -266,7 +296,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Power-on behavior 5", custom_configs=localtuya_selector( - "power_on,power_off,last", "ON,OFF,Last State" + {"power_on": "ON", "power_off": "OFF", "last": "Last State"} ), condition_contains_any=["power_on", "power_off", "last"], ), @@ -275,7 +305,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 5", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -283,7 +315,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 5", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.RELAY_STATUS_6, @@ -291,7 +325,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Power-on behavior 6", custom_configs=localtuya_selector( - "power_on,power_off,last", "ON,OFF,Last State" + {"power_on": "ON", "power_off": "OFF", "last": "Last State"} ), condition_contains_any=["power_on", "power_off", "last"], ), @@ -300,7 +334,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 6", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -308,49 +344,41 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior 6", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.LIGHT_MODE, entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector("relay,pos,none", "State,Position,OFF"), + custom_configs=localtuya_selector( + {"relay": "State", "pos": "Position", "none": "OFF"} + ), name="Light Mode", ), ), # Heater # https://developer.tuya.com/en/docs/iot/categoryqn?id=Kaiuz18kih0sm "qn": ( - LocalTuyaEntity( - id=DPCode.MODE, - name="Mode", - custom_configs=localtuya_selector("smart,auto", "Smart,Auto"), - ), LocalTuyaEntity( id=DPCode.LEVEL, name="Temperature Level", icon="mdi:thermometer-lines", - custom_configs=localtuya_selector("1,2,3", "1,2,3"), + custom_configs=localtuya_selector( + {"1": "Level 1", "2": " Levell 2", "3": " Level 3"} + ), ), LocalTuyaEntity( id=DPCode.COUNTDOWN, name="Set Countdown", icon="mdi:timer-cog-outline", - custom_configs=localtuya_selector( - "cancel,1,2,3,4,5,6", "Cancel,1H,2H,3H,4H,5H,6H" - ), + custom_configs=localtuya_selector(COUNT_DOWN), ), LocalTuyaEntity( id=DPCode.COUNTDOWN_SET, name="Set Countdown", icon="mdi:timer-cog-outline", - custom_configs=localtuya_selector( - "cancel,1h,2h,3h,4h,5h,6h", "Cancel,1H,2H,3H,4H,5H,6H" - ), - ), - LocalTuyaEntity( - id=(DPCode.C_F, DPCode.TEMP_UNIT_CONVERT), - name="Temperature Unit", - custom_configs=localtuya_selector("c,f", "Celsius,Fahrenheit"), + custom_configs=localtuya_selector(COUNT_DOWN_HOURS), ), ), # Siren Alarm @@ -360,26 +388,21 @@ def localtuya_selector(options, options_name=None): id=DPCode.ALARM_VOLUME, name="Volume", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector( - "low,middle,high,mute", "Low,Middle,High,Mute" - ), + custom_configs=localtuya_selector("low,middle,high,mute"), ), LocalTuyaEntity( id=DPCode.ALARM_STATE, name="State", entity_category=EntityCategory.CONFIG, custom_configs=localtuya_selector( - "alarm_sound,alarm_light,alarm_sound_light,normal", - "Sound,Light,Sound and Light,Normal", + "alarm_sound,alarm_light,alarm_sound_light,normal" ), ), LocalTuyaEntity( id=DPCode.BRIGHT_STATE, name="Brightness", entity_category=EntityCategory.CONFIG, - custom_configs=localtuya_selector( - "low,middle,high,strong", "Low,Middle,High,Strong" - ), + custom_configs=localtuya_selector("low,middle,high,strong"), ), ), # Smart Camera @@ -389,7 +412,7 @@ def localtuya_selector(options, options_name=None): id=DPCode.IPC_WORK_MODE, entity_category=EntityCategory.CONFIG, name="Working mode", - custom_configs=localtuya_selector("0,1", "Low Power,Continuous"), + custom_configs=localtuya_selector({"0": "Low Power", "1": "Continuous"}), ), LocalTuyaEntity( id=DPCode.DECIBEL_SENSITIVITY, @@ -397,7 +420,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Decibel Sensitivity", custom_configs=localtuya_selector( - "0,1", "Low Sensitivity,Hight Sensitivity" + {"0": "Low Sensitivity", "1": "High Sensitivity"} ), ), LocalTuyaEntity( @@ -406,7 +429,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Record Mode", custom_configs=localtuya_selector( - "1,2", "Record Events Only,Allways Record" + {"1": "Record Events Only", "2": "Allways Record"} ), ), LocalTuyaEntity( @@ -414,21 +437,23 @@ def localtuya_selector(options, options_name=None): icon="mdi:theme-light-dark", entity_category=EntityCategory.CONFIG, name="IR Night Vision", - custom_configs=localtuya_selector("0,1,2", "Auto,OFF,ON"), + custom_configs=localtuya_selector({"0": "Auto", "1": "OFF", "2": "ON"}), ), LocalTuyaEntity( id=DPCode.BASIC_ANTI_FLICKER, icon="mdi:image-outline", entity_category=EntityCategory.CONFIG, name="Anti-Flicker", - custom_configs=localtuya_selector("0,1,2", "Disable,50 Hz,60 Hz"), + custom_configs=localtuya_selector( + {"0": "Disable", "1": "50 Hz", "2": "60 Hz"} + ), ), LocalTuyaEntity( id=DPCode.MOTION_SENSITIVITY, icon="mdi:motion-sensor", entity_category=EntityCategory.CONFIG, name="Motion Sensitivity", - custom_configs=localtuya_selector("0,1,2", "Low,Medium,High"), + custom_configs=localtuya_selector({"0": "Low", "1": "Medium", "2": "High"}), ), LocalTuyaEntity( id=DPCode.PTZ_CONTROL, @@ -436,21 +461,29 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="PTZ control", custom_configs=localtuya_selector( - "0,1,2,3,4,5,6,7", - "UP,Upper Right,Right,Bottom Right,Down,Bottom Left,Left,Upper Left", + { + "0": "UP", + "1": "Upper Right", + "2": "Right", + "3": "Bottom Right", + "4": "Down", + "5": "Bottom Left", + "6": "Left", + "7": "Upper Left", + } ), ), LocalTuyaEntity( id=DPCode.FLIGHT_BRIGHT_MODE, entity_category=EntityCategory.CONFIG, name="Brightness mode", - custom_configs=localtuya_selector("0,1", "Manual,Auto"), + custom_configs=localtuya_selector({"0": "Manual", "1": "Auto"}), ), LocalTuyaEntity( id=DPCode.PIR_SENSITIVITY, entity_category=EntityCategory.CONFIG, name="PIR sensitivity", - custom_configs=localtuya_selector("0,1,2", "Low,Medium,High"), + custom_configs=localtuya_selector({"0": "Low", "1": "Medium", "2": "High"}), ), ), # Dimmer Switch @@ -461,7 +494,9 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior", - custom_configs=localtuya_selector("on,off,memory", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"on": "ON", "off": "OFF", "memory": "Last State"} + ), condition_contains_any=["on", "off", "memory"], ), LocalTuyaEntity( @@ -469,37 +504,35 @@ def localtuya_selector(options, options_name=None): icon="mdi:circle-double", entity_category=EntityCategory.CONFIG, name="Power-on behavior", - custom_configs=localtuya_selector("0,1,2", "ON,OFF,Last State"), + custom_configs=localtuya_selector( + {"0": "ON", "1": "OFF", "2": "Last State"} + ), ), LocalTuyaEntity( id=DPCode.LIGHT_MODE, entity_category=EntityCategory.CONFIG, name="Light Mode", - custom_configs=localtuya_selector("relay,pos,none", "State,Position,OFF"), + custom_configs=localtuya_selector( + {"relay": "State", "pos": "Position", "none": "OFF"} + ), ), LocalTuyaEntity( id=DPCode.LED_TYPE_1, entity_category=EntityCategory.CONFIG, name="Led Type 1", - custom_configs=localtuya_selector( - "led,incandescent,halogen", "LED,Incandescence,Halogen" - ), + custom_configs=localtuya_selector("led,incandescent,halogen"), ), LocalTuyaEntity( id=DPCode.LED_TYPE_2, entity_category=EntityCategory.CONFIG, name="Led Type 2", - custom_configs=localtuya_selector( - "led,incandescent,halogen", "LED,Incandescence,Halogen" - ), + custom_configs=localtuya_selector("led,incandescent,halogen"), ), LocalTuyaEntity( id=DPCode.LED_TYPE_3, entity_category=EntityCategory.CONFIG, name="Led Type 3", - custom_configs=localtuya_selector( - "led,incandescent,halogen", "LED,Incandescence,Halogen" - ), + custom_configs=localtuya_selector("led,incandescent,halogen"), ), ), # Dimmer @@ -509,17 +542,13 @@ def localtuya_selector(options, options_name=None): id=DPCode.LED_TYPE_1, entity_category=EntityCategory.CONFIG, name="Led Type 1", - custom_configs=localtuya_selector( - "led,incandescent,halogen", "LED,Incandescence,Halogen" - ), + custom_configs=localtuya_selector("led,incandescent,halogen"), ), LocalTuyaEntity( id=DPCode.LED_TYPE_2, entity_category=EntityCategory.CONFIG, name="Led Type 2", - custom_configs=localtuya_selector( - "led,incandescent,halogen", "LED,Incandescence,Halogen" - ), + custom_configs=localtuya_selector("led,incandescent,halogen"), ), ), # Fingerbot @@ -528,9 +557,7 @@ def localtuya_selector(options, options_name=None): id=DPCode.MODE, entity_category=EntityCategory.CONFIG, name="Fingerbot Mode", - custom_configs=localtuya_selector( - "click,switch,toggle", "Click,Switch,Toggle" - ), + custom_configs=localtuya_selector("click,switch,toggle"), ), ), # Robot Vacuum @@ -541,18 +568,14 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, icon="mdi:water-opacity", name="Water Tank Adjustment", - custom_configs=localtuya_selector( - "low,middle,high,closed", "Low,Middle,High,Closed" - ), + custom_configs=localtuya_selector("low,middle,high,closed"), ), LocalTuyaEntity( id=DPCode.COLLECTION_MODE, entity_category=EntityCategory.CONFIG, icon="mdi:air-filter", name="Dust Collection Mode", - custom_configs=localtuya_selector( - "small,middle,large", "Small,Middle,Large" - ), + custom_configs=localtuya_selector("small,middle,large"), ), LocalTuyaEntity( id=DPCode.MODE, @@ -560,8 +583,7 @@ def localtuya_selector(options, options_name=None): icon="mdi:layers-outline", name="Mode", custom_configs=localtuya_selector( - "standby,random,smart,wall_follow,mop,spiral,left_spiral,right_spiral,right_bow,left_bow,partial_bow,chargego", - "StandBy,Random,Smart,Edges,Mop,Spiral,Left Spiral,Right Spiral,Right Bow,Left Bow,Partial Bow,Recharge", + "standby,random,smart,wall_follow,mop,spiral,left_spiral,right_spiral,right_bow,left_bow,partial_bow,chargego" ), ), ), @@ -573,41 +595,39 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, icon="mdi:format-vertical-align-center", name="Vertical swing", - custom_configs=localtuya_selector("30,60,90", "30 Deg,60 Deg,90 Deg"), + custom_configs=localtuya_selector( + {"30": "30 Deg", "60": "60 Deg", "90": "90 Deg"} + ), ), LocalTuyaEntity( id=DPCode.FAN_HORIZONTAL, entity_category=EntityCategory.CONFIG, icon="mdi:format-horizontal-align-center", name="Horizontal swing", - custom_configs=localtuya_selector("30,60,90", "30 Deg,60 Deg,90 Deg"), + custom_configs=localtuya_selector( + {"30": "30 Deg", "60": "60 Deg", "90": "90 Deg"} + ), ), LocalTuyaEntity( id=DPCode.WORK_MODE, entity_category=EntityCategory.CONFIG, icon="mdi:ceiling-fan-light", name="Light mode", - custom_configs=localtuya_selector( - "white,colour,colourful", "White,Colour,Colourful" - ), + custom_configs=localtuya_selector("white,colour,colourful"), ), LocalTuyaEntity( id=DPCode.COUNTDOWN, entity_category=EntityCategory.CONFIG, icon="mdi:timer-cog-outline", name="Countdown", - custom_configs=localtuya_selector( - "cancel,1,2,3,4,5,6", "Cancel,1H,2H,3H,4H,5H,6H" - ), + custom_configs=localtuya_selector(COUNT_DOWN), ), LocalTuyaEntity( id=DPCode.COUNTDOWN_SET, entity_category=EntityCategory.CONFIG, icon="mdi:timer-cog-outline", name="Countdown", - custom_configs=localtuya_selector( - "cancel,1h,2h,3h,4h,5h,6h", "Cancel,1H,2H,3H,4H,5H,6H" - ), + custom_configs=localtuya_selector(COUNT_DOWN_HOURS), ), ), # Curtain @@ -618,20 +638,22 @@ def localtuya_selector(options, options_name=None): name="Motor Direction", entity_category=EntityCategory.CONFIG, icon="mdi:swap-vertical", - custom_configs=localtuya_selector("forward,back", "Forward,Back"), + custom_configs=localtuya_selector("forward,back"), ), LocalTuyaEntity( id=DPCode.MOTOR_MODE, name="Motor Mode", entity_category=EntityCategory.CONFIG, icon="mdi:cog-transfer", - custom_configs=localtuya_selector("contiuation,point", "Auto,Manual"), + custom_configs=localtuya_selector( + {"contiuation": "Auto", "point": "Manual"} + ), ), LocalTuyaEntity( id=DPCode.MODE, entity_category=EntityCategory.CONFIG, name="Cover Mode", - custom_configs=localtuya_selector("morning,night", "Morning,Night"), + custom_configs=localtuya_selector("morning,night"), ), ), # Humidifier @@ -642,10 +664,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, icon="mdi:spray", name="Spraying mode", - custom_configs=localtuya_selector( - "auto,health,baby,sleep,humidity,work", - "Auto,Health,Baby,Sleep,Humidity,Work", - ), + custom_configs=localtuya_selector("auto,health,baby,sleep,humidity,work"), ), LocalTuyaEntity( id=DPCode.LEVEL, @@ -653,8 +672,7 @@ def localtuya_selector(options, options_name=None): icon="mdi:spray", name="Spraying level", custom_configs=localtuya_selector( - "level_1,level_2,level_3,level_4,level_5,level_6,level_7,level_8,level_9,level_10", - "Level 1,Level 2,Level 3,Level 4,Level 5,Level 6,Level 7,Level 8,Level 9,Level 10", + "level_1,level_2,level_3,level_4,level_5,level_6,level_7,level_8,level_9,level_10" ), ), LocalTuyaEntity( @@ -662,25 +680,21 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, icon="mdi:lightbulb-multiple", name="Mood light", - custom_configs=localtuya_selector("1,2,3,4,5", "1,2,3,4,5"), + custom_configs=localtuya_selector("1,2,3,4,5"), ), LocalTuyaEntity( id=DPCode.COUNTDOWN, entity_category=EntityCategory.CONFIG, icon="mdi:timer-cog-outline", name="Countdown", - custom_configs=localtuya_selector( - "cancel,1,2,3,4,5,6", "Cancel,1H,2H,3H,4H,5H,6H" - ), + custom_configs=localtuya_selector(COUNT_DOWN), ), LocalTuyaEntity( id=DPCode.COUNTDOWN_SET, entity_category=EntityCategory.CONFIG, icon="mdi:timer-cog-outline", name="Countdown", - custom_configs=localtuya_selector( - "cancel,1h,2h,3h,4h,5h,6h", "Cancel,1H,2H,3H,4H,5H,6H" - ), + custom_configs=localtuya_selector(COUNT_DOWN_HOURS), ), ), # Air Purifier @@ -691,18 +705,14 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, icon="mdi:timer-cog-outline", name="Countdown", - custom_configs=localtuya_selector( - "cancel,1,2,3,4,5,6", "Cancel,1H,2H,3H,4H,5H,6H" - ), + custom_configs=localtuya_selector(COUNT_DOWN), ), LocalTuyaEntity( id=DPCode.COUNTDOWN_SET, entity_category=EntityCategory.CONFIG, icon="mdi:timer-cog-outline", name="Countdown", - custom_configs=localtuya_selector( - "cancel,1h,2h,3h,4h,5h,6h", "Cancel,1H,2H,3H,4H,5H,6H" - ), + custom_configs=localtuya_selector(COUNT_DOWN_HOURS), ), ), # Dehumidifier @@ -713,21 +723,25 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, icon="mdi:timer-cog-outline", name="Countdown", - custom_configs=localtuya_selector("cancel,2h,4h,8h", "Cancel,2H,4H,8H"), + custom_configs=localtuya_selector( + {"cancel": "Disable", "2h": "2 Hours", "4h": "4 Hours", "8h": "8 Hours"} + ), ), LocalTuyaEntity( id=DPCode.DEHUMIDITY_SET_ENUM, name="Target Humidity", entity_category=EntityCategory.CONFIG, icon="mdi:water-percent", - custom_configs=localtuya_selector("10,20,30,40,50", "10,20,30,40,50"), + custom_configs=localtuya_selector("10,20,30,40,50"), ), LocalTuyaEntity( id=DPCode.SPRAY_VOLUME, name="Intensity", entity_category=EntityCategory.CONFIG, icon="mdi:volume-source", - custom_configs=localtuya_selector("small,middle,large", "Low,Medium,High"), + custom_configs=localtuya_selector( + {"small": "Low", "middle": "Medium", "large": "High"} + ), ), ), # sous vide cookers @@ -738,8 +752,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Cooking Mode", custom_configs=localtuya_selector( - "vegetables,meat,shrimp,fish,chicken,drumsticks,beef,rice", - "Vegetables,Meat,Shrimp,Fish,Chicken,Drumsticks,Beef,Rice", + "vegetables,meat,shrimp,fish,chicken,drumsticks,beef,rice" ), ), ), @@ -752,7 +765,7 @@ def localtuya_selector(options, options_name=None): entity_category=EntityCategory.CONFIG, name="Mode", custom_configs=localtuya_selector( - "mode_auto,mode_on,mode_off", "AUTO,ON,OFF" + {"mode_auto": "AUTO", "mode_on": "ON", "mode_off": "OFF"} ), ), ), @@ -763,17 +776,9 @@ def localtuya_selector(options, options_name=None): id=DPCode.SENSORTYPE, entity_category=EntityCategory.CONFIG, name="Temperature sensor", - custom_configs=localtuya_selector("0,1,2", "Internal,External,Both"), - ), - ), - # Thermostat - # https://developer.tuya.com/en/docs/iot/f?id=K9gf45ld5l0t9 - "wk": ( - LocalTuyaEntity( - id=DPCode.SENSORTYPE, - entity_category=EntityCategory.CONFIG, - name="Temperature sensor", - custom_configs=localtuya_selector("0,1,2", "Internal,External,Both"), + custom_configs=localtuya_selector( + {"0": "Internal", "1": "External", "2": "Both"} + ), ), ), } @@ -798,111 +803,3 @@ def localtuya_selector(options, options_name=None): # Heater SELECTS["rs"] = SELECTS["kt"] - - -# # Select Options [ options : friendly name for options ] -# MORING_NIGHT = {OPS_VALS: "morning,night", OPS_NAME: "Morning,Night"} - -# # Cover -# FORWARD_BACK = {OPS_VALS: "forward,back", OPS_NAME: "Forward,Back"} -# FAN_WORK_MODE = {OPS_VALS: "contiuation,point", OPS_NAME: "Auto,Manual"} - - -# # THIS IS FOR alarm_control_panel.py -# # Multi-functional Sensor -# MASTER_MODE = {OPS_VALS: "disarmed,arm,home,sos", OPS_NAME: "Disarmed,Arm,Home,sos"} -# ALARM_VOLUME = {OPS_VALS: "low,middle,high,mute", OPS_NAME: "Low,Middle,High,Mute"} -# ALARM_RINGTONE = {OPS_VALS: "1,2,3,4,5", OPS_NAME: "1,2,3,4,5"} -# ALARM_STATES = { -# OPS_VALS: "alarm_sound,alarm_light,alarm_sound_light,normal", -# OPS_NAME: "Sound,Light,Sound and Light,Normal", -# } - -# # Coffee maker -# CUP_NUMBER = { -# OPS_VALS: "1,2,3,4,5,6,7,8,9,10,11,12", -# OPS_NAME: "1,2,3,4,5,6,7,8,9,10,11,12", -# } -# CONCENTRATION_SET = {OPS_VALS: "regular,middle,bold", OPS_NAME: "Regular,Middle,Bold"} -# MATERIAL = {OPS_VALS: "bean,powder", OPS_NAME: "Bean,Powder"} -# COFFE_MODES = { -# OPS_VALS: "espresso,americano,machiatto,caffe_latte,cafe_mocha,cappuccino", -# OPS_NAME: "Espresso,Americano,Machiatto,Caffe Latte,Cafe Mocha,Cappuccino", -# } - -# # Switch alikes -# RELAY_STATUS = {OPS_VALS: "power_on,power_off,last", OPS_NAME: "ON,OFF,Last State"} -# RELAY_STATUS_V2 = {OPS_VALS: "0,1,2", OPS_NAME: "ON,OFF,Last State"} -# DIMMER_RELAY_STATUS = {OPS_VALS: "on,off,memory", OPS_NAME: "ON,OFF,Last State"} - -# LED_TYPE_1 = { -# OPS_VALS: "led,incandescent,halogen", -# OPS_NAME: "LED,Incandescence,Halogen", -# } -# LIGHT_MODE = {OPS_VALS: "relay,pos,none", OPS_NAME: "State,Position,OFF"} - -# # Heater -# HEATER_MODES = {OPS_VALS: "smart,auto", OPS_NAME: "Smart,Auto"} -# HEATER_LEVELS = {OPS_VALS: "1,2,3", OPS_NAME: "1,2,3"} - -# COUNTDOWN = {OPS_VALS: "cancel,1,2,3,4,5,6", OPS_NAME: "Cancel,1H,2H,3H,4H,5H,6H"} -# COUNTDOWN_SET = { -# OPS_VALS: "cancel,1h,2h,3h,4h,5h,6h", -# OPS_NAME: "Cancel,1H,2H,3H,4H,5H,6H", -# } - -# # Siren Alarm -# BRIGHT_STATE = {OPS_VALS: "low,middle,high,strong", OPS_NAME: "Low,Middle,High,Strong"} - -# # Smart Camera -# IPC_WORK_MODE = {OPS_VALS: "0,1", OPS_NAME: "Low Power,Continuous"} -# DECIBEL_SENSITIVITY = {OPS_VALS: "0,1", OPS_NAME: "Low Sensitivity,Hight Sensitivity"} -# IPC_WORK_MODE = {OPS_VALS: "0,1", OPS_NAME: "Low Power,Continuous"} -# RECORD_MODE = {OPS_VALS: "1,2", OPS_NAME: "Record Events Only,Allways Record"} -# FLIGHT_BRIGHT_MODE = {OPS_VALS: "0,1", OPS_NAME: "Manual,Auto"} -# PIR_SENSITIVITY = {OPS_VALS: "0,1,2", OPS_NAME: "Low,Medium,High"} -# BASIC_NIGHTVISION = {OPS_VALS: "0,1,2", OPS_NAME: "Auto,OFF,ON"} -# BASIC_ANTI_FLICKER = {OPS_VALS: "0,1,2", OPS_NAME: "Disable,50 Hz,60 Hz"} -# MOTION_SENSITIVITY = {OPS_VALS: "0,1,2", OPS_NAME: "Low,Medium,High"} -# PTZ_CONTROL = { -# OPS_VALS: "0,1,2,3,4,5,6,7", -# OPS_NAME: "UP,Upper Right,Right,Bottom Right,Down,Bottom Left,Left,Upper Left", -# } - -# # Fingerbot -# CLICK_SWITCH_TOGGLE = {OPS_VALS: "click,switch,toggle", OPS_NAME: "Click,Switch,Toggle"} - -# # VACCUM -# VACCUM_MODE = { -# OPS_VALS: "standby,random,smart,wall_follow,mop,spiral,left_spiral,right_spiral,right_bow,left_bow,partial_bow,chargego", -# OPS_NAME: "StandBy,Random,Smart,Edges,Mop,Spiral,Left Spiral,Right Spiral,Right Bow,Left Bow,Partial Bow,Recharge", -# } -# VACCUM_CISTERN = { -# OPS_VALS: "low,middle,high,closed", -# OPS_NAME: "Low,Middle,High,Closed", -# } -# VACCUM_COLLECTION_MODE = { -# OPS_VALS: "small,middle,large", -# OPS_NAME: "Small,Middle,Large", -# } - -# # FAN -# SWING_30_60_90 = {OPS_VALS: "30,60,90", OPS_NAME: "30 Deg,60 Deg,90 Deg"} -# FAN_LIGHT_MODE = { -# OPS_VALS: "white,colour,colourful", -# OPS_NAME: "White,Colour,Colourful", -# } - -# # Humidifier -# MOODLIGHTING = {OPS_VALS: "1,2,3,4,5", OPS_NAME: "1,2,3,4,5"} -# HUMIDIFER_LEVEL = { -# OPS_VALS: "level_1,level_2,level_3,level_4,level_5,level_6,level_7,level_8,level_9,level_10", -# OPS_NAME: "Level 1,Level 2,Level 3,Level 4,Level 5,Level 6,Level 7,Level 8,Level 9,Level 10", -# } -# SPRAY_MODE = { -# OPS_VALS: "auto,health,baby,sleep,humidity,work", -# OPS_NAME: "Auto,Health,Baby,Sleep,Humidity,Work", -# } - -# # Dehumidifier -# DEHUMIDITY_SET_ENUM = {OPS_VALS: "10,20,30,40,50", OPS_NAME: "10,20,30,40,50"} diff --git a/custom_components/localtuya/light.py b/custom_components/localtuya/light.py index 748eeef72..72d282b7f 100644 --- a/custom_components/localtuya/light.py +++ b/custom_components/localtuya/light.py @@ -3,6 +3,7 @@ import textwrap from functools import partial from .config_flow import _col_to_select +from homeassistant.helpers import selector import homeassistant.util.color as color_util import voluptuous as vol @@ -28,7 +29,6 @@ CONF_COLOR_TEMP_MIN_KELVIN, CONF_COLOR_TEMP_REVERSE, CONF_SCENE_VALUES, - CONF_SCENE_VALUES_FRIENDLY, CONF_MUSIC_MODE, ) @@ -124,8 +124,7 @@ def flow_schema(dps): ), vol.Optional(CONF_COLOR_TEMP_REVERSE, default=DEFAULT_COLOR_TEMP_REVERSE): bool, vol.Optional(CONF_SCENE): _col_to_select(dps, is_dps=True), - vol.Optional(CONF_SCENE_VALUES): str, - vol.Optional(CONF_SCENE_VALUES_FRIENDLY): str, + vol.Optional(CONF_SCENE_VALUES): selector.ObjectSelector(), vol.Optional(CONF_MUSIC_MODE, default=False): bool, } @@ -166,18 +165,10 @@ def __init__( self._effect_list = [] self._scenes = None if self.has_config(CONF_SCENE): - if self.has_config(CONF_SCENE_VALUES) and self.has_config( - CONF_SCENE_VALUES_FRIENDLY - ): - values_list = [ - value.strip() - for value in self._config.get(CONF_SCENE_VALUES).split(",") - ] - friendly_values_list = [ - value.strip() - for value in self._config.get(CONF_SCENE_VALUES_FRIENDLY).split(",") - ] - self._scenes = dict(zip(friendly_values_list, values_list)) + if self.has_config(CONF_SCENE_VALUES): + values_list = list(self._config.get(CONF_SCENE_VALUES)) + values_name = list(self._config.get(CONF_SCENE_VALUES).values()) + self._scenes = dict(zip(values_name, values_list)) elif int(self._config.get(CONF_SCENE)) < 20: self._scenes = SCENE_LIST_RGBW_255 elif self._config.get(CONF_BRIGHTNESS) is None: @@ -325,6 +316,7 @@ async def async_turn_on(self, **kwargs): if not self.is_on: states[self._dp_id] = True features = self.supported_features + color_modes = self.supported_color_modes brightness = None if ATTR_EFFECT in kwargs and (features & LightEntityFeature.EFFECT): scene = self._scenes.get(kwargs[ATTR_EFFECT]) @@ -337,7 +329,7 @@ async def async_turn_on(self, **kwargs): elif kwargs[ATTR_EFFECT] == SCENE_MUSIC: states[self._config.get(CONF_COLOR_MODE)] = MODE_MUSIC - if ATTR_BRIGHTNESS in kwargs and self._brightness: + if ATTR_BRIGHTNESS in kwargs and ColorMode.BRIGHTNESS in color_modes: brightness = map_range( int(kwargs[ATTR_BRIGHTNESS]), 0, @@ -369,7 +361,7 @@ async def async_turn_on(self, **kwargs): states[self._config.get(CONF_COLOR)] = color states[self._config.get(CONF_COLOR_MODE)] = MODE_COLOR - if ATTR_HS_COLOR in kwargs and self._hs: + if ATTR_HS_COLOR in kwargs and ColorMode.HS in color_modes: if brightness is None: brightness = self._brightness hs = kwargs[ATTR_HS_COLOR] @@ -396,7 +388,7 @@ async def async_turn_on(self, **kwargs): states[self._config.get(CONF_COLOR)] = color states[self._config.get(CONF_COLOR_MODE)] = MODE_COLOR - if ATTR_COLOR_TEMP in kwargs and self._color_temp: + if ATTR_COLOR_TEMP in kwargs and ColorMode.COLOR_TEMP in color_modes: if brightness is None: brightness = self._brightness mired = int(kwargs[ATTR_COLOR_TEMP]) @@ -431,7 +423,7 @@ def status_updated(self): if ColorMode.HS in self.supported_color_modes: color = self.dp_value(CONF_COLOR) - if color is not None: + if color is not None and not self.is_white_mode: if self.__is_color_rgb_encoded(): hue = int(color[6:10], 16) sat = int(color[10:12], 16) @@ -444,6 +436,8 @@ def status_updated(self): ] self._hs = [hue, sat / 10.0] self._brightness = value + elif self._brightness is None: + self._brightness = 20 if ColorMode.COLOR_TEMP in self.supported_color_modes: self._color_temp = self.dp_value(CONF_COLOR_TEMP) diff --git a/custom_components/localtuya/select.py b/custom_components/localtuya/select.py index 79b6195e4..fd073dbe2 100644 --- a/custom_components/localtuya/select.py +++ b/custom_components/localtuya/select.py @@ -5,12 +5,12 @@ import voluptuous as vol from homeassistant.components.select import DOMAIN, SelectEntity from homeassistant.const import CONF_DEVICE_CLASS, STATE_UNKNOWN +from homeassistant.helpers import selector from .common import LocalTuyaEntity, async_setup_entry from .const import ( CONF_DEFAULT_VALUE, CONF_OPTIONS, - CONF_OPTIONS_FRIENDLY, CONF_PASSIVE_ENTITY, CONF_RESTORE_ON_RECONNECT, ) @@ -19,8 +19,7 @@ def flow_schema(dps): """Return schema used in config flow.""" return { - vol.Required(CONF_OPTIONS): str, - vol.Optional(CONF_OPTIONS_FRIENDLY): str, + vol.Required(CONF_OPTIONS, default={}): selector.ObjectSelector(), vol.Required(CONF_RESTORE_ON_RECONNECT): bool, vol.Required(CONF_PASSIVE_ENTITY): bool, vol.Optional(CONF_DEFAULT_VALUE): str, @@ -44,47 +43,23 @@ def __init__( super().__init__(device, config_entry, sensorid, _LOGGER, **kwargs) self._state = STATE_UNKNOWN self._state_friendly = "" - self._valid_options = self._config.get(CONF_OPTIONS).split(";") - # We split using comma, we still gonna use ; a little bit old configure devices. - if "," in self._config.get(CONF_OPTIONS): - self._valid_options = self._config.get(CONF_OPTIONS).split(",") # Set Display options - self._display_options = [] - display_options_str = "" - if CONF_OPTIONS_FRIENDLY in self._config: - display_options_str = self._config.get(CONF_OPTIONS_FRIENDLY).strip() - _LOGGER.debug("Display Options Configured: %s", display_options_str) - - if display_options_str.find(";") >= 0: - self._display_options = display_options_str.split(";") - elif display_options_str.find(",") >= 0: - self._display_options = display_options_str.split(",") - elif len(display_options_str.strip()) > 0: - self._display_options.append(display_options_str) - else: - # Default display string to raw string - _LOGGER.debug("No Display options configured - defaulting to raw values") - self._display_options = self._valid_options - - # Remove white spaces on the start - self._display_options = [opt.lstrip() for opt in self._display_options] - self._valid_options = [opt.lstrip() for opt in self._valid_options] + options_values, options_display_name = [], [] + for k, v in self._config.get(CONF_OPTIONS, {}).items(): + options_values.append(k) + options_display_name.append(v if v else k.replace("_", "").capitalize()) + + self._valid_options = options_values + self._display_options = options_display_name + + _LOGGER.debug("Display Options Configured: %s", options_display_name) _LOGGER.debug( "Total Raw Options: %s - Total Display Options: %s", str(len(self._valid_options)), str(len(self._display_options)), ) - if len(self._valid_options) > len(self._display_options): - # If list of display items smaller than list of valid items, - # then default remaining items to be the raw value - _LOGGER.debug( - "Valid options is larger than display options - \ - filling up with raw values" - ) - for i in range(len(self._display_options), len(self._valid_options)): - self._display_options.append(self._valid_options[i]) @property def current_option(self) -> str: diff --git a/custom_components/localtuya/translations/ar.json b/custom_components/localtuya/translations/ar.json index d3ea3df59..2fcf9992c 100644 --- a/custom_components/localtuya/translations/ar.json +++ b/custom_components/localtuya/translations/ar.json @@ -141,103 +141,107 @@ }, "configure_entity": { "title": "Configure entity", - "description": "يرجى ملء التفاصيل الخاصة بـ {entity} بالنوع {platform}. ", + "description": "Please fill out the details for {entity} with type {platform}. All settings (except for `Type` and `ID`) can be changed from the `Configure` page later.", "data": { - "id": "DP ID", - "friendly_name": "Friendly name for Entity", - "current": "Current", - "current_consumption": "Current Consumption", - "voltage": "Voltage", - "commands_set": "Open_Close_Stop Commands Set", - "positioning_mode": "Positioning mode", - "current_position_dp": "Current Position (for *position* mode only)", - "set_position_dp": "Set Position (for *position* mode only)", - "position_inverted": "Invert 0-100 position (for *position* mode only)", - "span_time": "Full opening time, in secs. (for *timed* mode only)", - "unit_of_measurement": "Unit of Measurement (optional)", - "device_class": "(Optional) Device Class", - "state_class": "(Optional) State Class", - "scaling": "Scaling Factor", - "state_on": "On Value", - "state_off": "Off Value", - "powergo_dp": "Power DP (usually 25 or 2)", - "idle_status_value": "Idle Status (comma-separated)", - "returning_status_value": "Returning Status", - "docked_status_value": "Docked Status (comma-separated)", - "fault_dp": "Fault DP (usually 11)", - "battery_dp": "Battery status DP (usually 14)", - "mode_dp": "Mode DP (usually 27)", - "modes": "Modes list", - "return_mode": "Return home mode", - "fan_speed_dp": "Fan speeds DP (usually 30)", - "fan_speeds": "Fan speeds list (comma-separated)", - "clean_time_dp": "Clean Time DP (usually 33)", - "clean_area_dp": "Clean Area DP (usually 32)", - "clean_record_dp": "Clean Record DP (usually 34)", - "locate_dp": "Locate DP (usually 31)", - "paused_state": "Pause state (pause, paused, etc)", - "stop_status": "Stop status", - "brightness": "Brightness (only for white color)", - "brightness_lower": "Brightness Lower Value", - "brightness_upper": "Brightness Upper Value", - "color_temp": "Color Temperature", - "color_temp_reverse": "Reverse Color Temperature?", - "color": "Color", - "color_mode": "Color Mode aka Work Mode", - "color_temp_min_kelvin": "Minimum Color Temperature in K", - "color_temp_max_kelvin": "Maximum Color Temperature in K", - "music_mode": "Music mode available?", - "scene": "Scene", - "scene_values": "Scene values, separate entries by comma ','", - "scene_values_friendly": "User friendly scene values, separate entries by comma ','", - "select_options": "Valid entries, separate entries by comma ','", - "select_options_friendly": "User Friendly options, separate entries by comma ','", - "fan_speed_control": "Fan Speed Control DP", - "fan_oscillating_control": "Fan Oscillating Control DP", - "fan_speed_min": "minimum fan speed integer", - "fan_speed_max": "maximum fan speed integer", - "fan_speed_ordered_list": "Fan speed list (overrides speed min/max), separate entries by comma ','", - "fan_direction": "Fan Direction DP", - "fan_direction_forward": "Forward DP string", - "fan_direction_reverse": "Reverse DP string", - "fan_dps_type": "DP value type", - "current_temperature_dp": "Current Temperature", - "target_temperature_dp": "Target Temperature", - "temperature_step": "Temperature Step (optional)", - "max_temp": "Max Temperature (Number)", - "min_temp": "Min Temperature (Number)", - "precision": "Precision (optional, for DPs values)", - "target_precision": "Target Precision (optional, for DP values)", - "temperature_unit": "Temperature Unit (optional)", - "hvac_mode_dp": "HVAC Mode DP (optional)", - "hvac_mode_set": "HVAC Mode Set (optional)", - "hvac_action_dp": "HVAC Current Action DP (optional)", - "hvac_action_set": "HVAC Current Action Set (optional)", - "preset_dp": "Presets DP (optional)", - "preset_set": "Presets Set (optional)", - "eco_dp": "Eco DP (optional)", - "eco_value": "Eco value (optional)", - "heuristic_action": "Enable heuristic action (optional)", - "dps_default_value": "(Optional) Default value when un-initialised", - "restore_on_reconnect": "Restore the last value set in Home Assistant after lost connection?", - "min_value": "Minimum Value", - "max_value": "Maximum Value", - "step_size": "Minimum increment between numbers", - "is_passive_entity": "Passive entity? (requires integration to send initialisation value)", - "entity_category": "Show the entity in this category", - "humidifier_available_modes": "(optional) Avaliable modes in device, separate entries by comma ','", - "humidifier_current_humidity_dp": "(optional) Current Humidity DP", - "humidifier_mode_dp": "(optional) Set mode DP", - "humidifier_set_humidity_dp": "(optional) Set Humidity DP", - "min_humidity": "Set the minimum supported humidity", - "max_humidity": "Set the maximum supported humidity" + "id": "DP ID", + "friendly_name": "Friendly name for Entity", + "current": "Current", + "current_consumption": "Current Consumption", + "voltage": "Voltage", + "commands_set": "Open_Close_Stop Commands Set", + "positioning_mode": "Positioning mode", + "current_position_dp": "Current Position (for *position* mode only)", + "set_position_dp": "Set Position (for *position* mode only)", + "position_inverted": "Invert 0-100 position (for *position* mode only)", + "span_time": "Full opening time, in secs. (for *timed* mode only)", + "unit_of_measurement": "(Optional) Unit of Measurement", + "device_class": "(Optional) Device Class", + "state_class": "(Optional) State Class", + "scaling": "(Optional) Scaling Factor", + "state_on": "On Value", + "state_off": "Off Value", + "powergo_dp": "Power DP (usually 25 or 2)", + "idle_status_value": "Idle Status (comma-separated)", + "returning_status_value": "Returning Status", + "docked_status_value": "Docked Status (comma-separated)", + "fault_dp": "Fault DP (usually 11)", + "battery_dp": "Battery status DP (usually 14)", + "mode_dp": "Mode DP (usually 27)", + "modes": "Modes list", + "return_mode": "Return home mode", + "fan_speed_dp": "Fan speeds DP (usually 30)", + "fan_speeds": "Fan speeds list (comma-separated)", + "clean_time_dp": "Clean Time DP (usually 33)", + "clean_area_dp": "Clean Area DP (usually 32)", + "clean_record_dp": "Clean Record DP (usually 34)", + "locate_dp": "Locate DP (usually 31)", + "paused_state": "Pause state (pause, paused, etc)", + "stop_status": "Stop status", + "brightness": "Brightness (only for white color)", + "brightness_lower": "Brightness Lower Value", + "brightness_upper": "Brightness Upper Value", + "color_temp": "Color Temperature", + "color_temp_reverse": "Reverse Color Temperature?", + "color": "Color", + "color_mode": "Color Mode aka Work Mode", + "color_temp_min_kelvin": "Minimum Color Temperature in K", + "color_temp_max_kelvin": "Maximum Color Temperature in K", + "music_mode": "Music mode available?", + "scene": "Scene", + "scene_values": "(Optional) Scene values", + "select_options": "Valid entries", + "fan_speed_control": "Fan Speed Control DP", + "fan_oscillating_control": "Fan Oscillating Control DP", + "fan_speed_min": "minimum fan speed integer", + "fan_speed_max": "maximum fan speed integer", + "fan_speed_ordered_list": "Fan speed list (overrides speed min/max), separate entries by comma ','", + "fan_direction":"Fan Direction DP", + "fan_direction_forward": "Forward DP string", + "fan_direction_reverse": "Reverse DP string", + "fan_dps_type": "DP value type", + "current_temperature_dp": "Current Temperature", + "target_temperature_dp": "Target Temperature", + "temperature_step": "(Optional) Temperature Step", + "min_temperature": "Min Temperature", + "max_temperature": "Max Temperature", + "precision": "Precision (optional, for DPs values)", + "target_precision": "Target Precision (optional, for DP values)", + "temperature_unit": "(Optional) Temperature Unit", + "hvac_mode_dp": "(Optional) HVAC Mode DP", + "hvac_mode_set": "(Optional) HVAC Modes", + "hvac_add_off": "(Optional) Include `OFF` in HVAC Modes", + "hvac_action_dp": "(Optional) HVAC Current Action DP", + "hvac_action_set": "(Optional) HVAC Actions", + "preset_dp": "(Optional) Presets DP", + "preset_set": "(Optional) Presets", + "eco_dp": "(Optional) Eco DP", + "eco_value": "(Optional) Eco value", + "heuristic_action": "(Optional) Enable heuristic action", + "dps_default_value": "(Optional) Default value when un-initialised", + "restore_on_reconnect": "Restore the last value set in Home Assistant after lost connection?", + "min_value": "Minimum Value", + "max_value": "Maximum Value", + "step_size": "Minimum increment between numbers", + "is_passive_entity": "Passive entity? (requires integration to send initialisation value)", + "entity_category": "Show the entity in this category", + "humidifier_available_modes": "(Optional) Avaliable modes in device, separate entries by comma ','", + "humidifier_current_humidity_dp": "(Optional) Current Humidity DP", + "humidifier_mode_dp": "(Optional) Set mode DP", + "humidifier_set_humidity_dp": "(Optional) Set Humidity DP", + "min_humidity": "Set the minimum supported humidity", + "max_humidity": "Set the maximum supported humidity" }, "data_description": { - "device_class": "Find out more about [Device Classes](https://www.home-assistant.io/docs/configuration/customizing-devices/#device-class)", - "state_class": "Find out more about [State Classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes)" + "hvac_mode_set":"Each line represents [ hvac_mode: device_value ] [Supported HVAC Modes](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-modes)", + "hvac_action_set":"Each line represents [ hvac_action: device_value ] [Supported HVAC Actions](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-action)", + "preset_set":"Each line represents [ device_value: friendly name ]", + "scene_values":"Each line represents [ device_value: friendly name ]", + "select_options":"Each line represents [ device_value: friendly name ]", + "device_class": "Find out more about [Device Classes](https://www.home-assistant.io/docs/configuration/customizing-devices/#device-class)", + "state_class": "Find out more about [State Classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes)" } - } } - }, - "title": "LocalTuya" +} +}, +"title": "LocalTuya" } \ No newline at end of file diff --git a/custom_components/localtuya/translations/en.json b/custom_components/localtuya/translations/en.json index 5cc81f936..8cfddc685 100644 --- a/custom_components/localtuya/translations/en.json +++ b/custom_components/localtuya/translations/en.json @@ -192,10 +192,8 @@ "color_temp_max_kelvin": "Maximum Color Temperature in K", "music_mode": "Music mode available?", "scene": "Scene", - "scene_values": "Scene values, separate entries by comma ','", - "scene_values_friendly": "User friendly scene values, separate entries by comma ','", - "select_options": "Valid entries, separate entries by comma ','", - "select_options_friendly": "User Friendly options, separate entries by comma ','", + "scene_values": "(Optional) Scene values", + "select_options": "Valid entries", "fan_speed_control": "Fan Speed Control DP", "fan_oscillating_control": "Fan Oscillating Control DP", "fan_speed_min": "minimum fan speed integer", @@ -214,12 +212,12 @@ "target_precision": "Target Precision (optional, for DP values)", "temperature_unit": "(Optional) Temperature Unit", "hvac_mode_dp": "(Optional) HVAC Mode DP", - "hvac_mode_set": "(Optional) HVAC Mode Set", + "hvac_mode_set": "(Optional) HVAC Modes", "hvac_add_off": "(Optional) Include `OFF` in HVAC Modes", "hvac_action_dp": "(Optional) HVAC Current Action DP", - "hvac_action_set": "(Optional) HVAC Current Action Set", + "hvac_action_set": "(Optional) HVAC Actions", "preset_dp": "(Optional) Presets DP", - "preset_set": "(Optional) Presets Set", + "preset_set": "(Optional) Presets", "eco_dp": "(Optional) Eco DP", "eco_value": "(Optional) Eco value", "heuristic_action": "(Optional) Enable heuristic action", @@ -238,6 +236,11 @@ "max_humidity": "Set the maximum supported humidity" }, "data_description": { + "hvac_mode_set":"Each line represents [ hvac_mode: device_value ] [Supported HVAC Modes](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-modes)", + "hvac_action_set":"Each line represents [ hvac_action: device_value ] [Supported HVAC Actions](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-action)", + "preset_set":"Each line represents [ device_value: friendly name ]", + "scene_values":"Each line represents [ device_value: friendly name ]", + "select_options":"Each line represents [ device_value: friendly name ]", "device_class": "Find out more about [Device Classes](https://www.home-assistant.io/docs/configuration/customizing-devices/#device-class)", "state_class": "Find out more about [State Classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes)" } diff --git a/custom_components/localtuya/translations/it.json b/custom_components/localtuya/translations/it.json index 2c496bd94..9576f4cda 100644 --- a/custom_components/localtuya/translations/it.json +++ b/custom_components/localtuya/translations/it.json @@ -140,7 +140,7 @@ }, "configure_entity": { "title": "Configure entity", - "description": "Si prega di compilare i dettagli per {entity} con tipo {platform}. Tutte le impostazioni (tranne `Tipo` e `ID`) possono essere modificate in seguito dalla pagina `Configura.", + "description": "Please fill out the details for {entity} with type {platform}. All settings (except for `Type` and `ID`) can be changed from the `Configure` page later.", "data": { "id": "DP ID", "friendly_name": "Friendly name for Entity", @@ -153,10 +153,10 @@ "set_position_dp": "Set Position (for *position* mode only)", "position_inverted": "Invert 0-100 position (for *position* mode only)", "span_time": "Full opening time, in secs. (for *timed* mode only)", - "unit_of_measurement": "Unit of Measurement (optional)", + "unit_of_measurement": "(Optional) Unit of Measurement", "device_class": "(Optional) Device Class", "state_class": "(Optional) State Class", - "scaling": "Scaling Factor", + "scaling": "(Optional) Scaling Factor", "state_on": "On Value", "state_off": "Off Value", "powergo_dp": "Power DP (usually 25 or 2)", @@ -182,15 +182,13 @@ "color_temp": "Color Temperature", "color_temp_reverse": "Reverse Color Temperature?", "color": "Color", - "color_mode": "Color Mode also Work Mode", + "color_mode": "Color Mode aka Work Mode", "color_temp_min_kelvin": "Minimum Color Temperature in K", "color_temp_max_kelvin": "Maximum Color Temperature in K", "music_mode": "Music mode available?", "scene": "Scene", - "scene_values": "Scene values, separate entries by comma ','", - "scene_values_friendly": "User friendly scene values, separate entries by comma ','", - "select_options": "Valid entries, separate entries by comma ','", - "select_options_friendly": "User Friendly options, separate entries by comma ','", + "scene_values": "(Optional) Scene values", + "select_options": "Valid entries", "fan_speed_control": "Fan Speed Control DP", "fan_oscillating_control": "Fan Oscillating Control DP", "fan_speed_min": "minimum fan speed integer", @@ -202,22 +200,22 @@ "fan_dps_type": "DP value type", "current_temperature_dp": "Current Temperature", "target_temperature_dp": "Target Temperature", - "temperature_step": "Temperature Step (optional)", - "max_temp": "Max Temperature (Number)", - "min_temp": "Min Temperature (Number)", + "temperature_step": "(Optional) Temperature Step", + "min_temperature": "Min Temperature", + "max_temperature": "Max Temperature", "precision": "Precision (optional, for DPs values)", "target_precision": "Target Precision (optional, for DP values)", - "temperature_unit": "Temperature Unit (optional)", - "hvac_mode_dp": "HVAC Mode DP (optional)", - "hvac_mode_set": "HVAC Mode Set (optional)", + "temperature_unit": "(Optional) Temperature Unit", + "hvac_mode_dp": "(Optional) HVAC Mode DP", + "hvac_mode_set": "(Optional) HVAC Modes", "hvac_add_off": "(Optional) Include `OFF` in HVAC Modes", - "hvac_action_dp": "HVAC Current Action DP (optional)", - "hvac_action_set": "HVAC Current Action Set (optional)", - "preset_dp": "Presets DP (optional)", - "preset_set": "Presets Set (optional)", - "eco_dp": "Eco DP (optional)", - "eco_value": "Eco value (optional)", - "heuristic_action": "Enable heuristic action (optional)", + "hvac_action_dp": "(Optional) HVAC Current Action DP", + "hvac_action_set": "(Optional) HVAC Actions", + "preset_dp": "(Optional) Presets DP", + "preset_set": "(Optional) Presets", + "eco_dp": "(Optional) Eco DP", + "eco_value": "(Optional) Eco value", + "heuristic_action": "(Optional) Enable heuristic action", "dps_default_value": "(Optional) Default value when un-initialised", "restore_on_reconnect": "Restore the last value set in Home Assistant after lost connection?", "min_value": "Minimum Value", @@ -225,14 +223,19 @@ "step_size": "Minimum increment between numbers", "is_passive_entity": "Passive entity? (requires integration to send initialisation value)", "entity_category": "Show the entity in this category", - "humidifier_available_modes": "(optional) Avaliable modes in device, separate entries by comma ','", - "humidifier_current_humidity_dp": "(optional) Current Humidity DP", - "humidifier_mode_dp": "(optional) Set mode DP", - "humidifier_set_humidity_dp": "(optional) Set Humidity DP", + "humidifier_available_modes": "(Optional) Avaliable modes in device, separate entries by comma ','", + "humidifier_current_humidity_dp": "(Optional) Current Humidity DP", + "humidifier_mode_dp": "(Optional) Set mode DP", + "humidifier_set_humidity_dp": "(Optional) Set Humidity DP", "min_humidity": "Set the minimum supported humidity", "max_humidity": "Set the maximum supported humidity" }, "data_description": { + "hvac_mode_set":"Each line represents [ hvac_mode: device_value ] [Supported HVAC Modes](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-modes)", + "hvac_action_set":"Each line represents [ hvac_action: device_value ] [Supported HVAC Actions](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-action)", + "preset_set":"Each line represents [ device_value: friendly name ]", + "scene_values":"Each line represents [ device_value: friendly name ]", + "select_options":"Each line represents [ device_value: friendly name ]", "device_class": "Find out more about [Device Classes](https://www.home-assistant.io/docs/configuration/customizing-devices/#device-class)", "state_class": "Find out more about [State Classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes)" } @@ -240,4 +243,4 @@ } }, "title": "LocalTuya" -} +} \ No newline at end of file diff --git a/custom_components/localtuya/translations/pl.json b/custom_components/localtuya/translations/pl.json index 28fdca357..4b90cde98 100644 --- a/custom_components/localtuya/translations/pl.json +++ b/custom_components/localtuya/translations/pl.json @@ -192,10 +192,8 @@ "color_temp_max_kelvin": "Maksymalna temperatura barwowa w K", "music_mode": "Dostępny tryb muzyczny", "scene": "Scena", - "scene_values": "Wartości scen, wpisy oddziel przecinkami ','", - "scene_values_friendly": "Przyjazne dla użytkownika wartości scen, wpisy oddziel przecinkami ','", - "select_options": "Prawidłowe wpisy, oddzielaj wpisy przecinkami ','", - "select_options_friendly": "Opcje przyjazne dla użytkownika, wpisy oddzielaj przecinkami ','", + "scene_values": "Wartości scen", + "select_options": "Prawidłowe wpisy", "fan_speed_control": "DP Kontroli prędkości wentylatora", "fan_oscillating_control": "DP Sterowania oscylacyjnego wentylatora", "fan_speed_min": "minimalna prędkość wentylatora", @@ -238,6 +236,11 @@ "max_humidity": "Ustaw maksymalną obsługiwaną wilgotność" }, "data_description": { + "hvac_mode_set":"Każda linia reprezentuje [ hvac_mode: device_value ] [Obsługiwane tryby HVAC](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-modes)", + "hvac_action_set":"Każda linia reprezentuje [ hvac_action: device_value ] [Obsługiwane działania HVAC](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-action)", + "preset_set":"Każda linia reprezentuje [ device_value: friendly name ]", + "scene_values":"Każda linia reprezentuje [ device_value: friendly name ]", + "select_options":"Każda linia reprezentuje [ device_value: friendly name ]", "device_class": "Dowiedz się więcej o [Klasach urządzeń](https://www.home-assistant.io/docs/configuration/customizing-devices/#device-class)", "state_class": "Dowiedz się więcej o [Klasach stanów](https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes)" } diff --git a/custom_components/localtuya/translations/pt-BR.json b/custom_components/localtuya/translations/pt-BR.json index a242fd77c..5782e15c2 100644 --- a/custom_components/localtuya/translations/pt-BR.json +++ b/custom_components/localtuya/translations/pt-BR.json @@ -140,7 +140,7 @@ }, "configure_entity": { "title": "Configure entity", - "description": "Por favor, preencha os detalhes de {entity} com o tipo `{platform}`. Todas as configurações, exceto `ID`, podem ser alteradas na página Opções posteriormente.", + "description": "Please fill out the details for {entity} with type {platform}. All settings (except for `Type` and `ID`) can be changed from the `Configure` page later.", "data": { "id": "DP ID", "friendly_name": "Friendly name for Entity", @@ -153,10 +153,10 @@ "set_position_dp": "Set Position (for *position* mode only)", "position_inverted": "Invert 0-100 position (for *position* mode only)", "span_time": "Full opening time, in secs. (for *timed* mode only)", - "unit_of_measurement": "Unit of Measurement (optional)", + "unit_of_measurement": "(Optional) Unit of Measurement", "device_class": "(Optional) Device Class", "state_class": "(Optional) State Class", - "scaling": "Scaling Factor", + "scaling": "(Optional) Scaling Factor", "state_on": "On Value", "state_off": "Off Value", "powergo_dp": "Power DP (usually 25 or 2)", @@ -187,10 +187,8 @@ "color_temp_max_kelvin": "Maximum Color Temperature in K", "music_mode": "Music mode available?", "scene": "Scene", - "scene_values": "Scene values, separate entries by comma ','", - "scene_values_friendly": "User friendly scene values, separate entries by comma ','", - "select_options": "Valid entries, separate entries by comma ','", - "select_options_friendly": "User Friendly options, separate entries by comma ','", + "scene_values": "(Optional) Scene values", + "select_options": "Valid entries", "fan_speed_control": "Fan Speed Control DP", "fan_oscillating_control": "Fan Oscillating Control DP", "fan_speed_min": "minimum fan speed integer", @@ -202,22 +200,22 @@ "fan_dps_type": "DP value type", "current_temperature_dp": "Current Temperature", "target_temperature_dp": "Target Temperature", - "temperature_step": "Temperature Step (optional)", - "max_temp": "Max Temperature (Number)", - "min_temp": "Min Temperature (Number)", + "temperature_step": "(Optional) Temperature Step", + "min_temperature": "Min Temperature", + "max_temperature": "Max Temperature", "precision": "Precision (optional, for DPs values)", "target_precision": "Target Precision (optional, for DP values)", - "temperature_unit": "Temperature Unit (optional)", - "hvac_mode_dp": "HVAC Mode DP (optional)", - "hvac_mode_set": "HVAC Mode Set (optional)", + "temperature_unit": "(Optional) Temperature Unit", + "hvac_mode_dp": "(Optional) HVAC Mode DP", + "hvac_mode_set": "(Optional) HVAC Modes", "hvac_add_off": "(Optional) Include `OFF` in HVAC Modes", - "hvac_action_dp": "HVAC Current Action DP (optional)", - "hvac_action_set": "HVAC Current Action Set (optional)", - "preset_dp": "Presets DP (optional)", - "preset_set": "Presets Set (optional)", - "eco_dp": "Eco DP (optional)", - "eco_value": "Eco value (optional)", - "heuristic_action": "Enable heuristic action (optional)", + "hvac_action_dp": "(Optional) HVAC Current Action DP", + "hvac_action_set": "(Optional) HVAC Actions", + "preset_dp": "(Optional) Presets DP", + "preset_set": "(Optional) Presets", + "eco_dp": "(Optional) Eco DP", + "eco_value": "(Optional) Eco value", + "heuristic_action": "(Optional) Enable heuristic action", "dps_default_value": "(Optional) Default value when un-initialised", "restore_on_reconnect": "Restore the last value set in Home Assistant after lost connection?", "min_value": "Minimum Value", @@ -225,14 +223,19 @@ "step_size": "Minimum increment between numbers", "is_passive_entity": "Passive entity? (requires integration to send initialisation value)", "entity_category": "Show the entity in this category", - "humidifier_available_modes": "(optional) Avaliable modes in device, separate entries by comma ','", - "humidifier_current_humidity_dp": "(optional) Current Humidity DP", - "humidifier_mode_dp": "(optional) Set mode DP", - "humidifier_set_humidity_dp": "(optional) Set Humidity DP", + "humidifier_available_modes": "(Optional) Avaliable modes in device, separate entries by comma ','", + "humidifier_current_humidity_dp": "(Optional) Current Humidity DP", + "humidifier_mode_dp": "(Optional) Set mode DP", + "humidifier_set_humidity_dp": "(Optional) Set Humidity DP", "min_humidity": "Set the minimum supported humidity", "max_humidity": "Set the maximum supported humidity" }, "data_description": { + "hvac_mode_set":"Each line represents [ hvac_mode: device_value ] [Supported HVAC Modes](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-modes)", + "hvac_action_set":"Each line represents [ hvac_action: device_value ] [Supported HVAC Actions](https://developers.home-assistant.io/docs/core/entity/climate/#hvac-action)", + "preset_set":"Each line represents [ device_value: friendly name ]", + "scene_values":"Each line represents [ device_value: friendly name ]", + "select_options":"Each line represents [ device_value: friendly name ]", "device_class": "Find out more about [Device Classes](https://www.home-assistant.io/docs/configuration/customizing-devices/#device-class)", "state_class": "Find out more about [State Classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-state-classes)" } @@ -240,4 +243,4 @@ } }, "title": "LocalTuya" -} +} \ No newline at end of file