Does anyone have an example of Template Sensors / Triggers?

FWIW

It is possible to create a template binary sensor to find the state of all the motion sensors in a specified area or list of areas. That would reduce your need to do code maintenance on your groups if you change a sensor’s physical location, but you would still have to do some maintenance updating the entity’s area…


{% set ns = namespace(m_areas = []) %}
{% set x = states.binary_sensor|selectattr('attributes.device_class', 'eq', 'motion')|map(attribute='entity_id')|list %}
{% for y in x %}
{% if area_name(y) == 'Kitchen' %}
  {% set ns.m_areas = ns.m_areas + ['{}'.format(states(y))] %}
{% endif %}{% endfor %}
{{ 'on' if 'on' in (ns.m_areas|join(', ')) else 'off'}}

To check a list of areas ( like your “First Floor Motion” example) you would modify the “{% if area_name(y)…” line :


{% if area_name(y) in ['Kitchen', 'Living Room', 'Dining Room'] %}

I don’t know for sure, but I think this approach would use more processing resources than using a group… the template is going to render any time any binary_sensor updates.

Thanks @Didgeridrew. I more interested in learning about Home Assistant than being worried about performance. This is a great example from which I will learn a lot.

Cool code. I have two questions. How would the code look if I would want to return the lowest value rather than the entity? It did return my Apple Watch as the entity which has the lowest battery which is totally correct, but not what I am looking for. What is I want to exclude the devices from my Apple iCloud integration?

I would just set a variable equal to the original code, then you can use the variable like you would an entity_id in any other template…

{% set x = states.sensor | selectattr('attributes.device_class', 'eq', 'battery')| rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state')|map(attribute='entity_id')| first %}
{{state_attr(x, 'friendly_name')}}: {{states(x)}}%

The above will return something like:

Tokyo’s Apple Watch: 50%

I don’t use the iCloud integration, so you’ll have to help me figure out a way to filter those entities. Some integrations create a state attribute called “attribution” whose value will be something like “Data provided by Accuweather”… does iCloud do anything like that…?

The way to do it without having to figure any of that out is to just make a list of the iCloud related battery sensors, then reject any entity_id in that list:

{% set icloud_batteries = ['sensor.apple_watch_battery', 'sensor.iphone_battery']%}
{% set x = states.sensor | rejectattr('entity_id', 'in', icloud_batteries)| selectattr('attributes.device_class', 'eq', 'battery')| rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state')|map(attribute='entity_id')| first %}
{{state_attr(x, 'friendly_name')}}: {{states(x)}}

Yes, the iCloud integration does the same. “Data provided by Apple uCloud”

Great! You should be able to use that as the attribute in a rejectattr filter so it automatically filters out any iCloud devices:

{% set x = states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state') | map(attribute='entity_id') | first %}
{{state_attr(x, 'friendly_name')}}: {{states(x)}}
template:
    - sensor:
        - name: "Lowest Battery Level"
          unit_of_measurement: "%"
          state_class: measurement
          device_class: battery
          state: >
            {% set x = states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state') | map(attribute='entity_id') | first %}
            {{states(x)}}

I am making good progress with the template sensor, but somehow it does not return the sensor information I expected. It returns a sensor with battery 100% while one of the sensors have battery 50%.

STATE: 50.0
ATTRIBUTES:
state_class: measurement
unit_of_measurement: '%'
friendly_name: 'MultiSensor 6: Battery level'
device_class: battery

Any suggestions on how to troubleshoot?

Also, I want to assign the friendly_name of that sensor to the friendly_name of the template sensor. HA complains friendly_name is not a valid option.

          state: >
            {% set x = states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state') | map(attribute='entity_id') | first %}
            {{states(x)}}
          friendly_name: >
            {% set x = states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state') | map(attribute='entity_id') | first %}
            {{state_attr(x, 'friendly_name')}}

Setting up the template sensor like you have may lead to some issues…

By putting it in the battery device class, it becomes self-referential. You can filter it out by adding another rejectattr, but I would just leave the device class as default.

The measurement state class isn’t really appropriate here.

The entity’s friendly name is created based on the name you give the sensor. As far as I know, it can’t be defined by a template. You can, however, use templates to define a custom attribute.

Below is a slightly different method that may work better for you.

template:
  sensor:
    - name: "Lowest Battery Level"
      unit_of_measurement: "%"
      state: >-
        {{ (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | map(attribute='state')) | list | map('int') | select("greaterthan", 0)| min }}
      attributes:
        sensor_name: >-
          {% set b = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery')| map(attribute='state')) | list | map('int') | select("greaterthan", 0)| min | string%}
          {% set c = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | selectattr('state', 'eq', b) | first) %}
          {{ c.name }}

Keep in mind that both methods have the same drawback… if a battery gets so low that the device goes offline, its state will be “unknown” or “unavailable” and it will not be displayed by this sensor.

Thanks for all the patience. I have been Googling, but have not come across any good tutorials. I understand the template scripts are based on Jinja2; that by itself is a bit of a paradigm shift for me. I hope this post will be helpful for others as well. Home Assistant is a bit overwhelming for a newbie, but I have realized that taking baby steps helps to overcome. Not to mention, the help from the community as well.

I did make some changes to the code since my last post and by putting friendly_name under attributes, it is possible to update it.

template:
    - sensor:
        - unique_id: lowest_battery_level
          state_class: measurement
          device_class: battery
          state: >
            {% set x = states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state') | map(attribute='entity_id') | first %}
            {{states(x)}}
          attributes:
            friendly_name: >
              {% set x = states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging', '100']) | sort( attribute = 'state') | map(attribute='entity_id') | first %}
              {{state_attr(x, 'friendly_name')}}

As you correctly noted, it does not make sense to use device_class: battery.

I will play around with your sample code provided here and let you know how it goes.

This what I have so far and seems to work well. Thanks @Didgeridrew

        - unique_id: lowest_battery_level
          name: "Lowest Battery Level"
          unit_of_measurement: "%"
          state: >-
            {{ (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | map(attribute='state')) | list | map('int') | select("greaterthan", 0)| min }}
          icon: >-
            {% set battery_level = states.sensor.lowest_battery_level.state|default(0)|int %}
            {% set battery_round = (battery_level / 10) |int * 10 %}
            {% if battery_round >= 100 %}
              mdi:battery
            {% elif battery_round > 0 %}
              mdi:battery-{{ battery_round }}
            {% else %}
              mdi:battery-alert
            {% endif %}
          attributes:
            sensor_name: >-
              {% set b = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery')| map(attribute='state')) | list | map('int') | select("greaterthan", 0)| min | string%}
              {% set c = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | selectattr('attributes.device_class', 'eq', 'battery') | selectattr('state', 'eq', b) | first) %}
              {{ c.name }}
1 Like

I am still struggling with getting the list ordered in increased state value. The following code seems to put the values with a .0 at the end.

{% set x = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | rejectattr('state', 'in', ['unavailable']) | selectattr('attributes.device_class', 'eq', 'battery') | sort(attribute='state',reverse=true) | map(attribute='state') | list) %}

[
  "87",
  "58",
  "50.0",
  "100.0",
  "100.0"
]

When putting an [int] in the sort, the 58 and 50.0 trade places, but the 87 is now listed last before 100.0.

{% set x = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | rejectattr('state', 'in', ['unavailable']) | selectattr('attributes.device_class', 'eq', 'battery') | sort(attribute='state'[int],reverse=true) | map(attribute='state') | list) %}

[
  "50.0",
  "65",
  "100.0",
  "100.0",
  "87"
]

Does anyone have any thoughts?

You have to remember that, unless you change it, everything produced by a template is a string… so what your first template is doing is sorting like you would sort words… by evaluating the left-most “letter” (in this case 8, 5, 5, 1, 1). The order is from highest to lowest because you reversed the sort.

In your second template the sort filter doesn’t make sense, so it is being ignored completely. If you erase it, the output will be the same.

Below is a variation on what I posted in post #15 above which will produce a list sorted by increasing state value.

{% set x = (states.sensor 
| rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud')
| selectattr('attributes.device_class', 'eq', 'battery') 
| rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging']) 
| map(attribute='state') 
| map('int') 
| sort()
| list) %}
{{ x }}

What if I would like to sort the entities based on the numerical value of the state? This code will treat the state as a string.

{% set x = (states.sensor 
| rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud')
| selectattr('attributes.device_class', 'eq', 'battery') 
| rejectattr('state', 'in', ['unavailable', 'unknown', 'discharging'])
| sort(attribute='state', reverse=true) | list) %}
{{ x }}

This seems to work:

template:
    - sensor:
        - unique_id: lowest_battery_level
          name: "Lowest Battery Level"
          unit_of_measurement: "%"
          state: >-
            {% set x = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | rejectattr('state', 'in', ['unavailable']) | selectattr('attributes.device_class', 'eq', 'battery')  ) %}
            {% set lowest_battery = namespace(entity=0, value=1000) %}
            {% for y in x %}
                {% if (y.state | int) < lowest_battery.value %}
                {% set lowest_battery.value = y.state | int %}
                {% set lowest_battery.entity = y %}
                {% endif %}
            {% endfor %}
            {{ lowest_battery.entity.state }}
          icon: >-
            {% set battery_level = states.sensor.lowest_battery_level.state|default(0)|int %}
            {% set battery_round = (battery_level / 10) |int * 10 %}
            {% if battery_round >= 100 %}
              mdi:battery
            {% elif battery_round > 0 %}
              mdi:battery-{{ battery_round }}
            {% else %}
              mdi:battery-alert
            {% endif %}
          attributes:
            sensor_name: >-
              {% set x = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | rejectattr('state', 'in', ['unavailable']) | selectattr('attributes.device_class', 'eq', 'battery')  ) %}
              {% set lowest_battery = namespace(entity=0, value=1000) %}
              {% for y in x %}
                {% if (y.state | int) < lowest_battery.value %}
                {% set lowest_battery.value = y.state | int %}
                {% set lowest_battery.entity = y %}
                {% endif %}
              {% endfor %}
              {{ lowest_battery.entity.name }}

That almost worked for me… I had to add “unknown” to the rejectattr and to get rid of a few straggling battery_state sensors that would return “charging”, “discharging”, etc I switched the device_class-based selecattr for:

| selectattr('entity_id', 'search', 'battery_level')

{% set x = (states.sensor 
| rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') 
| rejectattr('state', 'in', ['unavailable', 'unknown']) 
| selectattr('entity_id', 'search', 'battery_level') ) %}
{% set lowest_battery = namespace(entity=0, value=1000) %}
{% for y in x %}
    {% if (y.state | int) < lowest_battery.value %}
    {% set lowest_battery.value = y.state | int %}
    {% set lowest_battery.entity = y %}
    {% endif %}
{% endfor %}
{{ lowest_battery.entity.state }}

You seem to know this stuff very well. Are there any write ups or tutorials or is it a matter of trial and error?

I assume this searches for entities with entity id which includes battery_level. Is there a change that an entity is missed? Probably the same could be said for selecting entities which belongs to the device class battery. I found one entity which is of the device class battery and has entity id sensor.tradfri_remote_control.

By the way, just curious, what does the ‘-’ in state: > vs state: >- ?

Just like you, I’m no expert and I’m still learning… there are members on this forum who know this stuff way better than me. I just try to help out where I can.

I learned a lot of the basics from Youtube videos, from searching this forum, and from reading the Jinja template designer page, and the Home Assistant docs

Yes, there is a chance that an entity or two are missed with this template, or any other template. There are a lot of devices that work with Home Assistant, but not all integrations expose device information in the same format. If you have an entity that doesn’t create its own battery_level sensor, there are a couple methods that can be used to have that entity work with this template. I would just create a battery_level sensor using a template sensor.

The difference between “>” and “>-” can be found here. Either one will work for Home Assistant templates, I use “>-” out of habit more than necessity.

Very much appreciated. I learned a lot from going through this exercise.

I still prefer to filter on the device class because if the device class is battery, I can assume state is the battery level. After some polishing I can up with this.

template:
    - sensor:
        - unique_id: lowest_battery_level
          name: >-
            {# get list of battery entities #}
            {% set battery_entities = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | rejectattr('state', 'in', ['unavailable', 'unknown']) | selectattr('attributes.device_class', 'eq', 'battery')  ) %}
            {# get entity with lowest battery state #}
            {% set lowest_battery = namespace(entity=0, value=101) %}
            {% for x in battery_entities %}
                {% if (x.state | int) < lowest_battery.value %}
                    {% set lowest_battery.value = x.state | int %}
                    {% set lowest_battery.entity = x %}
                {% endif %}
            {% endfor %}
            {% if lowest_battery.entity %}
                {{ lowest_battery.entity.name }}
            {% else %}
                {{ "unknown" }}
            {% endif %}
          state: >-
            {# get list of battery entities #}
            {% set battery_entities = (states.sensor | rejectattr('attributes.attribution', 'eq', 'Data provided by Apple iCloud') | rejectattr('state', 'in', ['unavailable', 'unknown']) | selectattr('attributes.device_class', 'eq', 'battery')  ) %}
            {# get entity with lowest battery state #}
            {% set lowest_battery = namespace(entity=0, value=101) %}
            {% for x in battery_entities %}
                {% if (x.state | int) < lowest_battery.value %}
                    {% set lowest_battery.value = x.state | int %}
                    {% set lowest_battery.entity = x %}
                {% endif %}
            {% endfor %}
            {% if lowest_battery.entity %}
                {{ lowest_battery.entity.state }}
            {% else %}
                {{ "unknown" }}
            {% endif %}
          unit_of_measurement: "%"
          icon: >-
            {% set battery_level = states.sensor.lowest_battery_level.state|default(0)|int %}
            {% set battery_round = (battery_level / 10) |int * 10 %}
            {% if battery_round >= 100 %}
              mdi:battery
            {% elif battery_round > 0 %}
              mdi:battery-{{ battery_round }}
            {% else %}
              mdi:battery-alert
            {% endif %}

The only thing I am not have with is that I need to filter and iterate through the entities multiple times and wish there is a way to do that once and refer to the resulting entity multiple times.

There are a few feature request posts to have the ability to use variables added to Template Sensors… but until that happens you’re only other option is:

I have a follow up question regarding trigger based sensors. The documentation for trigger sensors states: trigger list (optional) Define an automation trigger to update the entities. Optional. If omitted will update based on referenced entities.
What would be the difference between

template:
  - sensor:

and

template:
  - trigger:
    sensor: