Groups behaviour of template sensors

For groups of most things, the value of the group is a result of ORing the values of it’s entities, groups of devices are ‘home’ if one of the devices are ‘home’ and groups of switches are ‘on’ if one of the group is one.

However I have made a group of template sensors and the value of the group is always ‘unknown’

I use template sensors to make sure my various PIR sensors all report the same when they’re activated, here’s the config for 3 z-wave PIRs:

- platform: template
  sensors:
    kitchen_motion:
      friendly_name: 'Kitchen Motion'
      value_template: >-
        {%- if is_state("sensor.aeotec_zw100_multisensor_6_burglar", "8") -%}
        true
        {%- else -%}
        false
        {%- endif -%}
    guest_motion:
      friendly_name: 'Guest Motion'
      value_template: >-
        {%- if is_state("sensor.aeotec_zw100_multisensor_6_burglar_2", "8") -%}
        true
        {%- else -%}
        false
        {%- endif -%}
    lounge_motion:
      friendly_name: 'Lounge Motion'
      value_template: >-
        {%- if is_state("binary_sensor.fibaro_system_fgms001_motion_sensor_sensor", "on") -%}
        true
        {%- else -%}
        false
        {%- endif -%}

and another MQTT based PIR:

- platform: mqtt
  state_topic: bruh/sensornode1
  name: "Office Motion"
  value_template: >-
    {%- if value_json.motion == "motion detected" -%}
    true
    {%- else -%}
    false
    {%- endif -%}

So they all report ‘true’ when they detect motion.

In my alarm config I have the following to try and detect when one of the devices triggers:

- alias: "TRIGGER the alarm when a PIR detects movement."
  trigger:
    platform: state
    entity_id: group.alarm_pirs
    to: 'true'
  condition:
    - condition: state
      entity_id: alarm_control_panel.ha_alarm
      state: armed_away
  action:
    - service: mqtt.publish
      data:
        topic: /notify/slack
        payload: 'Alarm triggered.'
    - service: alarm_control_panel.alarm_trigger
      entity_id: alarm_control_panel.ha_alarm

but the value of the group never changes from unknown.

FYI you can shrink all those template sensors to 1 line without calling out true/false:

- platform: template
  sensors:
    kitchen_motion:
      friendly_name: 'Kitchen Motion'
      value_template: >-
        {{ is_state("sensor.aeotec_zw100_multisensor_6_burglar", "8") }}
    guest_motion:
      friendly_name: 'Guest Motion'
      value_template: >-
        {{ is_state("sensor.aeotec_zw100_multisensor_6_burglar_2", "8") }}
    lounge_motion:
      friendly_name: 'Lounge Motion'
      value_template: >-
        {{ is_state("binary_sensor.fibaro_system_fgms001_motion_sensor_sensor", "on") }}

- platform: mqtt
  state_topic: bruh/sensornode1
  name: "Office Motion"
  value_template: >-
    {{ value_json.motion == "motion detected" }}

As for your question at hand. I’m not sure a group of sensors propigate to the group state. With that being said, another method to try would be this template trigger. Mind you, you cannot use the group because you need to get the entity objects to perform selectattr.

- alias: "TRIGGER the alarm when a PIR detects movement."
  trigger:
    platform: template
    value_template: >
      {% set group = [ states.sensor.guest_motion, states.sensor.kitchen_motion, states.sensor.lounge_motion, states.sensor.office_motion ] %}
      {% set output = group | selectattr('state', 'equalto', True) | list %}
      {{ output | length == group | length }}

Unfortunately, you have to hard code the names in the ‘set group’ because they need to be objects for selectattr.

What this does is filters your list to only contain items with a state that is true. If the lenght of the 2 lists are not equal, then one of the items is not true and therefore will not trigger.

1 Like

I think I could create a sensor using that same template:

- platform: template
  sensors:
    motion_detected:
      friendly_name: "Motion detected by any sensor"
          value_template: >
            {% set group = [ states.sensor.guest_motion, states.sensor.kitchen_motion, states.sensor.lounge_motion, states.sensor.office_motion ] %}
            {% set output = group | selectattr('state', 'equalto', True) | list %}
            {{ output | length == group | length }}

and while they are hard coded, it’s only the same as adding them to thr group, and I still only have to change the config in 1 place when I add more PIRs.

I’ll try it and let you know how I get on … Thanks @petro

No problem, glad to help.

which file did you configure these ?

this should be in the sensor section of your config.

EDIT: Heres the documentation on template sensors:

I create a sensor using that same template ,but why it show false?

My sensor is FIBARO MOTION SENSOR AND FIBARO WALL PLUG

not sure, it could be anything. YOu should post your yaml of all your configuration.

how would I append this for an already defined group i have? group.motion.sensors…

I don’t follow, what do you mean?

meant this:

