Something changed with my battery templates

I am guilty of not paying attention for at least 6 months (because life gets in the way sometimes) and therefore have been caught out - the hard way.
I have installed the hacs legacy template tool and read through the documentation and this post in it’s entirety. However, as you can guess I can’t get past whatever syntax issue is breaking my install and so I am wondering if some kindly soul can put me out of my misery !

I use packages - because of the advantages. Maybe that is why the legacy template fixing tool generated nothing, I don’t know.

I define packages like this:

homeassistant:
  packages: !include_dir_named packages

in batteries.yaml in the packages directory I have 10 batteries defined which worked fine until Thursday. The first two of the repeating syntax for all 10 is below.
The relative time stamp is working fine, it is only the actual voltage which is showing “unavailable” but it is present, read on.

## Batteries ##

template:

  # Garden Relay Battery Volts
  - trigger:
      - platform: state
        entity_id: sensor.garden_battery_volts_mqtt
    sensor:
      - name: garden_battery_volts_calc
        unique_id: 48a18864-99df-473e-841e-4faad4267333
        device_class: voltage
        state_class: measurement
        unit_of_measurement: "V"
        state: >-
          {% set status = states('sensor.garden_battery_volts_mqtt') %}
          {% if status is not none and status != 'unknown' and status != 'unavailable' %}
            {{ ((status |float -0.005) * 5) | round(3) }}
          {% else %}
            unavailable
          {% endif %}

  - sensor:
      - name: "Garden Battery Relative Timestamp"
        state: >
          {% set ts = states('sensor.garden_battery_volts_timestamp') %}
          {% if ts != 'unknown' and ts != 'unavailable' %}
            {{ relative_time(ts | as_datetime) }}
          {% else %}
            n/a
          {% endif %}

  # Tractor Battery Volts
  - trigger:
      - platform: state
        entity_id: sensor.tractor_battery_volts_mqtt
    sensor:
      - name: tractor_battery_volts_calc
        unique_id: b42551ec-e9c8-4a44-b01b-82d9f5275824
        device_class: voltage
        state_class: measurement
        unit_of_measurement: "V"
        state: >-
          {% set status = states('sensor.tractor_battery_volts_mqtt') %}
          {% if status is not none and status != 'unknown' and status != 'unavailable' %}
            {{ ((status |float -0.005) * 5) | round(3) }}
          {% else %}
            unavailable
          {% endif %}

  - sensor:
      - name: "Tractor Battery Relative Timestamp "
        state: >
          {% set ts = states('sensor.tractor_battery_volts_timestamp') %}
          {% if ts not in ['unknown', 'unavailable', 'none'] %}
            {{ relative_time(ts | as_datetime) }}
          {% else %}
            unknown
          {% endif %}

In the same batteries file are all the sensors which read the values from MQTT so that I can use force_update: true. This stale update logic is not possible elsewhere in HA for clear and good reasons, but I need it hence the design employed.

I have tried syntax changes with templates: template keyword changed to fix this and while all of these pass the YAML configuration test before the restart and appear to conform, they do not actually generate a state value for the entity.

These state jinja code blocks return fine in template test tool - so I KNOW its my template syntax and not my jinja syntax which is now broken.

          {% set status = states('sensor.tractor_battery_volts_mqtt') %}
          {% if status is not none and status != 'unknown' and status != 'unavailable' %}
            {{ ((status |float -0.005) * 5) | round(3) }}
          {% else %}
            unavailable
          {% endif %}

I am asking for help because my packages format with the relevant helper keyword type defined in each package file adds just enough dissimilarity from the examples and docs to generate these types of issue.

Thanks in advance and apologies for what will doubtless be irritatingly obvious to you.

Actually - I found the solution. Recent tightening of how trigger templates are handled has caught me out.

I aggressively control what HA is allowed to record. Since by default HA will fill a volume in short order with activity records. It seems that a trigger template MUST be able to read a previous record from the short term database and reading it from a previous state in memory is no longer a viable configuration.

So the fix was fairly simple, enable the entities to be able to write to the short term database and voila, working.

Deleted incorrect info

Trigger based template sensors restore state. So it should only be unknown when first created. unavailable during reload (but restore to previous state).

Wouldn’t that only be true if that template sensor isn’t excluded from the recorder?

restore state is a separate mechanism than recorder. Everything that can restore state will restore state regardless of recorder/history.

1 Like

The implication IIUC that a database record is not needed and just a restore state - which “I guess?” can come from the text files in .storage and doesn’t need a database record? (Would be lovely !)

But I spoke too soon and since until corrected I am assuming I need to depend on database entries . . . The sensor state is “unavailable”.

