ApexCharts card - A highly customizable graph card

Your settings leads my graph to displaying incorrect results.

Here is the reference:

With settings listed by me in the previous post (taken from the linked article), it calculates values for periods correctly

My assumption is, that the SUM has to be calculated by statistics part. Then diff calculates difference between periods (duration).

Interesting. When I have time and some current rain data displayed in the graph, I will experiment a bit more. But I am pretty sure my rain graphs are displaying correctly.

I am also having issues getting my chart full width, I have also tried editing the number of columns with no change, would you be able to check my code please (also a relative newbie at all this)?

@higgy_de and @clairec707 By all means paste your code.

I just added a new chart in sections view to double check my instructions

  1. Ensure you add the chart in a new section
  2. Click the edit pencil top right when hovering over the section. From there select how many sections wide it should be.

  1. Add the following code to your Apex chart.
  • grid_options: adjusts width.
  • height: adjust height. Make sure if you place this under apex_config: as shown. ensure the same indentation as below.
grid_options:
  columns: 48
  rows: auto
apex_config:
  chart:
    height: 150px

Thanks I’ll check this in the morning.

1 Like

thats fixed it, many thanks :slight_smile:

1 Like

I am pleased to hear.

Hi there, first of all, thanks for good job … I was long for that kind of graph to show historical data on my mower on the “same graph”, superposing Data reported in both Percentage and “On / OFF” status :

what would be the best way (I assume this is possible) to show on top of the “Battery %” and “Signal dbm”, the “Error” (No Error or error present), “Charging” (Charging or Not Charging), and “Festive mode” (Festif or Not festif) on top of those % graphs ?
On top is it possible to show the label over time like “Online” or “Not Online” ?

P.S. on the card, I would like to keep this 3 levels On / OFF status bars on top of each other, is it possible - something like this :

Many thanks !!!

@higgy_de
If you are still interested.
A:
Just put this at the top of the yaml underneath the “type”:

grid_options:
  columns: full

B:
Instead of the text in the “Now” marker I put in the current price
first add a variable with your current price sensor (example is my sensor). at the top there are already some variables.

  v_price: states['sensor.dresden_aktueller_strompreis'].state

then in the “now” section put your variable into the label section, see example

 now:
    show: true
    color: "#ff0000"
    label: ${v_price}

at the end this should look like this:

Hope that helps…

Tried all, but nothing works to just disable the time popup and detail popup, but have the cursor move over to the data point light up working.
It is all or nothing.
with:

apex_config:
  tooltip:
    enabled: false

All:

Nothing:

Apex charts is dead, outdated and unreliable.
Use statistics graph chart card, which has a lot of functionality from apex charts, is way more reliable and the author of it is really, really, really on fire with this and get’s bugs fixed in less than a week (mostly) and features implemented in the same time.

Give it a go…
Apexcharts was dead and abandoned a long time ago by it’s developer and has lot’s of bugs, is unreliable and haven’t got new features in months.

Hello
I augment the apex charts with a template config card. Sometimes the chart stops refreshing.
While it seems that the problem disappears once I remove the template config card, I cannot be sure if there is no coincidence and the real issue is on apex chart card.

At the end, it’s the apex chart that raises an unhandled error. Though I reported it also in config template card thread.

Can you advise any way to workaround or a way of debugging to find out why it is happening?

apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) Error: Element not found
    at apexcharts-card.js?hacstag=331701152223:1:1466595
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1449766)
    at Gc._initialLoad (apexcharts-card.js?hacstag=331701152223:1023:2575)
apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) Error: Element not found
    at apexcharts-card.js?hacstag=331701152223:1:1466595
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1449766)
    at Gc._initialLoad (apexcharts-card.js?hacstag=331701152223:1023:2575)
apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) Error: Element not found
    at apexcharts-card.js?hacstag=331701152223:1:1466595
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1449766)
    at Gc._initialLoad (apexcharts-card.js?hacstag=331701152223:1023:2575)
apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) Error: Element not found
    at apexcharts-card.js?hacstag=331701152223:1:1466595
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1449766)
    at Gc._initialLoad (apexcharts-card.js?hacstag=331701152223:1023:2575)
apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'node')
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448588)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448357)
    at apexcharts-card.js?hacstag=331701152223:1:1473538
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1473374)
    at apexcharts-card.js?hacstag=331701152223:1:1423429
    at Array.forEach (<anonymous>)
    at apexcharts-card.js?hacstag=331701152223:1:1422441
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1422296)
apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'node')
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448588)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448357)
    at apexcharts-card.js?hacstag=331701152223:1:1473538
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1473374)
    at apexcharts-card.js?hacstag=331701152223:1:1423429
    at Array.forEach (<anonymous>)
    at apexcharts-card.js?hacstag=331701152223:1:1422441
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1422296)
apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'node')
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448588)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448357)
    at apexcharts-card.js?hacstag=331701152223:1:1473538
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1473374)
    at apexcharts-card.js?hacstag=331701152223:1:1423429
    at Array.forEach (<anonymous>)
    at apexcharts-card.js?hacstag=331701152223:1:1422441
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1422296)
apexcharts-card.js?hacstag=331701152223:1 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'node')
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448588)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1448357)
    at apexcharts-card.js?hacstag=331701152223:1:1473538
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1473374)
    at apexcharts-card.js?hacstag=331701152223:1:1423429
    at Array.forEach (<anonymous>)
    at apexcharts-card.js?hacstag=331701152223:1:1422441
    at new Promise (<anonymous>)
    at e.value (apexcharts-card.js?hacstag=331701152223:1:1422296)

type: custom:config-template-card
variables:
  startCharging: |
    (() => {
      const s = states['sensor.pv_ctrl_cheapest_hours']?.attributes?.data?.start;
      if (!s || s === 'unknown' || s === 'unavailable' || s === 'undefined') return new Date().setHours(0,0,0,0);
      return new Date(s).getTime();
    })()
  endCharging: |
    (() => {
      const s = states['sensor.pv_ctrl_cheapest_hours']?.attributes?.data?.end;
      if (!s || s === 'unknown' || s === 'unavailable' || s === 'undefined') return new Date().setHours(0,0,0,0);
      return new Date(s).getTime();
    })()
  startDischargingEvening: |
    (() => {
      const s = states['sensor.pv_ctrl_most_expensive_hours_evening']?.attributes?.data?.start;
      if (!s || s === 'unknown' || s === 'unavailable' || s === 'undefined') return new Date().setHours(0,0,0,0);
      return new Date(s).getTime();
    })()
  endDischargingEvening: |
    (() => {
      const s = states['sensor.pv_ctrl_most_expensive_hours_evening']?.attributes?.data?.end;
      if (!s || s === 'unknown' || s === 'unavailable' || s === 'undefined') return new Date().setHours(0,0,0,0);
      return new Date(s).getTime();
    })()
  startDischargingMorning: |
    (() => {
      const s = states['sensor.pv_ctrl_most_expensive_hours_morning']?.attributes?.data?.start;
      if (!s || s === 'unknown' || s === 'unavailable' || s === 'undefined') return new Date().setHours(0,0,0,0);
      return new Date(s).getTime();
    })()
  endDischargingMorning: |
    (() => {
      const s = states['sensor.pv_ctrl_most_expensive_hours_morning']?.attributes?.data?.end;
      if (!s || s === 'unknown' || s === 'unavailable' || s === 'undefined') return new Date().setHours(0,0,0,0);
      return new Date(s).getTime();
    })()
  min_export_price: |
    (() => { 
      const s =  states['input_number.pv_ctrl_min_export_price']?.state;
      if (!s || s === 'unknown' || s === 'unavailable' || s === 'undefined') return 0;
      return Number(s);
    })()  
entities:
  - sensor.pv_ctrl_cheapest_hours
  - sensor.pv_ctrl_most_expensive_hours_morning
  - sensor.pv_ctrl_most_expensive_hours_evening
  - input_number.pv_ctrl_min_export_price
