Energy sensor templates, filters and logic questions a minor updates but still need input

Hi all,
Firstly a big thanks to @petro for his guidance on this topic on this thread Template loop detection

I have most of what I wanted to achieve completed with only some minor issues to clean up but also make sure I’m doing it right.

First a bit of background,
I have gone and cleaned up my naming convention for my devices and entities which allows me to dynamically create groups for power monitoring devices in each room I have them in the house.

So in my automations i have (as a example of the first room)

- id: "1641380832863"
  alias: Update Energy Groups
  description: ""
  trigger:
    - platform: homeassistant
      event: start
    - platform: event
      event_type: call service
      event_data:
        domain: group
        service: reload
  condition: []
  action:
    - service: group.set
      data_template:
        name: Rumpus Room Energy
        object_id: rumpus_room_energy
        entities: >
          {{ states.sensor 
            | selectattr('object_id', 'search', '^(rumpusroom)')
            | selectattr('object_id', 'search', '(_energy)$')
            | map(attribute='entity_id') | list }}

then in the configuration.yaml I have the following template sensors setup (I’ll move these to a sensors.yaml at a later date and I’ll stick with the rumpus room as the example)

sensor:
  #Total energy per room for monitoring
  - platform: template
    sensors:
      total_rumpus_room_energy:
        friendly_name_template: "Rumpus Room Total Energy"
        value_template: >
          {{ expand('group.rumpus_room_energy')
            | map(attribute='state') 
            | map('float', none)
            | reject('==', none)
            | sum | round(2) }}
        unit_of_measurement: "kWh"
        device_class: energy

and to get this to show up in the energy dashboard I have the following
(I’m in the first few hours, the kitchen has started to graph so I’ll be patient and wait for the others)

  customize_glob:
    sensor.total*_energy:
      last_reset: "1970-01-01T00:00:00+00:00"
      device_class: energy
      state_class: measurement

So the question now is to clean up a few anomalies that come up from time to time.

I want to add an availability template to each room template so I can remove any unavailable, unknown or none but looking at the post here

 availability_template: >-
    {% set sensors = expand('group.house_temperature_sensors') | list %}
    {{ sensors
       | rejectattr('state', 'in', ['unknown', 'unavailable', 'restored'])
       | selectattr("attributes.attribution")
       | list | count > 1
    }}
  value_template: >-
    {% set sensors = expand('group.house_temperature_sensors')
       | rejectattr('state', 'in', ['unknown', 'unavailable', 'restored'])
       | selectattr("attributes.attribution")
       | map(attribute='state') | map('float') | list %}
    {{ (sensors | sum / sensors | count) | round(1) }}

The example above uses the rejectattr in both the availability and value templates.
I just don’t understand why, I thought it might be listing the entities and checking those individually and if at least 1 was not in the rejected attr state it would then populate the value template.
If that’s right, then would I need to ensure that I have the availability template before the value template, or it wont matter as its all part of the same code block?

Would a suitable availability template be below ?
What else do I need to add to it to cover off the non-value responses.

        availability_template: >
          {{ expand('group.rumpus_room_energy')
           | rejectattr('state', 'in', ['unknown', 'unavailable', 'none'])
          }}

Finally I want to add a range filter to stop any wild +/- values that I’ve seen over time.
Can this be done in the availability template or does it need to be its own filter and could I use the same select logic to cover all my energy entities?

Final question if you see anything hear that’s going to bite me please let me know or if you need more details please free to ask.

The idea/plan is to have a near bullet proof way of collecting stats on energy usage.
I’m realistic to know there will be issues from time to time that will throw a curve ball so if someone else can use this then collectively we’ve done some good.

Thanks for your time and involvement in advance.
regards,

Ezekiel

1 Like

availability when resolved true means it’s available. That template you posted means it’s available if any sensor in that group exists.

No, it needs to resolve true or false.

Yes, but logically you’ll need to filter out the erroneous data.

Summer is over now and as the nights get longer (and colder) I’ve jumped back onto this.
For the most part its been pretty rock solid. As my power nodes are zwave and under local control I don’t get many availability issues. They only appear when I do upgrades to the zwave.js instance.

