ApexCharts card - A highly customizable graph card

You can. This is my (modified code (added fix to 2 decimal places, replaced the dot with a comma and added a € sign)). Plus points, gives a total. Negative points, replaces individual series values by default. I will try during the week to show both if I have the time. Note;- the code below is indented for using the custom:config-template-card add on. If not using, remove indentation by 2 spaces.

  apex_config:
    tooltip:
      enabled: true
      shared: false
      theme: light
      style:
        fontSize: 14px
      onDatasetHover:
        highlightDataSeries: false
      'y':
        formatter: |
          EVAL:function(value, { series, seriesIndex, dataPointIndex, w }) {
            let currentTotal = 0;
            series.forEach((s) => {
              currentTotal += s[dataPointIndex];

            })
            return '<div class="custom-tooltip">'+
              '<span><b>Total: €</b>' + currentTotal.toFixed(2).replace(".", ",") + '</span>' +
              '</div>'
            }
        title:
          formatter: |
            EVAL:function(value){
              value = ''; 
              return value;
              }
      x:
        show: true
        format: ddd dd MMM yyyy
      marker:
        show: false
      fixed:
        enabled: true
        position: topRight
        offsetX: -10
        offsetY: 5

Here is how I created x-axis annotations for sunrise, midday, sunset.

type: custom:config-template-card
entities:
  - sensor.sunset
  - sensor.solar_noon
  - sensor.sunrise
  - sensor.myenergi_the_willows_power_generation
card:
  type: custom:apexcharts-card
  config_templates: default
  header:
    title: Solar generation today
  span:
    start: day
  graph_span: 24h
  update_interval: 10mins
  all_series_config:
    type: area
    group_by:
      func: avg
      duration: 10mins
  color_list:
    - yellow
    - green
  series:
    - entity: sensor.myenergi_the_willows_power_generation
      name: Solar
    - entity: sensor.myenergi_the_willows_power_generation
      name: Solar last on house
      offset: '-24h'
      type: line
      opacity: 0.3
      stroke_width: 1
      show:
        in_header: false
  apex_config:
    yaxis:
      min: 0
      forceNiceScale: true
      decimalsInFloat: false
    annotations:
      xaxis:
        - x: ${new Date(states['sensor.sunrise'].state).getTime()}
          label:
            text: Sunrise ☉
            borderWidth: 0
            style:
              background: '#0000'
        - x: ${new Date(states['sensor.solar_noon'].state).getTime()}
          label:
            text: ☼
            borderWidth: 0
            style:
              background: '#0000'
        - x: ${new Date(states['sensor.sunset'].state).getTime()}
          label:
            text: Sunset ☾
            borderWidth: 0
            style:
              background: '#0000'
    chart:
      height: 150

6 Likes

That’s really cool, tahks for sharing. I guess I just have to get going with config-template-card then :slight_smile:

Updated javascript code showing series plus total. You have to enter your series names into an array as they are not passed over in the function call.

          EVAL:function(value, { series, seriesIndex, dataPointIndex, w }) {
            const array_list = ['Gas: €','Stroom: €']
            let currentTotal = 0;
            let detailTotal = '';
            let x = 0 * 1;
            series.forEach((s) => {
              currentTotal += s[dataPointIndex];
              detailTotal = detailTotal + array_list[x] + s[dataPointIndex].toFixed(2).replace(".", ",") + '<br>';
              x++;
            })
            return '<div class="custom-tooltip">'+
              detailTotal +
              '<span><b>Total: €</b>' + currentTotal.toFixed(2).replace(".", ",") + '</span>' +
              '</div>'              
            }

2 Likes

Yeah, at least using card_mod, it’s possible to change the font size of the header. Obviously, I don’t know what I am doing, I only did try copy the way they did in card_mod forum :slight_smile: Unfortunately, the change below would affect all text elements in the header, proportionally. And the “xaxis” somehow affected. At least I achieved the goal, to have a bit smaller texts so they render nicely on my phone!

Without card_mod style, the header font is bigger and the xaxis

image

1 Like

I have experienced similar “missing” data for some graphs. Setting cache: false solves it (probably at some performance expense that hasn’t been noticeable).

1 Like

Is it possible to create a history monthtly chart from a csv file or text instead of using a home assistant entity?

did you manage to find a way to get it working?

No, unfortunately not.

Akira & Lunkobelix

It can be done, but not with the HA implementation of ApexCharts. You would need to have a good working knowledge of HTML and Javascript and know about locahost, plus using Google to search for example code. There are also examples in the ApexCharts documentation.
Once you have written your code to access your data, say by a Text file, Excel or fixed within the ApexCharts, you can access your locahost enviroment by using the HA Webpage card.
Not only that, you have the best of two worlds, direct access by localhost and within HA.
Job done !!

1 Like

Is there a way to combine/calculate different sensors into a single serie value?

Use case: m3 gas consumption per daily degree day.

Situation 1:
If the user already has a daily degree-day sensor and the gas consumption is known. Both can be pulled from long-term data.
The data generator would in fact do the following:

  • Pull daily degree day per day from long term stats.
  • Pull gas consumption per day from long term stats.
  • Divide the gas consumption with the daily degree day to get the daily m3/DD value.