card:
  type: custom:apexcharts-card
  update_interval: 1min
  header:
    show: true
    title: Electricity spot price
    show_states: true
    colorize_states: true
  graph_span: 48h
  span:
    start: day
  now:
    show: true
    label: Now
    color: "#448866"
  series:
    - entity: sensor.pv_ctrl_spot_electricity_prices
      name: Current spot price
      show:
        in_chart: false
        in_header: true
        name_in_header: true
    - entity: sensor.pv_ctrl_spot_electricity_prices
      name: Spot price
      type: line
      data_generator: |
        const src = hass.states['sensor.pv_ctrl_spot_electricity_prices'];
        if (!src || !src.attributes.data) return [];

        return src.attributes.data.map((item) => {
          return [
            new Date(item.time).getTime(),
            item.price
          ];
        });
      stroke_width: 1
      curve: stepline
      show:
        in_chart: true
        in_header: false
    - entity: sensor.sql_pv_earnings_today
      transform: return hass.states['sensor.sql_pv_earnings_today'].attributes.avoided;
      name: Avoided
      show:
        in_chart: false
        in_header: true
    - entity: sensor.sql_pv_earnings_today
      transform: return hass.states['sensor.sql_pv_earnings_today'].attributes.sold;
      name: Sold
      show:
        in_chart: false
        in_header: true
    - entity: sensor.sql_pv_earnings_today
      transform: return hass.states['sensor.sql_pv_earnings_today'].attributes.purchased;
      name: Purchased
      show:
        in_chart: false
        in_header: true
  apex_config:
    grid:
      borderColor: rgba(118,128,128, 0.2)
    xaxis:
      type: datetime
    annotations:
      xaxis:
        - x: EVAL:new Date().setHours(24,0,0,0)
          borderColor: "#888888"
          strokeDashArray: 1
          label:
            text: Tomorrow
            borderWidth: 0
            style:
              background: DimGrey
              color: white
              border: 0px
        - x: ${startDischargingMorning}
          x2: ${endDischargingMorning}
          fillColor: var(--purple-color)
          opacity: 0.2
        - x: ${startDischargingEvening}
          x2: ${endDischargingEvening}
          fillColor: var(--purple-color)
          opacity: 0.2
        - x: ${startCharging}
          x2: ${endCharging}
          fillColor: "#B3F7CA"
          opacity: 0.3
      yaxis:
        - "y": ${min_export_price}
          borderColor: "#00AA00"
          strokeDashArray: 4
          label:
            text: ${min_export_price + ' threshold'}
            borderWidth: 0
            style:
              background: DimGrey
              color: white

Has anyone built a template that replaces the data generator for apex charts?

In my example, I've got a 5 minute price forecast and I want to show it in blocks of 30 minutes over the whole day, so I do a data generator, which works fine. But it's slow.

I was thinking if I could template it, it would remove all the extra data fields I don't need, reduce the 5 min intervals to 30 and add in a "now" starting point, regardless of where we are in the first 30 minutes. Also it would be only ever force updated on the 5 minute change.

I may be able to figure it out the expression but I don't quite get where to start. Is it a template helper? If so there's no "type" that suits I don't think. Does apex need a certain type of sensor to work?

Thanks,
Nick

My implementation with an use of additional cards for more flexibility

For some reason header show incorrect sensor value.

The "now" line is in correct place. The "Today" value in header should be 0.04, but it is showing 0.01, which could possibly be value from one hour ahead.

If I remove data_generator it works correctly. Generated data is also correct.

Card code
type: custom:apexcharts-card
visibility:
  - condition: state
    entity: input_boolean.show_electricity_chart
    state: "on"
span:
  start: day
now:
  show: true
  color: var(--primary-text-color)
section_mode: true
grid_options:
  rows: 4
header:
  show: true
  show_states: true
  colorize_states: true
apex_config:
  legend:
    show: false
  xaxis:
    tooltip:
      enabled: false
    axisBorder:
      color: var(--disabled-color)
    axisTicks:
      color: var(--disabled-color)
    crosshairs:
      show: false
  yaxis:
    stepSize: 0.1
  grid:
    borderColor: var(--disabled-color)
  tooltip:
    x:
      format: HH:mm
  fill:
    type:
      - gradient
      - solid
    gradient:
      type: vertical
      opacityFrom: 0.7
      opacityTo: 0.2
      stops:
        - 0
        - 70
        - 100