So the big thing to fix is when I get a occasional wild value and filter that out.
Reading the docs it looks like this is the way to go

{% for energy in expand('group.zwave_kwh') if is_number(energy.state) %}
  {{ energy.state }}
  {%- if not loop.last %}, {% endif -%}
{% endfor %}

This prints out all the energy values for the entities in the group.zwave_kwh.
problem with that is, its the current total value of each entity, so I’m not sure how I can build this to look at the difference between the previous read value and the new read value to ensure its stays within a possible range.

if new_state > upper_bound:
    upper_bound
if new_state < lower_bound:
    lower_bound
new_state

Where the upper bound is 1.25 and the lower bound is 0.
The thinking behind it is, that the power nodes have a max watts of 2500
and I’m polling every 30 minutes so theoretically the most I could use out of each node is 1.25kWh per 30 minutes as over 1 hour it would be 2.5kWh.

So the question is how do I filter the readings to only allow for a maximum reading of change of 1.25 if it records something above it. or 0 if it get 0 or a negative number.

Finally what’s the best place to put it.
as a filter like this

  - platform: filter
    name: "Zwave Energy Filter"
    entity_id: group.zwave_kwh
    filters:
      - filter: range
        lower_bound: 0
        upper_bound: 1.25

Which actually wont work because its a group not a sensor entity or
what I was thinking was something like this

{% for energy in expand('group.zwave_kwh') if is_number(energy.state) %}
  {{ energy.state }}
       if energy.state > '1.25':
         energy.state = '1.25'
       else
      if energy.state < 0:
         energy.state = '0'
  {%- if not loop.last %}, {% endif -%}
{% endfor %}

Any help would be great.

thanks

Hi Petro,
just to follow up on this thread.
I’ve been tinkering with the availability template and trying to apply your words of wisdom.

        availability_template: >
          {% set sensors = expand('group.rumpus_room_energy') | list %}
          {{ sensors
            | rejectattr('state', 'in', ['unknown', 'unavailable', 'none'])
            | list | count > 1
          }}
        value_template: >
          {{ expand('group.rumpus_room_energy')
            | map(attribute='state') 
            | map('float', none)
            | rejectattr('state', 'in', ['unknown', 'unavailable', 'none'])
            | sum | round(2) }}

So when I put the code above in my developer tools template I get true.
If my understanding is correct its because at the time of checking all the entities in the group are available or at least not in the unknown, unavailable or none state.

But your quote seems to success that the logic should be that if one of them is in this unknown, unavailable or none state. it should skip the collection and try again later (in this case 30 minutes later) if that true how would I adapt the code to say that?

thanks again and sorry for targeting you directly.
regards
Ezekiel

No, templates resolve on state changes. Not sure where you’re getting the 30 minutes. If you want a timed trigger like that, you’d need to use the new template sensor configuration with a 30 minute check. Otherwise, these templates will resolve when state changes occur, i.e. any time.

          {{ expand('group.rumpus_room_energy') 
            | selectattr('state', 'in', ['unknown', 'unavailable', 'none'])
            | list | count > 0
          }}

Sorry the 30 minutes is another thing I’m doing to refresh the zwave kWh values for the entities in the various rooms. For switch or power watts it updates automatically but for energy it needs a kick/refreash poll, else it doesn’t change and the state remains the same.

I’m pretty sure you helped me with that previously in the zwave thread.

Anyway thank you for the code snippet that now resolves as false rather than true which mine was doing previously.

I’m still unsure on what the behavior is when its true?

Its false because all entities are in a state other than unknown, unavailable or none.

if one of them goes into that state I.e unknown, it will become true which then means it wont write total value of the group or it will do all the values in the group that are available and skip the unknown one?

when it’s true, the sensor is available and will execute the value_template

So is the rejectattr in the value template is over kill as its also in the availability template?

Also back to the availability template question

Sorry got my logic wrong. I’ll rephrase the question.
So the code snippet you provided shows the rumpus room group as false because its entities are not in the unknown, unavailable, none state.
Which means based on the quote above that it will not execute the value_template?

if the sensor is not available (the availability_template resolves false), the state of the sensor will be unavailable. That’s all you need to understand.