vd Brink Home Automations

Home automations: Home Assistant, ESPHome, Node-RED and more.

Follow me on GitHub

Home Assistant: Templates

Home Assistant templates banner

Home Assistant logo

Here you find some Home Assistant template examples.
With these templates you can create new custom sensors based on other sensor values to use on the dashboard or in automations. This new sensor can have a textual output or a boolean value true/false.


Table of Contents


Home Assistant

What is the difference between a binary and normal sensor?

A normal sensor can have any output, text, number or a boolean also and a binary sensor can only have a boolean value as output. It can only have the state true or false. This sensor can be used in automations to check if a condition matches.

How to add a template

There are two ways to add a template to your Home Assistant:

Via configuration.yaml

One way to add a new template is by adding the code to the configuration.yaml file. In 2022 the configuration for template entities changed. Where previously the configuration was placed under the sensor: or binary_sensor: section a new template section was introduced. Using the modern template format has a couple of advantages. You can use a trigger and action (like in automations) which gives more control over when the entity should be updated, and it allows to set a state_class so the state of the entity will also be stored in Long Term Statistics. It also allows to create button, image, number and select entities which is not possible using the legacy platform.

For more information also see the Home Assistant documentation. The legacy format is still documented all the way at the bottom.

All the examples below start with the template: key. Be sure to define this only once in your configuration.yaml. All template enitites should be created under the same template: key.

Via the frontend

The other way is via the frontend, you can create a new template via the Settings menu item, then go to Devices and Services and select Helpers.
This button directly opens the Helpers page in your Home Assistant:

Open your Home Assistant instance and show your helper entities.

Select the bottom-right button + CREATE HELPER, select Template then one of the two options Template a sensor or Template a binary sensor.

Copy the value_template part from the below examples and add it in the visual editor under State template*.

In this example a (binary) template is created to check if the current month is August.

The template helpers are more user friendly to create, but lack some of the options the YAML configuration does, like templating the icon of the sensor, and working with triggers. It also doesn’t have the option to provide a template for availablity of the entity.


How to debug a template

Via the Home Assistant frontend you can create and test a Template.
Go to the Developer tools menu item, then go to Template tab.

Or use this button to open the Helpers in your Home Assistant:

Open your Home Assistant instance and show your template developer tools.

Now you’re here:

Template debug tool

In the Template editor the code can be placed and edit, and on the right you see direct the output.

Home Assistant use Jinja as a template engine to combine static text with variables.


Where to get help

Use the below examples, search the internet, use the Home Assistant Community forum, the HA Facebook groups, Reddit or ChatGPT to help you to create your own new templates.

The Home Assistant website contains also a lot examples!

ChatGPT is really useful and fast with helping you to create a new template and improve it to fine-tune it.

chatGPT as source

Template examples

Here are all kinds of different template examples. Note that every entity has a unique_id. This does not define the entity_id, the entity_id is defined by the name (so name: "Lights On" will generate sensor.lights_on). By providing a unique_id you will be able to change name, icon, entity_id and based on the type of entity also the device_class in the frontend. It also ensures you don’t get suffixes like _2 after changing your configuration and reloading the template entities.

Is it a specific day in the year

A boolean sensor to test if it is a specific month, season, day (like Christmas or April Fools’ Day etc.)? This will create binary_sensor enties which will be on when the template returns true and otherwise they will be off You can optionally refine the entities even more by providing a template for the icon


# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - binary_sensor:
      - name: "Is January"
        unique_id: is_january
        state: >
          {{ now().month == 1 }}
      - name: "Is Monday"
        unique_id: is_monday
        state: >
          {{ now().isoweekday() == 1 }}
      - name: "Is April Fools Day"
        unique_id: is_april_fools
        state: >
          {{ now().month == 4 and now().day == 1 }}
      - name: "Is Christmas"
        unique_id: is_christmas
        state: >
          {{ now().month == 12 and now().day == 25 }}
      - name: "Is around Christmas"
        unique_id: is_around_christmas
        state: >
          {{ (now().month == 12 and now().day > 10) or (now().month == 1 and now().day < 11) }}
      - name: "Is new years eve"
        unique_id: is_new_years_eve
        state: >
          {{ now().month == 12 and now().day == 31 }}


Count the number of lights on

Count the number of lights with the status on. By checking if the entity_id attribute exists on the light entities it will exclude the light groups created in Home Assistant. Otherwise, it would count both the group, and the members as light, which will give a higher number than expected. The icon is changed dynamically based on the state of the sensor itself, and self references the state using this.state.