series:
  - entity: sensor.nordpool
    name: Today
    float_precision: 2
    type: area
    curve: stepline
    stroke_width: 1
    color: var(--accent-color)
    data_generator: |
      return entity.attributes.raw_today.map((start, index) => {
         return [new Date(start["start"]).getTime() , entity.attributes.raw_today[index]["value"]];
       });
  - entity: sensor.nordpool_min_price
    name: Min
    float_precision: 2
    color: var(--primary-text-color)
    show:
      in_chart: false
  - entity: sensor.nordpool_mean_price
    name: Mean
    float_precision: 2
    color: var(--primary-text-color)
    show:
      in_chart: false
  - entity: sensor.nordpool_max_price
    name: Max
    float_precision: 2
    color: var(--primary-text-color)
    show:
      in_chart: false
  - entity: sensor.nordpool
    name: Tommorow
    curve: stepline
    float_precision: 2
    stroke_width: 1
    color: var(--primary-color)
    offset: +1d
    show:
      offset_in_name: false
      in_header: false
    data_generator: |
      return entity.attributes.raw_tomorrow.map((start, index) => {
         return [new Date(start["start"]).getTime() , entity.attributes.raw_tomorrow[index]["value"]];
       });

I could technically resolve this, by hiding the generated value from header and adding new entity without data generation shown just in the header.

The header shows the most recently rendered value for this axis, even if it’s not the current one.

To fix this, add the entity as a separate axis used only for displaying the value in the header (disable it in the graph, legend, and tooltip). Also, make sure the generated series is hidden from the header.

3 Likes

I'm new to using the Apexcharts cards (and JS) and loving them so far. However, I've been struggling with getting the datagenerator working correctly for weather forecast data for OpenWeatherMaps.

I've been trying to follow the examples from others on the forums (e.g.: Apexcharts and Openweathermap Forecast examples, Filter a response from openweathermap.get_minute_forecast based on timestamps), but I'm stuck with the card just showing "Loading..."

This is the code that I am using to generate my chart

type: custom:apexcharts-card
graph_span: 1h
span:
  start: minute
now:
  show: true
  label: now
series:
  - entity: sensor.openweathermap_minutebyminute_forecast
    type: column
    color: "#4275b8"
    data_generator: |
      return entity.attributes.forecast_data.map((entry) => {
        return [new Date(entry.datetime).getTime(), parseFloat(entry.precipitation)];
      });

I have this template entity to gather the minute-by-minute forecast from OpenWeatherMaps when there is rain forecasted in the next two hours.

- trigger:
    - platform: time_pattern
      minutes: "/2"
  condition:
    - condition: numeric_state
      entity_id: sensor.precipitation_probability_in_next_two_hours
      above: 0.20 #Note: I have not been able to find docs whether this should be fractional or %
  action:
    - action: openweathermap.get_minute_forecast
      target:
        entity_id: weather.openweathermap
      response_variable: next_hour_forecast
  sensor:
    - name: "OpenWeatherMap MinuteByMinute Forecast"
      unique_id: openweathermap_minute_forecast_data_sensor
      state: "{{ next_hour_forecast['weather.openweathermap']['forecast'][0]['precipitation'] }}"
      unit_of_measurement: mm
      attributes:
        forecast_data: "{{ next_hour_forecast['weather.openweathermap']['forecast'] }}"

This entity seems to be working roughly as intended, and has the following states (note at time of writing all 0 precipitation, but I've tested with the developed tools writing non-zero values with no effect)

forecast_data: >-
  [{'datetime': datetime.datetime(2026, 6, 7, 12, 43,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 44, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 45,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 46, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 47,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 48, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 49,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 50, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 51,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 52, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 53,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 54, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 55,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 56, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 57,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 12, 58, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 12, 59,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 0, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 1,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 2, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 3,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 4, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 5,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 6, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 7,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 8, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 9,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 10, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 11,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 12, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 13,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 14, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 15,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 16, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 17,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 18, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 19,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 20, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 21,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 22, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 23,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 24, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 25,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 26, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 27,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 28, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 29,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 30, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 31,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 32, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 33,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 34, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 35,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 36, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 37,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 38, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 39,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 40, tzinfo=datetime.timezone.utc),
  'precipitation': 0}, {'datetime': datetime.datetime(2026, 6, 7, 13, 41,
  tzinfo=datetime.timezone.utc), 'precipitation': 0}, {'datetime':
  datetime.datetime(2026, 6, 7, 13, 42, tzinfo=datetime.timezone.utc),
  'precipitation': 0}]
unit_of_measurement: mm
friendly_name: OpenWeatherMap MinuteByMinute Forecast

I've tried searching further through the Apexcards documentation to no avail, and it seems like the most likely issue is potentially with the entity itself (or how I'm trying to parse it with JS). Gemini's suggestion was that potentially there's an issue with how JS parses the datetime objects, but manually setting that to strings with the developer tool did not rectify the issue. Any help is greatly appreciated.

