Automation template vs DevTools Template

Looking for some help - I can’t seem to make the leap here to get this working.

I’m using GCal to set rgb colours on certain days of the year (green for St Patrick’s day, orange for halloween etc etc). Automation regularly checks the calendar and populates the agenda var.

I loop over the agenda, looking for a summary match (“BloomColour”) and if it exists I want to extract the message data that should contain the rgb code (0,255,0). When the BloomColour event isn’t present, I want to set the colour back to an empty string.

If I run the calendar.get_events in devtools/services, copy the output yaml → json and then post it into the Template editor with the appropriate name, the following for-loop works fine - I can see the {{target_colour}} value being printed out.

{%- for key, value in agenda.items() %}
	{%- for event in value.events if 'BloomColour' in event.summary %}
  		{%- set target_colour = event.message %}
	{%- endfor %}
{%- endfor %}
{{ target_colour }}

When I run the full automation, the value doesn’t change from an empty string.

....
  action:
    - service: calendar.get_events
      target:
        entity_id: calendar.homeassistant
      data:
        duration:
          hours: 24
      response_variable: agenda
    - variables:
        target_colour: ''
    - if:
      - condition: template
        value_template: |-
          {%- for key, value in agenda.items() %}
            {%- for event in value.events if 'BloomColour' in event.summary %}
              {%- set target_colour = event.message %}
              {{ 'true' }}
            {%- endfor %}
          {%- endfor %}

      then:
        - service: notify.slack_notification
          data:
            message: "{{ target_colour }}"
            target: debug
        - service: input_text.set_value
          data:
            value: "{{ target_colour }}"
          target:
            entity_id: input_text.colour_to_use
        - service: input_boolean.turn_on
          target:
            entity_id: input_boolean.special_alarm

      else:
        - service: input_text.set_value
          data:
            value: ""
          target:
            entity_id: input_text.colour_to_use
        - service: input_boolean.turn_off
          target:
            entity_id: input_boolean.special_alarm

I’ve tried using:

        - service: input_text.set_value
          data:
            value_template: |
              {{ target_colour }}
          target:
            entity_id: input_text.colour_to_use

but this just throws errors (“Error: extra keys not allowed @ data[‘value_template’]”).

Traces tells me it’s hitting the right path in the if-then-else statement, it’s just not populating.

Can someone explain why the {{target_colour}} input_text not updating in the automation? Pretty sure it’s simple, I’m just too close to see it.

A final question, is there a more elegant way to make the true/false work in the if-then-else rather than manually putting {{‘true’}} in the template block? I’m sure there is, but my brain is a bit fried over this.

It’s a variable scope issue. Changes made to the variable inside the if block will not be visible outside the if block. See: Scope of variables

So moving stuff into the local scope also fails to populate the var

    - if:
      - condition: template
        value_template: |-
          {% set target_colour = '' %}
          {%- for key, value in agenda.items() %}
            {%- for event in value.events if 'BloomColour' in event.summary %}
              {% set target_colour = event.message %}
              {{ 'true' }}
            {%- endfor %}
          {%- endfor %}

Setting the variable inside the then block:

    - if:
      - condition: template
        value_template: |-
          {%- for key, value in agenda.items() %}
            {%- for event in value.events if 'BloomColour' in event.summary %}
              {{ 'true' }}
            {%- endfor %}
          {%- endfor %}

      then:
        - variables:
            target_colour: |
              {%- for key, value in agenda.items() %}
                {%- for event in value.events if 'BloomColour' in event.summary %}
                  {{ event.message }}
                {%- endfor %}
              {%- endfor %}
        - service: notify.slack_notification
          data:
            message: "|{{ target_colour }}|"
            target: debug
        - service: input_text.set_value
          data:
            value: "{{ target_colour }}"
          target:
            entity_id: input_text.colour_to_use
        - service: input_boolean.turn_on
          target:
            entity_id: input_boolean.special_alarm

throws no errors, but when you run it and check the traces, the target_colour var remains stubbornly empty.

Update: TBH it’s also bloody ugly code - doing the same loop work twice isn’t very efficient

Not sure why you’re looping in the first place. I can’t see the structure of agenda, but I would imagine this would work:

{{ agenda['calendar.homeassistant']['events']
   |selectattr('summary','contains','BloomColour')
   |map(attribute='message')|first }}

You could code that into a trigger-based template sensor rather than running get_events within the automation, and use that sensor’s state in the automation.

Exact details depend on what you’re trying to do, but you’ve only posted partial code.

Can a namespace be used?

{%- set nsc = namespace(counter=0) -%}
{%- if (true) -%}
  {%- set nsc.counter=1 -%}
{%- endif -%}
{{- nsc.counter -}}
1 Like

Trying to see if there’s an all-day event in the calendar with a summary of ‘BloomColour’. If there is, get the message data from that calendar event and put it into an input_text field.

But the event.message data isn’t going where I want it to go.

So:

template:
  - trigger:
      - platform: time
        at: "00:00"    # SUBSTITUTE YOUR TRIGGER
    action:
      - service: calendar.get_events
        target:
          entity_id: calendar.homeassistant
        data:
          duration:
            hours: 24
        response_variable: agenda
    sensor:
      - name: Bloom colour
        state: >
          {{ agenda['calendar.homeassistant']['events']
             |selectattr('summary','contains','BloomColour')
             |map(attribute='message')|first|default('') }}

Then use sensor.bloom_colour within your automation:

trigger:
  - platform: state
    entity_id: sensor.bloom_colour
action:
  - service: input_text.set_value
    data:
      value: "{{ trigger.to_state.state }}"
    target:
      entity_id: input_text.colour_to_use
  - service: input_boolean.turn_{{ 'off' if trigger.to_state.state == '' else 'on' }}
    target:
      entity_id: input_boolean.special_alarm
  - if:
      - "{{ trigger.to_state.state != '' }}"
    then:
      - service: notify.slack_notification
        data:
          message: "{{ trigger.to_state.state }}"
          target: debug
1 Like

Perfect.

Thank you.

I knew there had to be an easier way than all those bloody loops. Just shows how weak my template-fu really is, couldn’t get a template sensor to work, so ended up with if-then-else hell.

1 Like