Dashboard real-time power meter with device-level detail

I combined Config Template Card, Custom Card Mod and Bar Card to create a nice power consumption meter for my main dashboard, which the whole household can see and understand at a glance. It supplements a regular Gauge card with a compact animated bar chart breaking down total power usage in categories. It’s making a difference to how we use energy. Here’s a post with details on how I put it together, in case it’s useful to someone else in the community.

power_meter

14 Likes

Intresting setup, thx for sharing!

1 Like

Hello, thanks for sharing!

This is exactly what I want to achieve (I’ve just finished installing an emporia vue 2 with 16 clamps to measure the power consumption of every breakers in my switchboard).

But it looks like Config Template Card cannot be installed through HACS anymore, and bar card is not maintained anymore.

Are you still using this visualization ? have you found some replacements ?

Many thanks !

I am still using this visualization and it’s working well. I have a friend who is also using it, and some people in the community seem to have also adapted it successfully.

I’m on HA 2022.12, have Bar Card 3.2.0 and config-template-card v1.3.6. The approach I took in my blog post has continued to work through version upgrades without any issues.

Bar Card works fine for me, even though it hasn’t had an update in a while. I installed config-template-card through HACS (via the “frontend” section). I don’t know why you can’t see it but you also have the option of manually installing it using the guide linked in it’s documentation.

Good luck!

1 Like

Thanks for your reply @seanblanchfield !

I ended up following another path, with vertical-stack + custom:auto-entities cards.

This is how it looks like on my dashboard :

The code, in case it can help :

type: vertical-stack
cards:
  - type: vertical-stack
    cards:
      - type: custom:auto-entities
        card:
          type: custom:bar-card
          title: Current Power
          show_icon: true
          align: split
          columns: 1
          positions:
            name: inside
            value: inside
          unit_of_measurement: W
          max: 100
          severity:
            - color: Green
              to: '100'
              from: '0'
        entities: []
        sort:
          method: state
          numeric: true
          reverse: true
        filter:
          include:
            - entity_id: sensor.prises_2eme_etage
            - entity_id: sensor.prises_bureau_salon_sam_baie
            - entity_id: sensor.chaudiere
            - entity_id: sensor.prises_garage_cuisine_sam
            - entity_id: sensor.frigo_congelateur_garage
            - entity_id: sensor.prises_cuisine_ch_parents
            - entity_id: sensor.vmc
            - entity_id: sensor.prises_ch_parents_douche
            - entity_id: sensor.prises_garage_entree
            - entity_id: sensor.seche_linge
            - entity_id: sensor.lumieres_ext_garage_entree_escalier_bureau
            - entity_id: sensor.seches_serviettes
            - entity_id: sensor.prises_cabanon_ext
            - entity_id: sensor.lave_linge
            - entity_id: sensor.lave_vaisselle
            - entity_id: sensor.plaques_electriques
            - entity_id: sensor.four
            - entity_id: sensor.volets_roulants
            - entity_id: sensor.unaccounted_power
            - entity_id: sensor.total_power

I’m sorry I couldn’t find the link to the message where I stole part of this code.

EDIT: @Sean I did stole your unaccounted_power sensor though : thanks !

2 Likes

Interesting but why the double vertical stack? Can be removed I think?

Here’s what I have based both of your solutions:


type: custom:auto-entities
card:
  type: custom:bar-card
  positions:
    name: inside
    value: inside
    indicator: 'off'
    icon: 'off'
  unit_of_measurement: W
  max: 100
  severity:
    - color: '#7bc13c'
      from: 0
      to: 50
    - color: '#c1bb3c'
      from: 50
      to: 200
    - color: '#ff8100'
      from: 200
      to: 500
    - color: '#ff6700'
      from: 500
      to: 1000
    - color: '#ff4d00'
      from: 1000
      to: 50000
  height: 30px
  style: "\n#states { padding: 0 } \nbar-card-name,\nbar-card-value {\n  \n  color: #ffffff;\n  }\nbar-card-value\t{\n  font-weight: bold;\n}\nbar-card-indicator {\n transform: scaleY(-1);\n}\n"
  stack: vertical
  direction: right
  decimals: 2
entities: []
sort:
  method: state
  numeric: true
  reverse: true
filter:
  include:
    - entity_id: sensor.socket_*_power
    - entity_id: sensor.socket_*_power_watt
  exclude:
    - state: < 2

@brechtvhb indeed you’re right, was a copy paste fail, you don’t need the double vertical stack.
Thanks for the feedback !

