diff --git a/custom_components/localtuya/config_flow.py b/custom_components/localtuya/config_flow.py index af91729fc..f70241d15 100644 --- a/custom_components/localtuya/config_flow.py +++ b/custom_components/localtuya/config_flow.py @@ -433,7 +433,7 @@ async def validate_input(hass: core.HomeAssistant, entry_id, data): for new_dps in manual_dps_list + (reset_ids or []): # If the DPS not in the detected dps list, then add with a # default value indicating that it has been manually added - if str(new_dps) not in detected_dps: + if str(new_dps) not in detected_dps and not str(new_dps) == "0": detected_dps[new_dps] = -1 except (ConnectionRefusedError, ConnectionResetError) as ex: @@ -1154,10 +1154,6 @@ def available_dps_strings(self): used_dps = [str(entity[CONF_ID]) for entity in self.entities] for dp_string in self.dps_strings: dp = dp_string.split(" ")[0] - # 0 Is only using to bypass status check. - if dp == "0": - continue - if dp not in used_dps: available_dps.append(dp_string) return available_dps diff --git a/custom_components/localtuya/const.py b/custom_components/localtuya/const.py index df7fca333..7b64adef0 100644 --- a/custom_components/localtuya/const.py +++ b/custom_components/localtuya/const.py @@ -160,6 +160,7 @@ # Remote CONF_RECEIVE_DP = "receive_dp" +CONF_KEY_STUDY_DP = "key_study_dp" # States ATTR_STATE = "raw_state" diff --git a/custom_components/localtuya/core/ha_entities/base.py b/custom_components/localtuya/core/ha_entities/base.py index 3f82b812e..2f799dda3 100644 --- a/custom_components/localtuya/core/ha_entities/base.py +++ b/custom_components/localtuya/core/ha_entities/base.py @@ -310,6 +310,7 @@ class DPCode(StrEnum): IPC_WORK_MODE = "ipc_work_mode" IR_SEND = "ir_send" IR_STUDY_CODE = "ir_study_code" + KEY_STUDY = "key_study" LED_TYPE_1 = "led_type_1" LED_TYPE_2 = "led_type_2" LED_TYPE_3 = "led_type_3" diff --git a/custom_components/localtuya/core/ha_entities/remotes.py b/custom_components/localtuya/core/ha_entities/remotes.py index f7fd2aca7..75649fdab 100644 --- a/custom_components/localtuya/core/ha_entities/remotes.py +++ b/custom_components/localtuya/core/ha_entities/remotes.py @@ -25,6 +25,7 @@ LocalTuyaEntity( id=DPCode.IR_SEND, receive_dp=DPCode.IR_STUDY_CODE, + key_study_dp=DPCode.KEY_STUDY, ), ), } diff --git a/custom_components/localtuya/remote.py b/custom_components/localtuya/remote.py index 7425a8a06..fca30b988 100644 --- a/custom_components/localtuya/remote.py +++ b/custom_components/localtuya/remote.py @@ -30,7 +30,7 @@ from homeassistant.helpers.storage import Store from .common import LocalTuyaEntity, async_setup_entry -from .const import CONF_RECEIVE_DP +from .const import CONF_RECEIVE_DP, CONF_KEY_STUDY_DP NSDP_CONTROL = "control" # The control commands NSDP_TYPE = "type" # The identifier of an IR library @@ -41,9 +41,15 @@ class ControlType(StrEnum): + ENUM = "Enum" + JSON = "Json" + + +class ControlMode(StrEnum): SEND_IR = "send_ir" STUDY = "study" STUDY_EXIT = "study_exit" + STUDY_KEY = "study_key" class RemoteDP(StrEnum): @@ -61,6 +67,7 @@ def flow_schema(dps): vol.Optional( CONF_RECEIVE_DP, default=RemoteDP.DP_RECIEVE.value ): _col_to_select(dps, is_dps=True), + vol.Optional(CONF_KEY_STUDY_DP): _col_to_select(dps, is_dps=True), } @@ -79,6 +86,7 @@ def __init__( self._dp_send = str(self._config.get(self._dp_id, RemoteDP.DP_SEND)) self._dp_recieve = str(self._config.get(CONF_RECEIVE_DP, RemoteDP.DP_RECIEVE)) + self._dp_key_study = self._config.get(CONF_KEY_STUDY_DP) self._device_id = self._device_config.id @@ -98,6 +106,13 @@ def __init__( RemoteEntityFeature.LEARN_COMMAND | RemoteEntityFeature.DELETE_COMMAND ) + @property + def _ir_control_type(self): + if self.has_config(CONF_KEY_STUDY_DP): + return ControlType.ENUM + else: + return ControlType.JSON + async def async_turn_on(self, **kwargs: Any) -> None: """Turn on the remote.""" self._attr_is_on = True @@ -140,13 +155,13 @@ async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> Non if repeats: current_repeat = 0 while current_repeat < repeats: - await self.send_signal(ControlType.SEND_IR, base64_code) + await self.send_signal(ControlMode.SEND_IR, base64_code) if repeats_delay: await asyncio.sleep(repeats_delay) current_repeat += 1 continue - await self.send_signal(ControlType.SEND_IR, base64_code) + await self.send_signal(ControlMode.SEND_IR, base64_code) async def async_learn_command(self, **kwargs: Any) -> None: """Learn a command from a device.""" @@ -168,7 +183,7 @@ async def async_learn_command(self, **kwargs: Any) -> None: for command in commands: last_code = self._last_code - await self.send_signal(ControlType.STUDY) + await self.send_signal(ControlMode.STUDY) persistent_notification.async_create( self.hass, f"Press the '{command}' button.", @@ -181,14 +196,14 @@ async def async_learn_command(self, **kwargs: Any) -> None: if last_code != (dp_code := self.dp_value(RemoteDP.DP_RECIEVE)): self._last_code = dp_code sucess = True - await self.send_signal(ControlType.STUDY_EXIT) + await self.send_signal(ControlMode.STUDY_EXIT) break now += 1 await asyncio.sleep(1) if not sucess: - await self.send_signal(ControlType.STUDY_EXIT) + await self.send_signal(ControlMode.STUDY_EXIT) raise ServiceValidationError(f"Failed to learn: {command}") finally: @@ -219,14 +234,24 @@ async def async_delete_command(self, **kwargs: Any) -> None: await self._delete_command(device, command) async def send_signal(self, control, base64_code=None): - command = {NSDP_CONTROL: control} + if self._ir_control_type == ControlType.ENUM: + command = {self._dp_id: control} + if control == ControlMode.SEND_IR: + command[self._dp_id] = ControlMode.STUDY_KEY.value + command[self._dp_key_study] = base64_code + + else: + command = {NSDP_CONTROL: control} - if control == ControlType.SEND_IR: - command[NSDP_TYPE] = 0 - command[NSDP_HEAD] = "" - command[NSDP_KEY1] = base64_code + if control == ControlMode.SEND_IR: + command[NSDP_TYPE] = 0 + command[NSDP_HEAD] = "" # also known as ir_code + command[NSDP_KEY1] = base64_code # also code: key_code - await self._device.set_dp(json.dumps(command), self._dp_send) + command = {self._dp_id: json.dumps(command)} + + _LOGGER.debug(f"Sending: {command}") + await self._device.set_dps(command) async def _delete_command(self, device, command) -> None: """Store new code into stoarge.""" @@ -238,7 +263,9 @@ async def _delete_command(self, device, command) -> None: devices_data = codes_data[ir_controller] if device not in devices_data: - raise ServiceValidationError(f"Couldn't find the device: {device}.") + raise ServiceValidationError( + f"Couldn't find the device: {device} available devices is on this IR Remote is: {list(devices_data)}." + ) commands = devices_data[device] if command not in commands: @@ -299,7 +326,9 @@ def _get_code(self, device, command): devices_data = codes_data[ir_controller] if device not in devices_data: - raise ServiceValidationError(f"Couldn't find the device: {device}.") + raise ServiceValidationError( + f"Couldn't find the device: {device} available devices is on this IR Remote is: {list(devices_data)}." + ) commands = devices_data[device] if command not in commands: diff --git a/custom_components/localtuya/translations/ar.json b/custom_components/localtuya/translations/ar.json index 74756f14c..e8850c5c3 100644 --- a/custom_components/localtuya/translations/ar.json +++ b/custom_components/localtuya/translations/ar.json @@ -234,7 +234,8 @@ "min_humidity": "Set the minimum supported humidity", "max_humidity": "Set the maximum supported humidity", "alarm_supported_states": "States supported by the device", - "receive_dp":"Receiving signals DP. (default is 202)" + "receive_dp":"Receiving signals DP. (default is 202)", + "key_study_dp":"(Optional) Key Study DP (usually 7)" }, "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)", diff --git a/custom_components/localtuya/translations/en.json b/custom_components/localtuya/translations/en.json index 7e865de83..24e56d998 100644 --- a/custom_components/localtuya/translations/en.json +++ b/custom_components/localtuya/translations/en.json @@ -238,7 +238,8 @@ "min_humidity": "Set the minimum supported humidity", "max_humidity": "Set the maximum supported humidity", "alarm_supported_states": "States supported by the device", - "receive_dp":"Receiving signals DP. (default is 202)" + "receive_dp":"Receiving signals DP. (default is 202)", + "key_study_dp":"(Optional) Key Study DP (usually 7)" }, "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)", diff --git a/custom_components/localtuya/translations/it.json b/custom_components/localtuya/translations/it.json index c0abd9e21..2f597d3d8 100644 --- a/custom_components/localtuya/translations/it.json +++ b/custom_components/localtuya/translations/it.json @@ -233,7 +233,8 @@ "min_humidity": "Set the minimum supported humidity", "max_humidity": "Set the maximum supported humidity", "alarm_supported_states": "States supported by the device", - "receive_dp":"Receiving signals DP. (default is 202)" + "receive_dp":"Receiving signals DP. (default is 202)", + "key_study_dp":"(Optional) Key Study DP (usually 7)" }, "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)", diff --git a/custom_components/localtuya/translations/pl.json b/custom_components/localtuya/translations/pl.json index e6f8f54d1..f7818ae51 100644 --- a/custom_components/localtuya/translations/pl.json +++ b/custom_components/localtuya/translations/pl.json @@ -238,7 +238,8 @@ "min_humidity": "Ustaw minimalną obsługiwaną wilgotność", "max_humidity": "Ustaw maksymalną obsługiwaną wilgotność", "alarm_supported_states": "States supported by the device", - "receive_dp":"Receiving signals DP. (default is 202)" + "receive_dp":"Receiving signals DP. (default is 202)", + "key_study_dp":"(Optional) Key Study DP (usually 7)" }, "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)", diff --git a/custom_components/localtuya/translations/pt-BR.json b/custom_components/localtuya/translations/pt-BR.json index e0a91de1a..82d13e027 100644 --- a/custom_components/localtuya/translations/pt-BR.json +++ b/custom_components/localtuya/translations/pt-BR.json @@ -233,7 +233,8 @@ "min_humidity": "Set the minimum supported humidity", "max_humidity": "Set the maximum supported humidity", "alarm_supported_states": "States supported by the device", - "receive_dp":"Receiving signals DP. (default is 202)" + "receive_dp":"Receiving signals DP. (default is 202)", + "key_study_dp":"(Optional) Key Study DP (usually 7)" }, "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)",