AppleTV integration keyboard commands

I would like to be able to send text to my Apple TV.

The Apple TV integration uses the pyatv library, which already supports this feature.

However, remote.send_command of the Apple TV integration only interacts with the atv.remote_control interface. It would be great to support the list of commands in atv.keyboard.

Here’s an updated implementation that supports all methods on atv with up to 1 string or int argument. That makes e.g. keyword.text_set callable via remote.send_command.

    async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None:
        """Send a command to one device."""
        num_repeats = kwargs[ATTR_NUM_REPEATS]
        delay = kwargs.get(ATTR_DELAY_SECS, DEFAULT_DELAY_SECS)

        if not self.is_on:
            _LOGGER.error("Unable to send commands, not connected to %s", self.name)
            return

        for _ in range(num_repeats):
            for single_command in command:
                split = single_command.split(' ')
                command_name = split[0]
                if '.' in command_name:
                    attr_value = self.atv
                    for command_path in command_name.split('.'):
                        attr_value = getattr(attr_value, command_path, None)
                else:
                    attr_value = getattr(self.atv.remote_control, single_command, None)
                if not attr_value:
                    raise ValueError("Command not found. Exiting sequence!!!")

                _LOGGER.info("Sending command %s", single_command)
                arg = ' '.join(split[1:])
                args = []
                if arg:
                    args.append(arg)
                await attr_value(*args)
                await asyncio.sleep(delay)

And another thing: The commands have hold actions. For example, holding the right button enables the fast forwarding mode. pyatv supports this feature, but it is not usable from the Apple TV integration. Here’s a slight update that makes e.g. remote_control.right 2 enable fast forward mode. It’s a little bit hacky.

    async def async_send_command(self, command: Iterable[str], **kwargs: Any) -> None:
        """Send a command to one device."""
        num_repeats = kwargs[ATTR_NUM_REPEATS]
        delay = kwargs.get(ATTR_DELAY_SECS, DEFAULT_DELAY_SECS)

        if not self.is_on:
            _LOGGER.error("Unable to send commands, not connected to %s", self.name)
            return

        for _ in range(num_repeats):
            for single_command in command:
                split = single_command.split(' ')
                command_name = split[0]
                if '.' in command_name:
                    attr_value = self.atv
                    for command_path in command_name.split('.'):
                        attr_value = getattr(attr_value, command_path, None)
                else:
                    attr_value = getattr(self.atv.remote_control, single_command, None)
                if not attr_value:
                    raise ValueError("Command not found. Exiting sequence!!!")

                _LOGGER.info("Sending command %s", single_command)
                arg = ' '.join(split[1:])
                args = []
                if arg:
                    if command_name.startswith('remote_control') and arg.isdigit():
                        arg = InputAction(int(arg))
                    args.append(arg)
                await attr_value(*args)
                await asyncio.sleep(delay)

I have added this to the apple_tv component under remote.py. However, when I call the service, it shows failed to call service, command not found. Here is my service call

service: remote.send_command
target:
entity_id: remote.living_room_apple_4k
data:
num_repeats: 1
delay_secs: 0.4
hold_secs: 0
command: remote_control.right 2

if I just add remote_control.right it skips 10 seconds forward as expected.
Your help is appreciated.

I answered my own question, adding

from pyatv.const import InputAction

worked like a charm. Thanks for the hack. Great addition!

Where would I add this? :slight_smile:

I have this question too! I’m not sure where or how to find the remote.py file or make the update. Would love any tips! Been trying to figure it out with google but I haven’t found any obvious links / docs on updating the code(?) in an integration!