Add attributes to Template cover

just like we can use and set those on Sensor and Binary_sensor. or an attribute_templates,as allowed for the legacy format templates

unfortunately:

Invalid config for [cover.template]: [attribute_templates] is an invalid option for [cover.template]. Check: cover.template->covers->rolluik_studenten_template->attribute_templates. (See ?, line ?). 

Combined with the new this variable, an attribute, in below use case for id, would allow us to completely copy a full entity config, and fill out the essential id automatically, using a yaml anchor.

Compare the strength of that in a template sensor like:

template:

  - sensor:

      - unique_id: dark_sky_forecast_0
        <<: &config_dsf
          name: >
            {% set id = this.attributes.get('id',0) %}
            {{as_timestamp(now() + timedelta(days=id|int(default=0)),none)|timestamp_custom('%a %-d %b',default="Not yet set")}}: {{
              states('sensor.dark_sky_forecast_icon_'~id~'d').replace('-',' ')|capitalize}}

          state: >
            {% set id = this.attributes.get('id',0) %}
            {{- states('sensor.dark_sky_forecast_daytime_high_temperature_'~id~'d')}}°/
            {{- states('sensor.dark_sky_forecast_overnight_low_temperature_'~id~'d')}}°/
            {{- states('sensor.dark_sky_forecast_precip_probability_'~id~'d')}}%
          picture: >
            {% set id = this.attributes.get('id',0) %}
            {{'/local/weather/icons/' ~ states('sensor.dark_sky_forecast_icon_'~id~'d') ~ '.png'}}
        attributes:
          id: 0

      - unique_id: dark_sky_forecast_1
        <<: *config_dsf
        attributes:
          id: 1

      - unique_id: dark_sky_forecast_2
        <<: *config_dsf
        attributes:
          id: 2

and now for the Template cover, which we can Not use an attribute, and as a consequence need to copy the full config for all Covers:

cover:

  - platform: template
    covers:
      rolluik_voorkamer_template:
        unique_id: rolluik_voorkamer_template
        device_class: shutter
        friendly_name: Rolluik voorkamer template
        open_cover:
          service: cover.open_cover
          target: &voor
            entity_id: >
              {% set id = 'voorkamer' %}
              {% set silent = states('input_boolean.discrete_covers') %}
              {% if silent == 'on' %} cover.rolluik_{{id}}_low_speed
              {% else %} cover.rolluik_{{id}}
              {% endif %}
        position_template: >
          {% set id = 'voorkamer' %}
          {{state_attr('cover.rolluik_'~id,'current_position')}}
        close_cover:
          service: cover.close_cover
          target: *voor
        stop_cover:
          service: cover.stop_cover
          target: *voor
        set_cover_position:
          service: cover.set_cover_position
          target: *voor
          data:
            position: '{{position}}'
        availability_template: >
          {% set id = 'voorkamer' %}
          {{state_attr('cover.rolluik_'~id,'current_position')|is_number}}

      rolluik_logeerkamer_template:
        unique_id: rolluik_logeerkamer_template
        device_class: shutter
        friendly_name: Rolluik logeerkamer template
        open_cover:
          service: cover.open_cover
          target: &logeer
            entity_id: >
              {% set id = 'logeerkamer' %}
              {% set silent = states('input_boolean.discrete_covers') %}
              {% if silent == 'on' %} cover.rolluik_{{id}}_low_speed
              {% else %} cover.rolluik_{{id}}
              {% endif %}
        position_template: >
          {% set id = 'logeerkamer' %}
          {{state_attr('cover.rolluik_'~id,'current_position')}}
        close_cover:
          service: cover.close_cover
          target: *logeer
        stop_cover:
          service: cover.stop_cover
          target: *logeer
        set_cover_position:
          service: cover.set_cover_position
          target: *logeer
          data:
            position: '{{position}}'
        availability_template: >
          {% set id = 'logeerkamer' %}
          {{state_attr('cover.rolluik_'~id,'current_position')|is_number}}

thanks for considering

This example actually has a bug, it’s going to be wrong at restart of HA and then correct itself next update. The problem is this piece in every template:

I get why you put that. If you don’t you get errors at startup because the state template is evaluated before the attributes ones. But by putting it you’re actually hiding a different error. dark_sky_forecast_1 and dark_sky_forecast_2 are going to set their state identical to dark_sky_forecast_0 at startup because id is going to default to 0.

I believe a better way to do this is to use customization to add that attribute to those entities. That way after a startup the value of the id attribute is already there before the state template runs. And there’s no need to add the problematic default value, you can just do this.attributes.get('id').

The other benefit is customization works fine with all types of entities, covers too. So whenever this support is added to template covers you can use the YAML anchor approach there too without needing support for attribute templates.

thx Mike!

hehe, I knew I should have provided another example… its just I had posted it to Erik, and I wanted to sync those 2 action of mine :wink:

maybe I should have used:

      - unique_id: marijn_abroad
        attributes:
          id: marijn
        <<: &id_abroad
          name: >
            {% set id = this.attributes.id|default('Not yet set') %}
            {{id|title}} abroad
          state: >
            {% set id = this.attributes.id|default('Not yet set') %}
            {{not is_state_attr('sensor.' ~ id ~ '_app_geocoded_location','ISO Country Code','NL')}}
          picture: >
            {% set id = this.attributes.id|default('Not yet set') %}
            {% set cc = state_attr('sensor.' ~ id ~ '_app_geocoded_location','ISO Country Code')|lower %}
            {% set path = '/local/flags/' %}
            {% set ext = '.png' %}
            {% if cc is not none %}
            {% set flag = cc %}
            {% else %} {% set flag = 'nl' %}
            {% endif %}
            {{[path,flag,ext]|join('')}}

      - unique_id: wijke_abroad
        attributes:
          id: wijke
        <<: *id_abroad

