Template sensor with last good value stored in attribute

I have written a template sensor which increments itself together with a source sensor, skipping any resets and unknown/unavailable states. This is to decouple my e.g. cumulative energy sensors from the states of the source devices which can get reset or go bad, throwing my energy monitoring setup into disarray every so often.

- trigger:
    - platform: state
      entity_id:
        - sensor.electricity_a_energy
      not_to:
        - "unknown"
        - "unavailable"
      variables:
        to_state: "{{trigger.to_state.state}}"
  sensor:
    - name: Electricity A Energy cumulative
      icon: mdi:lightning-bolt
      device_class: energy
      unit_of_measurement: kWh
      state_class: total_increasing
      unique_id: "roigjoreoifnofnvewwefwgeo"
      state: >-
        {% set current = this.state|float(0)%}
        {% set from_state = this.attributes.last_good|float(0)%}
        {% if to_state | is_number %}
          {% set to_state = to_state|float%}
          {{(current + to_state - from_state)|round(3) if to_state > from_state else current}}
        {% else %}
          {{current}}
        {% endif %}
      attributes:
        last_good: "{{to_state if to_state|is_number else this.attributes.last_good}}"

My aim is that the sensor stores the last known good value of the source sensor in the last_good attribute and uses that to fidn the difference between the current source sensor value and the last good one, in case something went wrong with the sensor in the mean time.

(Morally, the utility_meter seems to achieve the same thing, but it resets and it can’t be used with the energy dashboard. But maybe there is a workaround to get a non-reseting utilitility_meter that always increases?)

I would now like to extend this template to work with multiple source sensors, and e.g. return their sum, while storing the last good state for each of the source sensors individually. I can do this by hand, creating a separate trigger for each of the entities and then create a separate attribute for each of them. But maybe there is a better way?

I was hoping to just list the multiple entities together in the state trigger

- platform: state
  entity_id: 
    - sensor.object_id1
    - sensor.object_id2

I can then get the name of the triggering entity with something like

{% set trigent = trigger.to_state.object_id%}

and then I would like to write the state as an individual key into the attributes. I thought maybe I could just make the last_good attribute a dictionary, something like

{% set last_good = { 'object_id1': 100, 'object_id2': 200} %}

which is allowed and it seems like I can actually retrieve the values from this dictionary using last_good[trigent] but I cannot figure out how to update them, i.e. last_good.update({trigent: to_state}) is not allowed and I cannot see any other way of updating the dictionary value. I’ve also tried putting the dictionary in a namespace, setting the key value through set.

Is there some way? Or is it possible to achieve what I want differently?

I managed to solve it thanks for some help from the Discord forums.

For posterity: here is an example of a template which sums an arbitrary set sensors, remains available when the source sensors are disappear and does not decrease its state when the source sensors get reset.

Another nice feature of this is that if you decide you no longer want to track one of the devices, you just remove the sensor from the trigger and it will never get included in the future, without rebasing this sensor’s state.

My aim is to use this for grouping together energy use of various devices.

template:
- trigger:
    - platform: state
      entity_id:
        - sensor.electricity_a_energy
        - sensor.electricity_b_energy
        - sensor.electricity_c_energy
      not_to:
        - "unknown"
        - "unavailable"
      variables:
        to_state: "{{trigger.to_state.state}}"
        trig_ent: "{{trigger.to_state.object_id}}"
  sensor:
    - name: Electricity Total Energy cumulative
      icon: mdi:lightning-bolt
      device_class: energy
      unit_of_measurement: kWh
      state_class: total_increasing
      unique_id: "roig4rtbretyeryrut"
      state: >-
        {% set current = this.state|float(0)%}
        {% if this.attributes.last_good is defined and this.attributes.last_good[trig_ent] is defined%}
          {% set from_state = this.attributes.last_good[trig_ent]|float(0)%}
        {% else %}
          {% set from_state = 0%}
        {% endif%}
        {% if to_state | is_number %}
          {% set to_state = to_state|float%}
          {{(current + to_state - from_state)|round(3) if to_state > from_state else current}}
        {% else %}
          {{current}}
        {% endif %}
      attributes:
        last_good: >-
          {% if this.attributes.last_good is defined %}
            {% set last_dict = this.attributes.last_good %}
          {%else%}
            {% set last_dict= {} %}
          {% endif %}
          {% if to_state | is_number %}
            {{dict(last_dict,**{trig_ent: to_state})}}
          {% else %}
            {{last_dict}}
          {% endif %}
4 Likes

If you are interested, I believe the last_good template can be reduced to this:

      attributes:
        last_good: >-
          {% set last_dict = this.attributes.get('last_good', {}) %}
          {{ dict(last_dict,**{trig_ent: to_state}) if to_state | is_number else last_dict }}
2 Likes

Thanks Taras.

I can’t find the docs on .get — it returns the second argument if the first one is not defined?

Btw — is there a difference between

if bla is number and if bla | is_number ? Is the latter somehow more jinjy?