Dashboard real-time power meter with device-level detail

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

Great to hear. @mfisher224 - maybe this will help you too if it’s still an issue. And I can confirm negative isn’t the issue, it was just an unavailable sensor which I presume returned a string such as “unavailable” rather than an integer.

Also, huge thank you to @seanblanchfield - I love this visualization. I was quickly able to pinpoint a ton of usage in my house thanks to this. And a few perplexing mystery consumers to hunt down some day.

1 Like

Thanks for the great detective work @edlin303.

Changing the line

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

to

${ Math.max(...vars.map(v => states[v.entity].state).filter(n => !isNaN(n)))}

should filter out any non-numbers from the expression and hopefully avoid the display issue with unavailable sensors. It would definitely be nicer to log an error about any sensors like this, but it’s not immediately obvious to me how to do this without spamming the javascript console with a message every time the meter is rendered.

If anyone reading this knows if there is a place in custom:config-template-card to run template code only at startup, let me know. We could put something like the following in there:

let badEntities = vars.filter(v => isNaN(states[v.entity].state));
if(badEntities.length) {
    console.warning("Power meter was provided with non-numerical entities: ", badEntities);
}

3 Likes

Hi, Did you solve this problem. I am struggling with this at my hass and with no results.

Wow, this is exactly what I had in mind to build, glad I found this before I spent the time, you saved me a ton of work. Thank you.
I used the “Group” helper in “sum” mode to make finding the unaccounted power calculation a bit easier to maintain. Whenever I monitor a new device, I add it to that helper group. The unaccounted power template sensor is {{ ( states('sensor.house_load_power') | float * 1000 ) - ( states('sensor.individual_devices_total_power') | float ) | round(1) }}

2 Likes

Based on the comments above, I have updated my blog post with new code that gracefully handles problems with the power sensors, such as them not existing, typos, being in an unknown state etc.

Any problems with any of the sensors will now be logged to the javascript console. In the meantime, the power meter should continue to display. If anyone wants update their existing code with this changes, you can just update the entities and max parameters passed to the 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)}

and

    max: ${ Math.max(...vars.map(v => states[v.entity]).filter(e => !!e).map(e => e.state).filter(n => !isNaN(n))) }

Hello @seanblanchfield and thank you for this. For my (very crowded) dashboard I’m trying to do two separate cards in a horizontal stack, one showing the first 5 top consuming devices and the second showing devices 6 to 10 following the same order. Also for aesthetic reasons I’d like to always show ten bars (5 + 5) even if the value is 0.

Could yo help me modify your code to achieve this? Thanks!

It looks like recent updates have broken the severity colors of the bar chart. rgb codes work, but the width of the bars isn’t working anymore. The colors also look muted when using rgb values, which was the first issue I started seeing with recent updates until the colors were gone completely.

This is what it looks like with rgb values