Releases: cataseven/Statistics-Graph-Chart-Card
Release list
✨ New Features & 🐛 Bug Fix
✨ New Features
🗓️ Per-dashboard energy date pickers — energy_collection_key
If you run several dashboards, each with its own energy-date-selection card using a collection_key, the card used to follow whichever collection it found first — so every dashboard danced to the first dashboard's picker (#349). You can now bind a card to a specific picker:
energy_date_sync: true
energy_collection_key: energy_dashboard2 # same key as your energy-date-selection cardLeave it empty and the card follows the default collection, exactly as before.
🪞 Period comparison comes to State Timeline (#350)
The per-entity compare option now works in State Timeline mode. Each comparison renders as its own row directly under the main entity — "Landing Motion (yesterday)" — with the same state colors at reduced opacity, time-aligned so yesterday's 14:00 sits right under today's 14:00. Tooltips on the comparison row show the real historical time, clicking the legend hides main + comparison together, and periods beyond your recorder retention simply show an empty row. All the existing compare forms work: yesterday, last_week, previous_period, hours, or a list with periods_back.
chart_mode: state_timeline
entities:
- entity: binary_sensor.landing_motion
compare: yesterday⏮️ Sequential comparison — past and present side by side (#351)
The per-entity compare gains a second way of drawing: layout: sequential. Instead of overlaying the previous period on top of the live data, the X axis extends backward and the previous period is drawn at its real position — past on the left (dashed), present on the right (solid), meeting in the middle as one continuous timeline. Great for "how did today follow from yesterday" reading rather than "today vs yesterday at the same hour".
entities:
- entity: sensor.temperature
compare:
period: previous_period
layout: sequentialA Layout dropdown on each comparison row in the editor switches between Overlay (default) and Sequential. It applies to previous_period on line/bar charts; tooltips show each half's real date and time, and brush zoom works across the whole extended axis. Existing compare configs are untouched — overlay stays the default.
🔕 -- instead of "unavailable" in the state row
An entity that is unavailable, unknown or has an empty state now shows a compact -- in the state row and legend instead of the long word, which used to stretch the row and break the card's alignment (#347). Entities whose state is genuinely a word (sunny, on, …) still show that word, and the State Timeline still labels its bands as before.
🔍 The Y axis now follows your zoom
Zooming into a chart (brush or pinch) now rescales the Y axis to the visible data, so small variations become readable instead of staying flattened against the full-range axis — the behavior you know from every charting tool. Your hard bounds (lower_bound/upper_bound) and min_bound_range still win, and zooming back (double-click / double-tap) restores the full axis.
🛠 Fixes & reliability
🎨 Fill gradients now follow the data's sign (#338)
4.00 fixed the fill gradient for invert: true series; this release completes the picture for naturally negative data (grid export, sub-zero temperatures…): the gradient is now strongest at the line and fades toward the X axis, exactly like positive series — the direction is decided by where your values actually are, not by a config flag. As a side effect this also corrects the rare combination of invert: true on already-negative data (displayed positive), which was fading the wrong way. And series that cross zero now get a two-lobe gradient: strongest at the line on both sides, fading to transparent exactly at the zero axis — so a mostly-negative chart with brief positive edges finally looks right too.
📊 Legend MIN/MAX no longer nonsensical for inverted series
With invert: true, the legend used to print the value magnitudes but with the roles reversed — a sensor ranging 3…10 showed MIN 10 / MAX 3. The legend now reports the sensor's actual range (MIN 3 / MAX 10), consistent with the state row; the chart itself is unchanged.
📏 Tiny bars are no longer invisible
A bar whose value was very small relative to the axis used to collapse to a sliver — or below half a pixel, disappear entirely. Any non-zero value now draws a bar of at least 2px, anchored at the baseline, so you can always tell the three states apart: no bar (zero or no data), a 2px stub (a value, tiny at this scale), a normal bar. Zeros and gaps still draw nothing, and the tooltip shows the exact value as always.
📐 height: auto no longer shrinks after a reload
With height: auto and no grid_options (masonry layouts, or sections without a fixed row count), the card's height depended on how tall its container happened to be at load time — fine when saved in the editor, smaller after F5. The card now uses its natural content height whenever no fixed row count exists, so it renders the same size every time; fill-to-container behavior is kept when grid_options.rows is a number.
✈️ Performance Improvements & 🐛 Bug Fix
v4.01
✈️ Performance Improvements
This release ships a comprehensive round of server-load optimizations across the card's entire data pipeline — dramatically fewer and smaller database queries, requests shared between cards, and smarter refresh timers — cutting a typical dashboard's Home Assistant database traffic significantly faster
##🏷️ x_axis_datetime_format no longer vanishes from auto_scale_rules
Editing any setting in the visual editor used to silently strip x_axis_datetime_format from every rule in auto_scale_rules — the editor rebuilt the rule rows without knowing about the new key (#339 follow-up). The key now survives editor edits, like datetime_format and x_axis_interval always did.
v4.00 (If you are updating from v3.xx)
🗂️ A reorganized, searchable card editor
The visual editor has been restructured around what you're actually configuring. New main section: CARD SETTINGS and SEARCH BAR
- Chart Settings (formerly General Settings) now holds only chart-related options, with Chart Mode pinned at the top — always visible, no matter which tab you're on.
- A new top-level Card Settings panel collects everything about the card itself, in three tabs: Header & Icon, Card Styling and Localization. No more digging through a "Card" tab inside the chart options.
- A search box at the top of the editor filters every setting live — type "opacity" or "border" and only the matching fields stay visible, with their panels opened for you. This covers entity settings too: entity cards with a match open up showing just the hits, and typing an entity's name reveals that entity's full settings. Options that don't apply to the current chart mode stay hidden, and clearing the search puts everything back the way it was.
- Each tab shows a small badge with the number of options you've changed in it, so you can see at a glance where your configuration lives.
Nothing moved in YAML — every option keeps its name and place; only the editor's layout changed.
🔢 Hide the numbers inside heatmap and calendar cells
A new Cell Values toggle (next to Grid in the editor's Chart tab) controls the numbers printed inside Heatmap and Calendar boxes:
show_cell_values: falseOff gives a clean, colour-only grid — the exact values stay one hover away in the tooltip, and the Calendar's day numbers stay visible. Defaults to on, so existing cards look exactly the same.
🏷️ Format the X-axis labels yourself
A new x_axis_datetime_format option gives you the axis labels you actually want, independent of the tooltip's datetime_format. It takes the same tokens (MMM, DD, ddd, YYYY, …) and also works per rule inside auto_scale_rules, so each zoom level can have its own label style:
auto_scale_rules:
- up_to_hours: 768
group_by: date
x_axis_interval: 1d
x_axis_datetime_format: "ddd DD" # Mon 27, Tue 28, …
- up_to_hours: 8784
group_by: month
x_axis_interval: 1M
x_axis_datetime_format: "MMM" # Jan, Feb, … (no year)The tick density adapts to the pattern length, so short formats like MMM fit more labels on the axis. Leave it unset and the axis formats itself exactly as before.
📡 group_by now works on attribute data sources
If your entity reads its points from an attribute array — electricity prices are the classic case — the calendar group_by modes now actually regroup them. A Nord Pool sensor publishing 96 quarter-hourly prices turns into clean hourly bars with just:
group_by: hour
entities:
- entity: sensor.nord_pool_prices
graph_type: bar
aggregate_func: avg
data_attribute: data
data_time_field: start
data_value_field: valueThe details:
- Works with
hour,date,week,monthandyear. The regroup only happens when the requested cell is genuinely coarser than the array's own spacing, so an array that is already hourly stays untouched undergroup_by: hour— existing cards render pixel-identical. aggregate_funcdecides how each cell is combined:avgfor price levels,maxfor peaks, and so on. Mind thatsumover quarter-hourly prices adds four prices per hour — that is rarely what you want for a tariff.- The state row and legend stats follow the grouped values, so with
avgthe shown maximum becomes the highest hourly average rather than the highest raw quarter. interval(the default) andrawkeep passing the array through exactly as published. The fixed2h–12hmodes are not supported for attribute arrays; the card now says so once in the console instead of staying silent.
🛠 Fixes & reliability
⚡ Long-range charts load much faster
A round of performance work aimed at charts showing weeks, months or a year of history:
None of this changes what is drawn: the whole release was gated on pixel-identical renders across the full chart-mode battery.
📏 The second Y axis now shares the grid
On a dual-axis chart, the right axis used to pick its own "nice" numbers and place them at its own heights — so its labels floated between the grid lines, and its bottom label didn't line up with the left axis. The right axis now labels the same grid rows as the left one, with its own values interpolated at each row. Every right-hand label sits exactly on a grid line, top and bottom aligned with the left axis. The values may carry a decimal (e.g. 15.3 instead of 15) — that is the price of perfect alignment, and the y_axis_decimals option controls how many.
0️⃣ Zero now sits on the axis — and both Y axes agree on it
With a bar chart on the primary axis and a line or area on the secondary, the two zeros didn't line up: bars sat on the plot floor while the second series floated about 7% higher, because the automatic "breathing room" below the lowest value was cancelled for bars but not for lines. The rule is now the same for every chart type: when your data never goes below zero, the axis never does either. Zero sits exactly on the plot floor, on both axes, in every combination.
This visibly changes any line or area chart whose values touch zero — the line now rests on the axis instead of hovering slightly above it (and thanks to the clipping fix below, it renders at full thickness there). Charts with negative values, and axes with explicit card-level bounds, keep their exact current behaviour.
↔️ Year and month views span the full chart width
On a line or area chart grouped by month or year, the first and last points used to sit half a slot in from the chart edges — a year view showed roughly half a month of empty space before January and after December. Line charts now stretch edge to edge: January's point sits on the left border, December's on the right, and the month labels move with them, so every label still sits directly under its point.
Bar and candlestick charts are untouched — bars need their full slots — and so are mixed cards that contain one. The now marker keeps its position inside the current month under the new spacing.
✂️ Lines at the plot edge are no longer half-clipped
A line sitting exactly on a chart boundary — a value pinned at its upper_bound, an auto-scaled peak touching the top, or a step chart's vertical jump at the very edge of the window — was drawn at half its thickness, because the plot's clipping box cut the stroke straight down its centre. The clip now leaves room for half the line width on every side, so edge-hugging lines render at full thickness. Nothing else moves: the change is a few pixels wide and only where a line actually touches the boundary.
🔄 Inverted series flip their fill gradient too
With invert: true the area fill kept fading top-to-bottom, so an inverted series ended up strongest at the x-axis and weakest at its own line — the mirror image of what every normal series shows. The gradient now flips with the series: strongest at the line, fading toward the axis, exactly like bars have always done for negative values.
📐 height: auto + rows: auto no longer shrinks on reload
A card with height: auto and grid_options.rows: auto looked right after saving, but shrank after a page refresh: on a cold load the dashboard measured the card before its data had arrived — a near-empty shell — and locked the row count to that. Three guards now make the height deterministic: the chart reserves its 200 px plot area from the first paint instead of trusting a transient measurement, and the card tells the dashboard a sane minimum row count up front. Saving and refreshing now agree on the same height. Set an explicit height (or fixed rows) as before if you want a specific size.
🚀🚀🚀 New Features 🚀🚀🚀
🗂️ A reorganized, searchable card editor
The visual editor has been restructured around what you're actually configuring. New main section: CARD SETTINGS and SEARCH BAR
- Chart Settings (formerly General Settings) now holds only chart-related options, with Chart Mode pinned at the top — always visible, no matter which tab you're on.
- A new top-level Card Settings panel collects everything about the card itself, in three tabs: Header & Icon, Card Styling and Localization. No more digging through a "Card" tab inside the chart options.
- A search box at the top of the editor filters every setting live — type "opacity" or "border" and only the matching fields stay visible, with their panels opened for you. This covers entity settings too: entity cards with a match open up showing just the hits, and typing an entity's name reveals that entity's full settings. Options that don't apply to the current chart mode stay hidden, and clearing the search puts everything back the way it was.
- Each tab shows a small badge with the number of options you've changed in it, so you can see at a glance where your configuration lives.
Nothing moved in YAML — every option keeps its name and place; only the editor's layout changed.
🔢 Hide the numbers inside heatmap and calendar cells
A new Cell Values toggle (next to Grid in the editor's Chart tab) controls the numbers printed inside Heatmap and Calendar boxes:
show_cell_values: falseOff gives a clean, colour-only grid — the exact values stay one hover away in the tooltip, and the Calendar's day numbers stay visible. Defaults to on, so existing cards look exactly the same.
🏷️ Format the X-axis labels yourself
A new x_axis_datetime_format option gives you the axis labels you actually want, independent of the tooltip's datetime_format. It takes the same tokens (MMM, DD, ddd, YYYY, …) and also works per rule inside auto_scale_rules, so each zoom level can have its own label style:
auto_scale_rules:
- up_to_hours: 768
group_by: date
x_axis_interval: 1d
x_axis_datetime_format: "ddd DD" # Mon 27, Tue 28, …
- up_to_hours: 8784
group_by: month
x_axis_interval: 1M
x_axis_datetime_format: "MMM" # Jan, Feb, … (no year)The tick density adapts to the pattern length, so short formats like MMM fit more labels on the axis. Leave it unset and the axis formats itself exactly as before.
📡 group_by now works on attribute data sources
If your entity reads its points from an attribute array — electricity prices are the classic case — the calendar group_by modes now actually regroup them. A Nord Pool sensor publishing 96 quarter-hourly prices turns into clean hourly bars with just:
group_by: hour
entities:
- entity: sensor.nord_pool_prices
graph_type: bar
aggregate_func: avg
data_attribute: data
data_time_field: start
data_value_field: valueThe details:
- Works with
hour,date,week,monthandyear. The regroup only happens when the requested cell is genuinely coarser than the array's own spacing, so an array that is already hourly stays untouched undergroup_by: hour— existing cards render pixel-identical. aggregate_funcdecides how each cell is combined:avgfor price levels,maxfor peaks, and so on. Mind thatsumover quarter-hourly prices adds four prices per hour — that is rarely what you want for a tariff.- The state row and legend stats follow the grouped values, so with
avgthe shown maximum becomes the highest hourly average rather than the highest raw quarter. interval(the default) andrawkeep passing the array through exactly as published. The fixed2h–12hmodes are not supported for attribute arrays; the card now says so once in the console instead of staying silent.
🛠 Fixes & reliability
⚡ Long-range charts load much faster
A round of performance work aimed at charts showing weeks, months or a year of history:
None of this changes what is drawn: the whole release was gated on pixel-identical renders across the full chart-mode battery.
📏 The second Y axis now shares the grid
On a dual-axis chart, the right axis used to pick its own "nice" numbers and place them at its own heights — so its labels floated between the grid lines, and its bottom label didn't line up with the left axis. The right axis now labels the same grid rows as the left one, with its own values interpolated at each row. Every right-hand label sits exactly on a grid line, top and bottom aligned with the left axis. The values may carry a decimal (e.g. 15.3 instead of 15) — that is the price of perfect alignment, and the y_axis_decimals option controls how many.
0️⃣ Zero now sits on the axis — and both Y axes agree on it
With a bar chart on the primary axis and a line or area on the secondary, the two zeros didn't line up: bars sat on the plot floor while the second series floated about 7% higher, because the automatic "breathing room" below the lowest value was cancelled for bars but not for lines. The rule is now the same for every chart type: when your data never goes below zero, the axis never does either. Zero sits exactly on the plot floor, on both axes, in every combination.
This visibly changes any line or area chart whose values touch zero — the line now rests on the axis instead of hovering slightly above it (and thanks to the clipping fix below, it renders at full thickness there). Charts with negative values, and axes with explicit card-level bounds, keep their exact current behaviour.
↔️ Year and month views span the full chart width
On a line or area chart grouped by month or year, the first and last points used to sit half a slot in from the chart edges — a year view showed roughly half a month of empty space before January and after December. Line charts now stretch edge to edge: January's point sits on the left border, December's on the right, and the month labels move with them, so every label still sits directly under its point.
Bar and candlestick charts are untouched — bars need their full slots — and so are mixed cards that contain one. The now marker keeps its position inside the current month under the new spacing.
✂️ Lines at the plot edge are no longer half-clipped
A line sitting exactly on a chart boundary — a value pinned at its upper_bound, an auto-scaled peak touching the top, or a step chart's vertical jump at the very edge of the window — was drawn at half its thickness, because the plot's clipping box cut the stroke straight down its centre. The clip now leaves room for half the line width on every side, so edge-hugging lines render at full thickness. Nothing else moves: the change is a few pixels wide and only where a line actually touches the boundary.
🔄 Inverted series flip their fill gradient too
With invert: true the area fill kept fading top-to-bottom, so an inverted series ended up strongest at the x-axis and weakest at its own line — the mirror image of what every normal series shows. The gradient now flips with the series: strongest at the line, fading toward the axis, exactly like bars have always done for negative values.
📐 height: auto + rows: auto no longer shrinks on reload
A card with height: auto and grid_options.rows: auto looked right after saving, but shrank after a page refresh: on a cold load the dashboard measured the card before its data had arrived — a near-empty shell — and locked the row count to that. Three guards now make the height deterministic: the chart reserves its 200 px plot area from the first paint instead of trusting a transient measurement, and the card tells the dashboard a sane minimum row count up front. Saving and refreshing now agree on the same height. Set an explicit height (or fixed rows) as before if you want a specific size.
✨ New Features & 🐛 Bug fixes
v3.33
🔍 Drill down into a bucket by clicking it
Seeing a spike on a monthly chart used to mean editing the card, or brushing over roughly the right area and hoping. Now you can just click it:
drill_down: trueClick a single bucket and the card reloads showing only that bucket, at the finer resolution the shorter window allows — click a month bar to see its days, click a day to see its hours, and keep going. Double-click steps back out one level, the same gesture that already undoes a brush zoom.
This is a real reload, not a magnifying glass: the card re-reads history at the finer resolution for the period you picked, so you see detail that simply was not in the original chart.
A few details:
- Clicking empty space, a bucket under a minute long, or a bucket that already fills the view, does nothing.
- Picking a new period from the date picker — a mode button, an arrow, a preset, a calendar day, or Now — drops you back out to that period. The same goes for the interval shortcuts, and for a period change arriving from a synced card. You never end up looking at a drilled-in slice of a range you have since moved away from.
zoom_synccarries each step to the other cards in the group, in and out, so the whole group stays on the same period. Turndrill_downon for each card you want fetching the finer data itself rather than just following the window.- It shares the double-click gesture with brush zooming, so a brush zoom is undone first, then drill levels. It shares the click handler too, which means it needs Brush Zooming left on.
- Timeline charts only, and off by default — the option sits next to Brush Zooming in the editor's Overlay tab.
🎨 Dial the fill under the line up or down
The shaded area under a line has always been drawn at one fixed strength. Some themes swallow it, and on a busy chart several overlapping fills turn into mud. Now each entity has its own Fill Opacity, sitting right next to Fill in the entity's Graph tab:
entities:
- entity: sensor.power
show_fill: true
fill_opacity: 0.150 makes the fill invisible, 1 makes it solid. Leave it empty and nothing changes — the default is exactly the fill you have today.
With Gradient on, this is the opacity at the top of the fill, fading down to an eighth of it at the bottom, so the soft fade is preserved at any strength. With Gradient off, the flat fill uses half the value.
Useful for layering: give the background series a low value and the one you actually care about a high one, and the chart reads instantly.
🛠 Fixes & reliability
📐 Cards no longer grow every time you open the calendar
In a Sections dashboard, a card set to height: auto with grid_options.rows: auto got taller each time the date picker's calendar was opened or closed — a fixed step every click, and it never shrank back.
v3.32
📖 WIKI PAGES
WIKI is available here.
Special thanks to @andyblac for this great contribution. You can also check his integration Advanced History which uses Statistics Graph Chart Card as default history visualizer
✨ New Features
🏷️ Name a series by the attribute it plots (#327)
Graph two attributes of the same entity — a thermostat's current and target temperature, say — and both series were labelled with the entity's friendly name. Two identical entries in the legend, two identical rows in the tooltip, no way to tell them apart.
Two new card options fix that, everywhere the name appears — state row, legend, tooltip, stats and exports:
include_attribute_name: true # "Lounge Heating · Current temperature"
use_only_attribute_name: true # "Current temperature"Pair the second with include_area_names and you get Current temperature · Lounge.
In the editor they are two toggles next to Area names, and they behave as alternatives — switching one on turns the other off.
🔠 State Timeline label size now covers the entity names too
state_timeline_label_font_size sized the state name drawn inside each segment, but the entity name in the column on the left stayed fixed at 11 px — so turning the segment font up left the two visibly out of step.
It now sizes both:
chart_mode: state_timeline
state_timeline_label_font_size: 16 # segments AND the entity names on the leftThe label column is measured at the new size, so names still wrap onto up to three lines instead of being cut off, and rows grow to fit them. Leaving the option unset is unchanged — 10 px inside segments, 11 px for entity names, exactly as before.
Because the setting now reaches the entity names as well, the editor field no longer disappears when Show State Labels is turned off — it stays available for the whole of State Timeline mode.
🔴 A "Live" value in the entity legend
The legend row under the graph could show Min, Avg, Max, Sum and Last — all of them describing the time range on screen. There's now a sixth option, Live: the entity's state right now, whatever period the chart is showing.
entities:
- entity: sensor.power
show_in_legend: true
legend_stats:
- avg
- live # today's average, next to what the meter reads this secondIn the editor it's a new checkbox next to Last and Sum, in the entity's Basic tab under Legend.
🛠 Fixes & reliability
📉 Stacked charts no longer break apart at zero (#330)
On a stacked chart, any series that touched 0 was cut in two there. A battery that stops charging, a grid feed that drops to nothing, a device that switches off — the line stopped dead, the fill ended, and both picked up again only once the value rose above zero. On a busy energy card that meant a row of ragged gaps right where the reading was simply zero.
🎨 State Timeline legend now shows the state colours (#332)
A State Timeline row is painted entirely from state_map — grey for off, yellow for on, whatever you defined. The legend ignored all of that and showed the entity's line colour, which in this mode is only a fallback for states you didn't map. With no colour set, that was a palette pick: a red chip sitting next to a grey-and-yellow row, pointing at nothing on screen.
🧩 No more hairline gaps between stacked areas
Where two stacked series met, thin slivers of the dashboard background showed through the seam — barely visible at normal size, obvious as dark wedges once you zoomed in with the brush.
The two series disagreed about the boundary they share. Series are drawn with smoothed curves by default, but each one closed the bottom of its fill with straight lines. So the lower series' rounded top and the upper series' straight bottom traced slightly different paths, and the background showed between them wherever the curve pulled away from the straight line.
🎨 card-mod styles no longer vanish on reload (#268)
Styling this card with card-mod was a lottery: your CSS applied while you were editing, then a page refresh or app restart silently dropped it, and re-saving the card brought it back.
The cause was a startup race. card-mod injects its style element into the card almost immediately, while the card builds its own content only after the first history fetch — and that first build rebuilt the card's insides from scratch, discarding whatever card-mod had already injected. card-mod never re-inserts on its own, so the styling stayed dead until something rebuilt the card (saving it in the editor, switching dashboards). Whether it "worked" simply depended on which of the two finished first.
✨ New Features & 🐛 Bug fixes
📖 WIKI PAGES
WIKI is available here.
Special thanks to @andyblac for this great contribution. You can also check his integration Advanced History which uses Statistics Graph Chart Card as default history visualizer
✨ New Features
🏷️ Name a series by the attribute it plots (#327)
Graph two attributes of the same entity — a thermostat's current and target temperature, say — and both series were labelled with the entity's friendly name. Two identical entries in the legend, two identical rows in the tooltip, no way to tell them apart.
Two new card options fix that, everywhere the name appears — state row, legend, tooltip, stats and exports:
include_attribute_name: true # "Lounge Heating · Current temperature"
use_only_attribute_name: true # "Current temperature"Pair the second with include_area_names and you get Current temperature · Lounge.
In the editor they are two toggles next to Area names, and they behave as alternatives — switching one on turns the other off.
🔠 State Timeline label size now covers the entity names too
state_timeline_label_font_size sized the state name drawn inside each segment, but the entity name in the column on the left stayed fixed at 11 px — so turning the segment font up left the two visibly out of step.
It now sizes both:
chart_mode: state_timeline
state_timeline_label_font_size: 16 # segments AND the entity names on the leftThe label column is measured at the new size, so names still wrap onto up to three lines instead of being cut off, and rows grow to fit them. Leaving the option unset is unchanged — 10 px inside segments, 11 px for entity names, exactly as before.
Because the setting now reaches the entity names as well, the editor field no longer disappears when Show State Labels is turned off — it stays available for the whole of State Timeline mode.
🔴 A "Live" value in the entity legend
The legend row under the graph could show Min, Avg, Max, Sum and Last — all of them describing the time range on screen. There's now a sixth option, Live: the entity's state right now, whatever period the chart is showing.
entities:
- entity: sensor.power
show_in_legend: true
legend_stats:
- avg
- live # today's average, next to what the meter reads this secondIn the editor it's a new checkbox next to Last and Sum, in the entity's Basic tab under Legend.
🛠 Fixes & reliability
📉 Stacked charts no longer break apart at zero (#330)
On a stacked chart, any series that touched 0 was cut in two there. A battery that stops charging, a grid feed that drops to nothing, a device that switches off — the line stopped dead, the fill ended, and both picked up again only once the value rose above zero. On a busy energy card that meant a row of ragged gaps right where the reading was simply zero.
🎨 State Timeline legend now shows the state colours (#332)
A State Timeline row is painted entirely from state_map — grey for off, yellow for on, whatever you defined. The legend ignored all of that and showed the entity's line colour, which in this mode is only a fallback for states you didn't map. With no colour set, that was a palette pick: a red chip sitting next to a grey-and-yellow row, pointing at nothing on screen.
🧩 No more hairline gaps between stacked areas
Where two stacked series met, thin slivers of the dashboard background showed through the seam — barely visible at normal size, obvious as dark wedges once you zoomed in with the brush.
The two series disagreed about the boundary they share. Series are drawn with smoothed curves by default, but each one closed the bottom of its fill with straight lines. So the lower series' rounded top and the upper series' straight bottom traced slightly different paths, and the background showed between them wherever the curve pulled away from the straight line.
🎨 card-mod styles no longer vanish on reload (#268)
Styling this card with card-mod was a lottery: your CSS applied while you were editing, then a page refresh or app restart silently dropped it, and re-saving the card brought it back.
The cause was a startup race. card-mod injects its style element into the card almost immediately, while the card builds its own content only after the first history fetch — and that first build rebuilt the card's insides from scratch, discarding whatever card-mod had already injected. card-mod never re-inserts on its own, so the styling stayed dead until something rebuilt the card (saving it in the editor, switching dashboards). Whether it "worked" simply depended on which of the two finished first.
✨ New Features & 🐛 Bug fixes
⚠️ Breaking change
🏠 include_area_on_duplicate_names is now include_area_names
The option that appends an entity's area to its name has been renamed, and its behaviour simplified. If you used the old key, rename it:
# before
include_area_on_duplicate_names: true
# now
include_area_names: trueIt no longer waits for two entities to share a name — every entity with an area gets it. The old rule made your legend change shape whenever an unrelated entity was added or removed. Entities you gave a Custom Name are untouched, and a name that already contains its area isn't doubled up.
✨ New in this release
➖ ref_entity — plot the difference of two entities, no need for template sensor anymore
Combine an entity with a second entity over time: indoor minus outdoor temperature, production minus consumption, target vs actual.
entities:
# ref_op defaults to subtract; with no name: the series is
# labelled "Indoor − Outdoor" automatically
- entity: sensor.indoor_temperature
ref_entity: sensor.outdoor_temperature
- entity: sensor.pool_temperature
ref_entity: weather.home
ref_attribute: temperature # read the reference from an attribute
ref_op: divide # subtract | add | multiply | divide
# + reverse_subtract (B−A), reverse_divide (B÷A)Each sample of your entity is combined with the reference value that was valid at that moment, so the result is a real time-aligned series rather than a single offset.
The reversed operators exist because swapping the two entity ids is not the same thing: the main entity decides the timeline, unit, aggregation and colour. Keep the better-sampled sensor as entity: and flip the arithmetic instead.
Two things to know:
subtract/addare refused withchange,diff,sumanddelta. Those aggregations already produce per-bucket differences, so subtracting on top of them is meaningless — the series renders empty with a console warning rather than a confident wrong number.multiply/dividework with any aggregation.- Nothing is invented before the reference exists. The reference is carried forward until it next changes (so a setpoint that changes twice a day works fine), but the stretch before its first sample is left as a gap. Add
break_on_null: trueif you'd rather the line break there.
The state row and trend arrow follow the combined series, so the header always agrees with the chart. Editor: entity → Advanced → Reference Entity / Operation / Reference Attribute.
🔤 state_timeline_label_font_size — size the labels inside State Timeline segments
The state name drawn inside each segment was fixed at 10 px. It is now configurable:
chart_mode: state_timeline
state_timeline_show_labels: true # default
state_timeline_label_font_size: 16 # px, 6-40, default 10A larger label simply shows fewer characters in a narrow segment instead of spilling out of it. In the editor the field sits next to Show State Labels under Visual Options, and appears only while that toggle is on.
🛠 Fixes & reliability
🏷️ State Timeline: long entity names were cropped by the edge of the card
A long friendly name in chart_mode: state_timeline ran off the left side of the card, leaving only its tail visible (…oom Contact Sensor Door).
The label column now sizes itself to the text and grows with the card, and a name that still doesn't fit wraps onto up to three lines — left-aligned, with the row growing to match — so the whole name stays readable on a narrow card, a More Info dialog or a phone:
bu uzun bir
isimdir deneme
amaçlı
Only a name too long even for three lines is shortened, and that one keeps the full text as a hover tooltip. A short name gives its space back to the timeline.
🔍 Visual editor: the Entity field could come up blank (#322)
Two separate faults left the Entity field empty on a card that was graphing perfectly well.
Switching back from the YAML tab left the picker unrendered for the rest of the session — editing the YAML again didn't help, and only saving the card and reopening the editor brought it back. The Tap Action and Battery entity pickers had the same problem. All three now render reliably.
Entities whose state isn't a number — a climate entity's state is heat — were also missing from the picker, even when the card was graphing one of their numeric attributes:
entities:
- entity: climate.lounge_heating
attribute: current_temperatureclimate, humidifier, water_heater and friends are now selectable, matching how Home Assistant's own History treats them, and whatever is already configured is always offered so the field can't be blank for a working card.
The Other badge on such a row is not an error — it marks a series that reads from an attribute, fixed value or state map, and therefore has no long-term statistics.
🔄 The Invert (Mirror) checkbox was hidden outside Timeline mode (#324)
invert: true was only offered in the editor in Timeline mode, so on a Waterfall chart — where inverting is the documented way to express a subtraction step — the checkbox simply wasn't there. You had to write it in YAML, or switch to Timeline, tick it, and switch back.
invert has always worked in every chart mode; only the editor field was hidden. The checkbox now appears in all modes, on the per-entity Advanced tab next to Fixed Value.
✨ New Features & 🐛 Bug fixes
enabled: false — switch an entity off as if it was never configured
For shared card templates (Streamline and friends) where some instances lack a sensor, each entity now takes a plain boolean enabled (default true). When false, the card behaves as if the row didn't exist at all: nothing is fetched or drawn, comparison ghosts aren't created, no card-wide logic (auto-scale guards, Y-bounds, automatic palette colors) considers it — and the entity id isn't even validated, so an unsubstituted template placeholder is harmless:
entities:
- entity: '[[current_entity]]'
name: Current
- entity: '[[target_entity]]'
name: Target
enabled: '[[has_target]]' # per-room template variableOne template, every room — the sensor-less room just passes has_target: false and can omit target_entity entirely. Deliberately not Jinja-templatable (it affects data fetching); static template engines substitute it before the card ever sees it. The visual editor shows disabled rows dimmed with an Enabled toggle, so they can be brought back anytime.
hide_name — a proper toggle to hide a state-row name (empty name now means "show Friendly Name")
The state row (the live value row above the graph) only ever showed a name when you set a custom name; leaving it empty showed nothing, and the only way to deliberately hide a name was the same empty name: "". Those two intents were tangled together. They're now separated:
- Leave the name empty → the entity's
friendly_nameis shown in the state row (it used to be blank). This matches what the compact legend already did. - A new per-entity
hide_nametoggle (defaultfalse) hides the name in the state row, leaving just the value — the explicit way to get a name-less value row.
entities:
- entity: sensor.kids_room # no name → state row shows "KIDS ROOM" (its friendly_name)
- entity: sensor.humidity
hide_name: true # state row shows just the valuehide_name affects the state row only — the compact legend and tooltip keep showing the name. Fully backward compatible: the legacy name: "" (empty custom name) still hides the name everywhere — state row, legend, and tooltip — and is left completely untouched, so no existing config changes. In the editor, an empty Custom Name field means "show Friendly Name"; clearing the field opts into that, while an untouched name: "" keeps hiding. Editor: the toggle lives on the entity's State Row tab.
include_area_on_duplicate_names — tell apart entities that share a friendly name
Integrations like Advanced History can hand several entities the same friendly name (e.g. three sensors all called Heating Temperature). On the legend, tooltip and stats they were indistinguishable. Turn on include_area_on_duplicate_names and the card appends each entity's area — but only where it actually helps:
include_area_on_duplicate_names: true # default false
entities:
- entity: sensor.lounge_heating # friendly_name: "Heating Temperature"
- entity: sensor.office_heating # friendly_name: "Heating Temperature"
- entity: sensor.kitchen_temp # friendly_name: "Kitchen Temp" (unique)
# Legend shows:
# Heating Temperature · Lounge
# Heating Temperature · Office
# Kitchen Temp ← unique name, left untouchedThe suffix is added only to names that collide with another entity's, so unique names never change. The area comes from the entity's own area, or its device's area if the entity has none; if neither resolves, the name is left as-is. A name that already contains its area (e.g. Lounge Heating Temperature in the Lounge) isn't doubled up. An explicit name: you set always wins and is never touched. Comparison ghosts inherit their parent's suffix (Heating Temperature · Lounge (previous period)). Off by default; resolution is a couple of registry key-lookups per entity, so the cost is negligible.
Date picker: calendar and rolling modes are visually separated
The picker's mode buttons mixed two families in one row — calendar periods (D / W / M / Y, which snap to day/week/month/year boundaries) and rolling windows (24H / 3D / 7D …, which always run back from now). Side by side, 3D was easy to read as a calendar shortcut like D. They're now grouped: the editor lists them under separate Calendar periods and Rolling windows (ending now) headings, and the picker bar draws a thin divider between the two families. No behavior change — purely a clarity fix.
🛠 Fixes & reliability
Energy date sync: previous_period comparison uses the calendar period, not the raw window length
With energy_date_sync: true and a previous_period comparison, the comparison series was shifted back by the window's duration instead of one calendar period — so a 31-day July compared against 31 days back (ending 30 June) rather than the previous calendar month, landing every June point one day early. The built-in date picker was already correct because it knows the selected mode; the energy path had no mode to consult. The card now infers the calendar period (day / week / month / year) from the synced range's boundaries and shifts by whole calendar units, wall-clock anchored in your timezone (so it's also correct across DST) — matching the built-in date picker for those selections.
Energy date sync: completed historical periods no longer show today's live value
With energy_date_sync: true, selecting a completed period on the Energy dashboard (e.g. last month) plotted the entity's current state at the end of that historical range — the chart ended at today's reading instead of the period's final value. The built-in date picker already handled this correctly; the energy-sync path just never told the live-tracking logic that a past period isn't live. Now live tracking (and the current-state injection) is off whenever the synced range has already ended, so a historical period ends exactly on its last recorded value. The current in-progress period still updates live as before. As a safety net, a live sample an hour or more past the window end is never folded back onto the trailing edge.
Editor: hover highlights follow the rounded corners (#313)
Hovering a section header or an entity card painted a square highlight whose top corners poked over the container's rounded border. The hover fills now carry their own radius (outer radius minus the border width), so they stay neatly inside the border in every state — open, closed, sections and entity rows alike.
Editor: focus no longer jumps to the first entity panel (#312)
With two entity panels open, editing a field in the second panel snapped the cursor back to the same field of the first panel after each keystroke's save. The editor restores focus across its re-renders by an element path built from CSS classes — and two open panels produce identical paths, so the restore always hit the first match. Paths now include each panel's (and each list row's) index, so focus stays exactly where you're typing.
graph_start + Extended Window: the view aligns to the period's boundaries
With graph_start: day and the extended-window multiplier, the chart opened as a rolling 24h ending at "now" — so the left edge sat at whatever time it happened to be (noon, tea time…). The viewport now aligns to the selected calendar period: a Day view opens midnight-to-midnight (a Week view Monday-to-Monday), the not-yet-elapsed remainder renders as empty space with the now-line marking the current moment, and scrolling still reaches the history behind it and any forecast ahead of it. Relative windows (hours_to_show) keep their rolling behavior, and graph_start without the multiplier is unchanged.
Translucent card backgrounds: the chart no longer shows through the sticky Y-axis
With a scrolling chart (extended_window_multiplier / max_visible_interval) the Y-axis stays pinned while the plot scrolls beneath it — masked by a strip painted in the card's background color. A semi-transparent card_background_color (e.g. rgba(255,255,255,0.30)) made that strip translucent too, so the chart showed straight through the axis. The scrolling content is now clipped to the viewport's plot area (the clip moves with the scroll), so nothing renders under the axis regardless of background opacity — the series, overlays (annotations, average/MA lines, the now-line, data labels), and the X-axis time labels and grid lines, which sit below the plot band and needed their own full-height clip. PNG exports still capture the whole chart — the export restores the full geometry.
⬆️ Improvements & 🐛 Bug fixes
If you are updating from v3.24 please see previous release 3.25, 3.26, 3.27, v3.28
Release v3.29
✨Extended Window — scroll back through history at the selected period's scale
Horizontal scrolling into the past without changing the scale you're looking at. The new card-level extended_window_multiplier renders N× the selected period and opens scrolled to the newest part:
show_date_picker: true
extended_window_multiplier: 2- The screen shows exactly the period you picked — same scale, same bucket density as a card without scrolling. No more "zoomed crop of a bigger chart".
- Scroll back (scrollbar or mouse wheel) through the extra (N−1) periods of history behind it.
- Follows the date picker: on a Week view, one extra week is scrollable behind the current one; switch to Day and it's one extra day — nothing to reconfigure. Works with
hours_to_showandgraph_startwindows too. - The picker's header and arrows stay on the selected period — scrolling is a peek; the arrows remain the navigation.
- Forecast-aware: with forecast entities (
data_attributearrays orforecast_horizondata reaching into the future) the chart opens with the current period in view — right edge at "now", scroll right for the forecast, left for history. Previously it opened on the furthest forecast point, leaving "now" off-screen. Withgraph_startset, the forecast tail is now rendered too (scrollable) instead of being cut off at the period end, and the viewport spans the full selected period so the scale stays stable through the day. (show_full_periodkeeps its "whole period, cut at its end" contract and is not extended.) - Period Comparison, annotations and the now-line keep working;
previous_periodghosts still shift by the selected period, not the extended render window. - Bounded by design (N ≤ 10): memory and recorder load stay predictable — this is why it's a multiplier rather than infinite scroll.
- Editor: Chart → Graph Data → Extended Window (× field next to Visible Window).
1/empty = off; overrides Visible Window while active.
✨ entity variable in entity-level templates — toggles, colors and names
Entity-level templates now receive the row's own entity id as a ready-made entity variable — first shipped for the display toggles (show_graph, show_state, show_in_legend, …) and now extended to the entity-level string fields: color, name, tooltip_name, icon, icon_color, state_color. One generic template can be copy-pasted across 20 entities unchanged:
show_graph: "{{ area_id(entity) == states('input_select.selected_zone') }}"
name: "{{ device_attr(entity, 'name_by_user') or device_attr(entity, 'name') }}"
color: "{{ state_attr('sensor.entity_colors','entities')[device_attr(entity, 'name')] | default('red') }}"Previously every template needed a hand-written {% set entity = 'sensor.…' %} line — with three templated toggles on twenty entities, that was sixty lines of boilerplate to keep in sync (and per-entity colors/names from a central registry were simply impossible without it). Templates that mention entity are evaluated once per entity (Home Assistant renders them with a per-entity variables payload); templates that don't still share a single deduplicated subscription, and templates that set their own {% set entity %} shadow the variable — existing cards are unaffected either way. Bonus: templated names now resolve in the chart tooltip immediately instead of one refresh late, and a templated tooltip_name renders its result instead of the raw template text.
✨ point_size — pick your own data point size
The dots drawn by the Data Points toggle were always auto-sized from the line width. The new entity-level point_size sets their radius in pixels:
entities:
- entity: sensor.temperature
show_points: true
point_size: 5- Leave it unset and nothing changes — dots keep scaling with
line_widthas before. - Also applies to the dot markers in scatter and radar modes (via YAML; in scatter, set it on the first entity — the one that styles the dots).
- Editor: the Point Size field appears right under the Data Points toggle whenever it is enabled.
✨ State Map labels in the chart tooltip
Entities with a state_map now show the mapped label in the timeline tooltip instead of a bare number: a media player reads YouTube, a door sensor reads on — previously the tooltip printed 1.0. When values are aggregated the nearest entry's label is used; entities without a map are untouched. Auto-detected maps (binary sensors, selects in step mode) use Home Assistant's localized state names — the same names the state-timeline tooltip shows — while labels you set yourself are always used verbatim.
✨ Custom Scale Rules now drive the axis and tooltip too
When an auto_scale_rules entry rescales the chart (say, a group_by: date card dropping to hourly buckets for a Day view), the X-axis and tooltip used to keep the base scale's presentation: a hand-set x_axis_interval: 1d left the axis nearly empty, and a datetime_format: DD MMM YYYY tooltip showed no time-of-day for hourly points (#308).
While a rule is active, the card-level x_axis_interval and datetime_format are now suspended — automatic ticks and locale-aware date+time formatting take over, matching the rule's scale. Prefer full control? Each rule accepts its own overrides:
auto_scale_rules:
- up_to_hours: 24
group_by: hour
x_axis_interval: 4h # optional — otherwise automatic while the rule is active
datetime_format: "HH:mm" # optional — otherwise locale date+timeCards without auto_scale_points (or when no rule matches the window) are untouched — your explicit axis settings apply exactly as before.
🛠 Fixes & reliability
Stale-translation fix — cached translations.js no longer survives an update
The line now always reaches the "now" line — every calendar grouping
With date / week / month / year grouping, the in-progress cell is stamped at its start — so on a Week view the line's last point sat at today 00:00 while the now-line (correctly) stood at the current time, up to a full day apart. v3.27 fixed this for hour cells only; now every calendar grouping moves the in-progress cell's tip to "now" (lines and steps — bars keep their cell geometry, where the now-line walks through the current bar instead). Relative windows (hours_to_show) get the same treatment — a subtle gate previously skipped exactly the live windows this exists for. Past periods are never touched.
Templated show_graph: false now hides comparison ghosts too
When a display toggle held a Jinja template — e.g. show_graph: "{{ states('input_boolean.x') == 'on' }}" — the resolved value was applied to the main series only: its Period Comparison ghost kept the raw template text internally and stayed visible, so a hidden main left an orphaned previous-period line on the chart. Resolved template toggles now propagate to the main's ghosts as well (ghost-specific switches like the per-comparison Fill / Show Average / Hide on Load are untouched), so main and ghosts appear and disappear together — same as clicking them in the legend.
⬆️ Improvements
If you are updating from 3.24 please see previous release 3.25, 3.26, 3.27
✨change_ignore_zero — accurate totals for counters that flap to 0
Some integrations report a literal 0 while their device is off or restarting — instead of going unavailable — and then jump straight back to the previous total. Under total_increasing semantics every such dip counts as a meter reset, so the restored value is re-counted as brand-new consumption: a PC network counter that sleeps twice a day can show a 58 GB day when the real usage was 6 GB, and monthly totals inflate by terabytes. The same applies to counters whose midnight reset happens as a rapid "staircase" of intermediate values instead of one clean drop.
The new per-entity change_ignore_zero: true (editor: Ignore transient zeros, shown while the aggregate is Change) fixes this at the card level:
- Zero readings are skipped entirely before the change calculation.
- With long-term statistics, the per-period change is recomputed from the
statecolumn — bypassing HA's own already-pollutedsum/changecolumns, so even historical data is rescued. - Counters that genuinely reset to zero and keep counting from there (daily
*_todaysensors) keep working — the climb after a real reset is still measured.
The proper long-term fix is to make the sensor report unavailable instead of 0, but this switch rescues existing history and third-party integrations you can't change.
✨Stacked Period Comparison
With stacked: true, comparison ghosts now stack with each other instead of rendering as loose overlapping bars: the previous period appears as its own faded stacked column right next to the current one — the same look you previously had to build manually with offset entities. Ghosts honor stack_group (one ghost stack per group and per comparison entry) and still never stack onto the current period.
The tooltip follows suit:
- Stacked-group totals now include a previous-period total row (e.g. "Aktuell Total (previous period)"), and the current group's Total carries a Δ% against it.
- The group-total label's "Total" word is now translated (it was hardcoded English — German dashboards now correctly read "Gesamt").
- When several entities are compared against the same period, the ghost rows share a single date sub-header instead of repeating it before every row — different periods in a multi-comparison keep their own.
✨ New Features 🐛 Bug fixes
⚠️ So many new features for user who are still using v3.24 or earlier while it is just a Hotfix for users who installed v3.26. I am sorry for frequent updates!
Release v3.27
✨Period Comparison: compare against several periods at once (#296)
compare now also accepts a list — one ghost series per entry, each reaching further back via periods_back:
entities:
- entity: sensor.temperature
compare:
- periods_back: 1 # previous period
- periods_back: 2 # two periods ago- Follows the date picker. With the picker on Week, the entries above show last week and two weeks ago; switch to Year and the same config shows last year and two years ago (calendar-aligned for month/year views, leap years handled).
- Each ghost is distinct. Later periods fade progressively by default (0.45 → 0.30 → 0.20 …), legends read "Name (previous period ×2)", and the tooltip shows every ghost's own date plus its own Δ% against the current value. With a single comparison everything looks exactly as in 3.25.
- Editor redesigned to match (as requested in the issue): the Period Comparison section starts empty with an Add Comparison button; each comparison is its own row — period, Periods Back, line style, color, opacity, Δ% — with a delete button. The period dropdown now names units to pair naturally with Periods Back: Day Before / Week Before / Month Before / Year Before (YAML values are unchanged:
yesterday,last_week,last_month,last_year). - Every entry still takes the full style set (
period,color,opacity,line_style,show_fill,show_points,show_in_legend,show_delta), and hiding the main series from the legend hides all of its ghosts. Existing singlecompareconfigs are untouched. hide_on_loadper comparison: an entry withhide_on_load: truestarts hidden when the card loads — click its legend entry to reveal it (and it stays revealed). Handy for keeping rarely-needed periods one click away instead of cluttering the chart. Also available as a Hide on Load toggle on each editor row.
✨Custom auto-scale rules (#297)
Auto Scale can now follow your thresholds instead of the built-in heuristic. Each rule says: when the visible period is up to N hours, use this Group By (and optionally a Points/Hour):
auto_scale_points: true
auto_scale_rules:
- up_to_hours: 24
group_by: hour
- up_to_hours: 168
group_by: date
- up_to_hours: 8784
group_by: month- Date-picker aware. A full month or year selection matches by its nominal length — pick a year in July and your yearly rule still applies, exactly like the built-in auto scale.
- Predictable fallbacks. The smallest matching threshold wins; a period beyond every threshold falls back to the built-in auto scale; an empty list means pure built-in behavior. The same safety guard applies: configs using
offset,forecast_horizonor attribute data keep their Group By untouched. - Editor: with Auto Scale on, a Custom Scale Rules list appears — Add Rule rows with Up to (hours), Group By (the same options as the main Group By select) and a Points/Hour preset dropdown that is enabled only for Interval rules (calendar buckets have a fixed size, so Points/Hour would do nothing there).
🛠 Fixes & reliability
-
Centered date-picker shortcuts no longer get cut off on narrow cards.
-
Pinch zoom actually zooms now.
Release v3.25
✨ Period Comparison
No more duplicating an entity and juggling offset by hand. One option overlays any series with a faded, dashed "ghost" of its previous period:
entities:
- entity: sensor.energy_consumption
compare: previous_period- Periods:
previous_period,yesterday,last_week,last_month,last_year, or a custom number of hours. - Smart shifting:
previous_periodfollows whatever window you are looking at. In the date picker's month view, July is compared with June aligned by calendar date — not by a fixed number of hours. Month-end dates are handled correctly (Mar 31 compares against Feb 28/29). - Tooltip Δ%: hovering shows the current value, the previous-period value, and the change in percent — green for up, red for down. The previous-period row also shows its own date and time (e.g. hovering 15 Jul, 14:00 shows 14 Jul, 14:00 above the comparison value), so you always know exactly which moment you are comparing against.
- One click, both series: hiding a series from the legend hides its ghost too.
- Fully styleable when you want more control:
entities:
- entity: sensor.energy_consumption
compare:
period: last_week
color: "#888888" # default: faded main color
opacity: 0.6 # default 0.45
line_style: dotted # default dashed
show_fill: false
show_delta: true # Δ% in the tooltip
show_in_legend: trueEverything is also configurable from the visual editor: each entity now has a Period Comparison section (timeline charts).
✨ PNG & CSV export
Turn it on and a small download icon appears in the top-right corner of the card:
show_export: true- Download PNG (Chart) — a crisp 2× image of the plot exactly as displayed (works for all chart modes, dark themes included).
- Download PNG (Card) — the whole card in one image: header, chart, state row and legend included. (If your theme uses an external background image the capture falls back to the chart-only export.)
- Download CSV — the visible series' plotted data in a spreadsheet-friendly wide format (UTF-8 with BOM, ISO timestamps in UTC). If you are zoomed in, both PNG and CSV export the zoomed range — you export what you see.
- Files are named after your card header, e.g.
Energy_Overview-20260715-1630.png. - Notes: candlestick CSV exports the bucket value (not OHLC); state-mapped series export their numeric values; the option is templatable like the other display toggles.
✨ Price Entity — consumption × tariff, done right
Chart what your energy actually costs, even on dynamic tariffs (Nordpool, Tibber, EPEX…):
entities:
- entity: sensor.energy_meter
aggregate_func: change
price_entity: sensor.electricity_price
unit: "€"- Every slice of consumption is billed at the price valid at that moment — Σ(kWhᵢ × priceᵢ) — not "average price × total kWh". With a day of 10 kWh cheap + 5 kWh peak power, the difference is real money.
- The price history is fetched automatically alongside your data (long windows use its long-term statistics), and prices are read as a step function — exactly how tariffs behave.
price_attributereads the price from an attribute instead of the state. Tariff changes refresh the card automatically. Period comparison works too: the ghost is billed at its period's prices.- Configure in the editor: Price Entity / Price Attribute under each entity's Advanced → Advanced Calculations section.
✨ Every chart speaks your language now
The remaining hardcoded English labels are gone: tooltip rows in Gauge (Peak/Low), RadialBar (Range/Progress), Radar (Range/Level), Pie/Ranking/Histogram (Share/Range/Count), the candlestick Change/Altitude rows, Scatter's empty-state message and the unknown-chart-mode notice are all translated into the card's 16 languages. Calendar weekday names and box-plot month names now come from your locale automatically.
A second sweep caught the stragglers: the Loading… placeholder, the radar "needs 3 entities" notice, the State option in the attribute dropdown, the date-picker navigation labels read by screen readers, and in the editor the annotation type names (Event marker, Time span, H-line, H-band), the icon-picker labels, the "Disabled when thresholds/trend active" notes and the remaining input placeholders (Off, All, current year, (all together)) — all translated now.
And the big one: all 226 ⓘ help tooltips in the visual editor are now translated into the card's 15 non-English languages. Hover any info icon and read the explanation in your own language — missing entries gracefully fall back to English. (This grows translations.js to ~1.6 MB; it is loaded once and cached by the browser.)
✨ Weeks start on your day
Weekly grouping, the date picker's week view and calendar grid, weekly x-axis ticks and box-plot weekly buckets now follow Home Assistant's First day of the week setting from your user profile. With the default ("Automatic"), the day comes from your language — US users get Sunday-based weeks, most of Europe keeps Monday. No configuration needed on the card.
✨ Templates for show/hide toggles
Display toggles now accept Jinja templates directly — same option, no extra _template keys. Drive card behavior from any helper or sensor:
show_legend: "{{ states('input_boolean.show_legend') == 'on' }}"
entities:
- entity: sensor.pow...