How can I condense (remove empty spaces from) my *for* loop?

Hi all,

I’m using the code below to notify me when some of the devices go unavailable (happens every so often).

action: input_text.set_value
target:
  entity_id: input_text.tts_text_en
data:
  value: >-
    Beware!
    {% for state in states.switch|rejectattr('entity_id','contains','esp32') %}
      {% if state.state == "unavailable" %}
          Switch {{[state.name]}} is unavailable.
      {% endif %}
    {% endfor %}
    {% for state in states.light|rejectattr('entity_id','contains','jastuk')|rejectattr('entity_id','contains','onkyo')|rejectattr('entity_id','contains','esp32') %}
      {% if state.state == "unavailable" %}
          Light {{[state.name]}} is unavailable.
      {% endif %}
    {% endfor %}
    {% for state in states.binary_sensor|rejectattr('entity_id','contains','esp32') %}
      {% if state.state == "unavailable" %}
          Sensor {{[state.name]}} is unavailable.
      {% endif %}
    {% endfor %}

The problem is, as you can see below, the answer contains a lot of empty spaces and lines:

    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
          Light ESP32CAM-3D_A1 LED Light is unavailable.
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
    
      
          Light Trigger ON-OFF is unavailable.

As I’m using it in input_text (for voice response) which has a limit of 256 characters, it generally does not work - the input text entity just remains blank.

Is there a simple way to remove all those empty lines? Or maybe a better solution that has the same output?

(I’m not good with programming, I just managed to put this together using given solutions from this and other forums)

Thanks in advance!

Jinja Whitespace Controls

  • You can compact your template a bit by setting up a list of the domains you are interested in, i.e “light”, “switch” and "sensor. Then loop over them instead of repeating basically the same template 3 times.
  • Using a namespace will allow you to concatenate the strings produced in the loops.
    • This can make the template more efficient because you can stop the looping once you exceed a character threshold.
    • By employing the truncate() function at the end, you won’t exceed the character limit for the input text’s state.
{%- set domains = ['switch','light','sensor'] -%}
{%- set ns = namespace(message='Beware! \n') -%}
{%- for domain in domains -%}
  {%- for state in states[domain]|selectattr('state', 'eq', 'unavailable')|rejectattr('entity_id','search','esp32|jastuk|onkyo') -%}
    {% if ns.message|count <= 270 %}
      {%- set ns.message = ns.message ~ domain|title~' '~ state.name ~' is unavailable.\n' -%}
    {%else%}{% break %}{%endif%}
  {%- endfor -%}
{%-endfor-%}
{{- ns.message | truncate(255) }}
3 Likes

And there’s Jinja whitespace control. End each line with -%} instead of %}; similarly -}} instead of }}. That’ll remove the newline that line would otherwise generate.

2 Likes

Thanks @Didgeridrew and @Troon for the whitespace control, works perfectly now!
I will read more about domains, and maybe switch to that if it’ll work better in tests.
Thanks!