{"id":18008931,"url":"https://github.com/mp3guy/yet-another-power-card","last_synced_at":"2026-01-06T07:36:58.734Z","repository":{"id":188114807,"uuid":"678132823","full_name":"mp3guy/yet-another-power-card","owner":"mp3guy","description":"Yet another power card (YAPC) for Home Assistant","archived":false,"fork":false,"pushed_at":"2024-08-02T10:36:24.000Z","size":232,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-31T15:38:59.666Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mp3guy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-08-13T19:37:41.000Z","updated_at":"2024-08-02T10:36:27.000Z","dependencies_parsed_at":"2023-08-13T20:38:31.515Z","dependency_job_id":"d1b6c777-49fd-4fb1-81f4-795c8efeee91","html_url":"https://github.com/mp3guy/yet-another-power-card","commit_stats":null,"previous_names":["mp3guy/yet-another-power-card"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mp3guy%2Fyet-another-power-card","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mp3guy%2Fyet-another-power-card/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mp3guy%2Fyet-another-power-card/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mp3guy%2Fyet-another-power-card/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mp3guy","download_url":"https://codeload.github.com/mp3guy/yet-another-power-card/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245662925,"owners_count":20652099,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-30T02:08:15.733Z","updated_at":"2026-01-06T07:36:58.702Z","avatar_url":"https://github.com/mp3guy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Yet Another Power Card (YAPC)\nFor Home Assistant.\n\nhttps://github.com/mp3guy/yet-another-power-card/assets/3238631/a4678dda-7f67-4633-9a88-a0d5b6599028\n\nThis is yet another power flow card for home assistant. It is a heavily modified hard fork of @reptilex's [tesla-style-solar-power-card](https://github.com/reptilex/tesla-style-solar-power-card). My home power setup is quite extensive and I couldn't find a solution for visualization that met my needs, so I created this card. Note the video above uses some placeholder values for illustration purposes only; the video below is a real setup capture.\n\n## Features\nFollowing the style of the source project, it supports:\n\n- A grid entity.\n- Two separate solar array entities, each connected to their own inverter.\n- A battery entity connected to one of the inverters.\n- Up to three additional building entities connected to the main building.\n- Up to three electric vehicle (EV) charger entities.\n- Up to five generic appliance entities.\n- Full icon, main value and extra value specification per node.\n- Auto-hiding of unspecified entities.\n\n## Limitations\nThe card has a few limitations, mostly inherited from the source:\n- The topology and connectivity is fixed. Sorry, I didn't have the time to create a general purpose graph card or optimal node layout routine.\n- Resizing is a bit choppy depending on your browser. It's _ok_ in Firefox, Chrome and the Home Assistant Android app but sometimes a refresh/resize is required.\n- Support and documentation will be very limited.\n\n## Installation\nCopy `power-card.js` into the `www` folder in your home assistant configuration directory root. You can then manually add it by going from your default view three dots in the top right \u003e edit dashboard \u003e three dots in the top right \u003e manage resources. Click add resource, type JavaScript module, URL `/local/power-card.js`, create.\n\nThen, add a custom YAML card on your dashboard like so:\n\n```yaml\ntype: custom:power-card\nappliance0_icon: mdi:water-boiler\nappliance1_icon: mdi:heat-pump\nappliance2_icon: mdi:shower-head\nappliance3_icon: mdi:kettle-steam\nappliance4_icon: mdi:water-pump\nev0_icon: mdi:car-sports\nev1_icon: mdi:car-hatchback\nev2_icon: mdi:car-estate\nbuilding0_icon: mdi:garage-variant\nbuilding2_icon: mdi:water-well\nbuilding3_icon: mdi:horse-variant\npv0_entity: sensor.solax_pv_total_power\npv0_extra_entity: sensor.south_yield\npv1_entity: sensor.solaredge_dc_power\npv1_extra_entity: sensor.solaredge_energy_today\nbattery_entity: sensor.solax_battery_power_charge\nbattery_extra_entity: sensor.solax_battery_capacity_charge\ninverter0_entity: sensor.solax_inverter_load\ninverter0_extra_entity: South\ninverter1_entity: sensor.solaredge_ac_power\ninverter1_extra_entity: E/W\ngrid_entity: sensor.solax_grid_power\ngrid_extra_entity: sensor.solaredge_imported_energy_template\nbuilding1_entity: sensor.building1_sum\nbuilding1_extra_entity: sensor.house_daily_energy_usage\nbuilding2_entity: sensor.shelly_em_water_shed_channel_1_power\nbuilding2_extra_entity: sensor.watershed_daily_energy_usage\nbuilding3_entity: sensor.shelly_em_stables_channel_1_power\nbuilding3_extra_entity: sensor.stables_daily_energy_usage\nev1_extra_entity: sensor.zappi_plug\nappliance0_extra_entity: sensor.myenergi_eddi_energy_used_today\nappliance3_extra_entity: sensor.steamer_daily_energy_usage\nappliance4_extra_entity: sensor.daily_water_usage_litres\nhide_inactive_entities: true\npv0_to_battery_entity: sensor.pv0_to_battery\npv0_to_inverter0_entity: sensor.pv0_to_inverter0\npv1_to_inverter1_entity: sensor.solaredge_dc_power\nbattery_to_inverter0_entity: sensor.battery_to_inverter0\ninverter0_to_battery_entity: sensor.inverter0_to_battery\ninverter1_to_inverter0_entity: sensor.inverter1_to_inverter0\ninverter0_to_building1_entity: sensor.inverter0_to_building1\ninverter0_to_grid_entity: sensor.inverter0_to_grid\ngrid_to_inverter0_entity: sensor.grid_to_inverter0\ngrid_to_building1_entity: sensor.grid_to_building1\ninverter1_to_grid_entity: sensor.inverter1_to_grid\ninverter1_to_building1_entity: sensor.inverter1_to_building1\nbuilding1_to_ev1_entity: sensor.myenergi_zappi_internal_load_ct1\nbuilding1_to_building2_entity: sensor.shelly_em_water_shed_channel_1_power\nbuilding1_to_building3_entity: sensor.shelly_em_stables_channel_1_power\nbuilding1_to_appliance0_entity: sensor.myenergi_eddi_internal_load_ct1\nbuilding2_to_appliance4_entity: sensor.shelly_em_water_shed_channel_2_power\nbuilding3_to_appliance3_entity: sensor.shelly_em_stables_channel_2_power\n```\nWith entities customized to your own specific values. This configuration looks like so:\n\nhttps://github.com/mp3guy/yet-another-power-card/assets/3238631/4c576c3c-73ae-4a20-85ef-6f4f2e8a5db5\n\n## How to calculate entities\nLike its predecessor, everything is specified in terms of `_to_` entities that are always positive. These can be tricky to work out, so here's a guide:\n\n```python\n# We have:\n# inverter0_ct (positive for outputting power, negative for drawing power)\n# inverter1_ct (positive for outputting power)\n# grid_ct (positive for outputting power from grid, negative for drawing power to grid)\n# battery_ct (positive for power going to battery, negative for power being drawn from battery)\n# pv0_ct (positive for outputting power)\n\n# We need:\n# The total usage is the sum of the three generators\nbuilding1_sum = inverter0_ct + inverter1_ct + grid_ct\n# This is the total of positive power only\nbuilding1_pos = max(0, inverter0_ct) + max(0, inverter1_ct) + max(0, grid_ct)\n# Each entity's contribution to the house is proportional to its positive power contribution\ninverter0_to_building1 = (max(0, inverter0_ct) / building1_pos) * building1_sum\ninverter1_to_building1 = (max(0, inverter1_ct) / building1_pos) * building1_sum\ngrid_to_building1 = (max(0, grid_ct) / building1_pos) * building1_sum\n\n# It is useful to work out the apportionment of the battery's power\n# The inverter only goes negative when putting power into the battery\ninverter0_to_battery = -min(0, inverter0_ct)\n# We can directly take the negative value for the opposite direction\nbattery_to_inverter0 = max(0, -battery_ct)\n# Any power going to the battery not accounted for by the inverter must be pv\npv0_to_battery = max(0, max(0, battery_ct) - inverter0_to_battery)\n# Power from pv to inverter is the remainder not going to the battery\npv0_to_inverter0 = pv0_ct - pv0_to_battery\n\n# The power going to the inverter from grid is any remaining not going to the building\ngrid_to_inverter0 = max(0, max(0, grid_ct) - grid_to_building1)\n# Because inverter0_ct is negative when going to battery, any remainder is grid bound\ninverter0_to_grid = max(0, max(0, inverter0_ct) - inverter0_to_building1)\n# Anything going to the grid not from inverter0 is inverter1\ninverter1_to_grid = max(0, -min(0, grid_ct) - inverter0_to_grid))\n# Anything leaving inverter1 not going to the grid or building is going to inverter0\ninverter1_to_inverter0 = max(0, inverter1_ct - (inverter1_to_grid + inverter1_to_building1))\n```\nThis may be somewhat specific to my setup where I have a hybrid inverter with DC coupled battery that is capable of harvesting power from my other regular string inverter.\n\nIn reality however, measurements are noisy and not time synchronized. Hitches happen so the actual template values themselves need some massaging. You'll likely get a couple of these directly from your solar inverter integrations, but the others will have to be coded up as templates. Here are mine for completeness, including my whole house backup feed (EPS) and some `max` operators to prevent bad values.\n\n```yaml\nbuilding1_sum:\n    value_template: \u003e-\n      {{\n          [states(\"sensor.solax_inverter_load\") | int(0) +\n           states(\"sensor.solax_eps_power\") | int(0) +\n           states(\"sensor.solaredge_ac_power\") | int(0) +\n           (0 - (states(\"sensor.solax_feedin_power\") | int(0))), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\nbuilding1_pos:\n    value_template: \u003e-\n      {{\n          [states(\"sensor.solax_inverter_load\") | int(0), 0] | max +\n          [states(\"sensor.solax_eps_power\") | int(0), 0] | max +\n          [states(\"sensor.solaredge_ac_power\") | int(0), 0] | max +\n          [(0 - (states(\"sensor.solax_feedin_power\") | int(0))), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\ninverter0_to_building1:\n    value_template: \u003e-\n      {{\n          [(((states(\"sensor.solax_eps_power\") | float(0) + [states(\"sensor.solax_inverter_load\") | float(0), 0] | max) /\n              states(\"sensor.building1_pos\") | float(0)) *\n              states(\"sensor.building1_sum\") | float(0)) | round(default=0) | int(0), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\ninverter1_to_building1:\n    value_template: \u003e-\n      {{\n          [((([states(\"sensor.solaredge_ac_power\") | float(0), 0] | max) /\n              states(\"sensor.building1_pos\") | float(0)) *\n              states(\"sensor.building1_sum\") | float(0)) | round(default=0) | int(0), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\ngrid_to_building1:\n    value_template: \u003e-\n      {{\n          [((([(0 - (states(\"sensor.solax_feedin_power\") | float(0))), 0] | max) /\n              states(\"sensor.building1_pos\") | float(0)) *\n              states(\"sensor.building1_sum\") | float(0)) | round(default=0) | int(0), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\ninverter0_to_battery:\n    value_template: \u003e-\n      {{\n          -([states(\"sensor.solax_inverter_load\") | int(0), 0] | min)\n      }}\n    device_class: power\n    unit_of_measurement: W\nbattery_to_inverter0:\n    value_template: \u003e-\n      {{\n          [-(states(\"sensor.solax_battery_power_charge\") | int(0)), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\npv0_to_battery:\n    value_template: \u003e-\n      {{\n            [([states(\"sensor.solax_battery_power_charge\") | int(0), 0] | max) -\n                states(\"sensor.inverter0_to_battery\") | int(0), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\npv0_to_inverter0:\n    value_template: \u003e-\n      {% if (states(\"sensor.solax_inverter_load\") | int(0)) \u003c 0 %}\n          0\n      {% else %}\n        {{ [([(states(\"sensor.solax_pv_total_power\") | int(0)) - (states(\"sensor.pv0_to_battery\") | int(0)), 0] | max), states(\"sensor.solax_inverter_load\") | int(0) + states(\"sensor.solax_eps_power\") | int(0)] | min }}\n      {% endif %}\n    device_class: power\n    unit_of_measurement: W\ngrid_to_inverter0:\n    value_template: \u003e-\n      {{\n          [([(0 - (states(\"sensor.solax_feedin_power\") | int(0))), 0] | max) -\n              states(\"sensor.grid_to_building1\") | int(0), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\ninverter0_to_grid:\n    value_template: \u003e-\n      {{\n          [([states(\"sensor.solax_inverter_load\") | int(0), 0] | max) -\n              states(\"sensor.inverter0_to_building1\") | int(0), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\ninverter1_to_grid:\n    value_template: \u003e-\n      {{\n          [states(\"sensor.solaredge_ac_power\") | int(0), [-([(0 - (states(\"sensor.solax_feedin_power\") | int(0))), 0] | min) -\n              states(\"sensor.inverter0_to_grid\") | int(0), 0] | max] | min\n      }}\n    device_class: power\n    unit_of_measurement: W\ninverter1_to_inverter0:\n    value_template: \u003e-\n      {{\n          [states(\"sensor.solaredge_ac_power\") | int(0) -\n            (states(\"sensor.inverter1_to_grid\") | int(0) +\n              states(\"sensor.inverter1_to_building1\") | int(0)), 0] | max\n      }}\n    device_class: power\n    unit_of_measurement: W\n```\nTo avoid flickering there are some thresholds, in the low double digit Watts to disable entities near inflection points (e.g. grid export/import near zero). Additionally, spurious non-zero values are also filtered.\n\nHere's the complete set of configuration options:\n```typescript\n//Line settings\nhide_inactive_entities?: boolean;\nspeed_factor?: number;\n\n// Icons\ngrid_icon?: string;\nbattery_icon?: string;\npv0_icon?: string;\npv1_icon?: string;\ninverter0_icon?: string;\ninverter1_icon?: string;\nbuilding0_icon?: string;\nbuilding1_icon?: string;\nbuilding2_icon?: string;\nbuilding3_icon?: string;\nappliance0_icon?: string;\nappliance1_icon?: string;\nappliance2_icon?: string;\nappliance3_icon?: string;\nappliance4_icon?: string;\nev0_icon?: string;\nev1_icon?: string;\nev2_icon?: string;\n\n// What click through to. The \"leaf\" node ev and appliances implicitly click through to their\n// entity from their parent to themselves\ngrid_entity?: string;\nbattery_entity?: string;\npv0_entity?: string;\npv1_entity?: string;\ninverter0_entity?: string;\ninverter1_entity?: string;\nbuilding0_entity?: string;\nbuilding1_entity?: string;\nbuilding2_entity?: string;\nbuilding3_entity?: string;\n\n// Power from one thing to another\npv0_to_battery_entity?: string;\npv0_to_inverter0_entity?: string;\npv1_to_inverter1_entity?: string;\nbattery_to_inverter0_entity?: string;\ninverter0_to_battery_entity?: string;\ninverter1_to_inverter0_entity?: string;\ninverter0_to_building1_entity?: string;\ninverter0_to_grid_entity?: string;\ngrid_to_inverter0_entity?: string;\ngrid_to_building1_entity?: string;\ninverter1_to_grid_entity?: string;\ninverter1_to_building1_entity?: string;\nbuilding1_to_ev1_entity?: string;\nbuilding1_to_building0_entity?: string;\nbuilding1_to_building2_entity?: string;\nbuilding1_to_building3_entity?: string;\nbuilding1_to_appliance2_entity?: string;\nbuilding1_to_appliance0_entity?: string;\nbuilding0_to_ev0_entity?: string;\nbuilding0_to_ev2_entity?: string;\nbuilding0_to_appliance1_entity?: string;\nbuilding2_to_appliance4_entity?: string;\nbuilding3_to_appliance3_entity?: string;\n\n// Extra entities that are shown on the card\ngrid_extra_entity?: string;\npv0_extra_entity?: string;\npv1_extra_entity?: string;\ninverter0_extra_entity?: string;\ninverter1_extra_entity?: string;\nbuilding0_extra_entity?: string;\nbuilding1_extra_entity?: string;\nbuilding2_extra_entity?: string;\nbuilding3_extra_entity?: string;\nbattery_extra_entity?: string;\nappliance0_extra_entity?: string;\nappliance1_extra_entity?: string;\nappliance2_extra_entity?: string;\nappliance3_extra_entity?: string;\nappliance4_extra_entity?: string;\nev0_extra_entity?: string;\nev1_extra_entity?: string;\nev2_extra_entity?: string;\n```\nNon-specified entities will not be drawn.\n\n## Development\nThis is a typescript project, so to build it first install packages:\n```bash\nnpm install\n```\nAnd then build\n```bash\nnpm run build\n```\nI included a convenience script, `deploy.sh`, that also runs the linter.\n\n## TODO / Accepting PRs on\nThere's a few nice-to-haves I didn't get a chance to implement I'm capturing here:\n- Dynamic static grid layout selection based on provided entities.\n  - The current fixed layout can leave some empty columns/rows if you don't have certain entities, which looks bad. It would be relatively straightforward to dynamically specify the CSS grid layout based on available entities to expand it and use up the full card.\n- Generalization of graph topology and entities.\n  - This is a bigger job, but it's partially complete. Basically allow arbitrary numbers of arbitrary entities with arbitrary connectivity and layout.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmp3guy%2Fyet-another-power-card","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmp3guy%2Fyet-another-power-card","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmp3guy%2Fyet-another-power-card/lists"}