Thank you all for this - really useful.
I got a bit OTT with it, and created a customisable dropdown set of graphs so you can easily cahnge between 4/8/12/24 hours forecasts, along with options to mess with colours.
Warning! Use at your own risk - I’m very new to HA!
I should probably stick this on github, but for now, comprehensive instructions in the code; then just copy and paste the yaml.

# ========================================
# Amber Electric Interactive Price Forecast Chart
# ========================================
#
# A customizable Home Assistant dashboard card that displays Amber Electric
# price forecasts with an interactive time span selector (4, 8, 12, or 24 hours).
#
# FEATURES:
# - Interactive dropdown to switch between different forecast time spans
# - Shows Buy Price (General) and Feed-In Tariff (FIT) prices
# - Displays prices in cents per kWh (c/kWh)
# - Detailed tooltips on hover
# - Clean, modern design
#
# ========================================
# DEPENDENCIES & PREREQUISITES
# ========================================
#
# REQUIRED:
# 1. Amber Electric Integration
# - Official Home Assistant integration for Amber Electric
# - Provides the forecast sensors needed for this card
#
# 2. ApexCharts Card (custom card via HACS)
# - Used to render the interactive price forecast graphs
# - Must be installed via HACS (Home Assistant Community Store)
#
# OPTIONAL:
# - card-mod (via HACS)
# - Only needed if you want to customize the styling of the dropdown selector
# - The card works perfectly fine without it
#
# NOTE: This guide assumes you already have these installed. If not, install them
# through HACS before proceeding.
#
# ========================================
# SETUP INSTRUCTIONS
# ========================================
#
# STEP 1: Find Your Amber Electric Sensor Names
# ----------------------------------------------
# Your sensor names will be different from the example below. To find them:
#
# Method 1 - Using Developer Tools (Easiest):
# 1. Go to Developer Tools → States
# 2. In the filter box, type "amber"
# 3. Look for sensors ending in "_general_forecast" and "_feed_in_forecast"
# 4. Copy the full entity IDs (e.g., sensor.your_address_general_forecast)
#
# Example sensor names you might see:
# - sensor.123_main_st_general_forecast
# - sensor.123_main_st_feed_in_forecast
#
# Method 2 - Using Entity Registry:
# 1. Go to Settings → Devices & Services
# 2. Click on the Amber Electric integration
# 3. Find the sensors named "General Forecast" and "Feed In Forecast"
# 4. Click on each one and copy the Entity ID
#
# STEP 2: Create the Input Select Helper
# ----------------------------------------------
# This creates the dropdown selector for choosing time spans.
#
# Via UI (Recommended):
# 1. Go to Settings → Devices & Services → Helpers
# 2. Click "+ CREATE HELPER"
# 3. Select "Dropdown"
# 4. Configure:
# - Name: Amber Chart Time Span
# - Icon: mdi:clock-outline
# - Options (add these exactly, with capital H):
# * 4 Hours
# * 8 Hours
# * 12 Hours
# * 24 Hours
# 5. Click CREATE
#
# Note: The entity ID will be automatically created as:
# input_select.amber_chart_time_span
#
# Via YAML (Alternative):
# Add this to your configuration.yaml:
#
# input_select:
# amber_chart_time_span:
# name: Amber Chart Time Span
# options:
# - "4 Hours"
# - "8 Hours"
# - "12 Hours"
# - "24 Hours"
# icon: mdi:clock-outline
#
# Then restart Home Assistant.
#
# STEP 3: Update the Card Configuration
# ----------------------------------------------
# Replace the sensor names in this file (search for "REPLACE_ME"):
# - sensor.REPLACE_ME_general_forecast → your actual general forecast sensor
# - sensor.REPLACE_ME_feed_in_forecast → your actual feed-in forecast sensor
#
# There are 8 occurrences total (2 per time span chart).
#
# STEP 4: Add to Your Dashboard
# ----------------------------------------------
# 1. Edit your dashboard
# 2. Click "+ ADD CARD"
# 3. Scroll down and click "Manual" (or three dots → Show Code Editor)
# 4. Copy and paste the YAML configuration below (starting from "type: vertical-stack")
# 5. Click SAVE
#
# ========================================
# CUSTOMIZATION OPTIONS
# ========================================
#
# Colors:
# - Buy Price: Change "#44739e" (blue) to your preferred hex color
# - FIT Price: Change "orange" to your preferred color name or hex code
#
# Time Spans:
# - Modify graph_span and offset values for each conditional card
# - Add or remove time span options by duplicating/removing conditional sections
# - Example: Add a "2 Hours" option by copying a section and changing to 2h
#
# Chart Title:
# - Change "Amber Electric Price Forecasts" to your preference
# - Located in the header section of each conditional card
#
# Tooltips:
# - Customize the tooltip text in the formatter sections
# - Change "Buy Price" or "FIT Price" labels
#
# Currency Display:
# - Currently shows c/kWh (cents per kilowatt-hour)
# - To show $/kWh instead: remove "* 100" from data_generator and change "c/kWh" to "$/kWh"
#
# ========================================
# TROUBLESHOOTING
# ========================================
#
# Issue: "Entity not found" at the top of the card
# Solution: The input_select helper hasn't been created or has a different entity ID.
# Follow STEP 2 above or check your helper's entity ID matches.
#
# Issue: No data on the chart / blank chart
# Solution: Check that your Amber sensor entity IDs are correct (STEP 1).
# Make sure the sensors have the "forecasts" attribute with data.
#
# Issue: Chart doesn't change when selecting different time spans
# Solution: Make sure the state values in the conditional sections match
# your helper options exactly (case-sensitive: "4 Hours" not "4 hours").
#
# Issue: "Custom element doesn't exist: apexcharts-card"
# Solution: Install ApexCharts Card via HACS and clear your browser cache.
#
# Issue: Dropdown selector shows but no chart appears
# Solution: The conditional states don't match. Check that your helper uses
# exactly "4 Hours", "8 Hours", "12 Hours", "24 Hours" (with capital H).
#
# Issue: Prices look wrong / multiplied by 100
# Solution: Your sensor might already provide data in c/kWh instead of $/kWh.
# Remove the "* 100" from the data_generator sections.
#
# ========================================
# DATA STRUCTURE NOTES
# ========================================
#
# This card expects Amber Electric sensors with the following structure:
#
# Attributes:
# forecasts:
# - start_time: "2025-10-30T14:00:00+11:00"
# per_kwh: 0.25 (for general price)
# spot_per_kwh: 0.08 (for feed-in price)
# - start_time: "2025-10-30T14:30:00+11:00"
# per_kwh: 0.28
# spot_per_kwh: 0.09
# ... etc
#
# ========================================
# CARD CONFIGURATION STARTS HERE
# ========================================
type: vertical-stack
cards:
# Dropdown selector for time span
- type: entities
entities:
- entity: input_select.amber_chart_time_span
name: Forecast Time Span
# 4 Hour Chart
- type: conditional
conditions:
- entity: input_select.amber_chart_time_span
state: "4 Hours"
card:
type: custom:apexcharts-card
graph_span: 4h
span:
offset: +4h
header:
show: true
title: Amber Electric Price Forecasts (4 Hours)
show_states: false
now:
show: false
label: Now
apex_config:
float_precision: 2
legend:
show: true
tooltip:
enabled: true
x:
format: dd MMM yyyy, HH:mm:00
"y":
formatter: |
EVAL:function(value, { series, seriesIndex, dataPointIndex, w }) {
let buyPrice = series[0][dataPointIndex] || 0
let fitPrice = series[1][dataPointIndex] || 0
if (seriesIndex === 0) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">Buy Price: ' + buyPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
} else if (seriesIndex === 1) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">FIT Price: ' + fitPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
}
}
title:
formatter: |
EVAL: function(seriesName) {
return ""
}
xaxis:
tooltip:
enabled: false
all_series_config:
stroke_width: 1.5
yaxis:
- id: first
decimals: 2
series:
# REPLACE THE SENSOR NAMES BELOW WITH YOUR OWN!
- entity: sensor.REPLACE_ME_general_forecast
type: line
color: "#44739e"
name: Buy Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.per_kwh || 0) * 100
]);
return result;
- entity: sensor.REPLACE_ME_feed_in_forecast
type: line
color: orange
name: FIT Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.spot_per_kwh || 0) * 100
]);
return result;
# 8 Hour Chart
- type: conditional
conditions:
- entity: input_select.amber_chart_time_span
state: "8 Hours"
card:
type: custom:apexcharts-card
graph_span: 8h
span:
offset: +8h
header:
show: true
title: Amber Electric Price Forecasts (8 Hours)
show_states: false
now:
show: false
label: Now
apex_config:
float_precision: 2
legend:
show: true
tooltip:
enabled: true
x:
format: dd MMM yyyy, HH:mm:00
"y":
formatter: |
EVAL:function(value, { series, seriesIndex, dataPointIndex, w }) {
let buyPrice = series[0][dataPointIndex] || 0
let fitPrice = series[1][dataPointIndex] || 0
if (seriesIndex === 0) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">Buy Price: ' + buyPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
} else if (seriesIndex === 1) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">FIT Price: ' + fitPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
}
}
title:
formatter: |
EVAL: function(seriesName) {
return ""
}
xaxis:
tooltip:
enabled: false
all_series_config:
stroke_width: 1.5
yaxis:
- id: first
decimals: 2
series:
# REPLACE THE SENSOR NAMES BELOW WITH YOUR OWN!
- entity: sensor.REPLACE_ME_general_forecast
type: line
color: "#44739e"
name: Buy Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.per_kwh || 0) * 100
]);
return result;
- entity: sensor.REPLACE_ME_feed_in_forecast
type: line
color: orange
name: FIT Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.spot_per_kwh || 0) * 100
]);
return result;
# 12 Hour Chart
- type: conditional
conditions:
- entity: input_select.amber_chart_time_span
state: "12 Hours"
card:
type: custom:apexcharts-card
graph_span: 12h
span:
offset: +12h
header:
show: true
title: Amber Electric Price Forecasts (12 Hours)
show_states: false
now:
show: false
label: Now
apex_config:
float_precision: 2
legend:
show: true
tooltip:
enabled: true
x:
format: dd MMM yyyy, HH:mm:00
"y":
formatter: |
EVAL:function(value, { series, seriesIndex, dataPointIndex, w }) {
let buyPrice = series[0][dataPointIndex] || 0
let fitPrice = series[1][dataPointIndex] || 0
if (seriesIndex === 0) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">Buy Price: ' + buyPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
} else if (seriesIndex === 1) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">FIT Price: ' + fitPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
}
}
title:
formatter: |
EVAL: function(seriesName) {
return ""
}
xaxis:
tooltip:
enabled: false
all_series_config:
stroke_width: 1.5
yaxis:
- id: first
decimals: 2
series:
# REPLACE THE SENSOR NAMES BELOW WITH YOUR OWN!
- entity: sensor.REPLACE_ME_general_forecast
type: line
color: "#44739e"
name: Buy Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.per_kwh || 0) * 100
]);
return result;
- entity: sensor.REPLACE_ME_feed_in_forecast
type: line
color: orange
name: FIT Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.spot_per_kwh || 0) * 100
]);
return result;
# 24 Hour Chart
- type: conditional
conditions:
- entity: input_select.amber_chart_time_span
state: "24 Hours"
card:
type: custom:apexcharts-card
graph_span: 24h
span:
offset: +24h
header:
show: true
title: Amber Electric Price Forecasts (24 Hours)
show_states: false
now:
show: false
label: Now
apex_config:
float_precision: 2
legend:
show: true
tooltip:
enabled: true
x:
format: dd MMM yyyy, HH:mm:00
"y":
formatter: |
EVAL:function(value, { series, seriesIndex, dataPointIndex, w }) {
let buyPrice = series[0][dataPointIndex] || 0
let fitPrice = series[1][dataPointIndex] || 0
if (seriesIndex === 0) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">Buy Price: ' + buyPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
} else if (seriesIndex === 1) {
return '<div class="custom-tooltip">' +
'<span style="font-weight: 400;">FIT Price: ' + fitPrice.toFixed(2) + '<b> c/kWh</b></span>' +
'</div>';
}
}
title:
formatter: |
EVAL: function(seriesName) {
return ""
}
xaxis:
tooltip:
enabled: false
all_series_config:
stroke_width: 1.5
yaxis:
- id: first
decimals: 2
series:
# REPLACE THE SENSOR NAMES BELOW WITH YOUR OWN!
- entity: sensor.REPLACE_ME_general_forecast
type: line
color: "#44739e"
name: Buy Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.per_kwh || 0) * 100
]);
return result;
- entity: sensor.REPLACE_ME_feed_in_forecast
type: line
color: orange
name: FIT Price c/kWh
float_precision: 2
show:
legend_value: false
data_generator: |
const forecasts = entity.attributes.forecasts;
const result = forecasts.map(e => [
new Date(e.start_time).getTime(),
parseFloat(e.spot_per_kwh || 0) * 100
]);
return result;
# ========================================
# END OF CONFIGURATION
# ========================================
#
# Created: October 2025
# By Bernard Mc Clement
# License: Feel free to use and modify for your own setup at your own risk
#
# Questions? Check the troubleshooting section above
# ========================================