Create advanced template sensor with attributes from for loop

I have been trying to create this template sensor from the weather service, but something fails.

  - trigger:
      - platform: time_pattern
        hours: /1
      - platform: homeassistant
        event: start
    action:
      - service: weather.get_forecasts
        data:
          type: daily
        response_variable: daily
        target:
          entity_id: weather.rykkinn
    sensor:
      - name: "Weather Now and Daily"
        unique_id: weather_now_daily
        state: "To be replaced"
        attributes: >
          {% set forecast = daily['weather.rykkinn'].forecast %}
          {% set sun_state = 'day' if is_state('sun.sun', 'above_horizon') else 'night' %}
          {%- for i in range(6) %}
            datetime{{ i }}: "{{ forecast[i].datetime }}"
            condition{{ i }}: "{{ forecast[i].condition }}"
            cond_icon{{ i }}: "/local/ic/weather_icons/animated3/{{ forecast[i].condition }}_{{ sun_state }}.svg"
            temperature{{ i }}: "{{ forecast[i].temperature }}"
            precipitation{{ i }}: "{{ forecast[i].precipitation }}"
          {%- endfor %}

The error in the log is:

2024-08-07 11:50:29.310 ERROR (MainThread) [homeassistant.config] Invalid config for ‘template’ at configuration.yaml, line 679: expected a dictionary for dictionary value ‘sensor->0->attributes’, got '{% set forecast = daily['weather.rykkinn'].forecast %} {% set sun_state = 'day' if is_state('sun.sun', 'above_horizon') else 'night' %} {% set attributes = {} %} {%- for i in range(6) %}\n {% set attributes = attributes | merge({\n ('datetime' ~ i|string): forecast[i].datetime,\n ('condition' ~ i|string): forecast[i].condition,\n ('cond_icon' ~ i|string): “/local/ic/weather_icons/animated3/” ~ forecast[i].condition ~ “_” ~ sun_state ~ “.svg”,\n ('temperature' ~…

When I test config in the GUI it says all is well.

Output from the service is:

weather.rykkinn:
  forecast:
    - condition: cloudy
      precipitation_probability: 0.4
      datetime: "2024-08-07T10:00:00+00:00"
      wind_bearing: 154.2
      cloud_coverage: 100
      temperature: 21.5
      wind_gust_speed: 23.8
      wind_speed: 8.6
      precipitation: 0
      humidity: 64
    - condition: cloudy
      precipitation_probability: 0.6
      datetime: "2024-08-07T11:00:00+00:00"
      wind_bearing: 155.6
      cloud_coverage: 100
      temperature: 22.6
      wind_gust_speed: 24.8
      wind_speed: 10.1
      precipitation: 0
      humidity: 62
    - condition: cloudy
      precipitation_probability: 0.4
      datetime: "2024-08-07T12:00:00+00:00"
      wind_bearing: 155.5
      cloud_coverage: 94.4
      temperature: 23.1
      wind_gust_speed: 31.3
      wind_speed: 13.7
      precipitation: 0
      humidity: 61

(and more for the coming days)

Could anyone see what I have done wrong here? I thought this should work, but there is something HA is interpreting that I cannot catch. Also I find this very hard to test in the templating tool. Do you have a suggestion how I could debug the problem further?

You can’t template the entire attributes section of a template entity. And if you were able to do that, you’d have to return a dictionary in JSON, not yaml.

Thanks! The error comes when I boot HA and the code is as posted. The code is from configuration.yaml but I also struggle to understand the logged error.