@seanblanchfield I came upon your code on your site via a google search and am trying to make it work for me. I love you implementation, but am having a hard time and I can’t figure out what’s wrong.

The colors on my bars appear washed out and the bars themselves do not appear to be changing. Here is my code:

- type: custom:config-template-card
    variables:
      - entity: sensor.ac_1st_flr_air_handler_7_1min
        name: 1st Flr Air Handler
      - entity: sensor.ac_2nd_flr_air_handler_8_1min
        name: 2nd Flr Air Handler
      - entity: sensor.ac_1st_flr_compresoor_2_1min
        name: 1st Flr Compressor
      - entity: sensor.ac_2nd_flr_compressor_1_1min
        name: 2nd Flr Compressor
      - entity: sensor.refrigerator_kitchen_11_1d
        name: Kitchen Fridge
      - entity: sensor.well_pump_14_1min
        name: Well Pump
      - entity: sensor.balance_power
        name: Balance Power
      - entity: sensor.dryer_9_1min
        name: Dryer
      - entity: sensor.stove_6_1min
        name: Garage Refrigerator
      - entity: sensor.refrigerator_garage_10_1min
        name: Stove
      - entity: sensor.well_pump_5_1min
        name: Microwave
      - entity: sensor.wine_fridge_13_1min
        name: Wine Fridge
      - entity: sensor.attic_fan_current_consumption
        name: Attic Fan
      - entity: sensor.humidifier_current_consumption
        name: Humidifier
      - entity: sensor.draw_collar_current_consumption
        name: Draw Collar
      - entity: sensor.air_purifier_current_consumption
        name: Air Purifier
      - entity: sensor.furnace_12_1min
        name: Furnace
      - entity: sensor.ac_1_1
        name: 1st Flr AC
      - entity: sensor.ac_2_2
        name: 2nd Flr AC
    entities:
      - sensor.ac_1st_flr_air_handler_7_1min
      - sensor.ac_2nd_flr_air_handler_8_1min
      - sensor.ac_1st_flr_compresoor_2_1min
      - sensor.ac_2nd_flr_compressor_1_1min
      - sensor.refrigerator_kitchen_11_1min
      - sensor.well_pump_14_1min
      - sensor.balance_power
      - sensor.dryer_9_1min
      - sensor.main_panel_12_1min
      - sensor.refrigerator_kitchen_11_1min
      - sensor.refrigerator_garage_10_1min
      - sensor.stove_6_1min
      - sensor.main_panel_14_1min
      - sensor.well_pump_5_1min
      - sensor.wine_fridge_13_1min
      - sensor.attic_fan_current_consumption
      - sensor.humidifier_current_consumption
      - sensor.draw_collar_current_consumption
      - sensor.air_purifier_current_consumption
      - sensor.furnace_12_1min
      - sensor.ac_1_1
      - sensor.ac_2_2
    element:
      type: custom:bar-card
      entities: >-
        ${vars.filter(v => states[v.entity].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].state))}
      height: 25px
      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 > * {\n  margin: 1px;\n}\nbar-card-name,\nbar-card-value {\n  font-size: 0.9rem;\n  color: #ffffffaa;\n  font-weight: bold;\n}\nbar-card-value\t{\n  font-weight: bolder;\n}\nbar-card-indicator {\n  margin-top: 4px;\n  transform: scaleY(-1);\n}"

type or paste code here

I took your code and put it into a test dashboard on my HA instance, substituting in my power sensors instead of yours. It worked for me. It was not washed out, and it is updating in real-time. I had to adjust your indention, since everything after the first line is indented too far. Perhaps that is your issue. I also fixed the formatting of the style property to use a YAML multiline string for readability, but I didn’t change its contents.
Here is the exact code that is working for me, copied from your version above. I hope it works for you, but if it doesn’t I think something else must be interfering with it. I would try to debug the styling issue by taking a look in the shadow DOM with your browser dev tools.

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.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:
  - sensor.cooking_power
  - sensor.laundry_power
  - sensor.dishwasher_power
  - sensor.all_lights_power
  - sensor.fridge_smart_plug_power
  - 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 => states[v.entity].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].state))}
  height: 25px
  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);
    }

Thank you. I will look into it. There is definitely some kind of styling happening, maybe through Lovelace.

@seanblanchfield I narrowed it down to

max: ${ Math.max(...vars.map(v => states[v.entity].state))}

