A highly customizable Home Assistant Lovelace card for visualizing power flow between AC input, inverter/charger, battery, DC system, and AC output, with animated indicators whose direction and speed track real power.
Built for off-grid, RV/marine, and solar + battery + inverter systems (Victron, etc.), but works with any entities that report power.
Version 3.1.0 — full visual editor, a new Flow Behavior section (power-driven flow direction, deadbands, per-flow speed), a safe template evaluator (no
eval), and a large performance pass. See What's New.
- What's New in 3.1.0
- Features
- Installation
- Quick Start
- The Visual Editor
- Configuration Reference
- How flow direction & speed work
- Templates
- Styling with card-mod
- Examples
- Troubleshooting
- License
- Flow Behavior section (new). Each directional path can now be configured directly in the editor:
- Inverter ↔ Battery direction can follow the battery's actual power (sign = direction) instead of the inverter's reported mode text. A deadband forces the flow dark when power is negligible (e.g. tiny idle draw during pass-through).
- Battery ↔ DC and Inverter ↔ DC can be driven by the DC system's power, which handles cases like an alternator pushing power back into the bus and reversing the flow.
- Per-path "reverse" toggles calibrate your sensor's sign convention without editing code.
- Editable charging/discharging state lists for the inverter-state mode.
- Animation speed is now consistent and configurable. Previously each flow normalized speed to a different hidden reference, so a low-power flow could animate faster than a high-power one. Now there's a single global full-speed power reference (so 748 W is always faster than 10 W) plus per-flow overrides and global fastest/slowest bounds.
- Cleaner color pickers. Color fields are proper labeled rows with a square swatch (the old fields overlapped their label).
- Safer & faster. Template expressions are evaluated by a small whitelist parser instead of
eval(no arbitrary code execution). A change-detection pass means the card only recomputes when a watched entity actually changes, with icon/title/color caching to avoid redundant DOM writes — which also fixes long-session browser slowdowns.
All changes are backward compatible: an existing config keeps working, and every new option has a sensible default.
- Five-node layout — AC Input (top-left), AC Output (top-right), Inverter-Charger (center), Battery (bottom-left), DC System (bottom-right). Unused nodes hide automatically.
- Animated flow indicators — direction shows where power is going; speed scales with magnitude.
- Power-aware direction — drive flows from real power values with deadbands, or from inverter state text.
- Full visual editor — configure everything from the UI; no YAML required.
- Template support — Jinja2 templates and simple inline expressions for dynamic values.
- Per-flow colors — separate positive/negative colors for every path.
- Customizable appearance — line thickness, corner radius, glow, flow shape and size.
- Clickable nodes — link any node to another dashboard view.
- card-mod friendly — stable element IDs for deep styling.
- Responsive — recalculates paths on resize.
- Open HACS → Frontend.
- Use the menu (⋮) → Custom repositories.
- Add
https://github.com/NXJim/enhanced-power-flow-cardas a Lovelace repository. - Install Enhanced Power Flow Card.
- HACS adds the resource automatically. If not, add it manually (below).
-
Download
enhanced-power-flow-card.jsfrom the latest release. -
Copy it to
config/www/in your Home Assistant install. -
Add it as a dashboard resource:
Settings → Dashboards → ⋮ → Resources → Add Resource
- URL:
/local/enhanced-power-flow-card.js?v=3.1.0 - Type: JavaScript Module
- URL:
Tip: bump the
?v=value every time you update the file. Home Assistant and your browser cache resources aggressively — changing the query string forces a fresh fetch. After updating, also do a hard refresh (Ctrl/Cmd+Shift+R).
type: custom:enhanced-power-flow-card
entities:
ac_input:
entity: sensor.grid_power
ac_output:
entity: sensor.load_powertype: custom:enhanced-power-flow-card
title: Power Flow
entities:
ac_input:
entity: sensor.ac_input_power
name: Shore Power
unit: W
ac_output:
entity: sensor.ac_loads_power
name: AC Loads
unit: W
inverter_charger:
entity: sensor.inverter_power
name: Inverter
tertiary: sensor.inverter_state # e.g. "Bulk", "Inverting", "Float"
battery:
entity: sensor.battery_soc # state of charge (%)
power_entity: sensor.battery_power # signed power (+charge / -discharge)
name: Battery
unit: "%"
power_unit: W
dc:
entity: sensor.dc_system_power
name: DC System
unit: WThe fastest way to build a config is the visual editor — add the card to a dashboard and click Edit.
Adding the card opens a GUI editor with these sections:
| Section | What it configures |
|---|---|
| Card Configuration | Title, card background |
| Appearance | Line thickness, corner radius, glow, flow shape & size |
| AC Input (Top Left Node) | Entity, name, icon, units, secondary/tertiary, colors, link URL |
| AC Output (Top Right Node) | Same as above |
| Inverter-Charger (Center Node) | Entity, labels, on/off templates, Inverter↔Battery & Inverter↔DC colors |
| Battery (Bottom Left Node) | SoC entity + power entity, charge-state entity, Battery↔DC color |
| DC System (Bottom Right Node) | Entity, name, icon, units |
| Flow Behavior | Direction source/mode, deadbands, reverse, and animation speed for each path |
Everything written here can also be set in YAML — the keys are documented below.
| Option | Type | Default | Description |
|---|---|---|---|
type |
string | — | custom:enhanced-power-flow-card |
title |
string | — | Card title (omit for no title) |
show_background |
boolean | true |
Show the card surface/background |
line_width |
number | 2 |
Flow line thickness (0.1–10) |
corner_radius |
number | 8 |
Path corner radius (0–50) |
ball_diameter |
number | 4 |
Flow indicator size (1–20) |
shape |
string | oval |
Flow shape: circle, oval, squircle, square |
line_glow_size |
number | 3 |
Glow radius on the line (0–20) |
line_glow_brightness |
number | 0.4 |
Line glow intensity (0–1) |
ball_glow_size |
number | 3 |
Glow radius on the indicator (0–20) |
ball_glow_brightness |
number | 1 |
Indicator glow intensity (0–1) |
ac_in_url |
string | — | Navigate target when the AC Input node is clicked |
ac_output_url |
string | — | Navigate target for AC Output node |
inverter_url |
string | — | Navigate target for Inverter node |
battery_url |
string | — | Navigate target for Battery node |
dc_url |
string | — | Navigate target for DC System node |
entities |
object | — | Node entity configuration (below) |
flow_colors |
object | — | Per-path flow colors (below) |
flow_behavior |
object | — | Direction & speed configuration (below) |
entities accepts five nodes: ac_input, ac_output, inverter_charger, battery, dc. Common fields:
| Field | Type | Description |
|---|---|---|
entity |
string | Entity ID, or a {{ }} template that resolves to a number |
name |
string | Display name under the node |
icon |
string | MDI icon (e.g. mdi:battery) |
unit |
string | Unit shown after the value |
secondary |
string | Second line — entity ID, plain text, or template |
secondary_unit |
string | Unit for the secondary line |
tertiary |
string | Third line — entity ID, plain text, or template |
tertiary_unit |
string | Unit for the tertiary line |
color_positive |
color | Flow color when the value is positive |
color_negative |
color | Flow color when the value is negative |
positive |
boolean | Force the displayed value to its absolute value |
invert |
boolean | (AC nodes) flip the animation direction |
Battery extras (entities.battery):
| Field | Description |
|---|---|
entity |
State of charge (%) shown on the node |
power_entity |
Signed battery power (+charge / −discharge) — drives direction in power mode |
power_unit |
Unit for the power value |
flow_state_entity |
Entity/template that reports charge state text (e.g. "Charging"/"Discharging") |
dc_flow_template |
On/off binary sensor or template that gates the Battery↔DC flow in template mode |
inverter_battery_color_positive / _negative |
Override colors for the Inverter↔Battery path |
Inverter extras (entities.inverter_charger):
| Field | Description |
|---|---|
tertiary |
Inverter state text (e.g. Bulk, Absorption, Float, Inverting) — used by inverter-state direction mode |
dc_flow_template |
On/off gate for the Inverter↔DC flow in template mode |
flow_colors overrides the colors of the three "internal" paths:
flow_colors:
inverter_battery:
positive: "#2f80ed"
negative: "#f2994a"
battery_dc:
positive: "#27ae60"
negative: "#f2994a"
inverter_dc:
positive: "#27ae60"
negative: "#f2994a"Colors must be 6-digit hex (#rrggbb).
The new flow_behavior block controls how each directional path decides its direction and speed. Everything here is optional — omit it and the card uses the defaults below.
flow_behavior:
inverter_battery:
direction_source: power # "power" (battery W sign) or "state" (inverter mode)
deadband: 50 # go dark when |power| < this many watts
reverse: false # flip the arrow if it points the wrong way
charging_states: "bulk, absorption, float" # used only in "state" mode
discharging_states: "inverting, assisting, power supply"
max_power: 1800 # optional per-flow full-speed reference (W)
battery_dc:
direction_mode: template # "template" (on/off sensor) or "power" (DC W sign)
deadband: 50
reverse: false
max_power: 360
inverter_dc:
direction_mode: template
deadband: 50
reverse: false
max_power: 1000
speed:
min_duration: 1.5 # fastest animation, seconds
max_duration: 5 # slowest animation, seconds
max_power: 3500 # power at which any flow hits full speed (global)| Path | Key | Default | Notes |
|---|---|---|---|
| Inverter ↔ Battery | direction_source |
power |
power follows the battery power sign; state follows inverter mode text |
deadband |
50 |
flow goes dark below this magnitude | |
reverse |
false |
flips animation direction | |
charging_states / discharging_states |
Victron defaults | comma-separated, used in state mode |
|
| Battery ↔ DC | direction_mode |
template |
template uses the on/off sensor; power uses DC power sign |
| Inverter ↔ DC | direction_mode |
template |
same options |
| Speed | min_duration / max_duration |
1.5 / 5 |
animation bounds in seconds |
max_power |
3500 |
global full-speed reference; per-path max_power overrides it |
Direction. Each path can decide which way to animate from one of two signals:
- Power mode — the path follows the sign of the relevant power value. Positive points one way, negative the other, and a deadband keeps it dark when the value is near zero. This is the most honest mode: the arrow matches what the meter actually reports.
- State / template mode — the path follows the inverter's reported mode text (for Inverter↔Battery) or an on/off binary sensor (for the DC paths). This preserves the classic behavior and is useful when you don't have a clean signed power sensor.
The reverse toggle simply flips the result, so you can match your sensor's sign convention without worrying about which way "positive" is wired.
Example — pass-through with a tiny idle draw. On AC pass-through, an inverter may report a charging state ("Bulk") while the battery actually nets a small discharge (say −40 W of overhead). In power mode with a 50 W deadband, Inverter↔Battery correctly goes dark instead of showing a misleading "charging" arrow.
Example — alternator charging. A DC system with an alternator can source power into the bus. Set Battery ↔ DC to power mode and the flow reverses (DC → Battery) when the alternator feeds in. Use reverse to match your sensor's sign.
Speed. Animation duration scales from max_duration (slow, low power) to min_duration (fast, at or above the full-speed power). Because every flow shares the same global max_power reference by default, higher power always animates faster than lower power across the whole card. Need one flow tuned differently? Give that path its own max_power.
Any of entity, secondary, tertiary, and the dc_flow_template / flow_state_entity fields accept Jinja2 templates:
secondary: "{{ states('sensor.battery_voltage') }} V"
tertiary: "{{ (states('sensor.solar_power') | float / 1000) | round(2) }} kW"Inline conditional expressions are also supported and are evaluated by a built-in safe whitelist parser — only numbers, strings, comparisons, arithmetic, and ternaries are allowed, so templates can never execute arbitrary code:
secondary: "state > 0 ? 'Charging' : 'Discharging'"The card exposes stable element IDs for card-mod.
Nodes: #ac-in-node, #ac-output-node, #inverter-node, #battery-node, #dc-node
Per-node parts: …-icon, …-title, …-value, …-secondary, …-tertiary (battery also has #battery-charge-state and #battery-power)
Flows: #flow-ac, #flow-load, #flow-inverter-bat, #flow-dc-in, #flow-dc-out
Containers: #grid, #flow-svg
type: custom:enhanced-power-flow-card
card_mod:
style: |
#battery-node { transform: scale(1.05); }
#battery-title { color: var(--primary-color); font-weight: 700; }
#flow-inverter-bat { stroke-width: 3; }
entities:
# ...type: custom:enhanced-power-flow-card
title: Energy
line_width: 2.5
corner_radius: 12
shape: oval
entities:
ac_input:
entity: sensor.shore_power
name: Shore
unit: W
ac_output:
entity: sensor.ac_loads
name: AC Loads
unit: W
inverter_charger:
entity: sensor.inverter_power
name: MultiPlus
tertiary: sensor.vebus_state
battery:
entity: sensor.battery_soc
power_entity: sensor.battery_power
name: Battery
unit: "%"
power_unit: W
flow_state_entity: sensor.battery_charge_state
dc:
entity: sensor.dc_power
name: DC System
unit: W
flow_behavior:
inverter_battery:
direction_source: power
deadband: 50
battery_dc:
direction_mode: power
deadband: 30
speed:
min_duration: 1.5
max_duration: 5
max_power: 4000type: custom:enhanced-power-flow-card
entities:
ac_input:
entity: sensor.pedestal_power
name: Pedestal
ac_output:
entity: sensor.rv_loads
name: Loads
battery:
entity: sensor.house_battery_soc
power_entity: sensor.house_battery_power
name: House
unit: "%"Card doesn't render / "Custom element doesn't exist".
The JavaScript failed to load. Check that the resource URL is correct and the file is actually at that path. Then bump the ?v= query string and hard refresh — a stale cached copy is the most common cause. Confirm the type: line uses plain hyphens: type: custom:enhanced-power-flow-card.
A flow points the wrong way. Open Flow Behavior and toggle Reverse direction for that path. That calibrates the card to your sensor's sign convention.
A flow shows the wrong direction during low/idle power. Increase that path's deadband so small values are treated as "off."
One flow animates faster/slower than expected.
All flows share the global full-speed power by default. Give a specific path its own max_power to tune it, or adjust the global min_duration / max_duration.
A node is missing. Nodes hide automatically when their entity isn't configured or doesn't resolve. Verify the entity ID exists in Developer Tools → States.
Battery shows the wrong charge/discharge direction.
Make sure power_entity points at a signed power sensor (positive = charging, negative = discharging). If your sensor uses the opposite convention, enable reverse on the Inverter↔Battery path.
Released under the MIT License.