An automated pie chart of all power consumers in my home

I created a pie chart that shows the current power usage of all devices in my home. It automatically includes all power meters I have, so no painfully keeping a list of device ids up-to-date any more. I thought I share with you all how I did it. There may be other ways and there may be better ways. This is just how I did it.

Let’s start with the end result. When you hover the mouse over one of the parts of the chart, it’ll show you that part’s name plus current usage.
image

Here’s the yaml for the card. I’ll explain some of the details later on.

type: custom:auto-entities
card:
  type: custom:apexcharts-card
  chart_type: pie
  header:
    show: false
  apex_config:
    legend:
      show: false
  update_interval: 30sec
sort:
  method: name
entities:
  - entity: sensor.utilities_unmetered_power
filter:
  template: >
    {{ states.sensor  | rejectattr('attributes.device_class', 'undefined')  |
    selectattr('attributes.device_class', 'eq', 'power')  |
    rejectattr('attributes.unit_of_measurement', 'undefined')  |
    selectattr('attributes.unit_of_measurement', 'in', ['W', 'kW'])  |
    rejectattr('entity_id', 'in', area_entities('energie'))  |
    map(attribute='entity_id')  | list() }}

As you can see I’ve used some custom HACS components for this. If you want to use my code you’ll need these components installed. The instructions how to install them can be found with each repository.

The chart automatically includes all entities that have a device_class: power and have a unit_of_measurement of either ‘W’ of ‘kW’. However not all ‘power’ entities in HA are consumer entities. Some are totals like for example my whole-home energy meter and solar panel’s entities. Such entities I want to exclude from the chart (and other lists of consumers), so I put all of these into an ‘area’ called ‘energie’ (should actually better have used ‘utilities’, but I realized this only after I had already created several automations). Now when I find an entity is incorrectly included as a consumer, all I have to do is move that entity (or the device as a whole) into the ‘energie’ area and it will be excluded from all consumer lists and thus from this chart too.

Because it’s nearly impossible to have metering on all devices in my home and I still want to the chart to show the full 100% of all power used in my home, I created one additional template sensor that has the total of unmetered Watts as its value: sensor.utilities_unmetered_power. This one sensor I always add by default to the graph. It is a template helper with below template. The template again uses the same mechanism of selecting all power sensors, plus it uses one additional sensor.envoy_121831009724_current_power_consumption that has the total power used by my home (i.e. 100%) as measured by my solar installation integration (enphase) (*).

{% set usage = float(states('sensor.envoy_121831009724_current_power_consumption')) %}
{% if state_attr('sensor.envoy_121831009724_current_power_consumption', 'unit_of_measurement') == 'kW' %}
{% set usage = usage * 1000 %}
{% endif %}
{% set sensors = states.sensor
      | rejectattr('attributes.device_class', 'undefined') 
      | selectattr('attributes.device_class', 'eq', 'power') 
      | rejectattr('attributes.unit_of_measurement', 'undefined') 
      | rejectattr('entity_id', 'in', area_entities('energie'))
      | rejectattr('state', 'in', ['unknown', 'unavailable']) %}
{% set watts = sensors
      | selectattr('attributes.unit_of_measurement', 'eq', 'W')
      | map(attribute='state')
      | map('float')
      | list()%}
{% set kilowatts = sensors
      | selectattr('attributes.unit_of_measurement', 'eq', 'kW')
      | map(attribute='state')
      | map('float')
      | list()%}
{{ max(usage - (watts|sum + 1000.0 * kilowatts|sum), 0) }}

Please note that each power sensor in HA updates at its own interval. i.e. There will be temporary fluctuations where one sensor has updated while another hasn’t yet. There can thus be for example negative unmetered values. I added a max( …, 0) to the template such that the unmetered value can not go below 0 to suppress the effect of such temporary negative value on my chart. The unmetered value can therefor not be exact. It is just the difference between the total and the sum of all consumers at any one point in time.

(*) My solar integration gives me the total usage of my home. If yours doesn’t, you can still calculate total usage of your home by creating template sensor that adds the Watt (W) values for your solar to the grid-in, then subtracts the value for grid-out. f.e.:

template:
  - sensor:
      - name: power_used
        unique_id: "power_used"
        unit_of_measurement: W
        device_class: power
        state_class: measurement
        state: >
          {%- set src = 'sensor.electricity_meter_power_consumption' %}
          {%- set grid_in = (states(src) | float * 0.001 if is_state_attr(src, 'unit_of_measurement', 'kW') else states(src) | float * 1.0 if is_state_attr(src, 'unit_of_measurement', 'W') else 'unknown') %}
          {%- set src = 'sensor.electricity_meter_power_production' %}
          {%- set grid_out = (states(src) | float * 0.001 if is_state_attr(src, 'unit_of_measurement', 'kW') else states(src) | float * 1.0 if is_state_attr(src, 'unit_of_measurement', 'W') else 'unknown') %}
          {%- set src = 'sensor.envoy_121831009724_current_power_production' %}
          {%- set solar = (states(src) | float * 0.001 if is_state_attr(src, 'unit_of_measurement', 'kW') else states(src) | float * 1.0 if is_state_attr(src, 'unit_of_measurement', 'W') else 'unknown') %}
          {{ (solar + grid_in) - (grid_out) }}
        availability: >
          {{ has_value('sensor.electricity_meter_power_consumption') 
              and has_value('sensor.electricity_meter_power_production') 
              and has_value('sensor.envoy_121831009724_current_power_production') }}
4 Likes

This looks very interesting and exactly what I am looking for. Please forgive my ignorance but where should I put those code blocks? I haven’t ever customized a dashboard in HA so please bear with me

  • Edit the dashboard that you want to add the card to (in the latest HA version you click the pencil icon in the right top, in previous versions you had to click the three dots in the top, then select ‘edit dashboard’).

  • Click the blue “+ ADD CARD” button in the bottom.

  • Scroll down to the bottom of the available card types and select “Manual”.

  • In the “Card configuration” window, paste the text from the 1st text box into this card, overwriting the text “type: ‘’” that is in there by default.

  • In the simplest form, remove the line with - entity: sensor.utilities_unmetered_power. This sensor will only be available after you’ve also added the template helper from the 2nd text box.

Once you’ve managed to add the chart without the unmetered power sensor, let me know and I’ll add instructions for adding that sensor too.

1 Like

Thank you very much, that worked beautifully!

You got both the pie chart and the unmetered_power sensor working? Great!. If I may ask, did you use a whole-home energy meter (like my enphase solar system’s lifetime_energy sensor) or did you use the calculation of (grid-in + solar) - grid-out for the usage calculation?

I used a whole-home energy meter (Zemismart SPM-02).

Do you know whether it’s possible to have a similar chart with consumed energy (kWh), like in the default “Energy” dashboard, instead of instantaneous power (W)?

Yes, theoretically this should possible. However, energy readings (kWh) are stored differently in the long-term statistics table than power readings (W) and the apex-charts diagram can’t read such energy readings at the moment. Several requests have been made to add support for them, and from the check-in comments a version even seems to have been built into a dev stream, but it looks like the project has been abandoned since then as no new development has been done on it for some time already. So in practice it is not available in the released product and I have not been able to do this yet.

This is amazing, thanks a lot for sharing!

Instead of using an area, I actually used a label, and integrated it like: 'entity_id', 'in', label_entities('ignoreforcurrentpowerusage')

1 Like