My MariaDB purge interval is 2 days. The sensor only provides a value every 2 hours from 10pm to 10am each day and then the board sleeps until 10pm when the cycle repeats. The value could be the same as the previous one but MQTT is used precisely to retain and ignore this and see any update as a new value. So the report timestamps are all accurate and correct in the sensor.garden_battery_relative_timestamp. (not in the database below though for the voltages).

The state in the database for the voltage entity which shows entries where no state was written and where no update could have been sent. I am not sure why HA is writing state unless the source entity has triggered an update? I have rebooted HA a few times recently for integration updates during the day so I am wondering if that triggers a record update in the recorder?

state_id state last_reported_ts last_updated_ts
9405942	12.671	1770623089	        1770615890
9406754	12.581	NULL	            1770623089
9406980	12.581	1770624744	        1770624744
9408231	unavailable	1770636968	    1770636968
9408259	12.581	1770636968	        1770636968
9408431	unavailable	1770638846	    1770638846
9408463	12.581	1770638846	        1770638846
9408494	unavailable	1770638897	    1770638897
9408524	12.581	1770649282	        1770638897
9409536	unavailable	NULL	        1770649443
9419838	unavailable	NULL	        1770760670

Converted to GMT

state_id	state	last_reported_ts	         last_updated_ts
9405942	12.671	Tue 18 Feb 2026, 17:04:49	Tue 18 Feb 2026, 15:04:50
9406754	12.581	NULL	                    Tue 18 Feb 2026, 17:04:49
9406980	12.581	Tue 18 Feb 2026, 17:32:24   Tue 18 Feb 2026, 17:32:24
9408231	unavailable	Tue 18 Feb 2026, 20:56:08 Tue 18 Feb 2026, 20:56:08
9408259	12.581	Tue 18 Feb 2026, 20:56:08   Tue 18 Feb 2026, 20:56:08
9408431	unavailable	Tue 18 Feb 2026, 21:27:26 Tue 18 Feb 2026, 21:27:26
9408463	12.581	Tue 18 Feb 2026, 21:27:26   Tue 18 Feb 2026, 21:27:26
9408494	unavailable	Tue 18 Feb 2026, 21:28:17 Tue 18 Feb 2026, 21:28:17
9408524	12.581	Wed 19 Feb 2026, 00:21:22   Tue 18 Feb 2026, 21:28:17
9409536	unavailable	NULL	                Wed 19 Feb 2026, 00:24:03
9419838	unavailable	NULL	                Thu 20 Feb 2026, 07:17:50

The attributes for the sensor in the HA states dev view (there is no state) show restored: true as can be seen. So I am wondering if that is what I need to understand and focus on to solve this.

restored: true
state_class: measurement
device_class: voltage
friendly_name: garden_battery_volts_calc
supported_features: 0
unit_of_measurement: V

The actual jinja code as per the initial post above to render the template state, is returning the correct value just fine.

        {% set status = states('sensor.garden_battery_volts_mqtt') %}
        {% if status is not none and status != 'unknown' and status != 'unavailable' %}
          {{ ((status |float -0.005) * 5) | round(3) }}
        {% else %}
          unavailable
        {% endif %}

12.561v right now.

  1. Is there a source of reading I can do on this - because some architectural comprehension of how to do this correctly is missing is my sense.
  2. Not sure what is triggering updates in MariaDB when the board is sleeping.
  3. Clueless about why the sensor is being so fussy about working . . . !

I thought this worked from memory (.strorage previous state) until very recently without the need to involve the database at all?

You should not be returning a word to a numerical sensor.

Use an availability template to make the entity go unavailable

Since I implemented this you have kindly been making some great improvements to the codebase around templates. I herculean task!

I don’t think I really need to use trigger based templates since the sensor value is retained in MQTT and so it is in fact always available and will just update 6 times a night.

I removed the availability [thanks for that, used elsewhere] and the “trigger” and removed it from the database as well and now it displays as I am expecting, the retained MQTT value.
#Overengineered

So I went to this:

  # Garden Relay Battery Volts
  - sensor:
      - name: garden_battery_volts_calc
        unique_id: 48a18864-99df-473e-841e-4faad4267333
        device_class: voltage
        state_class: measurement
        unit_of_measurement: "V"
        state: >-
          {% set status = states('sensor.garden_battery_volts_mqtt') %}
          {{ ((status |float -0.005) * 5) | round(3) }}
 
  - sensor:
      - name: "Garden Battery Relative Timestamp"
        state: >
          {% set ts = states('sensor.garden_battery_volts_timestamp') %}
          {{ relative_time(ts | as_datetime) }}

And removed these entities from the recorder allow yaml - to exclude them from the short term DB.

Many thanks !