How to Configure Automations for More Than 10k Iterations?

Hi everyone,

I’ve been working on an automation that involves rapid and frequent loops, such as creating strobe effects for outdoor lights during December. The automation works great, but I recently ran into an issue where Home Assistant terminated the automation because it looped 10,000 times. Here’s the exact error message:

Error: Until condition [{‘condition’: ‘template’, ‘value_template’: Template<template=({% set now_time = now().timestamp() %} {% set weekday_cutoff = now().replace(hour=23, minute=0, second=0).timestamp() %} {% set weekend_cutoff = as_timestamp(state_attr(‘sun.sun’, ‘next_rising’)) - 3600 %} {% if now().weekday() < 5 %} {{ now_time >= weekday_cutoff }} {% else %} {{ now_time >= weekend_cutoff }} {% endif %}) renders=20000>}] terminated because it looped 10000 times

I understand this limit is likely in place to prevent infinite loops or performance issues. However, in my use case, I intentionally need more than 10,000 iterations to achieve the desired effect over longer durations.

Here’s what I’d like to know:

  • Is there a way to configure or increase the iteration limit in Home Assistant?
  • For example, adjusting some configuration file or system setting?
  • If not, are there alternative approaches for handling frequent, long-running loops?

Performance Concerns:

  • If increasing the iteration limit is possible, are there any potential risks I should be aware of? For example, how would this impact CPU or memory usage, and what precautions should I take?

Best Practices:

  • Are there better ways to design this type of automation? For instance, would breaking the loop into smaller chunks, using scripts, or external integrations (e.g., Node-RED) be more effective?

Any guidance on how to handle long-running, high-frequency loops in Home Assistant would be much appreciated. Thank you in advance for your help!

choose:
  - conditions:
      - condition: template
        value_template: '{{ now().month == 12 }}'
    sequence:
      - repeat:
          sequence:
            - target:
                device_id:
                  - e900c80760b1c3b934c57b30fd2110cd
                  - 2e148914a26414e1d9f1784dd19accd0
                  - f604857169d33314e9578436aaf369f9
                  - 0e5af39e7b7c9df3b177f590750fd088
              data:
                brightness: 255
              action: light.turn_on
            - delay: '00:00:00.5'
            - target:
                device_id:
                  - e900c80760b1c3b934c57b30fd2110cd
                  - 2e148914a26414e1d9f1784dd19accd0
                  - f604857169d33314e9578436aaf369f9
                  - 0e5af39e7b7c9df3b177f590750fd088
              action: light.turn_off
              data: {}
            - delay: '00:00:00.5'
          until:
            - condition: template
              value_template: >
                {% set now_time = now().timestamp() %} {% set weekday_cutoff =
                now().replace(hour=23, minute=0, second=0).timestamp() %} {% set
                weekend_cutoff = as_timestamp(state_attr('sun.sun',
                'next_rising')) - 3600 %} {% if now().weekday() < 5 %}
                  {{ now_time >= weekday_cutoff }}
                {% else %}
                  {{ now_time >= weekend_cutoff }}
                {% endif %}
  - conditions:
      - condition: template
        value_template: '{{ now().month != 12 }}'
    sequence:
      - repeat:
          sequence:
            - target:
                device_id:
                  - e900c80760b1c3b934c57b30fd2110cd
                  - 2e148914a26414e1d9f1784dd19accd0
                  - f604857169d33314e9578436aaf369f9
                  - 0e5af39e7b7c9df3b177f590750fd088
              data:
                brightness: '{{ range(50, 255) | random }}'
              action: light.turn_on
            - delay: '00:00:05'
          until:
            - condition: template
              value_template: >
                {% set now_time = now().timestamp() %} {% set weekday_cutoff =
                now().replace(hour=23, minute=0, second=0).timestamp() %} {% set
                weekend_cutoff = as_timestamp(state_attr('sun.sun',
                'next_rising')) - 3600 %} {% if now().weekday() < 5 %}
                  {{ now_time >= weekday_cutoff }}
                {% else %}
                  {{ now_time >= weekend_cutoff }}
                {% endif %}

I believe you can nest scripts.

So automation loops 1000 times and calls scrip1 that loops 1000 times and calls script2 that loops…
And so on…

But is there really no better option?

1 Like

Don’t use loops. Use two automations.

Automation 1:
triggered by light being off for 5 seconds.
conditions: month = 12
action: turn light on.

Automation 2:
triggered by light being on for 5 seconds.
conditions: month = 12
action: turn light off.

1 Like

Yeah, this makes sense. I’ll split the logic into separate automations—one for December and another for the rest of the year. For the child looping automation, I’ll set it up to either stop when an end condition is met (like a time check) or after a maximum number of iterations (e.g., 1,000). Here’s an example of what the looping automation could look like:

alias: Looping Automation - December Lights
action:
  - variables:
      max_iterations: 1000
      current_iteration: 0
  - repeat:
      while:
        - condition: template
          value_template: >
            {{ current_iteration < max_iterations and
               not (now().hour >= 23 or now().hour < 6) }}
      sequence:
        - service: light.turn_on
          target:
            entity_id:
              - light.device1
              - light.device2
          data:
            brightness: 255
        - delay: "00:00:01"
        - service: light.turn_off
          target:
            entity_id:
              - light.device1
              - light.device2
        - delay: "00:00:01"
        - variables:
            current_iteration: "{{ current_iteration + 1 }}"

You missed the point. Don’t use loops in the automation. Use two automations that form a loop. On turns the light on, the other turns the light off. You can run this for as long as your lights last.