Efficient design of home assistant - do templates slow down the performance

Dear Friends,

I have a rather large (at least I consider it large) setup of home assistant with the following components:

  • 488 KNX entities including mostly tunable lights, covers, switches actuators and around 60 presence sensors
  • Unifi network integration with around 20 access points and 50 connected devices
  • I will be using at least 300 template sensors for various functions
  • I will use input_numbers, input_select and input_boolean to use in automations instead of putting numbers in automation triggers (like in the “for” field)
  • 40-50 different integrations

I am reaching out to our expert colleagues to let me know if the above deployment is feasible or will it become slow?
Are there any considerations to keep the functioning efficient?
My home assistant is installed on i7 Dell latitude laptop, replacing the operating system dedicatedly running HA.

Templates will slow down the performance, which is just a fact of adding more things that needs to be computed.
The question is if the slow down is noticeable and unless you have some wild templates that have to do ineffiecient searches on lists with several thousand elements, then you will as a human not feel a difference, especially not with an i7 CPU.


Thanks a lot @WallyR

My templates are like ones below. Do you think I could do this templating in a better way that consumes lesser resources?

{% if state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:9c:50'%}
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:b5:38' %}
  Basement Lounge
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:a0:88' %}
  Basement Living
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:b6:dc' %}
  Mandeep Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:af:d0' %}
  Ground Entrance
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:a2:7c' %}
  Kavya Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:b1:d0'%}
  Aryan Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:e0:1a:50' %}
  Mom Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:e0:2b:64' %}
  First Lounge
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == '70:a7:41:d6:4a:a8' %}
  First Living
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == '70:a7:41:d6:57:1c' %}
  Sandeep Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:e0:14:38' %}
  Alika Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:e0:21:d0'%}
  Khushi Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:e0:1f:38' %}
  Minnie Room
{% elif state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') == 'd0:21:f9:b1:ad:98'%}
  Sun Room
{% else %}
{% endif %}
{% for state in states
           if ( 'esp' in state.entity_id 
                and state.domain in ['sensor']
                and state.state == 'alika_room' ) -%}
         {% if loop.last -%}
           {{ loop.index }}
         {%- endif %}
       {% else %}
       {%- endfor %}
{% if states('sensor.gf_kavya_bedroom_touchpad_humidity_sensor') | float > states('input_number.gf_kavya_bedroom_humidity_threshold_for_ac_automation') | float %}
{% else %}
{% endif %}
{{ states('sensor.gf_foyer_brightness_sensor') | float < states('input_number.kavya_bedroom_light_threshold') | float }}

First template should be faster using dictionary indexing and the get method (docs);

{{ {'d0:21:f9:b1:9c:50':'Cinema',
    'd0:21:f9:b1:b5:38':'Basement Lounge',
    'd0:21:f9:b1:a0:88':'Basement Living',
    'd0:21:f9:b1:b6:dc':'Mandeep Room',
    'd0:21:f9:b1:af:d0':'Ground Entrance',
    'd0:21:f9:b1:a2:7c':'Kavya Room',
    'd0:21:f9:b1:b1:d0':'Aryan Room',
    'd0:21:f9:e0:1a:50':'Mom Room',
    'd0:21:f9:e0:2b:64':'First Lounge',
    '70:a7:41:d6:4a:a8':'First Living',
    '70:a7:41:d6:57:1c':'Sandeep Room',
    'd0:21:f9:e0:14:38':'Alika Room',
    'd0:21:f9:e0:21:d0':'Khushi Room',
    'd0:21:f9:e0:1f:38':'Minnie Room',
    'd0:21:f9:b1:ad:98':'Sun Room'}
    .get(state_attr('device_tracker.unifi_alika_iphone', 'ap_mac'),'x') }}

Second one could be made more efficient with filtering (filter docs). I think it’s trying to count sensors with 'esp' in the entity_id and a state of alika_room? If so:

{{ states.sensor|selectattr('entity_id','contains','esp')
                |list|count }}

These look more efficient than your originals, but it depends on how the template interpreter and subsequent layers convert this into executable machine code. Testing is the only practical way to be sure.

As already said, though, unless you’re doing a lot of these operations very frequently on low-power hardware, you’re unlikely to encounter a problem.

What sort of house needs 15 Unifi APs to provide coverage?! The installation I put in our large-ish multi-room church with some thick stone walls only uses eight!

1 Like

Some optimization can probably be done, like the one Troon suggest, but it is like improving the runtime in like 3rd decimal of a ms.

Troon’s examples is mostly better because it improves your readability a lot and maintenance therefore becomes easier.

Thanks @Troon

This is a 5 floor house with brick walls. Fifteen was the minimum I could use. I have extensively tried to reduce the number of APs using the Unifi design tool.

I tried the first one and it just returns x as result. I am sure I am missing something.

The second one worked like a breeze and I could get he logic.

Would be great if you could help me troubleshoot the first one. I just copy/pasted it.

Thanks a lot @WallyR

Unless you would look at the machine code and see which code is the most efficient (which also depends on the underlying hardware architecture) its hard to tell, especially if its almost not noticeable. Remember the Pareto Rule. The last 20% gain most likely requires 80% of the work.

1 Like

What does this return?

{{ state_attr('device_tracker.unifi_alika_iphone', 'ap_mac') }}

If it’s not exactly one of the MAC addresses in your list, it will return x. It should always return the same result as your first template.

The only templates that are typically resource heavy are templates that use states or states.<domain>. There has already been many efforts in the past to make templates faster when using the states object in that manner. Currently any template that uses states without a domain, will be throttled to at most 1 update per minute. Meaning, the heavy calculation will only be performed once per minute. Domains have a similar restriction, they will only be updated at most once per second. There are no other restrictions on templates in that regard.

As a sidebar, I have a large setup with mostly template entities. I don’t see any slow downs.

Templates specifically or automations?

A CPUs speed is sometimes measured in MIPS (Millions of Instructions Per Second).
Unless you try to operate on the entire amount of HAs sensor values, which is the limitations Petro referred to, then add only maybe a couple of hundred thousand instructions when you make an automation or template and an optimization might only shave ten thousand instructions off.

Of course if you are running on a RPi3 with a lot of sensors and events going off, then the hardware can be pressed hard already and then your templates and automations might be an issues, but then a hardware upgrade is over due anyway.

Look at the hardware page in HA and then watch how the CPU react to your templates and automations. Most of the time your will not see a much of a spike and the general CPU load will be well below 50%.
I agree that optimization is a good thing, but the effort might not be worth it, if it is only for lowering hardware usage. Do it for readability mainly!

Thanks a lot.

Extremely useful. Thanks.

This was extremely helpful @Troon

I was able to fix the problem. Actually the device tracker was not at home. Once I put a device tracker that is home, BOOM - returned correct result.

1 Like