示例#1
0
 def setUp(self):
     """Set up a `FireTVDevice` media player."""
     with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[
             self.PATCH_KEY], patchers.patch_shell("")[self.PATCH_KEY]:
         aftv = setup("HOST", 5555, device_class="firetv")
         self.aftv = FireTVDevice(aftv, "Fake Fire TV", {}, True, None,
                                  None)
示例#2
0
    def test_update_lock_not_acquired(self):
        """Test that the state does not get updated when a `LockNotAcquiredException` is raised."""
        patch_key = "server"

        with patchers.patch_connect(True)[patch_key], patchers.patch_shell(
                "")[patch_key]:
            aftv = setup("HOST",
                         5555,
                         adb_server_ip="ADB_SERVER_IP",
                         device_class="androidtv")
            self.aftv = AndroidTVDevice(aftv, "Fake Android TV", {}, True,
                                        None, None)

        with patchers.patch_shell("")[patch_key]:
            self.aftv.update()
            assert self.aftv.state == STATE_OFF

        with patch("androidtv.androidtv.androidtv_sync.AndroidTVSync.update",
                   side_effect=LockNotAcquiredException):
            with patchers.patch_shell("1")[patch_key]:
                self.aftv.update()
                assert self.aftv.state == STATE_OFF

        with patchers.patch_shell("1")[patch_key]:
            self.aftv.update()
            assert self.aftv.state == STATE_STANDBY
示例#3
0
 def setUp(self):
     """Set up a `FireTVDevice` media player."""
     with patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell("")[self.PATCH_KEY]:
         aftv = setup(
             "HOST", 5555, adb_server_ip="ADB_SERVER_IP", device_class="firetv"
         )
         self.aftv = FireTVDevice(aftv, "Fake Fire TV", {}, True, None, None)
示例#4
0
def setup_androidtv(hass, config):
    """Generate an ADB key (if needed) and connect to the Android TV / Fire TV."""
    adbkey = config.get(CONF_ADBKEY, hass.config.path(STORAGE_DIR, "androidtv_adbkey"))
    if CONF_ADB_SERVER_IP not in config:
        # Use "adb_shell" (Python ADB implementation)
        if not os.path.isfile(adbkey):
            # Generate ADB key files
            keygen(adbkey)

        adb_log = f"using Python ADB implementation with adbkey='{adbkey}'"

    else:
        # Use "pure-python-adb" (communicate with ADB server)
        adb_log = f"using ADB server at {config[CONF_ADB_SERVER_IP]}:{config[CONF_ADB_SERVER_PORT]}"

    aftv = setup(
        config[CONF_HOST],
        config[CONF_PORT],
        adbkey,
        config.get(CONF_ADB_SERVER_IP, ""),
        config[CONF_ADB_SERVER_PORT],
        config[CONF_STATE_DETECTION_RULES],
        config[CONF_DEVICE_CLASS],
        10.0,
    )

    return aftv, adb_log
    def test_setup(self):
        """Test that the ``setup`` function works correctly."""
        with self.assertRaises(ValueError):
            setup("HOST", 5555, device_class="INVALID")

        with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(
            DEVICE_PROPERTIES_OUTPUT1
        )[self.PATCH_KEY]:
            ftv = setup("HOST", 5555)
            self.assertIsInstance(ftv, FireTVSync)
            self.assertDictEqual(ftv.device_properties, DEVICE_PROPERTIES_DICT1)

        with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(
            DEVICE_PROPERTIES_OUTPUT2
        )[self.PATCH_KEY]:
            atv = setup("HOST", 5555)
            self.assertIsInstance(atv, AndroidTVSync)
            self.assertDictEqual(atv.device_properties, DEVICE_PROPERTIES_DICT2)

        with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(
            DEVICE_PROPERTIES_OUTPUT1
        )[self.PATCH_KEY]:
            ftv = setup("HOST", 5555, device_class="androidtv")
            self.assertIsInstance(ftv, AndroidTVSync)
            self.assertDictEqual(ftv.device_properties, DEVICE_PROPERTIES_DICT1)

        with patchers.PATCH_ADB_DEVICE_TCP, patchers.patch_connect(True)[self.PATCH_KEY], patchers.patch_shell(
            DEVICE_PROPERTIES_OUTPUT2
        )[self.PATCH_KEY]:
            atv = setup("HOST", 5555, device_class="firetv")
            self.assertIsInstance(atv, FireTVSync)
            self.assertDictEqual(atv.device_properties, DEVICE_PROPERTIES_DICT2)
    def test_adb_command_key(self):
        """Test sending a key command via the `androidtv.adb_command` service."""
        patch_key = "server"
        command = "HOME"
        response = None

        with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]:
            aftv = setup("HOST", 5555, adb_server_ip="ADB_SERVER_IP", device_class="androidtv")
            self.aftv = AndroidTVDevice(aftv, "Fake Android TV", {}, True, None, None)

        with patch("androidtv.basetv.basetv_sync.BaseTVSync.adb_shell", return_value=response) as patch_shell:
            self.aftv.adb_command(command)

            patch_shell.assert_called_with("input keyevent {}".format(self.aftv._keys[command]))
            assert self.aftv._adb_response is None
示例#7
0
    def test_adb_command_get_properties(self):
        """Test sending the "GET_PROPERTIES" command via the `androidtv.adb_command` service."""
        patch_key = "server"
        command = "GET_PROPERTIES"
        response = {"key": "value"}

        with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]:
            aftv = setup(
                "HOST", 5555, adb_server_ip="ADB_SERVER_IP", device_class="androidtv"
            )
            self.aftv = AndroidTVDevice(aftv, "Fake Android TV", {}, True, None, None)

        with patch("androidtv.androidtv.androidtv_sync.AndroidTVSync.get_properties_dict", return_value=response) as patch_get_props:
            self.aftv.adb_command(command)

            assert patch_get_props.called
            assert self.aftv._adb_response == str(response)
示例#8
0
    def test_adb_command(self):
        """Test sending a command via the `androidtv.adb_command` service."""
        patch_key = "server"
        command = "test command"
        response = "test response"

        with patchers.patch_connect(True)[patch_key], patchers.patch_shell("")[patch_key]:
            aftv = setup(
                "HOST", 5555, adb_server_ip="ADB_SERVER_IP", device_class="androidtv"
            )
            self.aftv = AndroidTVDevice(aftv, "Fake Android TV", {}, True, None, None)

        with patch("androidtv.basetv.BaseTV.adb_shell", return_value=response) as patch_shell:
            self.aftv.adb_command(command)

            patch_shell.assert_called_with(command)
            assert self.aftv._adb_response == response
示例#9
0
    def test_setup(self):
        """Test that the ``setup`` function works correctly.
        """
        with self.assertRaises(ValueError):
            setup('IP:5555', device_class='INVALID')

        with patchers.patch_adb_device, patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(
                    DEVICE_PROPERTIES_OUTPUT1)[self.PATCH_KEY]:
            ftv = setup('IP:5555')
            self.assertIsInstance(ftv, FireTV)
            self.assertDictEqual(ftv.device_properties,
                                 DEVICE_PROPERTIES_DICT1)

        with patchers.patch_adb_device, patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(
                    DEVICE_PROPERTIES_OUTPUT2)[self.PATCH_KEY]:
            atv = setup('IP:5555')
            self.assertIsInstance(atv, AndroidTV)
            self.assertDictEqual(atv.device_properties,
                                 DEVICE_PROPERTIES_DICT2)

        with patchers.patch_adb_device, patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(
                    DEVICE_PROPERTIES_OUTPUT1)[self.PATCH_KEY]:
            ftv = setup('IP:5555', device_class='androidtv')
            self.assertIsInstance(ftv, AndroidTV)
            self.assertDictEqual(ftv.device_properties,
                                 DEVICE_PROPERTIES_DICT1)

        with patchers.patch_adb_device, patchers.patch_connect(True)[
                self.PATCH_KEY], patchers.patch_shell(
                    DEVICE_PROPERTIES_OUTPUT2)[self.PATCH_KEY]:
            atv = setup('IP:5555', device_class='firetv')
            self.assertIsInstance(atv, FireTV)
            self.assertDictEqual(atv.device_properties,
                                 DEVICE_PROPERTIES_DICT2)