Number of lights on

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "# lights on"
        unique_id: count_lights_on
        icon: "{{ 'mdi:lightbulb' if this.state | int(0) > 0 else 'mdi:lightbulb-off' }}"
        unit_of_measurement: "lights"
        state: >
          {{ states.light | rejectattr('attributes.entity_id', 'defined') | selectattr('state', 'eq', 'on') | list | count }}


Calculate temperature differences

Calculate the temperature difference between an inside room temperature and the outside temperature, and round by two decimals. This sensor introduces an availability template, which will ensure the template sensor will only be available when both source sensors are working properly. If not, the template sensor will show as unavailable.

Temperature difference with outside

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Temperature diff office and outside"
        unique_id: template_diff_office_and_outside
        icon: mdi:thermometer
        unit_of_measurement: "°C"
        state: >
          {% set temp1 = states('sensor.espscd40_co2_temperature') | float %}
          {% set temp2 = states('sensor.tempest_outside_temperature') | float %}
          {{ (temp1 - temp2) | round(2, 'ceil') }}
        availabilty: "{{ 'sensor.espscd40_co2_temperature' | has_value and 'sensor.tempest_outside_temperature' | has_value }}"


Unavailable devices

Get all devices by name that have the state unavailable in a sorted list. As states are limited to 255 characters, the list is stored in an attribute, the state of the entity will be a count of the unavailable devices. The device is considered unavailable when ALL entities belonging to that device are unavailable, as it could happen that only one entity is unavailable for specific reasons.
The icon is changed dynamically and will show the number of devices as well (9+ in case it’s over 9).


# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Unavailable devices"
        unique_id: count_unavailable_devices
        state: " {{ this.attributes.get('devices', []) | count }}"
        icon: >
          {% set count = this.attributes.get('devices', []) | count %}
          {{ 'mdi:numeric-9-plus-circle' if count > 9 else ('mdi:numeric-' ~ count ~ '-circle') }}
        attributes:
          devices: >
            {% set devices = states
                               | map(attribute='entity_id')
                               | map('device_id')
                               | select()
                               | unique
            %}
            {% set ns = namespace(unavailable=[]) %}
            {% for d in devices %}
              {% set u = device_entities(d) | select('has_value') | list | count %}
              {% if device_entities(d) | count > 0 and u == 0 %}
                {% set ns.unavailable = ns.unavailable + [device_attr(d, 'name_by_user') or device_attr(d, 'name')]  %}
              {% endif %}
            {% endfor %} 
            {{ ns.unavailable }}


Low battery

Get all devices by name that have the battery level with less than 10% in a sorted list. It is not possible to simply filter on the state, as all states in Home Assistant are a string, and if you compare the string "6" with the string "10" you get unwanted results ("6" < "10" returns false).
Therefore, it is needed to convert the strings to a number first.
As we also still want to access the other properties, this requires a for-loop. To access the data created in the for loop outside the for loop, a namespace has to be used. Just like in the previous example, the names are listed in an attribute, because otherwise the character limit of 255 characters for an entity state can become an issue.

low battery devices

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Low Battery Devices"
        unique_id: count_low_batt_devices
        state: " {{ this.attributes.get('devices', []) | count }}"
        icon: >
          {% set count = this.attributes.get('devices', []) | count %}
          {{ 'mdi:numeric-9-plus-circle' if count > 9 else ('mdi:numeric-' ~ count ~ '-circle') }}
        attributes:
          devices: >
            {% set threshold = 10 %}
            {% set batt_sensors = states.sensor | selectattr('attributes.device_class', 'defined') | selectattr('attributes.device_class', 'eq', 'battery') | list %}
            {% set ns = namespace(batt_low=[]) %}
            {% for s in batt_sensors if s.state | float(101) <= threshold %}
              {% set ns.batt_low = ns.batt_low + [device_attr(s.entity_id, 'name_by_user') or device_attr(s.entity_id, 'name') or s.name] %}
            {% endfor %}
            {{ ns.batt_low }}


Floor activity

Check if there is any activity on a specific floor or section based on multiple sensors.
One minute after the last trigger the state goes back to off.

floor activity

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - binary_sensor:
      - name: "Activity downstairs"
        unique_id: activity_downstairs_sensor
        state: >
         {{ is_state("binary_sensor.motion1_occupancy", "on")
           or is_state("binary_sensor.motion2_occupancy", "on") 
           or is_state("binary_sensor.motion3_occupancy", "on") 
         }}
        device_class: occupancy
        delay_off: "00:01:00"


Day of the week translation

By default, the day of the week is in English.
With this template, it translates the day to a non-English language (like here to Dutch).

Day of the week translated

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Day of week"
        unique_id: day_of_week_sensor
        icon: mdi:calendar
        state: >
          {{ ["maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag", "zondag"][now().weekday()] }}


Trash bin days countdown

Count the days before the paper bin will be picked up.

days countdown

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Paper Waste Pickup Countdown"
        unique_id: paper_waste_pickup_countdown
        icon: mdi:delete-empty
        state: >
          {% set pickup_date = strptime(state_attr('sensor.cyclus_papier','Sort_date'), '%Y%m%d') %}
          {{ (pickup_date.date() - now().date()).days }}
        unit_of_measurement: days
        availability: "{{ strptime(state_attr('sensor.cyclus_papier','Sort_date', none), '%Y%m%d') is not none }}"

The sensor sensor.cyclus_papier has an attribute Sort_date which holds the date for the bin pickup day in the format “YYYYMMDD”.
Based on today’s date the diff in days is calculated.
(The sensor value is not always accurate, that’s why I use the attribute value.)

date attribute

Minutes since mail is delivered

Minutes since the snail mail is delivered.

minutes since mail is delivered

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Mail Delivered"
        unique_id: sensor_mail_delivered
        state: >
          {% set mailbox_datetime = states.binary_sensor.contact2_contact.last_changed %}
          {{ (now() - mailbox_datetime).total_seconds() // 60  }}
        icon: mdi:mailbox
        unit_of_measurement: minutes


What to wear outside

Based on the outside temperature defined what to wear when you go outside.

What to wear outside

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Wear outside"
        unique_id: sensor_wear_outside
        icon: mdi:tshirt-crew
        state: >-
          {% set temp = states('sensor.tempest_temperature_feels_like_rounded') | float %}
          {% if temp <= 5 %}
            winter jacket and hand gloves
          {% elif temp <= 14 %}
            softshell
          {% elif temp <= 18 %}
            thin jacket
          {% else %}
            T-shirt
          {% endif %}
        availability: "{{ 'sensor.tempest_temperature_feels_like_rounded' | has_value }}

This is the code for the mushroom card, as shown on the image, based on this template.


# Sourcecode by vdbrink.github.io
# dashboard card code
type: custom:mushroom-chips-card
chips:
  - type: entity
    entity: sensor.what_to_wear_outside
    icon: mdi:tshirt-v


Calculate daylight brightness percentage

Based on the sun sensor elevation and the cloud coverage, calculate the daylight brightness percentage. Which can be used to control the lights, the window blinds or on a floor map as overlay image.


# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Sunlight pct"
        unique_id: sunlight_pct_sensor
        state: >
          {%- set elevation = state_attr('sun.sun','elevation') | float %}
          {%- set cloud_coverage = states('sensor.dark_sky_cloud_coverage') | float %}
          {%- set cloud_factor = (1 - (0.75 * ( cloud_coverage / 100) ** 3 )) %}
          {%- set min_elevation = -6 %}
          {%- set max_elevation = 90 %}
          {%- set adjusted_elevation = elevation - min_elevation %}
          {%- set adjusted_elevation = [adjusted_elevation,0] | max %}
          {%- set adjusted_elevation = [adjusted_elevation,max_elevation - min_elevation] | min %}
          {%- set adjusted_elevation = adjusted_elevation / (max_elevation - min_elevation) %}
          {%- set adjusted_elevation = adjusted_elevation %}
          {%- set adjusted_elevation = adjusted_elevation * 100 %}
          {%- set brightness = adjusted_elevation * cloud_factor %}
          {{ brightness | round }}
        unit_of_measurement: '%'
        device_class: 'illuminance'


Daylight brightness to opacity

Daylight brightness, from the previous template, converted to opacity for CSS to use as overlay on a floor map.


# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Sunlight Opacity"
        unique_id: sensor_sunlight_opacity
        state: > 
          {%- set sunpct = states('sensor.sunlight_pct') | float %}
          {{ sunpct / 100 | float }}
 

Is it night

Boolean state if it is night. Will be on when it’s night, otherwise it will be off.


# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - binary_sensor:
      - name: "Night State"
        unique_id: binary_sensor_night_state
        state: "{{ is_state('sun.sun', 'below_horizon') }}"
        icon: "{{ 'mdi:weather-night' if is_state('sun.sun', 'below_horizon') else 'mdi:weather-sunny' }}" 


Expected rain amount

Expected rain amount for the coming hours based on the Dutch Buienradar data.

Expected rain amount

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Rain Expected"
        unique_id: sensor_expected_rain
        state: >
          {% set rain = state_attr('sensor.neerslag_buienalarm_regen_data', 'data').precip %}
          {{ rain | sum | round }}
        unit_of_measurement: 'mm'


Rain intensity

Rain intensity for the coming hours based on the Dutch Buienradar data.

Rain intensity

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: Buienalarm Rain Level
        icon: mdi:weather-pouring
        state: >-
          {% set threshold_light = '0.4' | float %}
          {% set threshold_medium = '2.0' | float %}
          {% set threshold_heavy = '5.0' | float %}
          {% set rain = state_attr('sensor.neerslag_buienalarm_regen_data', 'data').precip[0] %}
          {% if rain >= threshold_light %}
            light rain
          {% elif rain >= threshold_medium %}
            medium rain
          {% elif rain >= threshold_heavy %}
            heavy rain
          {% else %}
            no rain
          {% endif %}


CO2 threshold values

Create three static value sensors with the threshold values: 800, 1200 and 1500. As the entity_id is based on the name field, this template sensor uses a trick to give it the right name to base the entity_id on when the entity is created. After that, the name will indicate the threshold name.

C02 base values

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "{{ 'CO2 value 800' if this.state == 'unknown' else 'Good' }}"
        unique_id: sensor_co2_value_800
        state: 800
        unit_of_measurement: "ppm"
      - name: "{{ 'CO2 value 1200' if this.state == 'unknown' else 'Good' }}"
        unique_id: sensor_co2_value_1200
        state: 1200
        unit_of_measurement: "ppm"
      - name: "{{ 'CO2 value 1500' if this.state == 'unknown' else 'Good' }}"
        unique_id: sensor_co2_value_1500
        state: 1500
        unit_of_measurement: "ppm"

It’s also possible to use a Number helper for this. This generates an input_number.800 entity which can also be used in graphs. It’s important to set here also the right unit of measurement.

static helper

Overlay based on lux

When you have a floor plan and want to show a dark overlay when the lux is low, you can create a new binary sensor based on the lux value.


# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - binary_sensor:
      - name: "Overlay"
        unique_id: sensor_overlay
        state: "{{ states('sensor.motion_illuminance_lux') | float > 5 }}"
        availability: "{{ 'sensor.motion_illuminance_lux' | has_value }}"


Moon image based on state

The default moon component in Home Assistant gives the moon phase as a text value. With an image corresponding to each phase, you can show the moon phase as an image.

moon phase

Download here the moon images.


# Sourcecode by vdbrink.github.io
# configuration.yaml
# the template for the moon phase pictures using the original moon component
template:
  - sensor:
      - name: "Moon phase"
        unique_id: sensor_moon_phase
        state: "{{ states('sensor.moon') }}"
        entity_picture: /local/moon_phases/{{ this.state }}.png


DIY Sink leak status

I created a custom leak sensor based on a contact sensor. The used sensor stores the value if it detects a leak in an attribute value contact. This attribute is now used to create a boolean value.

sink leak

# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - sensor:
      - name: "Leak Sink"
        unique_id: sensor_leak_sink
        icon: mdi:water
        state: >
          {{ state_attr('binary_sensor.water_contact', 'contact') | lower }}


DIY Chair occupancy status

I created a custom chair occupancy sensor based on a contact sensor. If you sit on it the contact sensor return off.
The normal value of the contact sensor needs to be inverted.
That’s what happened here.


# Sourcecode by vdbrink.github.io
# configuration.yaml
template:
  - binary_sensor:
      - name: "Chair"
        unique_id: binary_sensor_chair
        state: >
          {{ is_state('binary_sensor.contact1_contact', 'off') }}
        device_class: presence


That’s it; I hope you can use some of these templates in your own setup.

Let me know which cool templates you use!


^^ Top

<< See also my other Home Assistant tips and tricks

Dashboard: Layout examples >>


Top | Homepage | Best Buy Tips