Posting for posterity, but this was an issue with the sensor itself outputting a datetime object, not a string. I fixed this by adjusting my sensor entity attributes as shown below:

- trigger:
    - platform: time_pattern
      minutes: "/2"
  condition:
    - condition: numeric_state
      entity_id: sensor.precipitation_probability_in_next_two_hours
      above: 0.20
  action:
    - action: openweathermap.get_minute_forecast
      target:
        entity_id: weather.openweathermap
      response_variable: next_hour_forecast
  sensor:
    - name: "OpenWeatherMap MinuteByMinute Forecast"
      unique_id: openweathermap_minute_forecast_data_sensor
      state: "{{ next_hour_forecast['weather.openweathermap']['forecast'][0]['precipitation'] }}"
      unit_of_measurement: mm
      attributes: #changed from first post (and the actual fix)
        forecast_precip: "{{ next_hour_forecast['weather.openweathermap']['forecast'] | map(attribute='precipitation') | list }}"
        forecast_times: "{{ next_hour_forecast['weather.openweathermap']['forecast'] | map(attribute='datetime') | map('string') | list }}"

My card was then straightforward loop through these two attributes:

type: custom:apexcharts-card
graph_span: 1h
span:
  start: minute
now:
  show: true
  label: now
series:
  - entity: sensor.openweathermap_minutebyminute_forecast
    type: column
    color: "#4275b8"
    data_generator: |
      const times = entity.attributes.forecast_times;
      const precip = entity.attributes.forecast_precip;

      if (!times || !precip || times.length !== precip.length){
        return [];
      }

      return times.map((timeString, index) => {
        const timeMs = new Date(timeString).getTime();
        const value = precip[index];
        return [timeMs, value];
      });
1 Like

Thanks and here is the link people

1 Like

I have a challenge, which I simply do not get how to solve...

I have a energy sensor, which has two lists of date/times in it self, looks like this for example:

list: 
- start: '2026-06-14T07:15:00+02:00'
  end: '2026-06-14T14:45:00+02:00'
- start: '2026-06-14T15:00:00+02:00'
  end: '2026-06-14T15:30:00+02:00'

active_number_of_slots: 6
failsafe: 
start: '22:00:00'
end: '23:30:00'

expiration: 2026-06-15T00:00:00+02:00
updated_at: 2026-06-13T20:49:02.961480+02:00
fetch_date: 2026-06-14
name: Cheapest Hours
type: CheapestHoursBinarySensor
calendar: false
archived: 
max_price: 0
min_price: -8.77
mean_price: -2.6446875
next: 
list:
  - start: '2026-06-15T04:00:00+02:00'
    end: '2026-06-15T04:15:00+02:00'
  - start: '2026-06-15T05:00:00+02:00'
    end: '2026-06-15T05:15:00+02:00'
  - start: '2026-06-15T16:00:00+02:00'
    end: '2026-06-15T16:45:00+02:00'
  - start: '2026-06-15T17:00:00+02:00'
    end: '2026-06-15T17:15:00+02:00'
expiration: '2026-06-16T00:00:00+02:00'
extra:
  mean_price: 166.88833333333335
  max_price: 221.8
  min_price: 91.88

first_hour: 0
last_hour: 23
starting_today: false
number_of_slots: 6
failsafe_starting_hour: 22
is_sequential: false
failsafe_active: false
inversed: false
unique_id: cheapest_hours
icon: mdi:clock
friendly_name: Cheapest Hours

Now, in my Apex Card data_generation of this sensor I only get the first list - and not the second part. The second part is tomorrow, and it well should look like this:

However, what I get is this:

And here is the code I am trying to use:

type: custom:apexcharts-card
experimental:
  color_threshold: true
apex_config:
  legend:
    show: false
  xaxis:
    labels:
      datetimeFormatter:
        hour: HH
  tooltip:
    fixed:
      enabled: true
      position: topLeft
graph_span: 2d
show:
  last_updated: true
header:
  title: Elkostnad och nyttjande
  show: true
  show_states: true
  colorize_states: true
span:
  start: day
now:
  show: true
series:
  - entity: binary_sensor.test_billigaste_tid
    name: Cheapest
    type: area
    curve: stepline
    yaxis_id: kWh
    opacity: 0.6
    stroke_width: 0
    color: lightgreen
    show:
      extremas: false
      in_header: false
    data_generator: |
      let data = [];
      let periods = entity.attributes.list || [];
      periods.forEach((p) => {
        let s = new Date(p.start).getTime();
        let e = new Date(p.end).getTime();
        data.push([s, 1]);    // jump up at start
        data.push([e, 1]);    // stay high until end
        data.push([e, 0]);    // drop straight down
      });
      return data;
  - entity: binary_sensor.cheapest_hours
    name: Cheapest
    type: area
    curve: stepline
    yaxis_id: kWh
    opacity: 0.9
    stroke_width: 0
    color: lightgray
    show:
      extremas: false
      in_header: false
    data_generator: |
      let data = [];
      let periods = entity.attributes.list || [];
      periods.forEach((p) => {
        let s = new Date(p.start).getTime();
        let e = new Date(p.end).getTime();
        data.push([s, 1]);    // jump up at start
        data.push([e, 1]);    // stay high until end
        data.push([e, 0]);    // drop straight down
      });
      return data;
  - entity: sensor.electricity_prices_today
    yaxis_id: SEK
    type: line
    show:
      extremas: false
      in_header: false
    float_precision: 3
    stroke_width: 3
    extend_to: false
    color: green
    color_threshold:
      - value: 1.5
        color: blue
      - value: 2
        color: green
      - value: 2.5
        color: yellow
      - value: 3
        color: orange
      - value: 3.5
        color: red
      - value: 4
        color: pink
      - value: 5
        color: "#ffffff"
    data_generator: |
      const data = entity.attributes.data.map((entry) => {
        // Center each 15-minute period correctly
        const start = new Date(entry.start).getTime();
        const end = new Date(entry.end).getTime();
        const midpoint = start + (end - start) / 2;
        return [midpoint, entry.value];
      });
      return data;
  - entity: sensor.electricity_prices_tomorrow
    yaxis_id: SEK
    type: line
    show:
      extremas: false
      in_header: false
    float_precision: 3
    stroke_width: 3
    extend_to: false
    color: green
    color_threshold:
      - value: 1.5
        color: blue
      - value: 2
        color: green
      - value: 2.5
        color: yellow
      - value: 3
        color: orange
      - value: 3.5
        color: red
      - value: 4
        color: pink
      - value: 5
        color: "#ffffff"
    data_generator: |
      const data = entity.attributes.data.map((entry) => {
        // Center each 15-minute period correctly
        const start = new Date(entry.start).getTime();
        const end = new Date(entry.end).getTime();
        const midpoint = start + (end - start) / 2;
        return [midpoint, entry.value];
      });
      return data;    
  - entity: sensor.shellypro3em_ece334eddd28_total_active_power
    yaxis_id: kWh
    name: Power Usage Chart
    color: orange
    opacity: 0.8
    float_precision: 2
    show:
      extremas: false
      in_header: true
    type: line
    curve: stepline
    stroke_width: 1
    extend_to: false
    unit: kW
    transform: return x /1000;
    group_by:
      func: avg
      duration: 15m
  - entity: sensor.electricity_prices_today
    name: Current Price
    yaxis_id: SEK
    float_precision: 3
    show:
      in_header: true
      in_chart: false
    unit: Kr/kWh
    color: green
yaxis:
  - id: SEK
    min: 0
    max: ~6
    opposite: true
    apex_config:
      tickAmount: 6
      forceNiceScale: true
      title:
        text: SEK
  - id: kWh
    min: 0
    max: ~4
    apex_config:
      tickAmount: 6
      forceNiceScale: true
      title:
        text: kWh

So what I am after is how to do a data_generator that can handle the two list parts in the first sensor. The way I solved it in the how it should look, is by using a 2nd sensor - however that will only work today - tomorrow I am back at only one list since the 2nd sensor only has the last list part in it self. And I can not understand how to loop over two lists in this data_generator...?