infrared.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. """
  2. Implementation of Tuya infrared control devices
  3. """
  4. import asyncio
  5. import json
  6. import logging
  7. from homeassistant.components.infrared import InfraredCommand, InfraredEntity
  8. from tinytuya.Contrib.IRRemoteControlDevice import IRRemoteControlDevice as IR
  9. from .device import TuyaLocalDevice
  10. from .entity import TuyaLocalEntity
  11. from .helpers.config import async_tuya_setup_platform
  12. from .helpers.device_config import TuyaEntityConfig
  13. _LOGGER = logging.getLogger(__name__)
  14. async def async_setup_entry(hass, entry, async_add_entities):
  15. """Set up the Tuya Local infrared control platform."""
  16. config = {**entry.data, **entry.options}
  17. await async_tuya_setup_platform(
  18. hass,
  19. async_add_entities,
  20. config,
  21. "infrared",
  22. TuyaLocalInfrared,
  23. )
  24. class TuyaLocalInfrared(TuyaLocalEntity, InfraredEntity):
  25. """Representation of a Tuya Local infrared control device."""
  26. def __init__(self, device: TuyaLocalDevice, config: TuyaEntityConfig):
  27. """Initialize the infrared control device."""
  28. super().__init__()
  29. dps_map = self._init_begin(device, config)
  30. self._send_dp = dps_map.pop("send", None)
  31. self._command_dp = dps_map.pop("control", None)
  32. self._type_dp = dps_map.pop("code_type", None)
  33. self._init_end(dps_map)
  34. async def async_send_command(self, command: InfraredCommand) -> None:
  35. """Handle sending an infrared command."""
  36. timings = command.get_raw_timings()
  37. split = {}
  38. raw = []
  39. i = 0
  40. for timing in timings:
  41. if timing.high_us > 50000:
  42. split[i] = timing.high_us - 5000
  43. raw.append(5000)
  44. raw.append(timing.low_us)
  45. elif timing.low_us > 50000:
  46. raw.append(timing.high_us)
  47. raw.append(5000)
  48. split[i + 2] = timing.low_us - 5000
  49. else:
  50. raw.append(timing.high_us)
  51. raw.append(timing.low_us)
  52. i += 2
  53. # HA's converter leaves the last low timing as 0, but Tuya seems to expect around 5 - 10 ms
  54. if raw[-1] == 0:
  55. raw[-1] = 5000
  56. start = 0
  57. for s, t in split.items():
  58. tuya_command = IR.pulses_to_base64(raw[start:s])
  59. _LOGGER.info("%s sending command: %s", self._config.config_id, tuya_command)
  60. start = s
  61. await self._ir_send(tuya_command)
  62. await asyncio.sleep(t / 1000000.0)
  63. if start < len(raw):
  64. tuya_command = IR.pulses_to_base64(raw[start:])
  65. _LOGGER.info("%s sending command: %s", self._config.config_id, tuya_command)
  66. await self._ir_send(tuya_command)
  67. async def _ir_send(self, tuya_command: str):
  68. """Send the infrared command to the device."""
  69. if self._send_dp:
  70. if self._command_dp:
  71. await self._device.async_set_properties(
  72. self._package_multi_dp_send(tuya_command)
  73. )
  74. else:
  75. await self._send_dp.async_set_value(
  76. self._device,
  77. self._package_single_dp_send(tuya_command),
  78. )
  79. def _package_single_dp_send(self, command: str) -> str:
  80. """Package the command for a single DP (usually dp id 201) send."""
  81. json_command = {
  82. "control": "send_ir",
  83. "type": 0,
  84. "head": "",
  85. "key1": "1" + command,
  86. }
  87. return json.dumps(json_command)
  88. def _package_multi_dp_send(self, command: str) -> dict:
  89. """Package the command for a multi DP send"""
  90. return {
  91. f"{self._command_dp.id}": "send_ir",
  92. f"{self._type_dp.id}": 0,
  93. f"{self._send_dp.id}": command,
  94. }