Visualising Amber Electric Forecast Data

I am an Amber Electric customer in Australia. Amber delivers buy and sell price forecasts via 2 sensors in the integration. Each sensor has many attributes in the following format.


state_class: measurement
forecasts:
  - duration: 30
    date: "2025-05-10"
    nem_date: "2025-05-10T12:30:00+10:00"
    per_kwh: -0.02
    spot_per_kwh: -0.01
    start_time: "2025-05-10T02:00:01+00:00"
    end_time: "2025-05-10T02:30:00+00:00"
    renewables: 71
    spike_status: none
    descriptor: extremely_low
  - duration: 30
    date: "2025-05-10"
    nem_date: "2025-05-10T13:00:00+10:00"
    per_kwh: -0.02
    spot_per_kwh: -0.01
    start_time: "2025-05-10T02:30:01+00:00"
    end_time: "2025-05-10T03:00:00+00:00"
    renewables: 70
    spike_status: none
    descriptor: extremely_low

The list of forecasts has 40 entries, being the 40 x 30 min forecasts for the next 20 hours.

I have successfully visualised these in a list on a dashboard, like this

12:30, 0.06
13:00, 0.05
13:30, 0.05
14:00, 0.07
14:30, 0.07
15:00, 0.08
…

I would like to visualise it as a chart (line or bar). I’m still pretty new to all this and my Python and HA skill is still in its infancy. I’ve read that I can’t visualise this in a chart unless I get the data into an entity or maybe the recorder db, or maybe influxDB. I’m happy to do the hard yards, but would appreciate any advice on the best way forward. Ideally I would be able to compare forecasts over time, but that is nice to have.

1 Like

You could probably graph it with an apexcharts data generator. See here for an example: REST API command/platform fails on POST to external URL (solcast) - #121 by tjafbe

1 Like

Thanks for your advice. Using the approach suggested I was able to visualise the data in an Apex chart as follows.

For the benefit of others, here is my code. If someone knows how I can eliminate the 3 hours of unused space on the left, I would appreciate a suggestion.


type: custom:apexcharts-card
view_layout:
  grid-column: span 4
graph_span: 24h
span:
  start: day
  offset:  10h
header:
  show: true
  title: Price Forecasts
  show_states: false
now:
  show: true
  label: Now
apex_config:
  legend:
    show: true
  tooltip:
    enabled: false
yaxis:
  - id: first
    decimals: 2
series:
  - entity: sensor.my_feed_in_forecast
    type: line
    name: FIT Forecast
    unit: $/kWh
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const offsetMs = 60 * 60;
      const result = forecasts.map(e => [
        new Date(new Date(e.start_time).getTime()   offsetMs),
        parseFloat(e.per_kwh || 0)
      ]);
      console.log("Adjusted forecast:", result);
      return result;
  - entity: sensor.my_general_forecast
    type: line
    name: Buy Price Forecast
    unit: $/kWh
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const offsetMs = 60 * 60; 
      const result = forecasts.map(e => [
        new Date(new Date(e.start_time).getTime()   offsetMs),
        parseFloat(e.per_kwh || 0)
      ]);
      console.log("Adjusted forecast:", result);
      return result;


1 Like

Here is an update for anyone wanting to do this.

The only thing I want to do that i haven’t succeeded with so far is to remove the current values from the legend (or format them 2 decimals would also be fine)


type: custom:apexcharts-card
graph_span: 24h
span:
  offset:  24h
header:
  show: true
  title: Price Forecasts
  show_states: false
now:
  show: true
  label: Now
apex_config:
  legend:
    show: true
  tooltip:
    "y":
      enabled: true
      formatter: function (val) { return val.toFixed(2); }
yaxis:
  - id: first
    decimals: 2
series:
  - entity: sensor.short_street_general_forecast
    type: line
    color: red
    name: Buy Price Forecast
    unit: $/kWh
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const result = forecasts.map(e => [
        new Date(e.start_time).getTime(),
        parseFloat(e.per_kwh || 0)
      ]);
      return result;
  - entity: sensor.short_street_feed_in_forecast
    type: line
    name: FIT Forecast
    unit: $/kWh
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const result = forecasts.map(e => [
        new Date(e.start_time).getTime(),
        parseFloat(e.per_kwh || 0)
      ]);
      return result;

https://github.com/RomRider/apexcharts-card?tab=readme-ov-file#series-show-options

series:
  - entity: sensor.short_street_general_forecast
    type: line
    ...
    show:
      legend_value: false

Thanks a lot for sharing the code. I modified it to show 2 decimal places on the tooltip

graph_span: 12h
span:
  offset: +12h
