this post was submitted on 06 Jan 2026
34 points (100.0% liked)

homeassistant

17432 readers
5 users here now

Home Assistant is open source home automation that puts local control and privacy first.
Powered by a worldwide community of tinkerers and DIY enthusiasts.

Home Assistant can be self-installed on ProxMox, Raspberry Pi, or even purchased pre-installed: Home Assistant: Installation

Discussion of Home-Assistant adjacent topics is absolutely fine, within reason.
If you're not sure, DM @GreatAlbatross@feddit.uk

founded 2 years ago
MODERATORS
 

I thought I'd share this tip, since I just found it a few weeks ago, and I thought maybe newer people might have overlooked the value of it. You can create a custom macro template for things that you use more than once.

For example, I use the sports tracker integration to track three teams. Then, I have conditional cards that start to appear the day before a game and stay visible through 16 hours after the game starts (i.e., showing the final score for a few hours into the next day).

This is a fairly complex example, but the complexity also demonstrates why you'd want to extract this out to a macro. Imagine having this repeated in 3 places (in my case), then realizing there was a bug, or you could improve it by just changing one little thing...With the macro, edit it in one place, reload the macro template, and boom, the change shows up everywhere you use the macro!

In /homeassistant/custom_templates/sports.jinja (I believe I had to create that directory, and the file), I have this code:

{% macro format_date(entity_id, interval) %}
{% if is_state(entity_id, "POST") %}
{{ state_attr(entity_id, "clock") }}
{% else %} 
    {% if is_state(entity_id, "PRE") %} 
        {% if as_timestamp(state_attr(entity_id, 'date')) | timestamp_custom("%d") == as_timestamp(now()) | timestamp_custom("%d") %}
{{ as_timestamp(state_attr(entity_id, 'date')) | timestamp_custom("Today at %-I:%M %p") }}
        {% elif as_timestamp(state_attr(entity_id, 'date')) | timestamp_custom("%d") == as_timestamp(now()+ timedelta(days = 1)) | timestamp_custom("%d") %}
{{ as_timestamp(state_attr(entity_id, 'date')) | timestamp_custom("Tomorrow at %-I:%M %p") }}
        {% else %}
{{ as_timestamp(state_attr(entity_id, 'date')) | timestamp_custom("%A at %-I:%M %p") }}
        {% endif %}
    {% else %}
{{ state_attr(entity_id, "clock") }} {{ interval }}
    {% endif %}
{% endif %}
{% endmacro %}

The macro line has two variables specified - the entity to use (in my case, sensor.capitals from the integration), and the "interval", which is only used to fill in whether it's a "period" or a "quarter" for the game. (I could have if/thens to figure it out from the attribute data, but just passing it in is really easy.)

There's a lot going on in this macro, mostly specific to the sports integration, but here's an overview:

  • If it's postgame, then just put up the "clock" attribute, which will have something like "Final" or "Final/OT", etc.
  • If it's pregame, then it checks if the game is today, and if so, it says "Today at 7:00 pm" or whatever. If it's tomorrow, it says, "Tomorrow at 7". If it's beyond tomorrow, it gives the day of the week and the time.
  • If it's during the game, which is the only other option, put up the current clock info and whether it's a period or quarter.

Next, let's look at how to use it. Here's the yaml for the hockey team card:

  - type: custom:mushroom-template-card
    primary: >-
      {{ state_attr("sensor.capitals", "team_abbr") }} {{
      state_attr("sensor.capitals", "team_score") }} - {{
      state_attr("sensor.capitals", "opponent_abbr") }} {{
      state_attr("sensor.capitals", "opponent_score") }} 
    icon: mdi:hockey-puck
    features_position: bottom
    entity: sensor.template_away_team
    visibility:
      - condition: or
        conditions:
          - condition: state
            entity: sensor.capitals
            state: IN
          - condition: and
            conditions:
              - condition: state
                entity: sensor.capitals
                state: POST
              - condition: numeric_state
                entity: sensor.caps_hours_until_next_game
                above: -16
          - condition: and
            conditions:
              - condition: state
                entity: sensor.capitals
                state: PRE
              - condition: numeric_state
                entity: sensor.caps_hours_until_next_game
                below: 49
    secondary: |-
      {% from 'sports.jinja' import format_date %}
      {{ format_date('sensor.capitals', 'period') }}
    picture: "{{ state_attr(\"sensor.capitals\", \"team_logo\") }}"

The primary shows the score and the teams, and you can see the visibility that I hopefully described correctly before. But, look at the secondary spec: The first line tells it what file you saved that jinja code in and the macro you want to use, and the second line calls the macro.

That's it!

And if I want to change it, I only have to change it in one place, and then remember to re-load the custom templates by invoking the "homeassistant.reload_custom_templates" action (note this doesn't show up on the YAML page on the developer tools - you have to trigger it on the Actions page).

Note that I'm using it in the secondary info, but it could be used anywhere that takes a template - such as the primary in this card. For example, I could write another macro to format the teams such that the home team is always second...and I probably will at some point.

This info is in the Reusing Templates section of the Templating page on HA's website, but I overlooked it for a long time. Hopefully this tip helps someone else.

Where it would have been really helpful is that I have quite a few sensors that measure how many days since I changed water filters, cleaned the pet's recirculating water bowl, did flea and tick treatment on the pets, exercised the generator, drained and repressurized the pressure tank, changed the batteries in my pinball machine, etc. etc. etc.

So, I have quite a few templates that use a helper for the last date I did something, then count how many days since then...and they're all coded independently in my configuration.yaml (these were done before the UI helper interface was as useful as it is now). And even though all of those do essentially the same thing, I coded some of them differently for various reasons along the way. It's a mess, no question. I could recreate all of them with one short macro.

Had I noticed this macro ability a few years ago, when I first started, I could have saved myself a lot of headache!

top 1 comments
sorted by: hot top controversial new old
[–] EarMaster@lemmy.world 4 points 4 days ago

That's a great tip. I use that to format some sensor readings coming from an external source via REST. It is annoying though you have to import the template every time you use it - I wish this could be done automatically...