Situation 2:
In case someone doesn’t even have a daily degree day value but does have temperature stats it should be the following:

  • Pull outdoor temperature per day from long term stats.
  • Pull indoor (target) temperature per day from long term stats.
  • Subtract outdoor temperature from indoor temperature with a minimum of 0 to create the daily degree day value.
  • Pull gas consumption per day from long term stats.
  • Divide the gas consumption with the daily degree day value to get the daily m3/DD value.

I know of course that I can create template sensors and work it out like this but there are two downsides from this:

  1. You cannot get data from the past.
  2. It puts a lot more data into the long term stats tables which I feel is not needed.

Hope this is possible and someone could help me with this.

Thanks, love this plugin!

Ok, total noob here and could use some guidance. I’m trying to display values sent over MQTT, serialized with JSON. I followed a few examples above but am clearly doing something wrong.

Sample JSON message:

{
  "msg_id": 71168,
  "manual_control": "False",
  "dt_level_sensor": "Wet",
  "qt_level_sensor": "Wet",
  "dt_water_level": "22.0",
  "qt_water_level": "16.8",
  "dt_solenoid": "Closed",
  "qt_solenoid": "Closed"
}

And I’m receiving that as a sensor in Home Assistant as:

  - platform: mqtt
    name: reef_controller_ato
    state_topic: "reef/controller/ato"
    value_template: '{{ value_json }}'
    json_attributes_topic: reef/controller/ato