- platform: template
  sensors:
    motion_detected:
      friendly_name: "Motion detected by any sensor"
          value_template: >
            {% set group = [ states.sensor.guest_motion, states.sensor.kitchen_motion, states.sensor.lounge_motion, states.sensor.office_motion ] %}
            {% set output = group | selectattr('state', 'equalto', True) | list %}
            {{ output | length == group | length }}

set group = [etc] needs the separate entities, creating a list, but Id like to use a group here I already have. Group.motion_sensors. If I could use that group in this template sensor, I would not have to change the logic of the sensor, because the motion sensors wouldn’t be hard coded?

using the variable Last motion right now, but this could be a valid alternative.

I don’t think there is a way because of how jinja works. It’s really annoying but the looping scope causes issues when trying to access a groups objects directly and to have the functionality seen above.

The problem is here:

We need a list, we cannot use for loop because that is iterating through the list.

states.group.mygroup.attributes.entity_id returns a tuple of strings. In order to use the selectattr() filter, we need to have an actual object. Well it is not possible to get the tuple of strings into a tuple of objects in jinja without using a for loop.

So your only option is to hard code the objects in the value_template.

i see, thanks. So it is possible with a for loop? That might be another option to try then?
bw, if I fill out my individual sensor entities here, the value remains False, while waving actively :wink:

yep, you can use a for loop but that template won’t behave properly with a for loop because of the scope limitations of jinja. It’s pretty much a catch-22.

too bad really.
Well, will keep using this then, works fine:

automation:
# Update Last Motion variable
  - alias: "Update Last Motion"
    id: 'Update Last Motion'
    initial_state: 'on'
    trigger:
      platform: state
      entity_id:
        - sensor.corridor_motion_sensor
        - sensor.auditorium_motion_sensor
        - sensor.dining_table_motion_sensor
        - sensor.master_bedroom_motion_sensor
        - sensor.dorm_motion_sensor
        - sensor.frontdoor_motion_sensor
        - sensor.control_room_motion_sensor
        - sensor.attic_motion_sensor
      to: 'on'
    action:
      service: variable.set_variable
      data:
        variable: last_motion
        attributes_template: >
          {
                "history_1": "{{ variable.state }}",
                "history_2": "{{ variable.attributes.history_1 }}",
                "history_3": "{{ variable.attributes.history_2 }}",
                "history_4": "{{ variable.attributes.history_3 }}",
                "history_5": "{{ variable.attributes.history_4 }}"
          }
      data_template:
        value: "{{ trigger.to_state.attributes.friendly_name }}"

A you see, this also needs the sensors to be hardcoded, hence my desire to try differently.
and as mentioned, if I use these sensors in the template motion_detected, nothing happens and the value remains False…having changed to selectattr(‘state’, ‘equalto’, ‘on’) since my sensors have that state

check what @dale3h has come up with:

{{ dict((states|selectattr('entity_id', 'in', state_attr('group.entrypoints', 'entity_id'))|list)|groupby('state'))['open']|map(attribute='name')|list|join(', ') }}

changed into:

{{ dict((states|selectattr('entity_id', 'in', state_attr('group.philips_motion_sensors', 'entity_id'))|list)|groupby('state'))['on']|map(attribute='name')|list|join(', ') }}

or

      {{ dict((states|selectattr('entity_id', 'in', state_attr('group.all_lights_only', 'entity_id'))
      |list)|groupby('state'))['on']|map(attribute='name')|list|join(', ') }}

so cool.

I did not know that ‘in’ was an option for selectattr. Nore did I think about using it against the state object… so with that being the case, this is what the jinja would look like instead of hard coding the motion devices.

- platform: template
  sensors:
    motion_detected:
      friendly_name: "Motion detected by any sensor"
          value_template: >
            {% set group = states | selectattr('entity_id', 'in', state_attr('group.motion', 'entity_id')) | list %}
            {% set output = group | selectattr('state', 'equalto', True) | list %}
            {{ output | length == group | length }}

Thanks @dale3h, makes this easier.

1 Like

keeps giving False…

btw the @dale3h template acts a bit unexpectedly in the frontend:

while showing this correctly in the dev-tools:

it shows only this in the frontend:

4654

same goes for the motion sensors… only one showing, and with reasonable amount of lag, so it skips sensors on my walk to the espresso machine :wink:

The example above is to see if all motion sensors are tripping. Translating that to ‘everyone being home’ requires True to change to ‘Home’ or ‘home’ (not sure which one).

- platform: template
  sensors:
    everyone_home:
      friendly_name: "Sensor that tells me if Everyone is home"
          value_template: >
            {% set all_people = states | selectattr('entity_id', 'in', state_attr('group.family', 'entity_id')) | list %}
            {% set home_people = all_people | selectattr('state', 'equalto', 'home') | list %}
            {{ all_people | length == home_people | length }}

Sure, but I have changed that accordingly, as in the template shown here.

Neither work