I created a nice real-time power meter with device-level info to display on my Home Assistant dashboard. This shows the current overall power usage in the house, along with a bar chart that shows how it breaks down by appliance type. Here’s how I made it.

I display this power meter on my main dashboard, which is displayed on a wall mounted tablet in the kitchen. It’s amazing how feedback like this can nudge your behaviour towards being more power efficient!

The power meter in action, while I turn devices and appliances on and off around the house

Requirements

  • Home Assistant (of course!)
  • Power sensors. I previously posted about how I used Powercalc to create power and energy sensors that estimated the power usage of all the smart devices (and some dumb devices) in my house. Since then I’ve bought and installed a bunch of Shelly Plus 1PMs and Shelly 1PMs and (and some power monitoring zigbee smart plugs) to monitor the power usage of all our big dumb appliances. I also bought and installed a Shelly EM to monitor total electricity usage at main supply to the house from my consumer unit/breaker box (and I got an extra clamp to measure my electric oven / stove 32A circuit). My Home Assistant now has a near complete view of electricity usage in my house. You’ll might need something similar for this to be of use to you.
  • Bar Card to drive the basic bar chart (install from HACS)
  • Config Template Card to use javascript templates as values in Home Assisant YAML configuration (install from HACS if you don’t already use it).
  • Custom Card Mod to define custom CSS styles for the bar chart (install from HACS if you don’t already use it)

Creating the power categories

Power sensors that are generated by Powercalc can be grouped together in the Powercalc config, which will automatically create summary sensors for the groups. For other devices, I had to make my own summary sensors. For example, I didn’t want to clutter the bar chart by showing each cooking applicance individually; instead I wanted one “cooking” sensor that contained the power usage of all those appliances.

I created some template sensors to hold the current total power usage of devices in various categories. I already had some template sensors enabled from my configuration.yaml as follows:

template:
  - sensor: !include_dir_merge_list  templates/sensors/

This allows me to define template sensors by placing them in a new file in the /config/template/sensors/ directory, as follows (/config/template/sensors/power.yaml):


- name: cooking_power
  unique_id: cooking_power
  unit_of_measurement: W
  device_class: power
  state_class: measurement
  state: >-
    {{ 
      states('sensor.fuse_box_energy_meter_oven_and_hob_power')|float(0)
      + states('sensor.kettle_socket_power')|float(0)
      + states('sensor.microwave_smart_plug_power')|float(0)
    }}

Creating the “Other” category

I also added a template sensor to capture the delta between the total measured power usage of the house, and the sum of all device-level power sensors (whether estimated by Powercalc or measured at the socket). This is the “other” category in the bar chart. It represents:

  • discrepancies between reality and my powercalc estimates
  • time discrepancy between sensors reporting in
  • dumb appliances (like a hair dryer) that are being used from non-monitored sockets.

- name: unaccounted_power
  unique_id: unaccounted_power
  unit_of_measurement: W
  device_class: power
  state_class: measurement
  state: >-
    {{ 
      (
      states('sensor.fuse_box_energy_meter_main_power')|float(0) 
      - states('sensor.all_estimated_usage_power')|float(0)
      - states('sensor.fuse_box_energy_meter_oven_and_hob_power')|float(0)
      - states('sensor.kettle_socket_power')|float(0)
      - states('sensor.microwave_smart_plug_power')|float(0)
      - states('sensor.dishwasher_power')|float(0)
      - states('sensor.washing_machine_power')|float(0)
      - states('sensor.dryer_power')|float(0)
      - states('sensor.fridge_smart_plug_power')|float(0)
      - states('sensor.tv_smart_plug_power')|float(0)
      - states('sensor.workstation_sensor_power')|float(0)
      - states('sensor.boiler_sensor_power')|float(0)
      - states('sensor.pump_sensor_power')|float(0)
      - states('sensor.comms_shelf_power')|float(0)
      - states('sensor.dining_room_socket_power')|float(0)
      )| round(1)
    }}

Creating the Power Meter Cards

I placed the power meter code in the yaml file corresponding to a dashboard that I manage manually. If I was managing dashboards from the UI (as you probably are), I would have placed the code below in “manual” cards.

The main graphic is a native gauge card, defined as follows:

The main power gauge

  - type: gauge
    min: 0
    entity: sensor.fuse_box_energy_meter_main_power
    name: Current Electricity Usage
    max: 5000
    needle: true
    severity:
        green: 0
        yellow: 500
        red: 2000

The animated bar chart uses Config Template Card to define an array of variables, where each item is the entity ID of a power sensor and display name. It uses Bar Card to display those sensors. The list of sensors in the Bar Card is templated (courtesy of Config Template Card) to filter the variables array so that only sensors with a current reading of greater than 5W are displayed. The maximum value of the Bar Card is also templated, so the card automatically re-scales according to the highest current power value. Custom styling is then performed (courtesy of Custom Card Mod).

It’s a shame that Config Template Card’s entities array cannot itself be templated. Config Template Card monitors this list to re-evaluate templates whenever the state of those entities change. It turns out that it needs to be a literal list, and you can’t use a template expression.


type: 'custom:config-template-card'
variables:
  - entity: sensor.cooking_power
    name: Cooking
  - entity: sensor.laundry_power
    name: Laundry
  - entity: sensor.dishwasher_power
    name: Dishwasher
  - entity: sensor.all_lights_power
    name: Lights
  - entity: sensor.fridge_smart_plug_power
    name: Fridge
  - entity: sensor.fridge_fake
    name: FakeFridge
  - entity: sensor.tv_smart_plug_power
    name: TV
  - entity: sensor.workstation_sensor_power
    name: Workstation
  - entity: sensor.boiler_sensor_power
    name: Boiler
  - entity: sensor.pump_sensor_power
    name: Pump
  - entity: sensor.comms_shelf_power
    name: Comms
  - entity: sensor.dining_room_socket_power
    name: Dining Room Socket
  - entity: sensor.estimated_device_power
    name: Estimated Devices
  - entity: sensor.unaccounted_power
    name: Other
entities: 
  # Note: this list of entities may seem redundant, but is necessary to inform
  # config-template-card which entities to watch for updates.
  - sensor.cooking_power
  - sensor.laundry_power
  - sensor.dishwasher_power
  - sensor.all_lights_power
  - sensor.fridge_smart_plug_power
  - sensor.fridge_fake
  - sensor.tv_smart_plug_power
  - sensor.workstation_sensor_power
  - sensor.boiler_sensor_power
  - sensor.pump_sensor_power
  - sensor.comms_shelf_power
  - sensor.dining_room_socket_power
  - sensor.estimated_device_power
  - sensor.unaccounted_power
element:
  type: 'custom:bar-card'
  entities: |- 
      ${ vars.filter(v => {
        let ent = states[v.entity];
        if(ent === undefined || ent.state === undefined) {
          console.warn(`Power meter: Entity ${v.entity} not found`);
        }
        else if(ent.state === 'unknown') {
          console.warn(`Power meter: Entity ${v.entity} state is unknown`);
        }
        else if(isNaN(ent.state)) {
          console.warn(`Power meter: Entity ${v.entity} state is not a number`);
        }
        else return Number(ent.state) > 5;
      }).sort((v1,v2) => states[v2.entity].state - states[v1.entity].state)}
    direction: right
    entity_row: true
    min: 0
    max: ${ Math.max(...vars.map(v => states[v.entity]).filter(e => !!e).map(e => e.state).filter(n => !isNaN(n))) }
  height: 20px
  stack: vertical
  decimal: 0
  icon: 'mdi:flash'
  positions:
    icon: off
    indicator: outside
    name: inside
    value: inside
  severity:
  - color: '#a1a1a18a'
    from: 0
    to: 2
  - color: '#3ea8328a'
    from: 2
    to: 10
  - color: '#85a8328a'
    from: 10
    to: 50
  - color: '#a8a4328a'
    from: 50
    to: 200
  - color: '#a887328a'
    from: 200
    to: 500
  - color: '#a867328a'
    from: 500
    to: 1000
  - color: '#a846328a'
    from: 1000
    to: 3000
  - color: '#a832328a'
    from: 3000
    to: 10000
  style: |-
    #states > * {
      margin: 1px;
    }
    bar-card-name,
    bar-card-value {
      font-size: 0.9rem;
      color: #ffffffaa;
      font-weight: bold;
    }
    bar-card-value	{
      font-weight: bolder;
    }
    bar-card-indicator {
      margin-top: 4px;
      transform: scaleY(-1);
    }