But when you say I cannon use jinja2 in a template sensor, then I do not understand how this works:

      - name: "Weather Now"
        unique_id: weather_now
        state: "Something"
        attributes:
          condition: "{{ daily['weather.rykkinn'].forecast[0].condition }}"
          cond_icon: >
            {% set weather = daily['weather.rykkinn'].forecast[0].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature: "{{ daily['weather.rykkinn'].forecast[0].temperature }}"
          feels_like: "{{ daily['weather.rykkinn'].forecast[0].condition }}"
          precipitation: "{{ daily['weather.rykkinn'].forecast[0].precipitation }}"
          precipitation_percent: "{{ daily['weather.rykkinn'].forecast[0].precipitation_probability }}"
          wind_dir: "{{ daily['weather.rykkinn'].forecast[0].wind_bearing }}"
          wind_speed: "{{ daily['weather.rykkinn'].forecast[0].wind_speed }}"
          wind_gust_speed: "{{ daily['weather.rykkinn'].forecast[0].wind_gust_speed }}"
          datetime1: "{{ daily['weather.rykkinn'].forecast[1].datetime }}"
          condition1: "{{ daily['weather.rykkinn'].forecast[1].condition }}"
          cond_icon1: >
            {% set weather = daily['weather.rykkinn'].forecast[1].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature1: "{{ daily['weather.rykkinn'].forecast[1].temperature }}"
          precipitation1: "{{ daily['weather.rykkinn'].forecast[1].precipitation }}"
          datetime2: "{{ daily['weather.rykkinn'].forecast[2].datetime }}"
          condition2: "{{ daily['weather.rykkinn'].forecast[2].condition }}"
          cond_icon2: >
            {% set weather = daily['weather.rykkinn'].forecast[2].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature2: "{{ daily['weather.rykkinn'].forecast[2].temperature }}"
          precipitation2: "{{ daily['weather.rykkinn'].forecast[2].precipitation }}"
          datetime3: "{{ daily['weather.rykkinn'].forecast[3].datetime }}"
          condition3: "{{ daily['weather.rykkinn'].forecast[3].condition }}"
          cond_icon3: >
            {% set weather = daily['weather.rykkinn'].forecast[3].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature3: "{{ daily['weather.rykkinn'].forecast[3].temperature }}"
          precipitation3: "{{ daily['weather.rykkinn'].forecast[3].precipitation }}"
          datetime4: "{{ daily['weather.rykkinn'].forecast[4].datetime }}"
          condition4: "{{ daily['weather.rykkinn'].forecast[4].condition }}"
          cond_icon4: >
            {% set weather = daily['weather.rykkinn'].forecast[4].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature4: "{{ daily['weather.rykkinn'].forecast[4].temperature }}"
          precipitation4: "{{ daily['weather.rykkinn'].forecast[4].precipitation }}"
          datetime5: "{{ daily['weather.rykkinn'].forecast[5].datetime }}"
          condition5: "{{ daily['weather.rykkinn'].forecast[5].condition }}"
          cond_icon5: >
            {% set weather = daily['weather.rykkinn'].forecast[5].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature5: "{{ daily['weather.rykkinn'].forecast[5].temperature }}"
          precipitation5: "{{ daily['weather.rykkinn'].forecast[5].precipitation }}"

The purpose is to build a customised weather forecast card for my dashboard.

This is not what was said. Notice the one that works templates each attribute. Not the entire attributes section.

1 Like

This should work

  - trigger:
      - platform: time_pattern
        hours: /1
      - platform: homeassistant
        event: start
    action:
      - service: weather.get_forecasts
        data:
          type: daily
        response_variable: daily
        target:
          entity_id: weather.rykkinn
    sensor:
      - name: "Weather Now"
        unique_id: weather_now
        state: "Something"
        attributes:
          condition: "{{ daily['weather.rykkinn'].forecast[0].condition }}"
          cond_icon: >
            {% set weather = daily['weather.rykkinn'].forecast[0].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature: "{{ daily['weather.rykkinn'].forecast[0].temperature }}"
          feels_like: "{{ daily['weather.rykkinn'].forecast[0].condition }}"
          precipitation: "{{ daily['weather.rykkinn'].forecast[0].precipitation }}"
          precipitation_percent: "{{ daily['weather.rykkinn'].forecast[0].precipitation_probability }}"
          wind_dir: "{{ daily['weather.rykkinn'].forecast[0].wind_bearing }}"
          wind_speed: "{{ daily['weather.rykkinn'].forecast[0].wind_speed }}"
          wind_gust_speed: "{{ daily['weather.rykkinn'].forecast[0].wind_gust_speed }}"
          forecast: >
            {% set ns = namespace(items=[]) %}
            {% set keys = ['temperature', 'precipitation', 'datetime', 'condition'] %}
            {% for i in range(1, 6) %}
              {% for key in keys %}
                {% set value = daily['weather.rykkinn'].forecast[i][key] %}
                {% set ns.items = ns.items + [ (key ~ i, value) ] %}
                {% if key == 'condition' %}
                  {% set icon = '' if is_state('sun.sun', 'above_horizon') else '_night' %}
                  {% set ns.items = ns.items + [('cond_icon5', '/local/ic/weather_icons/animated3/%s%s.svg'%(value, icon)] %}
                {% endif %}
              {% endfor %}
            {% endfor %}
            {{ dict.from_keys(ns.items) }}

Keep in mind that your to display things in the frontend, you’ll need to use forecast.condition1 for the first condition and so on.

Otherwise you’ll need to hardcode it all, like you’re doing.

1 Like

Thanks, I will test this evening :love_you_gesture::moneybag::+1:

Cool, I think now I understand both what you are saying, and I think this is a workable solution. Thanks to both @123 and @petro for helping me better understand the logic.

If anyone wants to use this in the future, I just have to mention there was a missing paranthesis and some wrong logic for the cond_icon. Though that was simple to fix. Here is the corrected code (also updated the state):

  - trigger:
      - platform: time_pattern
        hours: /1
      - platform: homeassistant
        event: start
    action:
      - service: weather.get_forecasts
        data:
          type: daily
        response_variable: daily
        target:
          entity_id: weather.rykkinn
    sensor:
      - name: "Weather Now and Daily"
        unique_id: weather_now_daily
        state: "{{ daily['weather.rykkinn'].forecast[0].condition }}"
        attributes:
          condition: "{{ daily['weather.rykkinn'].forecast[0].condition }}"
          cond_icon: >
            {% set weather = daily['weather.rykkinn'].forecast[0].condition %}
            {% if is_state('sun.sun', 'above_horizon') %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '.svg' }}
            {% else %}
              {{ '/local/ic/weather_icons/animated3/' + weather + '_night.svg' }}
            {% endif %}
          temperature: "{{ daily['weather.rykkinn'].forecast[0].temperature }}"
          feels_like: "{{ daily['weather.rykkinn'].forecast[0].condition }}"
          precipitation: "{{ daily['weather.rykkinn'].forecast[0].precipitation }}"
          precipitation_percent: "{{ daily['weather.rykkinn'].forecast[0].precipitation_probability }}"
          wind_dir: "{{ daily['weather.rykkinn'].forecast[0].wind_bearing }}"
          wind_speed: "{{ daily['weather.rykkinn'].forecast[0].wind_speed }}"
          wind_gust_speed: "{{ daily['weather.rykkinn'].forecast[0].wind_gust_speed }}"
          forecast: >
            {% set ns = namespace(items=[]) %}
            {% set keys = ['temperature', 'precipitation', 'datetime', 'condition'] %}
            {% for i in range(1, 6) %}
              {% for key in keys %}
                {% set value = daily['weather.rykkinn'].forecast[i][key] %}
                {% set ns.items = ns.items + [(key ~ i, value)] %}
                {% if key == 'condition' %}
                  {% set icon = '' if is_state('sun.sun', 'above_horizon') else '_night' %}
                  {% set ns.items = ns.items + [('cond_icon' ~ i, '/local/ic/weather_icons/animated3/' ~ value ~ icon ~ '.svg')] %}
                {% endif %}
              {% endfor %}
            {% endfor %}
            {{ dict(ns.items) }}

To read the attribute I found that I have to write it this way:

{{ state_attr('sensor.weather_now_and_daily', 'forecast')['condition1'] }}

And so forth … :slight_smile: