Skip to content

Releases: cataseven/Statistics-Graph-Chart-Card

✨ New Features & 🐛 Bug Fix

Choose a tag to compare

@cataseven cataseven released this 11 Aug 22:19
783a438

✨ 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:

image
energy_date_sync: true
energy_collection_key: energy_dashboard2   # same key as your energy-date-selection card

Leave 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.

image
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".

image image
entities:
  - entity: sensor.temperature
    compare:
      period: previous_period
      layout: sequential

A 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

Choose a tag to compare

@cataseven cataseven released this 08 Aug 16:06
2f523bc

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

search
  • 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: false

Off 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: value

The details:

  • Works with hour, date, week, month and year. 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 under group_by: hour — existing cards render pixel-identical.
  • aggregate_func decides how each cell is combined: avg for price levels, max for peaks, and so on. Mind that sum over 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 avg the shown maximum becomes the highest hourly average rather than the highest raw quarter.
  • interval (the default) and raw keep passing the array through exactly as published. The fixed 2h12h modes 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 🚀🚀🚀

Choose a tag to compare

@cataseven cataseven released this 07 Aug 23:48
9d92531

🗂️ 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

search
  • 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: false

Off 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: value

The details:

  • Works with hour, date, week, month and year. 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 under group_by: hour — existing cards render pixel-identical.
  • aggregate_func decides how each cell is combined: avg for price levels, max for peaks, and so on. Mind that sum over 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 avg the shown maximum becomes the highest hourly average rather than the highest raw quarter.
  • interval (the default) and raw keep passing the array through exactly as published. The fixed 2h12h modes 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

Choose a tag to compare

@cataseven cataseven released this 30 Jul 13:45
89ec631

v3.33

🔍 Drill down into a bucket by clicking it

Drill

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: true

Click 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_sync carries each step to the other cards in the group, in and out, so the whole group stays on the same period. Turn drill_down on 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:

image
entities:
  - entity: sensor.power
    show_fill: true
    fill_opacity: 0.15

0 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 left

The 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 second

In 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

Choose a tag to compare

@cataseven cataseven released this 29 Jul 21:36
ff573be

📖 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 left

The 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 second

In 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

Choose a tag to compare

@cataseven cataseven released this 25 Jul 14:51
8531019

⚠️ 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: true

It 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.

image
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/add are refused with change, diff, sum and delta. 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/divide work 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: true if 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 → AdvancedReference 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:

image
chart_mode: state_timeline
state_timeline_show_labels: true      # default
state_timeline_label_font_size: 16    # px, 6-40, default 10

A 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_temperature

climate, 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

Choose a tag to compare

@cataseven cataseven released this 21 Jul 11:23
aaf6998

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:

image
entities:
  - entity: '[[current_entity]]'
    name: Current
  - entity: '[[target_entity]]'
    name: Target
    enabled: '[[has_target]]'   # per-room template variable

One 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:

image
  • Leave the name empty → the entity's friendly_name is shown in the state row (it used to be blank). This matches what the compact legend already did.
  • A new per-entity hide_name toggle (default false) 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 value

hide_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:

image
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 untouched

The 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

Choose a tag to compare

@cataseven cataseven released this 18 Jul 19:20
f9b884f

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

image scroll3

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_show and graph_start windows 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_attribute arrays or forecast_horizon data 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. With graph_start set, 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_period keeps its "whole period, cut at its end" contract and is not extended.)
  • Period Comparison, annotations and the now-line keep working; previous_period ghosts 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_width as 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+time

Cards 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

Choose a tag to compare

@cataseven cataseven released this 17 Jul 10:38
f720b8e

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 state column — bypassing HA's own already-polluted sum/change columns, so even historical data is rescued.
  • Counters that genuinely reset to zero and keep counting from there (daily *_today sensors) 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

image

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

Choose a tag to compare

@cataseven cataseven released this 16 Jul 20:11
8101e7b

⚠️ 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)

periodcompare

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 single compare configs are untouched.
  • hide_on_load per comparison: an entry with hide_on_load: true starts 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)

custom

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_horizon or 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

image image

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_period follows 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: true

Everything is also configurable from the visual editor: each entity now has a Period Comparison section (timeline charts).

✨ PNG & CSV export

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…):

price
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_attribute reads 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...
Read more