I know this portion is working correctly, but displaying a single sensor attribute in the ApexChart just isn’t working (several attempts have even caused Home Assistant to hang/crash). The goal will be to overlay water_level values (discrete #) with level_sensor inputs (toggles between ‘wet’ and ‘dry’) but I’d settle for just displaying the water level to start. Any guidance would be most appreciated!

Can someone help with rounding values in the radialBar display value?

The 2 graphs below show battery (delivered already in %) and signal (dBi) I have created a range (Min: -130, Max: -40) As you can however see, when the values come through, this is not rounded, ideally to no decimal places.

image

This is the card yaml

      - cards:
          - type: custom:apexcharts-card
            chart_type: radialBar
            experimental:
              color_threshold: true
            apex_config:
              legend:
                show: false
              chart:
                height: 250px
              plotOptions:
                radialBar:
                  startAngle: -90
                  endAngle: 90
                  dataLabels:
                    name:
                      show: true
                      offsetY: 35
                    value:
                      show: true
                      offsetY: -25
                    total:
                      show: true
                      label: Battery
                      formatter: |
                        EVAL:(w) => {
                          return w.globals.seriesTotals + '%';
                        }
                  hollow:
                    size: 45%
                    imageWidth: 70
                    imageHeight: 70
                    imageOffsetY: -40
                    imageClipped: false
                  track:
                    show: true
                    strokeWidth: 175%
                    dropShadow:
                      enabled: true
                      top: 2
                      left: 0
                      blur: 4
                      opacity: 0.15
              stroke:
                dashArray: 5
                lineCap: butt
            series:
              - entity: sensor.lorawan_school_meds_battery_percentage
                show:
                  header_color_threshold: true
                color_threshold:
                  - color: '#B20000'
                    value: 10
                  - color: '#FF9912'
                    value: 15
                  - color: '#FFFF00'
                    value: 25
                  - color: '#98FB98'
                    value: 60
                  - color: '#008C23'
                    value: 100
          - type: custom:apexcharts-card
            chart_type: radialBar
            experimental:
              color_threshold: true
            apex_config:
              legend:
                show: false
              chart:
                height: 250px
              plotOptions:
                radialBar:
                  startAngle: -90
                  endAngle: 90
                  dataLabels:
                    name:
                      show: true
                      offsetY: 35
                    value:
                      show: true
                      offsetY: -25
                    total:
                      show: true
                      label: Signal
                      formatter: |
                        EVAL:(w) => {
                          return w.globals.seriesTotals + '%';
                        }
                  hollow:
                    size: 45%
                    imageWidth: 70
                    imageHeight: 70
                    imageOffsetY: -40
                    imageClipped: false
                  track:
                    show: true
                    strokeWidth: 175%
                    dropShadow:
                      enabled: true
                      top: 2
                      left: 0
                      blur: 4
                      opacity: 0.15
              stroke:
                dashArray: 5
                lineCap: butt
            series:
              - entity: sensor.lorawan_school_meds_signal
                max: -40
                min: -130
                show:
                  header_color_threshold: true
                color_threshold:
                  - color: '#B20000'
                    value: -150
                  - color: '#FFFF00'
                    value: -120
                  - color: '#008C23'
                    value: -100
        type: grid
        columns: 2
        square: false

Can anyone help steer me in the right direction?

Many thanks

are the additional values delivered over MQTT

“manual_control”: “False”,
“dt_level_sensor”: “Wet”,
“qt_level_sensor”: “Wet”,
“dt_water_level”: “22.0”,
“qt_water_level”: “16.8”,
“dt_solenoid”: “Closed”,
“qt_solenoid”: “Closed”

sent as attributes in the sensor.reef_controller_ato or how are these displayed in Home Asstant (assuming that this is a MQTT sensor as opposed to binary_sensor?)

If you are purely looking for the wet/dry sensor, you could create an MQTT binary_sensor out of just those 2 attributes?

something like this (in your mqtt.yaml file):

binary_sensor:
  - state_topic: "reef/controller/ato"
    name: "reef_controller_ato_dt_level_sensor_state"
    value_template: '{{ value_json["object"]["dt_level_sensor"] | int }}'
    payload_on: "Wet"
    payload_off: "Dry"
    device_class: "moisture"
    unique_id: reef_controller_ato_dt_level_sensor_state
1 Like

actually solved this by simply changing min/max to

                max: -40
                min: -140

turn

return w.globals.seriesTotals + '%';

to

return ~~w.globals.seriesTotals + '%';
2 Likes

Correct, they are attributes in the sensor.reef_controller_ato. Good idea to break them all out into their own sensors as you proposed. It would be nice if I could just grab the attribute and compute from there, but whatever works in the end!

you can possibly do this in the sensor definition in apex cards? something like

value_template: "{{state_attr('sensor.reef_controller_ato', 'dt_level_sensor')}}"

this is also how you would configure each of the attributes as an individual sensor if you were configuring the sensor.yaml as opposed to the mqtt.yaml

so it would be like this then (in sensors.yaml)

- platform: template
  sensors:
   dt_level_sensor:
      value_template: "{{state_attr('sensor.reef_controller_ato', 'dt_level_sensor')}}"
      friendly_name: "dt_level_sensor"

so as you can see, there are loads of different paths to achieve the same outcome.

You should however just pick one and standardise on that for maintenance purposes moving forward (in case you need to change something du to breaking changes)

personally, if the data point is important enough, i create a dedicated sensor for it…

have a look at this post

happy .yaml hunting! :slight_smile:

1 Like

you legend!

[SOLVED] See below.

Is there any way to control the sizing of the xaxis? As you can see below, the column charts are very thin. And they started in the middle.

image

type: custom:config-template-card
variables:
  - states['sensor.helper_electricity_consumption_this_month_normal'].state
entities:
  - sensor.time
  - sensor.helper_electricity_consumption_this_month_normal
  - sensor.helper_electricity_consumption_this_month_off_peak
card:
  type: custom:apexcharts-card
  header:
    show: true
    title: Consumption This Month (kWh)
    show_states: true
    colorize_states: true
  card_mod:
    style: |
      ha-card {
        font-size: 11px;
      }
  graph_span: 31d
  span:
    start: month
  all_series_config:
    unit: ' '
    show:
      legend_value: false
      datalabels: false
    float_precision: 2
    group_by:
      func: last
      duration: 1d
  stacked: true
  series:
    - entity: sensor.helper_electricity_consumption_this_month_normal
      name: Normal
      show:
        in_chart: false
    - entity: sensor.helper_electricity_consumption_this_month_off_peak
      name: Off peak
      show:
        in_chart: false
    - entity: sensor.helper_electricity_consumption_normal
      type: column
      name: Normal
      color: var(--chart-color-electricity-normal)
      show:
        in_header: false
    - entity: sensor.helper_electricity_consumption_off_peak
      type: column
      name: Off peak
      color: var(--chart-color-electricity-off-peak)
      show:
        in_header: false
    - entity: sensor.helper_electricity_consumption_this_month
      name: Total
      color: '#FFFFFF'
      show:
        in_chart: false
        in_header: true
    - entity: sensor.electricity_price_plafond
      name: Price Plafond
      color: var(--chart-color-price-plafond)
      show:
        in_chart: false
        in_header: true
    - entity: sensor.electricity_price_plafond_left_this_month
      name: Plafond left
      color: var(--chart-color-price-plafond-left)
      show:
        in_chart: false
        in_header: true
  apex_config:
    yaxis:
      forceNiceScale: true
      decimals: 3
      min: 0
      max: |
        EVAL: function(max) { return max }
    xaxis:
      tooltip: false
      labels:
        show: true
        style:
          fontSize: 12px
    tooltip:
      enabled: true
      x:
        format: MMM dd
      'y':
        formatter: |
          EVAL:function(value) {
          if (value == 0) { 
            return "0";
          }
          let text = parseFloat(value).toFixed(3);
          let result = text.replace(".", ".");
          return result;
          }
        title:
          formatter: |
            EVAL: function(seriesName) {
            return "";
            }
      fixed:
        enabled: true
        offsetX: -175
        offsetY: -60
    chart:
      zoom:
        enabled: false
      toolbar:
        show: false
        tools:
          zoom: true
          zoomin: true
          zoomout: true
          pan: true
          reset: true

Just learned how to integrate JavaScript :slight_smile: So, using JavaScript code below, the graph_span is dynamic with at least 7 days, based on the current date.

  graph_span: |-
      ${ var nDay = new Date().getDate();
         if (nDay < 7) {
           nDay = 7
         };
         var nDayStr = String(nDay)+"d";
         nDayStr
      }