A Home Assistant lovelace card to display a sankey chart. For example for energy/power/water consumption.
![License][license-shield]
[![GitHub Activity][commits-shield]][commits]
This card is intended to display connections between entities with numeric state. It is not a general graph card.

Install through HACS
| Name | Type | Default | Description |
|---|---|---|---|
| type | string | custom:sankey-chart |
|
| autoconfig | object | Experimental. See autoconfig | |
| nodes | list | List of entities/nodes to display. See nodes object. Required unless using autoconfig. | |
| links | list | Connections between nodes. See links object | |
| sections | list | Section-level configuration (sorting, min_width). See sections object | |
| layout | string | auto | Valid options are: 'horizontal' - flow left to right, 'vertical' - flow top to bottom & 'auto' - flips to vertical when the available width is smaller than the sum of all sections' min_width (default 150 each) |
| energy_date_selection | boolean | false | Integrate with the Energy Dashboard. Filters data based on a sibling energy-date-selection card. Use only for accumulated sensors (energy/water/gas). You still need to declare your entities and links — the card just uses the date range from the sibling card. Not compatible with time_period. For automatic node/link generation, see autoconfig. |
| energy_collection_key | string | Key of the energy collection to bind to. Auto-detected by default. Set this if you have multiple energy dashboards and the chart binds to the wrong one. The key follows the pattern _energy_<dashboard_url>, e.g. _energy_energy-dashboard |
|
| title | string | Optional header title for the card | |
| unit_prefix | string | Metric prefix for the unit of measurement. Supported values are m, k, M, G, T, and 'auto'. With 'auto', the appropriate prefix is chosen per value based on its magnitude (m for values <1, k for ≥1000, M for ≥1,000,000, etc.). See https://en.wikipedia.org/wiki/Unit_prefix. | |
| round | number | 0 | Round the value to at most N decimal places. May not apply to near zero values, see issue #29 |
| height | number | 200 | The height of the card in pixels. Only matters while in horizontal layout. Vertical layout height is dynamic based on content |
| show_icons | boolean | false | Display entity icons |
| show_names | boolean | false | Display entity names |
| show_states | boolean | true | Display entity states |
| show_units | boolean | true | Display unit of measurement |
| min_box_size | number | 3 | Minimum size of an entity box |
| min_box_distance | number | 5 | Minimum space between entity boxes in the same section (perpendicular to flow) |
| box_thickness | number | 15 | Thickness in px of the colored bar on each entity box (its width in horizontal layout, height in vertical) |
| connection_margin | number | 0 | Gap in px between a box and where its connection curves start/end (along the direction of flow). Increase to separate the curves from the box bars |
| min_state | number | >0 | Any entity below this value will not be displayed. Only positive numbers above 0 are allowed. The default is to show everything above 0. |
| throttle | number | Minimum time in ms between updates/rerenders | |
| static_scale | number | State value corresponding to the maximum size (height for horizontal layout and width in vertical) of the card. For example, if this is set to 1000, then a box with state 500 will take up half of its section. If some section exceeds the value of static_scale, the card will dynamically rescale overriding this option. See #153. |
|
| convert_units_to | string | If entities are electricity (kWh) or gas (ft³) usage, convert them to energy (MJ), cost (monetary) or carbon (gCO2). For cost, you must also specify electricity_price and/or gas_price, as well as the monetary_unit of the price(s). For gCO2, all kWh values will be multiplied by the varying grid CO2 intensity, as with the Energy Dashboard. |
|
| co2_intensity_entity | string | sensor.co2_signal_co2_intensity | Entity providing carbon intensity of electricity (gCO2eq/kWh). If you have solar or storage, you may wish to create a template sensor to convert grid CO2 intensity to consumption CO2 intensity. |
| gas_co2_intensity | number | 66.6 g/ft³ or 2352 g/m³ | Carbon intensity of gas, e.g. in gCO2eq/ft³. Default value depends on locale; units must match those of gas entities. |
| electricity_price | number | Unit price of electricity, e.g. in USD/kWh. Automatic conversion does not support varying electricity prices like the Energy Dashboard does. | |
| gas_price | number | Unit price of gas, e.g. in USD/ft³. | |
| monetary_unit | string | Currency of the gas or electricity price, e.g. 'USD' | |
| sort_by | string | Sort the entities. Valid options are: 'state' (sort by current state) and 'none' (no sorting; useful in sections[].sort_by to override a top-level value). If your values change often, you may want to use the throttle option to limit update frequency |
|
| sort_dir | string | desc | Sorting direction. Valid options are: 'asc' for smallest first & 'desc' for biggest first |
| time_period_from | string | Start of custom time period (e.g., "now-1d", "now/d"). Not compatible with energy_date_selection. See Time period |
|
| time_period_to | string | now | End of custom time period. Not compatible with energy_date_selection. See Time period |
| ignore_missing_entities | boolean | false | If true, missing entities will be treated as having a state of 0 instead of throwing an error |
| Name | Type | Requirement | Default | Description |
|---|---|---|---|---|
| id | string | Required | Unique node id in the chart graph. Defaults to the entity to read, unless entity_id is set. |
|
| entity_id | string | Optional | value of id |
Entity id to read state from. Lets a synthetic id (e.g. sensor.foo__copy) reference a real entity, so two nodes can render the same entity from different angles. See filters. |
| section | number | Optional | Index of the section this node belongs to (0-based). Determines horizontal/vertical position | |
| attribute | string | Optional | Use the value of an attribute instead of the state of the entity. unit_of_measurement and id will still come from the entity. For more complex customization, please use HA templates. | |
| type | string | Optional | entity | Possible values are 'entity', 'passthrough', 'remaining_parent_state', 'remaining_child_state', 'high_carbon_energy', 'low_carbon_energy'. See entity types |
| name | string | Optional | entity name from HA | Custom label for this entity |
| icon | string | Optional | entity icon from HA | Custom icon for this entity |
| unit_of_measurement | string | Optional | unit_of_measurement from HA | Custom unit_of_measurement for this entity. Useful when using attribute. If it contains a unit prefix, that must be in latin. Ex GВт, not ГВт |
| color | string/object | Optional | var(--primary-color) | Color of the box. Can be a simple color string ('red', '#FFAA2C', 'rgb(255, 170, 44)', 'random') or a range object for state-based coloring. See color ranges |
| add_entities | list | Optional | Experimental. List of entity ids. Their states will be added to this entity, showing a sum. | |
| subtract_entities | list | Optional | Experimental. List of entity ids. Their states will be subtracted from this entity's state | |
| filters | list | Optional | List of value transforms applied before the positive clamp. See filters. | |
| tap_action | action | Optional | more-info | Home assistant action to perform on tap. Supported action types are more-info, zoom, navigate, url, toggle, call-service, fire-dom-event. Ex: action: zoom |
| double_tap_action | action | Optional | Home assistant action to perform on double tap | |
| hold_action | action | Optional | Home assistant action to perform on hold | |
| children_sum | object | Optional | reconcile config. Determines how to handle mismatches between parents & children. For example if the sum of the energy from all rooms shouldn't exceed the energy of the whole house. See #37 and its related issues | |
| parents_sum | object | Optional | reconcile config. Determines how to handle mismatches between parents & children. For example if the sum of the energy from all rooms shouldn't exceed the energy of the whole house. See #37 and its related issues |
| Name | Type | Requirement | Default | Description |
|---|---|---|---|---|
| source | string | Required | Entity id of the parent/source node | |
| target | string | Required | Entity id of the child/target node | |
| value | string | Optional | Entity id of a sensor that determines how much of the parent flows into the child (connection entity) |
Filters transform a node's raw state before the chart's automatic clamp to ≥ 0. Each entry is a single-key object naming the transform (ESPHome/Plotly style).
| Filter | Argument | Effect |
|---|---|---|
multiply |
number | Multiplies the raw value. Use -1 to flip the sign of a signed sensor. |
divide |
number | Divides the raw value. |
offset |
number | Adds the argument to the raw value (use a negative number to subtract). |
Filters apply in order, so [{ multiply: 0.001 }, { offset: -5 }] first scales then offsets.
Pair filters with entity_id to render the negative half of a signed sensor as its own node — the sibling node reads the same entity but applies multiply: -1, so positive readings collapse to 0 (via the chart's positive clamp) and negative readings flow as their absolute value. This is how power-mode autoconfig surfaces grid export and battery charging from a single signed stat_rate.
nodes:
# Import flow: positive part of the signed sensor (negative readings clamp to 0).
- id: sensor.grid_power
section: 0
# Export flow: flip sign first, then clamp — surfaces only the negative readings.
- id: sensor.grid_power__export
entity_id: sensor.grid_power
filters:
- multiply: -1
section: 2
You can color nodes based on their state value by using an object instead of a simple color string:
nodes:
- id: sensor.temperature
color:
red:
from: 30 # red when >= 30
orange:
from: 20
to: 30 # orange when >= 20 and <= 30
green:
to: 20 # green when <= 20
| Name | Type | Requirement | Default | Description |
|---|---|---|---|---|
| sort_by | string | Optional | Sort the entities in this section. Overrides the top level option | |
| sort_dir | string | Optional | desc | Sorting direction for this section. Overrides the top level option |
| sort_group_by_parent | boolean | **Option |
$ claude mcp add ha-sankey-chart \
-- python -m otcore.mcp_server <graph>