When I comment out the entire line, everything looks normal but I obviously lose the dynamic scaling. Wish I knew enough code to understand why…

Sorry for the delay. I have no idea why that line isn’t working for you. That line of javascript uses some ES6 Javascript syntax, which wouldn’t be supported in old web browsers. What web browser and version are you running it in? It runs for me in Chrome and Firefox (and Brave and Fully Kiosk Browser on a Fire HD).

You could check the javascript console for errors, which might shine some light on the precise problem.

Alternatively, you could test that the following code runs without error when you paste it into the javascript console in the same web browser that is giving you issues:

// generate a short array of random numbers
vars = Array.from({length: 5}, () => Math.floor(Math.random() * 5));
// pick the biggest one in a roundabout way, using the ES6 spread operator and ES6 arrow function.
Math.max(...vars.map(v => v))

Thanks for the reply. I’m using Edge & Chrome. I ran the code your suggested without any errors in the console. I also don’t see any obvious errors related to this in the console when looking at the dashboard. Here is what I get:

Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'attribution-reporting'.
Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'run-ad-auction'.
Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'join-ad-interest-group'.
Error with Permissions-Policy header: Origin trial controlled feature not enabled: 'browsing-topics'.
main.js:1 👋 Hey ZED - Zoom Easy Downloader is enabled, if you like our extension please rate us on https://chrome.google.com/webstore/detail/zed-zoom-easy-downloader/pdadlkbckhinonakkfkdaadceojbekep
main.js:15 urlisa http://192.168.1.250:8123/dashboard-overview2/0
lovelace-card-mod.js:1  Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.
0:1  Uncaught (in promise) TypeError: Failed to fetch dynamically imported module: http://192.168.1.250:8123/config/www/community/lovelace-card-mod.js
vertical-stack-in-card.js?hacstag=142051833044:1 vertical-stack-in-cardVersion: 0.4.4
card-mod.js?hacstag=190927524322:5 CARD-MOD 3.2.2 IS INSTALLED
card-mod.js?hacstag=190927524322:5 You may not be getting optimal performance out of card-mod.
See https://github.com/thomasloven/lovelace-card-mod#performance-improvements
auto-entities.js?hacstag=1677445841121:172 AUTO-ENTITIES 1.12.1 IS INSTALLED
bar-card.js?hacstag=163363577320:4855   BAR-CARD   Version 3.1.7    
mushroom.js?hacstag=444350375310:3082 🍄 Mushroom 🍄 - 3.1.0
config-template-card.js?hacstag=172177543136:329  The main 'lit-element' module entrypoint is deprecated. Please update your imports to use the 'lit' package: 'lit' and 'lit/decorators.ts' or import from 'lit-element/lit-element.ts'. See https://lit.dev/msg/deprecated-import-path for more information.
(anonymous) @ config-template-card.js?hacstag=172177543136:329
config-template-card.js?hacstag=172177543136:735   CONFIG-TEMPLATE-CARD    Version 1.3.6         `Preformatted text`

It’s honestly not a big deal. I love what you created, so thank you!

I’m happy to help out a bit, especially if other people might find this thread with the same issues as you.

The output above says there was an error loading the card-mod javascript file. This is almost certainly your problem. See this other thread where someone had that issue due to how they configured the card-mod resource, and resolved it.

Incidentally, although most of the other stuff is info and warnings, the errors at the top are interesting. I think this is probably due to google’s new client-side ad targeting feature in Chrome. It’s breaking for some reason and leaving a mess in your console. Perhaps your adblocker is breaking it, or maybe something else is going on. You could probably prevent this by opting out using the instructions in the above link (although there’s an argument for supporting non-tracking based ad targeting).

1 Like

So here is another interesting issue. I was using an Emporia Vue2 for energy monitoring and recently went ahead and flashed it with esphome to keep everything local. As soon as I did that, the bar card will not update in real time. Only on page refresh. I think it has something to do with the config-template-card because if I do just a basic bar card or even just the sensor alone as a card, they update fine in real time. Any ideas?

That sounds like you haven’t included your new sensor in the entities list of config-template-card. It will only dynamically update in response to changes in those named entities.

Was your previous issue resolved?

The new sensors replaced all the old ones, so I updated it in both places. Here is the yaml just in case. Regarding the old issue, I checked everything in the other forums and it looks like everything in my config is correct. I really don’t have a clue why it’s not working! I went with max:1000 as a workaround. Not as nice, but gets the job done.

- type: custom:config-template-card
    variables:
      - entity: sensor.emporiavue2_kitchen_refrigerator
        name: Kitchen Refrigerator
      - entity: sensor.emporiavue2_well_pump
        name: Well Pump
      - entity: sensor.emporiavue2_balance_power
        name: Balance Power
      - entity: sensor.emporiavue2_dryer
        name: Dryer
      - entity: sensor.emporiavue2_garage_refrigerator
        name: Garage Refrigerator
      - entity: sensor.emporiavue2_stove
        name: Stove
      - entity: sensor.emporiavue2_microwave
        name: Microwave
      - entity: sensor.emporiavue2_wine_refrigerator
        name: Wine Fridge
      - entity: sensor.attic_fan_current_consumption
        name: Attic Fan
      - entity: sensor.humidifier_current_consumption
        name: Humidifier
      - entity: sensor.draw_collar_current_consumption
        name: Draw Collar
      - entity: sensor.air_purifier_current_consumption
        name: Air Purifier
      - entity: sensor.emporiavue2_furnace
        name: Furnace
      - entity: sensor.ac_first_floor_combined_1min
        name: 1st Flr AC
      - entity: sensor.ac_second_floor_combined_1min_2
        name: 2nd Flr AC
      - entity: sensor.emporiavue2_washing_machine
        name: Washing Machine
      - entity: sensor.emporiavue2_dishwasher
        name: Dishwasher
    entities: 
      -sensor.ac_first_floor_combined_1min
      -sensor.ac_second_floor_combined_1min_2 
      -sensor.emporiavue2_microwave
      -sensor.emporiavue2_garage_refrigerator 
      -sensor.emporiavue2_dryer
      -sensor.emporiavue2_stove 
      -sensor.emporiavue2_kitchen_refrigerator
      -sensor.emporiavue2_furnace 
      -sensor.emporiavue2_wine_refrigerator
      -sensor.emporiavue2_well_pump 
      -sensor.emporiavue2_dishwasher
      -sensor.emporiavue2_washing_machine 
      -sensor.attic_fan_current_consumption
      -sensor.humidifier_current_consumption
      -sensor.draw_collar_current_consumption
      -sensor.air_purifier_current_consumption 
      -sensor.emporiavue2_balance_power
    element:
      type: custom:bar-card
      entities: >-
        ${vars.filter(v => states[v.entity].state > 5).sort((v1,v2) =>
        states[v2.entity].state-states[v1.entity].state)}
      direction: right
      entity_row: true
      min: 0
      max: 1000
      height: 25px
      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 > * {\n  margin: 1px;\n}\nbar-card-name,\nbar-card-value {\n  font-size: 0.9rem;\n  color: #ffffffaa;\n  font-weight: bold;\n}\nbar-card-value\t{\n  font-weight: bolder;\n}\nbar-card-indicator {\n  margin-top: 4px;\n  transform: scaleY(-1);\n}\n  ha-card {   \n  box-shadow: none;\n  border: none;\n  border-radius: 0;\n  background: white; \n}"

I am also having this same issue. It was working fine up until a few months ago (timeline is fuzzy, not exactly sure when it started). I am running the latest version of HA (2023.11.3) and view in the mobile app on android and both Chrome and Firefox on my PC. All have the same issue. I tried the trouble shooting steps listed previously and none of them appear to have any promising results. Running the code provided in the javascript console in Firefox results in no errors. There are no errors in the console when running the dashboard that are related to card-mod. The only warning i get is:

The main 'lit-element' module entrypoint is deprecated. Please update your imports to use the 'lit' package: 'lit' and 'lit/decorators.ts' or import from 'lit-element/lit-element.ts'. See https://lit.dev/msg/deprecated-import-path for more information.

Also commenting out max: ${ Math.max(...vars.map(v => states[v.entity].state))} does get the colors back. Not sure why that would be the case and if there are any troubleshooting that can be done to narrow down the issue.

It may just be in my instance, but I was having the same, and it turned out one of the values was returning either negative or unavailable. Somehow the sensor I created changed to _2 and I hadn’t noticed. Hopefully that helps. @seanblanchfield - not sure if there’s a way to make that formula ignore non-numbers, but if so it might make it more durable. Or if there’s a way to list any non-number values on the page, it would help people spot the issue.

This was the solution! I also had a Z-Wave device that has been unplugged but not excluded from the network. Commenting out this line in the variables section fixed the color issue. Thanks!!!

1 Like