Use native energy-date-selection card to control custom Apexcharts / Plotly graphs

Introduction
Since I set up my Homeassistant I faced a big problem: The native graph cards offer barely any customization options and I have very clear opinion on how my graphs must look, so Apexcharts card was one of the first additions I downloaded from HACS. Having a possibility to display different time periods and comparing data was another requirement. I found that the native energy-date-selection card provides the necessary controls but does’nt expose its state in a straight forward way, so I went for a different solution.
Recently I went back to this initial idea of using the energy-date-selection card and actually found a way to make it work. I want to share this way here since I think other might find it useful but be aware that making it fully work requires some skills because it needs a modified third-party frontend module.

Prerequisites
Like already said I am using the Apexcharts card from RomRider. I also got it to work with the Plotly graph card from dbuezas and can share this as well if requested. The functionality is mostly achieved using the config-template-card from iantrich but to get the plot to immediately react on date changes like I already said a modification is required. You can find this modification along with some further in the priv branch of my fork. I also use the lovelace-card-mod from thomasloven but this is optional as it just tweaks the looks a little bit.

Result
The core of this solution is its functionality, not its looks, but just as an example I want to share the main graph of my Overview dashboard which is controlled by the energy-date-selection card on top of it:

Configuration
This is the YAML code of the example plot:

- type: energy-date-selection
  collection_key: energy_electricity_overview
  card_mod:
    style: '.card-content { padding: 8px 8px 8px 16px; }'
- type: custom:config-template-card
  variables:
    AVAILABLE: '{{ hass.connection?._energy_electricity_overview !== undefined }}'
    STARTDATE: '{{ hass.connection?._energy_electricity_overview?.start }}'
    ENDDATE: '{{ hass.connection?._energy_electricity_overview?.end }}'
    NOW: '{{ new Date() }}'
    ENDDAY: '{{ new Date(vars["NOW"].getFullYear(), vars["NOW"].getMonth(), vars["NOW"].getDate(), 23, 59, 59) }}'
    TIMEZONE_OFFSET_STARTDATE: '{{ vars["AVAILABLE"] ? vars["STARTDATE"].getTimezoneOffset() * 60000 : 0 }}'
    TIMEZONE_OFFSET_ENDDATE: '{{ vars["AVAILABLE"] ? vars["ENDDATE"].getTimezoneOffset() * 60000 : 0 }}'
    TIMEZONE_OFFSET_ENDDAY: '{{ vars["ENDDAY"].getTimezoneOffset() * 60000 }}'
    OFFSET: '{{ vars["AVAILABLE"] ? Math.round((vars["ENDDATE"].getTime() - vars["TIMEZONE_OFFSET_ENDDATE"] - vars["ENDDAY"].getTime() + vars["TIMEZONE_OFFSET_ENDDAY"]) / 3600000) : 0 }}'
    OFFSET_STRING: '{{ ("+" + String(vars["OFFSET"]) + "h").replace("+-", "-") }}'
    SPAN: '{{ vars["AVAILABLE"] ? Math.round((vars["ENDDATE"].getTime() - vars["TIMEZONE_OFFSET_ENDDATE"] - vars["STARTDATE"].getTime() + vars["TIMEZONE_OFFSET_STARTDATE"]) / 3600000) : 24 }}'
    SPAN_STRING: '{{ vars["SPAN"] + "h" }}'
    PERIOD: '{{ vars["SPAN"] >= 2160 ? "day" : (vars["SPAN"] >= 672 ? "hour" : "5minute") }}'
    TYPE: '{{ vars["SPAN"] >= 672 ? "column" : "area" }}'
    BUILDENTITIESCONFIGAPEXCHARTS: |
      (entitiesbase, compare = "") => {
        var entities = [];
        if (compare)
          entities.push(...entitiesbase.map((entry) => (
            {...entry, offset: "-" + compare, opacity: 0.5, show: {...(entry?.show ?? {}), in_header: false, name_in_header: false, legend_value: false}}
          )));
        entities.push(...entitiesbase); return entities;
      }
    SERIES: |
      BUILDENTITIESCONFIGAPEXCHARTS([
        { entity: "sensor.production_power",  name: "Production" },
        { entity: "sensor.battery_power",     name: "Battery" },
        { entity: "sensor.consumption_power", name: "Consumption" },
        { entity: "sensor.self_use_power",    name: "Self-Use", show: { hidden_by_default: true } },
        { entity: "sensor.feed_in_power",     name: "Feed-In",  show: { hidden_by_default: true } },
        { entity: "sensor.purchase_power",    name: "Purchase", show: { hidden_by_default: true } },
      ], hass.connection?._energy_electricity_overview?.compare === "previous" ? vars["SPAN_STRING"] : "")
  entities:
    - _energy_electricity_overview
  card:
    type: custom:apexcharts-card
    update_interval: 1min
    experimental:
      hidden_by_default: true
    color_list: ["green", "blue", "red", "darkcyan", "orange", "purple"]
    all_series_config:
      extend_to: false
      stroke_width: 2
      type: ${TYPE}
      statistics:
        type: mean
        period: ${PERIOD}
    graph_span: ${SPAN_STRING}
    span:
      end: day
      offset: ${OFFSET_STRING}
    apex_config:
      chart:
        height: 602px
        toolbar:
          show: true
      title:
        text: Powers
        floating: true
        offsetX: 6
        offsetY: 5
        style:
          fontSize: 16px
          fontWeight: 500
          fontFamily: Roboto,Noto,sans-serif
          color: '#727272'
      legend:
        position: top
        offsetX: 100
        offsetY: 10
      fill:
        type: gradient
        gradient:
          type: vertical
          shadeIntensity: 0
          opacityFrom: 0.7
          opacityTo: 0.3
      yaxis:
        decimalsInFloat: 0
      tooltip:
        x:
          format: d. MMM yyyy HH:mm:ss
    series: ${SERIES}

Limitations
Like already said, a custom version of the config-template-card frontend module is required. It will work without it but it will not react on changes of the energy-date-selection card immediately. Unfortunately, I could’nt find a way to make it work without.
The compare functionality is also implemented but looks kinda bad with the series type area, so everywhere I actually use it I use the series type line instead.
If you have any questions / suggestions etc. please feel free to ask.

2 Likes

Just a tip: You can use vertical stack in card to make two cards seamless as if they’re one card.

Yeah, I use this on a different dashboard, but here I thought it looks better if the cards are separated. I’m actually not super convinced of vertical-stack-in-card because I think it falls behind its potential. What I usually want is a table layout with unequal column widths which I can achieve with a grid-layout card and custom card-mod CSS. A grid-layout-in-card card would unleash the full potentail of vertical-stack-in-card.

UIX Forge now has a grid spark which allows you to specify a grid layout for any container.