Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add entity_ids filter on get_states websocket command #141237

Draft
wants to merge 3 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion homeassistant/components/websocket_api/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,13 +325,23 @@ def _async_get_allowed_states(


@callback
@decorators.websocket_command({vol.Required("type"): "get_states"})
@decorators.websocket_command(
{
vol.Required("type"): "get_states",
vol.Optional("entity_ids"): cv.entity_ids,
}
)
def handle_get_states(
hass: HomeAssistant, connection: ActiveConnection, msg: dict[str, Any]
) -> None:
"""Handle get states command."""
states = _async_get_allowed_states(hass, connection)
Copy link
Member

@bdraco bdraco Mar 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be much more efficient to filter them in this function and only return the ones they want vs fetching them all and than filtering them out.

Alternative you could use the same pattern already used for subscribe_enitites so we don't have two different way to filter entities

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After thinking about this, I think the subscribe entities pattern is better, since when we optimize that one, this one could get optimized as well without having to work on it twice

Copy link
Author

@ugomeda ugomeda Mar 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could modify the _async_get_allowed_states method to add an entity_id argument. If provided, if would call hass.states.get() for each entity instead of async_all .

This would improve performance for handle_subscribe_entities.

Edit: there is no async_get, i'm not sure this is even a valid option

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think thats a good next step. For the first iteration, lets uses the entity filer like subscribe_entities does


# filter states if entity_ids is set
entity_ids = set(msg.get("entity_ids", []))
if entity_ids:
states = [state for state in states if state.entity_id in entity_ids]

try:
serialized_states = [state.as_dict_json for state in states]
except (ValueError, TypeError):
Expand Down
22 changes: 22 additions & 0 deletions tests/components/websocket_api/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -2916,3 +2916,25 @@ def auto_off_listener(event):

await websocket_client.close()
await hass.async_block_till_done()


async def test_get_states_entity_id_filter(
hass: HomeAssistant, websocket_client: MockHAClientWebSocket
) -> None:
"""Test get_states command."""
hass.states.async_set("greeting.hello", "world")
hass.states.async_set("greeting.bye", "universe")

await websocket_client.send_json(
{
"id": 5,
"type": "get_states",
"entity_ids": ["greeting.bye", "greeting.missing"],
}
)

msg = await websocket_client.receive_json()
assert msg["id"] == 5
assert msg["type"] == const.TYPE_RESULT
assert msg["success"]
assert msg["result"] == [hass.states.get("greeting.bye").as_dict()]