Enhance androidtv.adb_command to return response data (#166945)

This commit is contained in:
tronikos
2026-08-27 12:44:52 +03:00
committed by GitHub
parent af17fe0233
commit 9220f9ddab
3 changed files with 56 additions and 14 deletions
@@ -247,29 +247,30 @@ class ADBDevice(AndroidTVEntity, MediaPlayerEntity):
await self.aftv.stop_app(self._app_name_to_id.get(source_, source_))
@adb_decorator()
async def adb_command(self, command: str) -> None:
async def adb_command(self, command: str) -> dict[str, str] | None:
"""Send an ADB command to an Android / Fire TV device."""
if key := KEYS.get(command):
await self.aftv.adb_shell(f"input keyevent {key}")
return
return None
if command == "GET_PROPERTIES":
self._attr_extra_state_attributes[ATTR_ADB_RESPONSE] = str(
await self.aftv.get_properties_dict()
)
adb_response = str(await self.aftv.get_properties_dict())
self._attr_extra_state_attributes[ATTR_ADB_RESPONSE] = adb_response
self.async_write_ha_state()
return
return {ATTR_ADB_RESPONSE: adb_response}
try:
response = await self.aftv.adb_shell(command)
except UnicodeDecodeError:
return
return None
if isinstance(response, str) and response.strip():
self._attr_extra_state_attributes[ATTR_ADB_RESPONSE] = response.strip()
adb_response = response.strip()
self._attr_extra_state_attributes[ATTR_ADB_RESPONSE] = adb_response
self.async_write_ha_state()
return {ATTR_ADB_RESPONSE: adb_response}
return
return None
@adb_decorator()
async def learn_sendevent(self) -> None:
@@ -4,7 +4,7 @@ import voluptuous as vol
from homeassistant.components.media_player import DOMAIN as MEDIA_PLAYER_DOMAIN
from homeassistant.const import ATTR_COMMAND
from homeassistant.core import HomeAssistant, callback
from homeassistant.core import HomeAssistant, SupportsResponse, callback
from homeassistant.helpers import config_validation as cv, service
from .const import DOMAIN
@@ -26,6 +26,7 @@ def async_setup_services(hass: HomeAssistant) -> None:
entity_domain=MEDIA_PLAYER_DOMAIN,
schema={vol.Required(ATTR_COMMAND): cv.string},
func="adb_command",
supports_response=SupportsResponse.OPTIONAL,
)
service.async_register_platform_entity_service(
hass,
@@ -509,17 +509,51 @@ async def test_adb_command(hass: HomeAssistant) -> None:
with patch(
"androidtv.basetv.basetv_async.BaseTVAsync.adb_shell", return_value=response
) as patch_shell:
await hass.services.async_call(
service_response = await hass.services.async_call(
DOMAIN,
"adb_command",
{ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
blocking=True,
return_response=True,
)
patch_shell.assert_called_with(command)
state = hass.states.get(entity_id)
assert state is not None
assert state.attributes["adb_response"] == response
assert service_response == {entity_id: {"adb_response": response}}
async def test_adb_command_empty_response(hass: HomeAssistant) -> None:
"""Test sending a command via the `androidtv.adb_command` service that returns an empty response."""
patch_key, entity_id, config_entry = _setup(CONFIG_ANDROID_DEFAULT)
config_entry.add_to_hass(hass)
command = "test command"
response = " "
with (
patchers.patch_connect(True)[patch_key],
patchers.patch_shell(SHELL_RESPONSE_OFF)[patch_key],
):
assert await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
with patch(
"androidtv.basetv.basetv_async.BaseTVAsync.adb_shell", return_value=response
) as patch_shell:
service_response = await hass.services.async_call(
DOMAIN,
"adb_command",
{ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
blocking=True,
return_response=True,
)
patch_shell.assert_called_with(command)
state = hass.states.get(entity_id)
assert state is not None
assert state.attributes["adb_response"] is None
assert service_response == {entity_id: None}
async def test_adb_command_unicode_decode_error(hass: HomeAssistant) -> None:
@@ -540,16 +574,18 @@ async def test_adb_command_unicode_decode_error(hass: HomeAssistant) -> None:
"androidtv.basetv.basetv_async.BaseTVAsync.adb_shell",
side_effect=UnicodeDecodeError("utf-8", response, 0, len(response), "TEST"),
):
await hass.services.async_call(
service_response = await hass.services.async_call(
DOMAIN,
"adb_command",
{ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
blocking=True,
return_response=True,
)
state = hass.states.get(entity_id)
assert state is not None
assert state.attributes["adb_response"] is None
assert service_response == {entity_id: None}
async def test_adb_command_key(hass: HomeAssistant) -> None:
@@ -569,17 +605,19 @@ async def test_adb_command_key(hass: HomeAssistant) -> None:
with patch(
"androidtv.basetv.basetv_async.BaseTVAsync.adb_shell", return_value=response
) as patch_shell:
await hass.services.async_call(
service_response = await hass.services.async_call(
DOMAIN,
"adb_command",
{ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
blocking=True,
return_response=True,
)
patch_shell.assert_called_with(f"input keyevent {KEYS[command]}")
state = hass.states.get(entity_id)
assert state is not None
assert state.attributes["adb_response"] is None
assert service_response == {entity_id: None}
async def test_adb_command_get_properties(hass: HomeAssistant) -> None:
@@ -600,17 +638,19 @@ async def test_adb_command_get_properties(hass: HomeAssistant) -> None:
"androidtv.androidtv.androidtv_async.AndroidTVAsync.get_properties_dict",
return_value=response,
) as patch_get_props:
await hass.services.async_call(
service_response = await hass.services.async_call(
DOMAIN,
"adb_command",
{ATTR_ENTITY_ID: entity_id, ATTR_COMMAND: command},
blocking=True,
return_response=True,
)
patch_get_props.assert_called()
state = hass.states.get(entity_id)
assert state is not None
assert state.attributes["adb_response"] == str(response)
assert service_response == {entity_id: {"adb_response": str(response)}}
async def test_learn_sendevent(hass: HomeAssistant) -> None: