Best way to configure a "template" that can be repeated for a template sensors

Hi,

I am attempting to setup several template sensors for air conditioner zones. There are 10 zones and I’d like to replicate10 sensors which are identical in structure but have information that is relevant to each zone. The entity/sensor has several attributes. The only thing that changes in each template definition is the zone name, which forms part of several of the entity names that the info is sourced from.

Is there a quick way of doing this?

I have looked at the macro function that is quite powerful, but from my experimentation is it can be used for a single data item i.e the state or attribute. What I’m looking at is defining a template for the whole entity (including attributes, icons, unique id etc.). Where I can pass the zone name as a parameter, say #zone, and it gets replaced through-out the syntax of the sensor config. Those of you familiar with C++ will know what I mean, but there is a pre-compiler step involved there.

Example config.

  - name: "ac zone kitchen"
    state: >
        {% if (states('schedule.sleep_time')) %}
          {% if (state_attr('climate.kitchen','current_temperature') | float >= state_attr('binary_sensor.ac_zone_sleep_time_temp_range_kitchen','upper') | float) %}
        hot
          {% elif (state_attr('climate.kitchen','current_temperature') | float <= state_attr('binary_sensor.ac_zone_sleep_time_temp_range_kitchen','lower') | float) %}
        cold
          {% else %}
        normal
          {% endif %}
        {% else %}
          {% if (state_attr('climate.kitchen','current_temperature') | float >= state_attr('binary_sensor.ac_zone_awake_time_temp_range_kitchen','upper') | float) %}
        hot
          {% elif (state_attr('climate.kitchen','current_temperature') | float <= state_attr('binary_sensor.ac_zone_awake_time_temp_range_kitchen','lower') | float) %}
        cold
          {% else %}
        normal
          {% endif %}
        {% endif %}
    icon: mdi:google-classroom
    attributes:
      current_temperature: >
        {{ state_attr('climate.kitchen','current_temperature') | float }}
      awake_time_temp_range_lower: >
        {{ states.binary_sensor.ac_zone_awake_time_temp_range_kitchen.attributes.lower }}
      awake_time_temp_range_upper: >
        {{ states.binary_sensor.ac_zone_awake_time_temp_range_kitchen.attributes.upper }}
      sleep_time_temp_range_lower: >
        {{ states.binary_sensor.ac_zone_sleep_time_temp_range_kitchen.attributes.lower }}
      sleep_time_temp_range_upper: >
        {{ states.binary_sensor.ac_zone_sleep_time_temp_range_kitchen.attributes.upper }}

  - name: "ac zone living"
    state: >
        {% if (states('schedule.sleep_time')) %}
          {% if (state_attr('climate.living','current_temperature') | float >= state_attr('binary_sensor.ac_zone_sleep_time_temp_range_living','upper') | float) %}
        hot
          {% elif (state_attr('climate.living','current_temperature') | float <= state_attr('binary_sensor.ac_zone_sleep_time_temp_range_living','lower') | float) %}
        cold
          {% else %}
        normal
          {% endif %}
        {% else %}
          {% if (state_attr('climate.living','current_temperature') | float >= state_attr('binary_sensor.ac_zone_awake_time_temp_range_living','upper') | float) %}
        hot
          {% elif (state_attr('climate.living','current_temperature') | float <= state_attr('binary_sensor.ac_zone_awake_time_temp_range_living','lower') | float) %}
        cold
          {% else %}
        normal
          {% endif %}
        {% endif %}
    icon: mdi:google-classroom
    attributes:
      current_temperature: >
        {{ state_attr('climate.living','current_temperature') | float }}
      awake_time_temp_range_lower: >
        {{ states.binary_sensor.ac_zone_awake_time_temp_range_living.attributes.lower }}
      awake_time_temp_range_upper: >
        {{ states.binary_sensor.ac_zone_awake_time_temp_range_living.attributes.upper }}
      sleep_time_temp_range_lower: >
        {{ states.binary_sensor.ac_zone_sleep_time_temp_range_living.attributes.lower }}
      sleep_time_temp_range_upper: >
        {{ states.binary_sensor.ac_zone_sleep_time_temp_range_living.attributes.upper }}

This is an example of two (of 10) zones - “kitchen” and “living”

I was able to use a macro for the “state”, which is quite handy as it is the most complex part. But would be great if I could replace text or even entities, for the whole template rather than each data item. This would make future maintenance easier as well.

I am a “tinkerer/hobbyist”. Any assistance on this is much appreciated - thanks in advance.

What’s faster?

  1. Building a tool to generate 10 Template Sensor configurations.
  2. Copy-pasting 1 configuration 10 9 times and editing each one.

I’d pick option 2 and use my text editor’s search and replace function.

Agreed. Notepad ++, Visual Studio Code or similar would makes this simple!

Many thanks @123 . Option 2 is what I have done for now.

What exactly did you mean by a “tool”. Is that some an editing tool outside home assistant?

The macro worked well for part of it!

  1. Finding a tool already written by someone else and learning it.
2 Likes

lol. Overlooking this thread prompted me to create the gomplate post, then I forgot about it :joy:

2 Likes

The linked tool still needs to be programmed to generate the ten Template Sensors in the desired format. Effectively, it’s the same as option 1; build a means of generating the desired output.

Whether you use C#, GO, shell script, even Jinja (in the Template Editor), the objective is to use something to create a means of rendering the desired output. Give it the skeleton of a single Template Sensor and ten sets of parameters and it generates ten unique Template Sensors.

A means of getting the output you want.

You give the tool the unique parameters of ten sensors and it would use them to generate ten Template Sensors based on the skeleton of one Template Sensor. How you create the “tool” is your choice and will largely depend on what programming/templating languages/facilities you’re most comfortable with … it could even be Jinja in the Template Editor.

FWIW, I and others have posted examples of using Jinja in the Template Editor to generate YAML configurations for various entities. However if one isn’t already comfortable with Jinja then the time needed to build the required templates may exceed simply copy-pasting multiple instances of a single Template Sensor.

There’s also the concept of YAML anchors and aliases … it’s useful when there are identical blocks of YAML but that’s not the case here.

Yep, and the time it would take to learn and program it means I would still copy/paste/edit 10 times.

1 Like

Thanks for that detailed description.

I’d say my jinja capability is average at best. I haven’t come across it being used to template a “re-usable” template for defining a full entity with attributes. The closest I got to it was macros. Perhaps I need to look harder!

Your example using GO and docker compose file was great. A little too complex for someone of my technical competency, particularly for such a small task. As being suggested by you and others, I will continue with copying and replacing and using Macros where possible.

What I’ve ended up with now is:

Template:

  - name: "ac zone dining"
    unique_id: "ac_zone_dining"
    icon: mdi:google-classroom
    state: >
      {% from 'ac_macros.jinja' import ac_zone %}  
      {{ ac_zone('climate.dining', 'binary_sensor.ac_zone_sleep_time_temp_range_dining', 'binary_sensor.ac_zone_awake_time_temp_range_dining') }}
    attributes:
      current_temperature: >
        {{ state_attr('climate.dining','current_temperature') | float }}
      target_temperature: >
        {{ state_attr('climate.dining', 'temperature') | float }}
      occupied: >
        {{ states('binary_sensor.zone_occupied_dining') }}
      sealed: >
        {{ states('binary_sensor.zone_sealed_dining') }}
      awake_time_temp_range_lower: >
        {{ states.binary_sensor.ac_zone_awake_time_temp_range_dining.attributes.lower }}
      awake_time_temp_range_upper: >
        {{ states.binary_sensor.ac_zone_awake_time_temp_range_dining.attributes.upper }}
      sleep_time_temp_range_lower: >
        {{ states.binary_sensor.ac_zone_sleep_time_temp_range_dining.attributes.lower }}
      sleep_time_temp_range_upper: >
        {{ states.binary_sensor.ac_zone_sleep_time_temp_range_dining.attributes.upper }}
      schedule_climate: >
        {% from 'ac_macros.jinja' import ac_zone_schedule_state %}
        {{ ac_zone_schedule_state('climate.dining', 'binary_sensor.ac_zone_sleep_time_temp_range_dining', 'binary_sensor.ac_zone_awake_time_temp_range_dining', 'schedule.ac_schedule_cool_dining', 'schedule.ac_schedule_heat_dining') }}
      schedule_cool: >
        {{states('schedule.ac_schedule_cool_dining')}}
      schedule_heat: >
        {{states('schedule.ac_schedule_heat_dining')}}

and a couple of macros:

{% macro ac_zone(zoneClimateEntity, zoneSleepTimeTempRangeEntity, zoneAwakeTimeTempRangeEntity) %}
      {% if (states('schedule.sleep_time')) %}
        {% if (state_attr(zoneClimateEntity,'current_temperature') | float >= state_attr(zoneSleepTimeTempRangeEntity,'upper') | float) %}
      hot
        {% elif (state_attr(zoneClimateEntity,'current_temperature') | float <= state_attr(zoneSleepTimeTempRangeEntity,'lower') | float) %}
      cold
        {% else %}
      normal
        {% endif %}
      {% else %}
        {% if (state_attr(zoneClimateEntity,'current_temperature') | float >= state_attr(zoneAwakeTimeTempRangeEntity,'upper') | float) %}
      hot
        {% elif (state_attr(zoneClimateEntity,'current_temperature') | float <= state_attr(zoneAwakeTimeTempRangeEntity,'lower') | float) %}
      cold
        {% else %}
      normal
        {% endif %}
      {% endif %}
{% endmacro %}

{% macro ac_zone_schedule_state(zoneClimateEntity, zoneSleepTimeTempRangeEntity, zoneAwakeTimeTempRangeEntity, zoneScheduleCoolEntity, zoneScheduleHeatEntity) %}
  {% from 'ac_macros.jinja' import ac_zone %}
  {% set zoneClimate = ac_zone(zoneClimateEntity, zoneSleepTimeTempRangeEntity, zoneAwakeTimeTempRangeEntity) %}
  {% if (zoneClimate == "hot")  %}
  {{states(zoneScheduleCoolEntity) }}
  {% elif zoneClimate == "cold" %}
  {{states(zoneScheduleHeatEntity) }}
  {% else %}
  off
  {% endif %}
{% endmacro %}

Still need copying pasting and replacing the entities, but the complex calcs are in the macros - at least only one place to maintain them, in case I change them!

Appreciate the help.