as an example, which uses a more logical string in the default.
Main point was the use of an attribute id, so we can copy&paste the full config, and have the id filled automatically.

Customization is a great thing yes, I use it a lot. Reason I didnt use it here, is I have been trying to cut down on those, and moving as much as possible into the core config options.

This might be the spot where not tom and keep customization. thanks for the suggestion!

Still, allowing custom attributes would be streamlining things… making core code more consistent.

So hope you’ll allow the FR to stand for a bit more?
Cheers!

btw, this is a first to me, but adding:

    cover.rolluik_studenten_template:
      id: studenten

    cover.rolluik_logeerkamer_template:
      id: logeerkamer

    cover.rolluik_slaapkamer_template:
      id: slaapkamer

in the customize: section requires a restart. Normally, customizations, even my templates and colors via custom-ui, are loaded via ‘reload customizations’, but not now.

I wonder why that would be.

btw, can confirm that:

    sensor.dark_sky_forecast_0:
      id: 0
    sensor.dark_sky_forecast_1:
      id: 1
    sensor.dark_sky_forecast_2:
      id: 2
    sensor.dark_sky_forecast_3:
      id: 3
    sensor.dark_sky_forecast_4:
      id: 4
    sensor.dark_sky_forecast_5:
      id: 5

and

      - unique_id: dark_sky_forecast_0
        <<: &config_dsf
          name: >
            {% set id = this.attributes.get('id') %}
            {{as_timestamp(now() + timedelta(days=id|int(default=0)),none)|timestamp_custom('%a %-d %b',default="Not yet set")}}: {{
              states('sensor.dark_sky_forecast_icon_'~id~'d').replace('-',' ')|capitalize}}

          state: >
            {% set id = this.attributes.get('id') %}
            {{- states('sensor.dark_sky_forecast_daytime_high_temperature_'~id~'d')}}°/
            {{- states('sensor.dark_sky_forecast_overnight_low_temperature_'~id~'d')}}°/
            {{- states('sensor.dark_sky_forecast_precip_probability_'~id~'d')}}%
          picture: >
            {% set id = this.attributes.get('id') %}
            {{'/local/weather/icons/' ~ states('sensor.dark_sky_forecast_icon_'~id~'d') ~ '.png'}}

      - unique_id: dark_sky_forecast_1
        <<: *config_dsf

      - unique_id: dark_sky_forecast_2
        <<: *config_dsf

works nicely, error free:

So my experience is that when you reload customizations in the UI then you see those customizations next time the state is updated for that entity. But until then it continues to display without them. The doc actually notes that in the warning at the bottom.

I’m not going to close it, it’s still a valid request. Although I will say that with all the work done to remove/eliminate attributes across core I’m a bit skeptical this one will be taken up. Not just all the recent performance work either it seems like there’s been a concerted effort to reduce or eliminate attributes for years now and instead make more sensors. You can see that not just in core but also even in HACS integrations and addons at this point as they refactor them out over time.

But others may disagree. Other template entities have them so I’m sure covers could too.

1 Like

yeah, I get that, though this would be an attribute of different ‘type’… we’ll see.

letting you know that the original reason for request is pretty nicely solved thanks to your suggestion:

cover:

  - platform: template
    covers:

      rolluik_studenten_template:
        unique_id: rolluik_studenten_template
#        attribute_templates:
#          id: '{{studenten}}'
        <<: &config
          device_class: shutter
          friendly_name: >
            Rolluik {{this.attributes.get('id')}} template
          open_cover:
            service: cover.open_cover
            target: &cover
              entity_id: >
                {% set id = this.attributes.get('id') %}
                {% set silent = states('input_boolean.discrete_covers') %}
                {% if silent == 'on' %} cover.rolluik_{{id}}_low_speed
                {% else %} cover.rolluik_{{id}}
                {% endif %}
          position_template: >
            {% set id = this.attributes.get('id') %}
            {{state_attr('cover.rolluik_'~id,'current_position')}}
          close_cover:
            service: cover.close_cover
            target: *cover
          stop_cover:
            service: cover.stop_cover
            target: *cover
          set_cover_position:
            service: cover.set_cover_position
            target: *cover
            data:
              position: '{{position}}'
          availability_template: >
            {% set id = this.attributes.get('id') %}
            {{state_attr('cover.rolluik_'~id,'current_position')|is_number}}

      rolluik_voorkamer_template:
        unique_id: rolluik_voorkamer_template
        <<: *config

      rolluik_logeerkamer_template:
        unique_id: rolluik_logeerkamer_template
        <<: *config

really cool!

1 Like

TIL template covers support this :grinning_face_with_smiling_eyes: I thought covers were one of the ones where support was still pending. Nice :+1:

omt:

we need to use

{% set id = this.attributes.get('id') %}

because when trying with:

{% set id = this.attributes.id %}

the error

Logger: homeassistant.helpers.template
Source: helpers/template.py:1914 
First occurred: July 6, 2022, 23:59:46 (18 occurrences) 
Last logged: July 6, 2022, 23:59:47

Template variable warning: 'homeassistant.util.read_only_dict.ReadOnlyDict object' has no attribute 'id' when rendering '{% set id = this.attributes.id %} /local/family/{{id}}_home.png'

returns, even though the attribute is already fixed and set to the template…

For some reason I have the expression

{% set id = this.attributes.get('id') %}
current {{ id }}

gives this result: “current None”