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.
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') }}