Aggregate devices for easier energy display

To make the new energy display easier to understand I’ve added template sensors that add up the energy from several devices to produce one aggregate device.

In templates/light_energy.yaml:

- sensor:
  - name: "outside_lights_energy_kwh"
    unique_id: outside_lights_energy_kwh
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: measurement
    state: >
      {{ expand([
        'sensor.allrum_balcony_switch_energy_kwh',
        'sensor.laundry_facade_switch_energy_kwh',
        'sensor.entrance_veranda_switch_energy_kwh',
        'sensor.dining_room_flood_switch_energy_kwh',
        'sensor.deck_flood_light_switch_energy_kwh',
        'sensor.covered_deck_light_switch_energy_kwh',
        'sensor.laundry_driveway_switch_energy_kwh'
        ]) | map(attribute='state') | map('float') | sum}}
    attributes:         
      last_reset: '1970-01-01T00:00:00+00:00'

You can use this by simply putting any device that measures energy in the list. You will then get a new sensor ‘sensor.outside_lights_energy_kwh’ that reports the total energy of the group, which you can add to the energy dashboard.

A few things to note:

  1. You need the unit_of_measurement, device_class, state_class, and last_reset for it to work with the energy dashboard.
  2. I have template: !include_dir_merge_list templates/ in my configuration.yaml and I put the file light_energy.yaml in the templates directory to load it.

To debug this you go to Configuration->Server control.
Click “Check Configuration” to find syntax errors.
Then reload “Template Entities”.
You then go to “Logs” and check for any other errors in the top entry.

(It should also be possible to add these to a group and expand the group in the sensor, but I didn’t think of that before I did this.)

Enjoy!
-David

3 Likes

I don’t think that this will work in the long run. The last_reset of each of the underlying sensors are not respected this way.

Say your allrum_balcony_switch_energy_kwh “kwh count” gets reset for some reason, then the sum of all kwh will be lower than before but the energy monitor will not see a changed last_reset of the “outer” template sensor and thus very likely be very confused and also probably show incorrect values.

Erik, that’s a great point. (I don’t think it will matter here since these are in-wall sensors that are really hard to reset.)

I can almost fix this but there are two problems. I can make the last_reset attribute find the max across all the devices like this:

- sensor:
  - name: "all_lights_energy_kwh"
    unique_id: all_lights_energy_kwh
    unit_of_measurement: "kWh"
    device_class: energy
    state_class: total_increasing
    state: >
      {{ expand([
        'sensor.outside_lights_energy_kwh',
        'sensor.dining_room_lights_energy_kwh',
        'sensor.allrum_room_lights_energy_kwh',
        'sensor.living_room_lights_energy_kwh',
        'sensor.kitchen_lights_energy_kwh',
        'sensor.work_lights_energy_kwh',
        'sensor.cozy_lights_energy_kwh',
        'sensor.bedroom_lights_energy_kwh',
        'sensor.bathroom_lights_energy_kwh'
        ]) | map(attribute='state') | map('float') | sum}}
    attributes:         
      last_reset: >
        {{ expand([
        'sensor.outside_lights_energy_kwh',
        'sensor.dining_room_lights_energy_kwh',
        'sensor.allrum_room_lights_energy_kwh',
        'sensor.living_room_lights_energy_kwh',
        'sensor.kitchen_lights_energy_kwh',
        'sensor.work_lights_energy_kwh',
        'sensor.cozy_lights_energy_kwh',
        'sensor.bedroom_lights_energy_kwh',
        'sensor.bathroom_lights_energy_kwh'
        ]) | map(attribute='attributes')|map(attribute='last_reset') |max}}

This works in that I get the right value, but it also causes an error in the logs:

TemplateError(‘UndefinedError: ‘mappingproxy object’ has no attribute ‘last_reset’’) while processing template 'Template

I don’t know how to fix that. When I run the code in the developer Template tool I get a valid last_reset for each one of those, and the template does give the right value.

The second issue is that it’s ugly: there are now two lists that have to be kept the same. I’d like to define a variable for the list, but I’m not sure how to do that. If I define it in the “state” template then it is not in scope for the “attributes” one. The “variable” section doesn’t work for templates the way it does for automations/scripts. I tried using an input_text, but it’s limited to 100 characters.

If you have any thoughts on

  1. how to get rid of the Template error,
    2 how to make the template more elegant, or,
  2. how important last_reset really is (I’m guessing the Energy display is wrong for one day at worst)
    I’d really appreciate it!

Thanks,
-David

I think I figured out how to get rid of the warning. I need to filter the list for items that have the 'last_reset" attribute. This effectively filters out items from the list that are Undefined. This seems to work:

      last_reset: >
        {{ expand([
          'sensor.outside_lights_energy_kwh',
          'sensor.dining_room_lights_energy_kwh',
          'sensor.allrum_room_lights_energy_kwh',
          'sensor.living_room_lights_energy_kwh',
          'sensor.kitchen_lights_energy_kwh',
          'sensor.work_lights_energy_kwh',
          'sensor.cozy_lights_energy_kwh',
          'sensor.bedroom_lights_energy_kwh',
          'sensor.bathroom_lights_energy_kwh'
        ]) |map(attribute='attributes')|selectattr('last_reset')|map(attribute='last_reset')|max}}

(Filtering the list by selectattr(‘last_reset’) removes all the Undefined entries from the list.)

Nope. I was wrong. That doesn’t cause errors in the Developer template tool, but I still get this error in the HA log:

Template variable warning: ‘mappingproxy object’ has no attribute ‘last_reset’ when rendering

I tried it again, and now I’m getting a different error. It looks like it doesn’t find the attribute when running in the template, because it is now complaining the list is empty when I filter it:

TemplateError(‘ValueError: max() arg is an empty sequence’)

Here’s a better way using a group sensor:

I’ve come up with a slightly better approach using the group sensor. Under sensor: in my configuration I have:

- platform: group
  name: Outside Lights Power
  unique_id: outside_lights_power
  ignore_non_numeric: true
  unit_of_measurement: W
  state_class: measurement
  device_class: power
  type: sum
  entities:
    - sensor.allrum_balcony_switch_power_w
    - sensor.laundry_facade_switch_power_w
    - sensor.entrance_veranda_switch_power_w
    - sensor.dining_room_flood_switch_power_w
    - sensor.deck_flood_switch_power_w
    - sensor.covered_deck_light_switch_power_w
    - sensor.laundry_driveway_switch_power_w
    - sensor.outdoor_plug_balcony_power_w
    - sensor.forest_lights_w
    - sensor.deck_lights_w
    - sensor.outdoor_plug_front_power_w

Your earlier posts were for energy (kWh) and noticed your last post was for power (kW). Have you found something that works better for grouping energy sensors or are you still using this?

Power appears to work well as a group summed but using a group or template for energy doesn’t work well as each sensor is reset at different times. This causes the energy total at the end of the day to be wildly inaccurate, especially when the energy group contains ESPHome devices that reset the energy total daily sometimes just seconds after midnight.

Trying the integral integration on the power group. So far it seems accurate.

2 Likes

I don’t have any energy sensors that reset daily so I haven’t run into problems summing either. The only issue I’ve had is that devices with their own internal power integration (energy reports) seem to be better than manually integrating their energy reports because sometimes they don’t report low power usages. (Of course I’m not certain they are integrating them in that case either…)

1 Like