Create combinatoric groups: Including and excluding entities from other groups

Tags: #<Tag:0x00007f73a5e42b48>

Think of the script as a set operation:

group.group_exclude_test_case = group.test_group_lights_switches \ group.computer_room

If you want to exclude the entity group.computer_room, you will have to wrap it in another group. There is no way (currently) to directly exclude single entities.

It seems like there is a “recursion depth” limitation. I think the script only goes down one level and finds whatever is there. This can be physical items such as lights, switches, locks, etc or non-physical items like more groups which could then contain even more groups or physical items.

If we made a list of physical items for the created group (only entities like lights, switches, etc without any groups) then when we excluded a group (or entity) it could create a list of physical items to remove from the “include list”.

the script only goes down one level

That’s true and by design. I thought about recursing the groups, but I ditched it for explicity.

Thanks for the replies. I’m starting to understand what is going on now. I’d like to work on recursing the groups, but I am having trouble testing the code in the template editor. Maybe due to how the variables are passed in? Is there a trick to putting the code in the template editor to play with it? Are you able to execute the code in the template editor?

You will need to

{% set include = '...' %}

for all variables you’d like to use. Then you can paste the script after that set’ing…

If you find a good way to recurse, maybe you make it optional via a recurse option and share the improved script here?

1 Like

Thanks @akloeckner. I was leaving off the “set” part when using the template editor. That helped a lot. I have modified your code to allow for recursion of the groups:

    alias: Create groups with enhanced include/exclude statements
    - service: group.set
        object_id:  "{{ object_id }}"
        name:       "{{ name or object_id }}"
        icon:       "{{ icon or '' }}"
        all:        "{{ all or False }}"
        entities: >-
          {# ENTITIES #}
          {% set ns = namespace(entities =
                          (entities.split(',') if entities is string else entities or [])) %}   
          {# TYPES #}
          {% for type in (types.split(',')     if types    is string else types or []) %}
          {% set ns.entities = ns.entities + (expand(states[type]) | map(attribute="entity_id") | list) %}
          {% endfor %}
          {# INCLUDE #}
          {% for group in (include.split(',')  if include  is string else include  or []) %}
          {% if expand_groups == True %}
          {% set ns.entities = ns.entities + (expand(group) | map(attribute="entity_id") | list)%}
          {% else %}
          {% set ns.entities = ns.entities +[group|regex_replace('^.*\.')].attributes.entity_id  | list %}
          {% endif %}
          {% endfor %}
          {# EXCLUDE #}
          {% for group in (exclude.split(',')  if exclude  is string else exclude  or []) %}
          {% if expand_groups == True %}
          {% set ns.entities = ns.entities | reject('in',(expand(group) | map(attribute="entity_id") | list)) | list %}
          {% else %}
          {% set ns.entities = ns.entities | reject('in',[group|regex_replace('^.*\.')].attributes.entity_id) | list %}
          {% endif %}
          {% endfor %}
          {# OUTPUT #}
          {{ ns.entities|join(',') }}

Example automation:

  - alias: Group Creation Test Case
      - platform: homeassistant
        event: start
      - service: script.group_set
          name: Group Exclude Test Case
          object_id: group_exclude_test_case
          - group.test_group_lights_switches
          exclude: group.computer_room
          expand_groups: True

This is the group that was created (works as desired):

@RonJ103, cool! Just to make sure: the exclude part has no expand in it. Is that intentional? I’ll add your changes to the first post then…

No, that wasn’t intentional, it was an oversight. I have fixed the code above.

Great, thank you! I included in the first post, so everyone can find it right away!

1 Like


How could i use this function and exclude the attribute is_deconz_group ? so it doesn’t pick up light groups from deconz?

You could simply use data_template when calling the built-in group.set script. Then you could do some templating, more or less like the following:

entities: {{ states.light | selectattr(... deconz stuff ...) | join(',') }}

You can test this in the template editor within Lovelace before putting it to work in your config.

Thanks for the pointer… gonna try experimenting a bit to try to understand where I’d put that line