Where can I create macros for templates?

I have searched the archives and I haven’t been able to find an answer to my question.

I have several sensor templates for battery levels and smoke detectors that have pretty much the same content. I read in the Jinja2 documentation that macros can be used like functions. This is exactly what I am looking for and when I try it out in the dev-template section of HA they work great, but the question I have is where do I put the macro definitions?

The macro goes in the template itself. I’ve got an example at Home-AssistantConfig/packages/battery_alert.yaml at master · notoriousbdg/Home-AssistantConfig · GitHub that should help. As far as reducing the amount of duplication, you might be able to use yaml anchors and references (more info at daemonl). Look at the usage of &low_battery_check and *low_battery_check in the package above.

That being said, you might be interested in that package as a whole since it automates the entire process of creating sensors for batteries as well as notification when low. You can see more about that in this thread or in comments in the package itself:

Thanks for the reply.

What is the purpose of your macro declaration because you declare it on line #297 and then again on line #344?

I think he is miss understanding your overall goal. Which is (I’m assuming) you want to declare the macro once, and use it in any template.

I’m not entirely sure that is possible.

That is the file that would need to be modified to support a new macro system wide.

You could just adjust that file and it may work, but anytime an update comes, it will be overwritten. You can’t place it in as a custom component because this is a helper file.

I think you may need to ping a dev on this one.

That is exactly correct!

1 Like

can you post your template? You may be able to get away with a python script and 1 automation.

        {% if state_attr('zwave.backdoor_sensor', 'battery_level') == None %}
          mdi:battery-alert
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 90 %}
          mdi:battery
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 80 %}
          mdi:battery-80
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 70 %}
          mdi:battery-70
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 60 %}
          mdi:battery-60
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 50 %}
          mdi:battery-50
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 40 %}
          mdi:battery-40
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 30 %}
          mdi:battery-30
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 20 %}
          mdi:battery-20
        {% elif state_attr('zwave.backdoor_sensor', 'battery_level') >= 10 %}
          mdi:battery-10
        {% else %}
          mdi:battery-outline
        {% endif %}

Not a direct answer to your original question, but if you set your sensor’s device_class to battery, HA will set the battery icon for you and that would still save a lot of work.

sensor:
  - platform: template
    sensors:
      left_garage_door_sensor_battery_level:
        friendly_name: 'Left Garage Door Sensor Battery'
        unit_of_measurement: '%'
        device_class: battery
        value_template: "{{ state_attr('zwave.left_garage_door', 'battery_level') }}"

I have the same exact yaml for my zwave smoke detector.

The code that generates the icon can be found here: https://github.com/home-assistant/home-assistant/blob/master/homeassistant/helpers/icon.py. The logic is not identical to yours but very close, and would then be consistent with the rest of HA. It would be nice if the zwave battery level was a built-in sensor.

another option from @freshcoast’s would be to simplify your template:

  {% set level = state_attr('zwave.backdoor_sensor', 'battery_level') | round(-1) | int %} // rounds to the 10 place
  {% if level in range(10, 81, 10) %} // if level is equal to 10, 20, 30, 40, 50, 60, 70, or 80
    mdi:battery-{{ level }} // returns mdi:battery-10 if level is 10
  {% elif level >= 90 %} // if the level is greater than or equal to 90
    mdi:battery
  {% else %} // otherwise
    mdi:battery-outline
  {% endif %}

Then you only have to adjust the first line’s entity_id.

I like both of these suggestions but I have similar templates for other devices in my house so simplifying them is great but repeating them still bugs me.

So moving to python script would be favorable, but then you have to make automations that update things using the python script and the python script handles the updating of the sensors. So it’s a bit different. You also need to know python. This may be doable with glob. @Tinkerer is it possible to glob an icon template on template sensors?

Those templates actually different even though they use the same macro. The ones that are the same starts with &low_battery_check anchor on line 296 is referenced again without duplication on line 457 with *low_battery_check. It’s not exactly what you’re looking for, but it can be used to remove duplication. The issue with battery templates is that each template needs to be different even though the majority of the code is the same.

I was pointing out the options that don’t require customization like you’re suggesting. It would be an awesome feature if that natively supported though.

I created the battery_alert package specifically for that reason. I didn’t want to have to create the templates and I didn’t like all of the duplication that it needed. The package uses automations and mqtt discovery to automatically create the sensors instead of using templates.

Hello,
Google results brought me here, and I’m trying to do exactly what you describe here “have a macro/filter that can work in any template”.
Any way to do that in 2022?
Thanks

3 Likes

Same question here. My macro definition works fine in the developer template playground but now I want to use it in a lovelace entities card and don’t know, how.

It’s not possible, you have to recreate the macro wherever you want to use it. Also, lovelace does not support templates in most places. You have to make template sensors (and use templates there) or use custom cards to use templates in the fronted.

1 Like

What I do is create the “config template” once, then use shell scripts to blast it out for other entities. This is working great for me, I have very little local config, and I use it across 2 HASS installs.

I have a example posted here for replicating a health template for every zwave device.

Okay, suppose I write template sensors in my configuration.yaml in the template: section. How would I put my macro definition there so that I can use it inside a template sensor definition?
Is it inside the template: section? After some keyword? Indented? Is there any documentation available regarding this use case? :flushed:

I recently showed you a template for converting the current day’s name from English to German. Instead of using it to create a macro, use it to create a Template Sensor.

Wherever you need the current day’s name in German, simply reference the Template Sensor’s value.

But then I have to write this long code 31 times, for each of the 31 date sensors!
That’s exactly what functions in programming languages are for.
There has to be a better way, hopefully!

You’ll need to clarify your intended application(s) otherwise you’ll continue to get suggestions that don’t meet your requirements. So far, all we know is that you created a macro and you wanted to use it in a card (which isn’t possible with the standard set of cards because they don’t support templates).