Skip to content

Commit

Permalink
Add support for IR Remote with enum control type #189
Browse files Browse the repository at this point in the history
  • Loading branch information
xZetsubou committed Apr 3, 2024
1 parent cdc1257 commit a797350
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 24 deletions.
6 changes: 1 addition & 5 deletions custom_components/localtuya/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions custom_components/localtuya/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@

# Remote
CONF_RECEIVE_DP = "receive_dp"
CONF_KEY_STUDY_DP = "key_study_dp"

# States
ATTR_STATE = "raw_state"
Expand Down
1 change: 1 addition & 0 deletions custom_components/localtuya/core/ha_entities/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
1 change: 1 addition & 0 deletions custom_components/localtuya/core/ha_entities/remotes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
LocalTuyaEntity(
id=DPCode.IR_SEND,
receive_dp=DPCode.IR_STUDY_CODE,
key_study_dp=DPCode.KEY_STUDY,
),
),
}
57 changes: 43 additions & 14 deletions custom_components/localtuya/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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):
Expand All @@ -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),
}


Expand All @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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."""
Expand All @@ -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.",
Expand All @@ -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:
Expand Down Expand Up @@ -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."""
Expand All @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
3 changes: 2 additions & 1 deletion custom_components/localtuya/translations/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
3 changes: 2 additions & 1 deletion custom_components/localtuya/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
3 changes: 2 additions & 1 deletion custom_components/localtuya/translations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
3 changes: 2 additions & 1 deletion custom_components/localtuya/translations/pl.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
3 changes: 2 additions & 1 deletion custom_components/localtuya/translations/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down

0 comments on commit a797350

Please sign in to comment.