apex_config:
  float_precision: 2
  legend:
    show: false
  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> $/kWh</b></span>' +
          '</div>';
          } else if (seriesIndex === 1) {
          return '<div class="custom-tooltip">' +
          '<span style="font-weight: 400;">FIT Price: ' + fitPrice.toFixed(2) + '<b> $/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:
  - entity: sensor.general_forecast
    type: line
    color: "#44739e"
    name: Buy Price
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const result = forecasts.map(e => [
        new Date(e.start_time).getTime(),
        parseFloat(e.per_kwh || 0)
      ]);
      return result;
  - entity: sensor.general_forecast
    type: line
    color: orange
    name: FIT Price
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const result = forecasts.map(e => [
        new Date(e.start_time).getTime(),
        parseFloat(e.spot_per_kwh || 0)
      ]);
      return result;
2 Likes

Thanks all for this thread. It solved my desire to graph the Amber Price Forecasts.
A few improvements - removing the values from the legend, that seem to be spurious.
Also since 5 minute price forecasting is now active for the next 2 hours, the forecasts array length is now variable and this does some odd things with the graph span and offset. I just set it all to 4h which gives a reasonable graph. The right-hand tail moves around a bit depending on where in the first hour you are.

type: custom:apexcharts-card
graph_span: 4h
span:
  offset: +4h
header:
  show: true
  title: Amber Electric Price Forecasts
  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> $/kWh</b></span>' +
          '</div>';
          } else if (seriesIndex === 1) {
          return '<div class="custom-tooltip">' +
          '<span style="font-weight: 400;">FIT Price: ' + fitPrice.toFixed(2) + '<b> $/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:
  - entity: sensor.your_general_forecast
    type: line
    color: "#44739e"
    name: Buy Price $/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)
      ]);
      return result;
  - entity: sensor.your_fit_forecast
    type: line
    color: orange
    name: FIT Price $/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)
      ]);
      return result;
2 Likes

Thanks for this, looks great!

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.

HA Amber price graphs

# ========================================
# 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
# ========================================

Thanks everyone in this thread for putting the pieces together.
One question I have is why people are using spot_per_kwh for FiT forecasts? My understanding was that per_kwh is more accurate as it includes other costs involved. Please correct me if I’m wrong!

I also wanted to add the price history to the chart and make some design tweaks to match my personal preferences and setup. Sharing the code here if anyone is interested. The only problem is that the tooltip no longer shows shared values, which I believe is because of the irregular timeseries involved. Potential solutions which I pursued but couldn’t get working: this and this.

type: custom:apexcharts-card
header:
  title: Price history & forecast
  standard_format: true
graph_span: 2d
span:
  offset: +1d
now:
  show: true
  label: now
apex_config:
  float_precision: 2
  legend:
    show: true
    position: top
    floating: true
    customLegendItems:
      - Import price
      - Export price
  tooltip:
    enabled: true
    x:
      format: h:mmtt dddd
    "y":
      formatter: |
        EVAL:function(value, { series, seriesIndex, dataPointIndex, w }) {
            return '<div class="custom-tooltip">' +
            '<span style="font-weight: 400;">' + w.config.series[seriesIndex].name + ': $' +(series[seriesIndex][dataPointIndex] || 0).toFixed(2) + ' per kWh</b></span>' +
            '</div>';
          }
      title:
        formatter: |
          EVAL: function(seriesName) {
            return ""
            }
  xaxis:
    labels:
      format: htt
    tooltip:
      enabled: false
all_series_config:
  stroke_width: 1.5
yaxis:
  - id: first
    align_to: 0.1
    apex_config:
      labels:
        formatter: |
          EVAL:function(value) {
            return "$" + value.toFixed(2);
          }
series:
  - entity: sensor.electricity_general_price
    name: Import price
    type: line
    color: "#44739e"
    extend_to: now
    float_precision: 2
  - entity: sensor.electricity_feed_in_price
    name: Export price
    type: line
    color: orange
    extend_to: now
    float_precision: 2
  - entity: sensor.electricity_general_forecast
    name: Forecast import price
    type: line
    color: "#44739e"
    opacity: 0.67
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const result = forecasts.map(e => [
        new Date(e.start_time).getTime(),
        parseFloat(e.per_kwh || 0)
      ]);
      return result;
  - entity: sensor.electricity_feed_in_forecast
    name: Forecast export price
    type: line
    color: orange
    opacity: 0.67
    data_generator: |
      const forecasts = entity.attributes.forecasts;
      const result = forecasts.map(e => [
        new Date(e.start_time).getTime(),
        parseFloat(e.per_kwh || 0)
      ]);
      return result;