What is the most efficient API to get all entities of domain X in an area Y?

Trying to create some generic code to populate some dashboard statuses and my limited knowledge of jinja and HA APIs is showing.
I did look at the area API docs and it says they can be used as a filter but I’m unsure how to do it.

E.g. if I want to return TRUE if at least one media player entity in area X is on.
I imagine something like this is the general form states.media_player|area_id('target_room_id')....|selectattr("state", 'eq','on')|list|count > 0? Or would I need to separately get all the entities in the area and then intersect the two sets which is kind of the worst of both worlds in terms of performance?

P.S. In terms of efficiency, I guess you want to start with the smallest collection of entities so depending on the room in some cases it would be better to start with the area entities and filter to domain and in other cases it would be better to start with the domain and filter to the area. But there’s no way that to be known dynamically so let’s set that aside. We can assume we always start with the domain.

P.P.S. BTW the interpreted nature of templating is killing me. I guess I’m too used to the ‘crutches’ of compile time safety and auto completion of APIs in an IDE but I’m finding I spend 10s of minutes and sometimes embarrassingly hours trying to get relatively trivial logic working in HA when writing scripts and automations and templating, mostly due to having neither compiler support nor IDE support. I do love the more recent automation UI improvements, they are fantastic! Even silly things like the IIF not shortcircuiting which granted is very well documented but is such an unexpected break in API behavior compared to the other two ways to do if/else.

just re-edited to add more color!

A list of all light entities in the kitchen area.

{{ area_entities('kitchen') | select('match', 'light') | list }}

Return true if at least one media_player in the kitchen area is playing.

{{ area_entities('kitchen') | select('match', 'media_player')
 | map('states') | select('eq','playing') | list | count > 0 }}
2 Likes

If you want to start with the domain as stated, here are the sensors in the Kitchen:

{{ states.sensor|selectattr('entity_id','in',area_entities('Kitchen'))|list }}

Returns full entities, not just IDs.

Thank you so much @123
May I bug you even more on a Fri and ask if I wanted to start with all light entities and filter them down to those in an area, is there a reasonable way to do that or I’d need to generate two sets (all entities in the room, and all entities of domain) and then intersect? Ie it will always be much less efficient?
Thanks again.

What compels you to do it it that way?

Given an area, area_entities() reports the entities in it .


FWIW, my choice is to start with the smallest available list of entities that fulfills the requirements. states.light is a list of state objects for every light entity in your system. In other words, it’s the largest available list of light entities.

Probably a totally unnecessary ‘performance’ worry.
E.g. in the living room we have 30+ entities (a ton of hue lights and humidity and temp sensors) but we only have 3 climate entities in the home.
So if I want to get to the climate entity in the living room, it would be “cheaper” to start with the climate domain and filter down to room.
This would be true basically for all domains other than lights.

Now, the actual performance impact is probably trivial and I have a lot more inefficiencies in my dashboards elsewhere.

Also, you can just ask me – for cases like climate entities that you have so few, why not just hardcode it in your dashboard. And normally I’d say yes but there are cases where this isn’t as good.

Either way that’s the long answer to your question.

Do you think it’s possible to start with domain in a way that would be more efficient or I’d need to get all the entities in the area anyway in order to intersect.
EDIT: just saw Troon’s example bnut taht one seems even worse because unless the whole jinja engine is smart about it, it feels like it would be ‘quadartic’ perf. For each entity in the domain, requery all the entities in the ktichen and intersect. Again,granted here N and M are small numbers so doesn’t matter much but it feels inefficient haha.

Regarding the dashboard, none of the standard cards (with the exception of the Markdown card) support templates. Therefore the templates posted above can’t be used in a standard card (but various custom cards do support templates).

If you start the template with states.climate, in order to “filter down to the room” you will still need to use still area_entities (as shown in Troon’s example) because it’s the only thing that indicates what’s in an area. That’s why I suggest starting with it rather than with an entire domain.

2 Likes

got it, thanks.
in that case i’ll mark your original reply as the answer as it’s the most efficient way even in the case of non-light domains for us since it seems you cannot avoid querying all the entities in the area anyway. P.S. I guess that makes sense since the area isn’t an attribute on the entities…

It doesn’t. As a test, this:

{{ range(10)|select('in',[range(10)|random])|list|count }}

returns 1 every time it is queried. If it were re-evaluating the one-element random list for each item being checked, other numbers would pop up.

It’s certainly a short template but without testing or examining the code you don’t know that.

1 Like

EDIT: i don’t get why i keep replying to my own reply…

that’s a fantastic test! glad that the result is cached by the jinja engine
in terms of operations (without looking at the cost of each operation) the first solution still has fewer operations.
but i agree that i don’t know the cost of e.g. looking up those attributes in the select in the solution but i think i’ve spent already way more time on this than i should have!
i hope it’s ok that i’ll keep Taras’ as the solution to my problem as it only generates an entities list in the room and then filters it down.
in your case, i do that + a domain query and then intersect them. So with your proof that it’s not quadratic, it is still a double query, though in big O i guess a constant of 2 is irrelevant :stuck_out_tongue:

:grin: Of course I’m not objecting to what is marked as a Solution (even if it does flagrantly ignore your bold text :wink: ).

Haha yes it ignore it, agreed :laughing:!
My… resignation to Tara’s solution is predicated on this assumption: In Tara’s solution the | map('states') is what queries the full object. I’m positing/hoping that call is targeted to that single entity id (once for each entity id after they’ve been filtered down), and cheaper than a single sensors.dome_domain call. Whether that’s true I don’t know as you say.

You didn’t ask for the following example but consider it a freebie. :slightly_smiling_face:

List the entity_ids of all lights in two areas whose brightness is greater than 125.

{{ (area_entities('family') + area_entities('kitchen'))
 | select('match', 'light') | expand
 | rejectattr('attributes.brightness', 'eq', none)
 | selectattr('attributes.brightness', 'gt', 125)
 | map(attribute='entity_id') | list  }}
1 Like

Thanks! A bit confused (don’t have access to HA right now to test), does area_entities return a full blown list of objects or just strings. I tohught it was the latter. so curious how this works if you don’t have a map to states?

It’s the |expand.

1 Like

It returns a list of strings that are entity_ids.


NOTE

expand converts a list of entity_ids into their state objects. It can be used as a filter (shown in the example above) or as a function. Both ways work in the Template Editor but, a long time ago, I encountered a problem using it as a filter in a Template Sensor (i.e. it failed with an error message).

I reported the bug in Home Assistant’s GitHub Core repository but there was no reply (and eventually the Issue went stale and automatically closed). It may have been quietly fixed since then but I have not tested it (I have been using it exclusively as a function in Template Sensors).

1 Like

thank you! ii thought this was some kind of standard jinja collection API lol so much magic in these woods :joy:

Home Assistant implements most, but not all, of the Jinja2 templating language. It also provides its own extensions and overrides (listed in the Templating section of Home Assistant’s documentation).

1 Like