示例#10
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Android TV / Fire TV platform."""
    hass.data.setdefault(ANDROIDTV_DOMAIN, {})

    host = f"{config[CONF_HOST]}:{config[CONF_PORT]}"

    if CONF_ADB_SERVER_IP not in config:
        # Use "adb_shell" (Python ADB implementation)
        if CONF_ADBKEY not in config:
            # Generate ADB key files (if they don't exist)
            adbkey = hass.config.path(STORAGE_DIR, "androidtv_adbkey")
            if not os.path.isfile(adbkey):
                keygen(adbkey)

            adb_log = f"using Python ADB implementation with adbkey='{adbkey}'"

            aftv = setup(
                host,
                adbkey,
                device_class=config[CONF_DEVICE_CLASS],
                state_detection_rules=config[CONF_STATE_DETECTION_RULES],
                auth_timeout_s=10.0,
            )

        else:
            adb_log = (
                f"using Python ADB implementation with adbkey='{config[CONF_ADBKEY]}'"
            )

            aftv = setup(
                host,
                config[CONF_ADBKEY],
                device_class=config[CONF_DEVICE_CLASS],
                state_detection_rules=config[CONF_STATE_DETECTION_RULES],
                auth_timeout_s=10.0,
            )

    else:
        # Use "pure-python-adb" (communicate with ADB server)
        adb_log = f"using ADB server at {config[CONF_ADB_SERVER_IP]}:{config[CONF_ADB_SERVER_PORT]}"

        aftv = setup(
            host,
            adb_server_ip=config[CONF_ADB_SERVER_IP],
            adb_server_port=config[CONF_ADB_SERVER_PORT],
            device_class=config[CONF_DEVICE_CLASS],
            state_detection_rules=config[CONF_STATE_DETECTION_RULES],
        )

    if not aftv.available:
        # Determine the name that will be used for the device in the log
        if CONF_NAME in config:
            device_name = config[CONF_NAME]
        elif config[CONF_DEVICE_CLASS] == DEVICE_ANDROIDTV:
            device_name = "Android TV device"
        elif config[CONF_DEVICE_CLASS] == DEVICE_FIRETV:
            device_name = "Fire TV device"
        else:
            device_name = "Android TV / Fire TV device"

        _LOGGER.warning("Could not connect to %s at %s %s", device_name, host,
                        adb_log)
        raise PlatformNotReady

    if host in hass.data[ANDROIDTV_DOMAIN]:
        _LOGGER.warning("Platform already setup on %s, skipping", host)
    else:
        if aftv.DEVICE_CLASS == DEVICE_ANDROIDTV:
            device = AndroidTVDevice(
                aftv,
                config[CONF_NAME],
                config[CONF_APPS],
                config.get(CONF_TURN_ON_COMMAND),
                config.get(CONF_TURN_OFF_COMMAND),
            )
            device_name = config[
                CONF_NAME] if CONF_NAME in config else "Android TV"
        else:
            device = FireTVDevice(
                aftv,
                config[CONF_NAME],
                config[CONF_APPS],
                config[CONF_GET_SOURCES],
                config.get(CONF_TURN_ON_COMMAND),
                config.get(CONF_TURN_OFF_COMMAND),
            )
            device_name = config[
                CONF_NAME] if CONF_NAME in config else "Fire TV"

        add_entities([device])
        _LOGGER.debug("Setup %s at %s %s", device_name, host, adb_log)
        hass.data[ANDROIDTV_DOMAIN][host] = device

    if hass.services.has_service(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND):
        return

    def service_adb_command(service):
        """Dispatch service calls to target entities."""
        cmd = service.data.get(ATTR_COMMAND)
        entity_id = service.data.get(ATTR_ENTITY_ID)
        target_devices = [
            dev for dev in hass.data[ANDROIDTV_DOMAIN].values()
            if dev.entity_id in entity_id
        ]

        for target_device in target_devices:
            output = target_device.adb_command(cmd)

            # log the output, if there is any
            if output:
                _LOGGER.info(
                    "Output of command '%s' from '%s': %s",
                    cmd,
                    target_device.entity_id,
                    output,
                )

    hass.services.register(
        ANDROIDTV_DOMAIN,
        SERVICE_ADB_COMMAND,
        service_adb_command,
        schema=SERVICE_ADB_COMMAND_SCHEMA,
    )
示例#11
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Android TV / Fire TV platform."""
    from androidtv import setup

    hass.data.setdefault(ANDROIDTV_DOMAIN, {})

    host = '{0}:{1}'.format(config[CONF_HOST], config[CONF_PORT])

    if CONF_ADB_SERVER_IP not in config:
        # Use "python-adb" (Python ADB implementation)
        adb_log = "using Python ADB implementation "
        if CONF_ADBKEY in config:
            aftv = setup(host, config[CONF_ADBKEY],
                         device_class=config[CONF_DEVICE_CLASS])
            adb_log += "with adbkey='{0}'".format(config[CONF_ADBKEY])

        else:
            aftv = setup(host, device_class=config[CONF_DEVICE_CLASS])
            adb_log += "without adbkey authentication"
    else:
        # Use "pure-python-adb" (communicate with ADB server)
        aftv = setup(host, adb_server_ip=config[CONF_ADB_SERVER_IP],
                     adb_server_port=config[CONF_ADB_SERVER_PORT],
                     device_class=config[CONF_DEVICE_CLASS])
        adb_log = "using ADB server at {0}:{1}".format(
            config[CONF_ADB_SERVER_IP], config[CONF_ADB_SERVER_PORT])

    if not aftv.available:
        # Determine the name that will be used for the device in the log
        if CONF_NAME in config:
            device_name = config[CONF_NAME]
        elif config[CONF_DEVICE_CLASS] == DEVICE_ANDROIDTV:
            device_name = 'Android TV device'
        elif config[CONF_DEVICE_CLASS] == DEVICE_FIRETV:
            device_name = 'Fire TV device'
        else:
            device_name = 'Android TV / Fire TV device'

        _LOGGER.warning("Could not connect to %s at %s %s",
                        device_name, host, adb_log)
        raise PlatformNotReady

    if host in hass.data[ANDROIDTV_DOMAIN]:
        _LOGGER.warning("Platform already setup on %s, skipping", host)
    else:
        if aftv.DEVICE_CLASS == DEVICE_ANDROIDTV:
            device = AndroidTVDevice(aftv, config[CONF_NAME],
                                     config[CONF_APPS],
                                     config.get(CONF_TURN_ON_COMMAND),
                                     config.get(CONF_TURN_OFF_COMMAND))
            device_name = config[CONF_NAME] if CONF_NAME in config \
                else 'Android TV'
        else:
            device = FireTVDevice(aftv, config[CONF_NAME], config[CONF_APPS],
                                  config[CONF_GET_SOURCES],
                                  config.get(CONF_TURN_ON_COMMAND),
                                  config.get(CONF_TURN_OFF_COMMAND))
            device_name = config[CONF_NAME] if CONF_NAME in config \
                else 'Fire TV'

        add_entities([device])
        _LOGGER.debug("Setup %s at %s%s", device_name, host, adb_log)
        hass.data[ANDROIDTV_DOMAIN][host] = device

    if hass.services.has_service(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND):
        return

    def service_adb_command(service):
        """Dispatch service calls to target entities."""
        cmd = service.data.get(ATTR_COMMAND)
        entity_id = service.data.get(ATTR_ENTITY_ID)
        target_devices = [dev for dev in hass.data[ANDROIDTV_DOMAIN].values()
                          if dev.entity_id in entity_id]

        for target_device in target_devices:
            output = target_device.adb_command(cmd)

            # log the output, if there is any
            if output:
                _LOGGER.info("Output of command '%s' from '%s': %s",
                             cmd, target_device.entity_id, output)

    hass.services.register(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND,
                           service_adb_command,
                           schema=SERVICE_ADB_COMMAND_SCHEMA)
示例#12
0
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Android TV / Fire TV platform."""
    from androidtv import setup

    hass.data.setdefault(ANDROIDTV_DOMAIN, {})

    host = '{0}:{1}'.format(config[CONF_HOST], config[CONF_PORT])

    if CONF_ADB_SERVER_IP not in config:
        # Use "python-adb" (Python ADB implementation)
        if CONF_ADBKEY in config:
            aftv = setup(host, config[CONF_ADBKEY],
                         device_class=config[CONF_DEVICE_CLASS])
            adb_log = " using adbkey='{0}'".format(config[CONF_ADBKEY])

        else:
            aftv = setup(host, device_class=config[CONF_DEVICE_CLASS])
            adb_log = ""
    else:
        # Use "pure-python-adb" (communicate with ADB server)
        aftv = setup(host, adb_server_ip=config[CONF_ADB_SERVER_IP],
                     adb_server_port=config[CONF_ADB_SERVER_PORT],
                     device_class=config[CONF_DEVICE_CLASS])
        adb_log = " using ADB server at {0}:{1}".format(
            config[CONF_ADB_SERVER_IP], config[CONF_ADB_SERVER_PORT])

    if not aftv.available:
        # Determine the name that will be used for the device in the log
        if CONF_NAME in config:
            device_name = config[CONF_NAME]
        elif config[CONF_DEVICE_CLASS] == DEVICE_ANDROIDTV:
            device_name = 'Android TV device'
        elif config[CONF_DEVICE_CLASS] == DEVICE_FIRETV:
            device_name = 'Fire TV device'
        else:
            device_name = 'Android TV / Fire TV device'

        _LOGGER.warning("Could not connect to %s at %s%s",
                        device_name, host, adb_log)
        return

    if host in hass.data[ANDROIDTV_DOMAIN]:
        _LOGGER.warning("Platform already setup on %s, skipping", host)
    else:
        if aftv.DEVICE_CLASS == DEVICE_ANDROIDTV:
            device = AndroidTVDevice(aftv, config[CONF_NAME],
                                     config[CONF_APPS],
                                     config.get(CONF_TURN_ON_COMMAND),
                                     config.get(CONF_TURN_OFF_COMMAND))
            device_name = config[CONF_NAME] if CONF_NAME in config \
                else 'Android TV'
        else:
            device = FireTVDevice(aftv, config[CONF_NAME], config[CONF_APPS],
                                  config[CONF_GET_SOURCES],
                                  config.get(CONF_TURN_ON_COMMAND),
                                  config.get(CONF_TURN_OFF_COMMAND))
            device_name = config[CONF_NAME] if CONF_NAME in config \
                else 'Fire TV'

        add_entities([device])
        _LOGGER.debug("Setup %s at %s%s", device_name, host, adb_log)
        hass.data[ANDROIDTV_DOMAIN][host] = device

    if hass.services.has_service(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND):
        return

    def service_adb_command(service):
        """Dispatch service calls to target entities."""
        cmd = service.data.get(ATTR_COMMAND)
        entity_id = service.data.get(ATTR_ENTITY_ID)
        target_devices = [dev for dev in hass.data[ANDROIDTV_DOMAIN].values()
                          if dev.entity_id in entity_id]

        for target_device in target_devices:
            output = target_device.adb_command(cmd)

            # log the output if there is any
            if output and (not isinstance(output, str) or output.strip()):
                _LOGGER.info("Output of command '%s' from '%s': %s",
                             cmd, target_device.entity_id, repr(output))

    hass.services.register(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND,
                           service_adb_command,
                           schema=SERVICE_ADB_COMMAND_SCHEMA)
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Android TV / Fire TV platform."""
    hass.data.setdefault(ANDROIDTV_DOMAIN, {})

    address = f"{config[CONF_HOST]}:{config[CONF_PORT]}"

    if address in hass.data[ANDROIDTV_DOMAIN]:
        _LOGGER.warning("Platform already setup on %s, skipping", address)
        return

    if CONF_ADB_SERVER_IP not in config:
        # Use "adb_shell" (Python ADB implementation)
        if CONF_ADBKEY not in config:
            # Generate ADB key files (if they don't exist)
            adbkey = hass.config.path(STORAGE_DIR, "androidtv_adbkey")
            if not os.path.isfile(adbkey):
                keygen(adbkey)

            adb_log = f"using Python ADB implementation with adbkey='{adbkey}'"

            aftv = setup(
                config[CONF_HOST],
                config[CONF_PORT],
                adbkey,
                device_class=config[CONF_DEVICE_CLASS],
                state_detection_rules=config[CONF_STATE_DETECTION_RULES],
                auth_timeout_s=10.0,
            )

        else:
            adb_log = (
                f"using Python ADB implementation with adbkey='{config[CONF_ADBKEY]}'"
            )

            aftv = setup(
                config[CONF_HOST],
                config[CONF_PORT],
                config[CONF_ADBKEY],
                device_class=config[CONF_DEVICE_CLASS],
                state_detection_rules=config[CONF_STATE_DETECTION_RULES],
                auth_timeout_s=10.0,
            )

    else:
        # Use "pure-python-adb" (communicate with ADB server)
        adb_log = f"using ADB server at {config[CONF_ADB_SERVER_IP]}:{config[CONF_ADB_SERVER_PORT]}"

        aftv = setup(
            config[CONF_HOST],
            config[CONF_PORT],
            adb_server_ip=config[CONF_ADB_SERVER_IP],
            adb_server_port=config[CONF_ADB_SERVER_PORT],
            device_class=config[CONF_DEVICE_CLASS],
            state_detection_rules=config[CONF_STATE_DETECTION_RULES],
        )

    if not aftv.available:
        # Determine the name that will be used for the device in the log
        if CONF_NAME in config:
            device_name = config[CONF_NAME]
        elif config[CONF_DEVICE_CLASS] == DEVICE_ANDROIDTV:
            device_name = "Android TV device"
        elif config[CONF_DEVICE_CLASS] == DEVICE_FIRETV:
            device_name = "Fire TV device"
        else:
            device_name = "Android TV / Fire TV device"

        _LOGGER.warning("Could not connect to %s at %s %s", device_name,
                        address, adb_log)
        raise PlatformNotReady

    device_args = [
        aftv,
        config[CONF_NAME],
        config[CONF_APPS],
        config[CONF_GET_SOURCES],
        config.get(CONF_TURN_ON_COMMAND),
        config.get(CONF_TURN_OFF_COMMAND),
        config[CONF_EXCLUDE_UNNAMED_APPS],
        config[CONF_SCREENCAP],
    ]

    if aftv.DEVICE_CLASS == DEVICE_ANDROIDTV:
        device = AndroidTVDevice(*device_args)
        device_name = config.get(CONF_NAME, "Android TV")
    else:
        device = FireTVDevice(*device_args)
        device_name = config.get(CONF_NAME, "Fire TV")

    add_entities([device])
    _LOGGER.debug("Setup %s at %s %s", device_name, address, adb_log)
    hass.data[ANDROIDTV_DOMAIN][address] = device

    if hass.services.has_service(ANDROIDTV_DOMAIN, SERVICE_ADB_COMMAND):
        return

    def service_adb_command(service):
        """Dispatch service calls to target entities."""
        cmd = service.data[ATTR_COMMAND]
        entity_id = service.data[ATTR_ENTITY_ID]
        target_devices = [
            dev for dev in hass.data[ANDROIDTV_DOMAIN].values()
            if dev.entity_id in entity_id
        ]

        for target_device in target_devices:
            output = target_device.adb_command(cmd)

            # log the output, if there is any
            if output:
                _LOGGER.info(
                    "Output of command '%s' from '%s': %s",
                    cmd,
                    target_device.entity_id,
                    output,
                )

    hass.services.register(
        ANDROIDTV_DOMAIN,
        SERVICE_ADB_COMMAND,
        service_adb_command,
        schema=SERVICE_ADB_COMMAND_SCHEMA,
    )

    def service_download(service):
        """Download a file from your Android TV / Fire TV device to your Home Assistant instance."""
        local_path = service.data[ATTR_LOCAL_PATH]
        if not hass.config.is_allowed_path(local_path):
            _LOGGER.warning("'%s' is not secure to load data from!",
                            local_path)
            return

        device_path = service.data[ATTR_DEVICE_PATH]
        entity_id = service.data[ATTR_ENTITY_ID]
        target_device = [
            dev for dev in hass.data[ANDROIDTV_DOMAIN].values()
            if dev.entity_id in entity_id
        ][0]

        target_device.adb_pull(local_path, device_path)

    hass.services.register(
        ANDROIDTV_DOMAIN,
        SERVICE_DOWNLOAD,
        service_download,
        schema=SERVICE_DOWNLOAD_SCHEMA,
    )

    def service_upload(service):
        """Upload a file from your Home Assistant instance to an Android TV / Fire TV device."""
        local_path = service.data[ATTR_LOCAL_PATH]
        if not hass.config.is_allowed_path(local_path):
            _LOGGER.warning("'%s' is not secure to load data from!",
                            local_path)
            return

        device_path = service.data[ATTR_DEVICE_PATH]
        entity_id = service.data[ATTR_ENTITY_ID]
        target_devices = [
            dev for dev in hass.data[ANDROIDTV_DOMAIN].values()
            if dev.entity_id in entity_id
        ]

        for target_device in target_devices:
            target_device.adb_push(local_path, device_path)

    hass.services.register(ANDROIDTV_DOMAIN,
                           SERVICE_UPLOAD,
                           service_upload,
                           schema=SERVICE_UPLOAD_SCHEMA)